diff options
author | Neeraj Garg <neerajkg@broadcom.com> | 2013-11-25 15:01:03 +0530 |
---|---|---|
committer | Riham Haidar <rhaidar@nvidia.com> | 2014-01-24 15:00:37 -0800 |
commit | c0ac4b83e1acb1b8886c78276e9fbf4c0282545c (patch) | |
tree | 75e69034c80606f9cb2a091b433fd5a4c0ea71b3 /drivers/net | |
parent | 00c1fe4eded33b0a470db9771409c0134f926d91 (diff) |
net: wireless: bcmdhd: update driver to version 1.88.55
Bug 1404820
Bug 1402287
Change-Id: I3e54be5870cf4ad1b1d75742e47dfb25485faca9
Signed-off-by: Neeraj Garg <neerajkg@broadcom.com>
Signed-off-by: Om Prakash Singh <omp@nvidia.com>
Reviewed-on: http://git-master/r/329514
(cherry picked from commit 36b4a62ebd491b0305c0c3a651217983c07f2df2)
Reviewed-on: http://git-master/r/335395
Reviewed-by: Mrutyunjay Sawant <msawant@nvidia.com>
Reviewed-on: http://git-master/r/347356
Reviewed-by: Jean Huang <jeanh@nvidia.com>
Tested-by: Jean Huang <jeanh@nvidia.com>
Diffstat (limited to 'drivers/net')
117 files changed, 17232 insertions, 8567 deletions
diff --git a/drivers/net/wireless/bcmdhd/Kconfig b/drivers/net/wireless/bcmdhd/Kconfig index b7cc046e93a7..013cfd445a17 100644 --- a/drivers/net/wireless/bcmdhd/Kconfig +++ b/drivers/net/wireless/bcmdhd/Kconfig @@ -1,6 +1,6 @@ config BCMDHD tristate "Broadcom 43xx wireless cards support" - depends on MMC + depends on MMC && CFG80211 ---help--- This module adds support for wireless adapters based on Broadcom 43xx chipset. @@ -24,20 +24,6 @@ config BCMDHD_NVRAM_PATH ---help--- Path to the calibration file. -config BCMDHD_WEXT - bool "Enable WEXT support" - depends on BCMDHD && CFG80211 = n - select WIRELESS_EXT - select WEXT_PRIV - help - Enables WEXT support - -config BCMDHD_CFG80211 - bool "Enable CFG80211 support" - depends on CFG80211 - help - Enables CFG80211 support - config BCMDHD_HW_OOB bool "Use out of band interrupt" depends on BCMDHD @@ -52,6 +38,13 @@ config BCMDHD_INSMOD_NO_FW_LOAD ---help--- Enable delayes firmware +config BCMDHD_EDP_SUPPORT + bool "BCMDHD EDP Support" + depends on BCMDHD && EDP_FRAMEWORK + ---help--- + Use BCMDHD EDP Support to register the driver to + battery edp manager. + config DHD_USE_STATIC_BUF bool "Enable memory preallocation" depends on BCMDHD @@ -66,35 +59,6 @@ config DHD_USE_SCHED_SCAN ---help--- Use CFG80211 sched scan -config BCMDHD_WIFI_CONTROL_FUNC - bool "Use bcmdhd_wlan device" - depends on BCMDHD - default n - ---help--- - Use this option to get various parameters from architecture specific - bcmdhd_wlan platform device. Say n if unsure. - -config BCMDHD_HW_OOB - bool "Use out of band interrupt" - depends on BCMDHD - default n - ---help--- - Use out of band interrupt for card interrupt and wake on wireless. - -config BCMDHD_INSMOD_NO_FW_LOAD - bool "Enable delayed firmware load" - depends on BCMDHD - default n - ---help--- - Enable delayes firmware - -config BCMDHD_CUSTOM_REGULATORY_DOMAIN - bool "Enable Custom Regulatory Domain" - depends on BCMDHD - default y - ---help--- - Use Custom Regulatory Domain set by driver. - config BCMDHD_DISABLE_P2P_SYSFS_DEVICE_NODE bool "Disable sysfs entry for P2P interfaces" depends on BCMDHD @@ -104,58 +68,3 @@ config BCMDHD_DISABLE_P2P_SYSFS_DEVICE_NODE This is a workaround to prevent management tools from directly managing P2P virtual devices. -config BCMDHD_CLAIM_BCM4325_SDGWB - bool "Claim BCM4325 SDGWB" - depends on BCMDHD - default y - ---help--- - Claim BCM4325 SDGWB - -config BCMDHD_CLAIM_BCM4325 - bool "Claim BCM4325" - depends on BCMDHD - default y - ---help--- - Claim BCM4325 - -config BCMDHD_CLAIM_BCM4319 - bool "Claim BCM4319" - depends on BCMDHD - default y - ---help--- - Claim BCM4319 - -config BCMDHD_CLAIM_BCM4330 - bool "Claim BCM4330" - depends on BCMDHD - default y - ---help--- - Claim BCM4330 - -config BCMDHD_CLAIM_BCM4334 - bool "Claim BCM4334" - depends on BCMDHD - default y - ---help--- - Claim BCM4334 - -config BCMDHD_CLAIM_BCM4324 - bool "Claim BCM4324" - depends on BCMDHD - default y - ---help--- - Claim BCM4324 - -config BCMDHD_CLAIM_BCM43239 - bool "Claim BCM43239" - depends on BCMDHD - default y - ---help--- - Claim BCM43239 - -config BCMDHD_CLAIM_SDIO_CLASS_NONE - bool "Claim SDIO chip with no class" - depends on BCMDHD - default y - ---help--- - Claim SDIO chip with no class diff --git a/drivers/net/wireless/bcmdhd/Makefile b/drivers/net/wireless/bcmdhd/Makefile index 914f045d9f75..cd8bb72ad61f 100644 --- a/drivers/net/wireless/bcmdhd/Makefile +++ b/drivers/net/wireless/bcmdhd/Makefile @@ -1,89 +1,80 @@ # bcmdhd -DHDCFLAGS = -Wall -Wstrict-prototypes -Dlinux -DBCMDRIVER \ + +DHDCFLAGS = -Wall -Wstrict-prototypes -Dlinux -DBCMDRIVER \ -DBCMDONGLEHOST -DUNRELEASEDCHIP -DBCMDMA32 -DBCMFILEIMAGE \ -DDHDTHREAD -DDHD_DEBUG -DSDTEST -DBDC -DTOE \ -DDHD_BCMEVENTS -DSHOW_EVENTS -DPROP_TXSTATUS -DBCMDBG \ - -DCUSTOMER_HW2 -DUSE_KTHREAD_API \ + -DCUSTOMER_HW2 \ -DMMC_SDIO_ABORT -DBCMSDIO -DBCMLXSDMMC -DBCMPLATFORM_BUS -DWLP2P \ -DWIFI_ACT_FRAME -DARP_OFFLOAD_SUPPORT \ -DKEEP_ALIVE -DGET_CUSTOM_MAC_ENABLE -DPKT_FILTER_SUPPORT \ - -DEMBEDDED_PLATFORM -DPNO_SUPPORT \ + -DEMBEDDED_PLATFORM -DPNO_SUPPORT \ -DDHD_USE_IDLECOUNT -DSET_RANDOM_MAC_SOFTAP -DROAM_ENABLE -DVSDB \ - -DWL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST -DSDIO_CRC_ERROR_FIX \ - -DESCAN_RESULT_PATCH -DHT40_GO -DPASS_ARP_PACKET -DSUPPORT_PM2_ONLY \ - -DCUSTOM_SDIO_F2_BLKSIZE=128 -DSET_LOW_LATENCY \ - -DDHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT \ + -DWL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST \ + -DESCAN_RESULT_PATCH -DHT40_GO -DPASS_ARP_PACKET \ + -DDHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT -DSUPPORT_PM2_ONLY \ + -DMIRACAST_AMPDU_SIZE=8 \ -Idrivers/net/wireless/bcmdhd -Idrivers/net/wireless/bcmdhd/include -# for supporting different type of bcm943341_wbfgn_x board. -DHDCFLAGS += -DNV_BCM943341_WBFGN_MULTI_MODULE_SUPPORT - -ifeq ($(CONFIG_BCMDHD_WIFI_CONTROL_FUNC), y) -DHDCFLAGS += -DCONFIG_WIFI_CONTROL_FUNC -endif -ifeq ($(CONFIG_BLUEDROID_PM),y) -DHDCFLAGS += -DENABLE_WiFI_BT_TURN_ON_SYNC -endif -#ifeq ($(CONFIG_BCM4334),y) -#DHDCFLAGS += -DPROP_TXSTATUS_VSDB -#DHDCFLAGS += -DCUSTOM_GLOM_SETTING=5 -#endif +DHDCFLAGS += -DWL_CFG80211 -DWL_CFG80211_STA_EVENT +# for < K3.8 +DHDCFLAGS += -DWL_ENABLE_P2P_IF -DWL_IFACE_COMB_NUM_CHANNELS +# for >= K3.8 +#DHDCFLAGS += -DWL_CFG80211_P2P_DEV_IF -DWL_IFACE_COMB_NUM_CHANNELS -#ifeq ($(CONFIG_BCM43341),y) -# for supporting different type of bcm943341_wbfgn_x board on NV reference design. -#DHDCFLAGS += -DNV_BCM943341_WBFGN_MULTI_MODULE_SUPPORT -#endif - -#ifeq ($(CONFIG_BCM43241),y) -DHDCFLAGS += -DAMPDU_HOSTREORDER -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 += -DQUEUE_BW -#DHDCFLAGS += -DVSDB_BW_ALLOCATE_ENABLE -DHDCFLAGS += -DP2P_DISCOVERY_WAR -DHDCFLAGS += -DSYSFS_IDLETIME -#DHDCFLAGS += -DRSSI_OFFSET=5 -#endif - -## Set dhd_dpd_thread priority to MAX to avoid starvation +DHDCFLAGS += -DDEBUGFS_CFG80211 +DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0 DHDCFLAGS += -DCUSTOM_DPC_PRIO_SETTING=99 +DHDCFLAGS += -DIOCTL_RESP_TIMEOUT=5000 +DHDCFLAGS += -DRXFRAME_THREAD +DHDCFLAGS += -DDHDTCPACK_SUPPRESS +DHDCFALGS += -DCONFIG_WIFI_CONTROL_FUNC ifeq ($(CONFIG_BCMDHD_HW_OOB),y) -DHDCFLAGS += -DHW_OOB -DOOB_INTR_ONLY + DHDCFLAGS += -DHW_OOB -DOOB_INTR_ONLY else -DHDCFLAGS += -DSDIO_ISR_THREAD + DHDCFLAGS += -DSDIO_ISR_THREAD endif ifeq ($(CONFIG_BCMDHD_INSMOD_NO_FW_LOAD),y) -DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD + DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD endif +ifeq ($(CONFIG_BCMDHD_EDP_SUPPORT),y) +DHDCFLAGS += -DWIFIEDP +endif ifneq ($(CONFIG_DHD_USE_SCHED_SCAN),) -DHDCFLAGS += -DWL_SCHED_SCAN + DHDCFLAGS += -DWL_SCHED_SCAN endif -DHDOFILES = aiutils.o bcmsdh_sdmmc_linux.o dhd_linux.o siutils.o bcmutils.o \ - dhd_linux_sched.o dhd_sdio.o bcmwifi_channels.o bcmevent.o hndpmu.o \ - bcmsdh.o dhd_cdc.o bcmsdh_linux.o dhd_common.o linux_osl.o \ - bcmsdh_sdmmc.o dhd_custom_gpio.o sbutils.o wldev_common.o wl_android.o +ifeq ($(CONFIG_BCMDHD),y) + DHDCFLAGS += -DBCM43241_CHIP + DHDCFLAGS += -DSDIO_CRC_ERROR_FIX + DHDCFLAGS += -DCUSTOM_SDIO_F2_BLKSIZE=128 + DHDCFLAGS += -DCUSTOM_ROAM_TRIGGER_SETTING=-65 + DHDCFLAGS += -DCUSTOM_ROAM_DELTA_SETTING=15 + DHDCFLAGS += -DCUSTOM_KEEP_ALIVE_SETTING=28000 + DHDCFLAGS += -DVSDB_BW_ALLOCATE_ENABLE + DHDCFLAGS += -DQMONITOR + DHDCFLAGS += -DP2P_DISCOVERY_WAR +endif -obj-$(CONFIG_BCMDHD) += bcmdhd.o -bcmdhd-objs += $(DHDOFILES) +DHDOFILES = bcmsdh.o bcmsdh_linux.o bcmsdh_sdmmc.o bcmsdh_sdmmc_linux.o \ + dhd_cdc.o dhd_cfg80211.o dhd_common.o dhd_custom_gpio.o dhd_ip.o \ + dhd_linux.o dhd_linux_sched.o dhd_pno.o dhd_sdio.o dhd_wlfc.o \ + aiutils.o bcmevent.o bcmutils.o bcmwifi_channels.o hndpmu.o \ + linux_osl.o sbutils.o siutils.o wldev_common.o wl_android.o \ + wl_cfg80211.o wl_cfgp2p.o wl_linux_mon.o -ifeq ($(CONFIG_BCMDHD_WEXT),y) -bcmdhd-objs += wl_iw.o -DHDCFLAGS += -DSOFTAP -DWL_WIRELESS_EXT -DUSE_IW +ifneq ($(findstring QMONITOR, $(DHDCFLAGS)),) + DHDOFILES += dhd_qmon.o endif -ifneq ($(CONFIG_CFG80211),) -bcmdhd-objs += wl_cfg80211.o wl_cfgp2p.o wl_linux_mon.o dhd_cfg80211.o -DHDCFLAGS += -DWL_CFG80211 -DWL_CFG80211_STA_EVENT -DWL_ENABLE_P2P_IF -endif +obj-$(CONFIG_BCMDHD) += bcmdhd.o +bcmdhd-objs += $(DHDOFILES) EXTRA_CFLAGS = $(DHDCFLAGS) ifeq ($(CONFIG_BCMDHD),m) -EXTRA_LDFLAGS += --strip-debug + EXTRA_LDFLAGS += --strip-debug endif diff --git a/drivers/net/wireless/bcmdhd/aiutils.c b/drivers/net/wireless/bcmdhd/aiutils.c index 904d4c3ad55d..c96a97c05151 100644..100755 --- a/drivers/net/wireless/bcmdhd/aiutils.c +++ b/drivers/net/wireless/bcmdhd/aiutils.c @@ -2,7 +2,7 @@ * Misc utility routines for accessing chip-specific features * of the SiliconBackplane-based Broadcom chips. * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -22,7 +22,7 @@ * 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: aiutils.c 347614 2012-07-27 10:24:51Z $ + * $Id: aiutils.c 385510 2013-02-15 21:02:07Z $ */ #include <bcm_cfg.h> #include <typedefs.h> @@ -38,6 +38,7 @@ #define BCM47162_DMP() (0) #define BCM5357_DMP() (0) +#define BCM4707_DMP() (0) #define remap_coreid(sih, coreid) (coreid) #define remap_corerev(sih, corerev) (corerev) @@ -207,7 +208,7 @@ ai_scan(si_t *sih, void *regs, uint devid) sii->oob_router = addrl; } } - if (cid != GMAC_COMMON_4706_CORE_ID) + if (cid != GMAC_COMMON_4706_CORE_ID && cid != NS_CCB_CORE_ID) continue; } @@ -249,10 +250,10 @@ ai_scan(si_t *sih, void *regs, uint devid) "0x%x\n", addrh, sizeh, sizel)); SI_ERROR(("First Slave ASD for" "core 0x%04x malformed " - "(0x%08x)\n", cid, asd)); - goto error; + "(0x%08x)\n", cid, asd)); + goto error; + } } - } } while (1); } sii->coresba[idx] = addrl; @@ -365,7 +366,7 @@ ai_setcoreidx(si_t *sih, uint coreidx) ASSERT(GOODREGS(sii->regs[coreidx])); } sii->curmap = regs = sii->regs[coreidx]; - if (!sii->wrappers[coreidx]) { + if (!sii->wrappers[coreidx] && (wrap != 0)) { sii->wrappers[coreidx] = REG_MAP(wrap, SI_CORE_SIZE); ASSERT(GOODREGS(sii->wrappers[coreidx])); } @@ -541,11 +542,41 @@ ai_flag(si_t *sih) 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; + } ai = sii->curwrap; return (R_REG(sii->osh, &ai->oobselouta30) & 0x1f); } +uint +ai_flag_alt(si_t *sih) +{ + si_info_t *sii; + aidmp_t *ai; + + sii = SI_INFO(sih); + if (BCM47162_DMP()) { + SI_ERROR(("%s: Attempting to read MIPS DMP registers on 47162a0", __FUNCTION__)); + return sii->curidx; + } + 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; + } + 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) { @@ -724,15 +755,15 @@ ai_core_disable(si_t *sih, uint32 bits) /* this is in big hammer path, so don't call wl_reinit in this case... */ } - W_REG(sii->osh, &ai->ioctrl, bits); - dummy = R_REG(sii->osh, &ai->ioctrl); - BCM_REFERENCE(dummy); - OSL_DELAY(10); - 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 @@ -793,6 +824,11 @@ ai_core_cflags_wo(si_t *sih, uint32 mask, uint32 val) __FUNCTION__)); return; } + if (BCM4707_DMP()) { + SI_ERROR(("%s: Accessing CHIPCOMMONB DMP register (ioctrl) on 4707\n", + __FUNCTION__)); + return; + } ASSERT(GOODREGS(sii->curwrap)); ai = sii->curwrap; @@ -823,6 +859,11 @@ ai_core_cflags(si_t *sih, uint32 mask, uint32 val) __FUNCTION__)); return 0; } + if (BCM4707_DMP()) { + SI_ERROR(("%s: Accessing CHIPCOMMONB DMP register (ioctrl) on 4707\n", + __FUNCTION__)); + return 0; + } ASSERT(GOODREGS(sii->curwrap)); ai = sii->curwrap; @@ -855,6 +896,11 @@ ai_core_sflags(si_t *sih, uint32 mask, uint32 val) __FUNCTION__)); return 0; } + if (BCM4707_DMP()) { + SI_ERROR(("%s: Accessing CHIPCOMMONB DMP register (ioctrl) on 4707\n", + __FUNCTION__)); + return 0; + } ASSERT(GOODREGS(sii->curwrap)); ai = sii->curwrap; diff --git a/drivers/net/wireless/bcmdhd/bcmevent.c b/drivers/net/wireless/bcmdhd/bcmevent.c index c0067d13e099..e66cc1a54bdf 100644..100755 --- a/drivers/net/wireless/bcmdhd/bcmevent.c +++ b/drivers/net/wireless/bcmdhd/bcmevent.c @@ -1,7 +1,7 @@ /* * bcmevent read-only data shared by kernel or app layers * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -20,7 +20,7 @@ * 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: bcmevent.c 370587 2012-11-22 09:32:38Z $ + * $Id: bcmevent.c 431563 2013-10-24 01:50:16Z $ */ #include <typedefs.h> @@ -29,7 +29,7 @@ #include <proto/bcmeth.h> #include <proto/bcmevent.h> -#if WLC_E_LAST != 107 +#if WLC_E_LAST != 130 #error "You need to add an entry to bcmevent_names[] for the new event" #endif @@ -82,9 +82,6 @@ const bcmevent_name_t bcmevent_names[] = { { WLC_E_UNICAST_DECODE_ERROR, "UNICAST_DECODE_ERROR" }, { WLC_E_MULTICAST_DECODE_ERROR, "MULTICAST_DECODE_ERROR" }, { WLC_E_TRACE, "TRACE" }, -#ifdef WLBTAMP - { WLC_E_BTA_HCI_EVENT, "BTA_HCI_EVENT" }, -#endif { WLC_E_IF, "IF" }, #ifdef WLP2P { WLC_E_P2P_DISC_LISTEN_COMPLETE, "WLC_E_P2P_DISC_LISTEN_COMPLETE" }, @@ -97,7 +94,7 @@ const bcmevent_name_t bcmevent_names[] = { { WLC_E_ACTION_FRAME_RX, "ACTION_FRAME_RX" }, { WLC_E_ACTION_FRAME_COMPLETE, "ACTION_FRAME_COMPLETE" }, #endif -#if 0 && (NDISVER >= 0x0620) +#if 0 && (0>= 0x0620) { WLC_E_PRE_ASSOC_IND, "ASSOC_RECV" }, { WLC_E_PRE_REASSOC_IND, "REASSOC_RECV" }, { WLC_E_CHANNEL_ADOPTED, "CHANNEL_ADOPTED" }, @@ -108,6 +105,7 @@ const bcmevent_name_t bcmevent_names[] = { { WLC_E_REASSOC_IND_NDIS, "REASSOC_IND_NDIS"}, { WLC_E_ACTION_FRAME_RX_NDIS, "WLC_E_ACTION_FRAME_RX_NDIS" }, { WLC_E_AUTH_REQ, "WLC_E_AUTH_REQ" }, + { WLC_E_IBSS_COALESCE, "IBSS COALESCE" }, #endif { WLC_E_ESCAN_RESULT, "WLC_E_ESCAN_RESULT" }, { WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE, "WLC_E_AF_OFF_CHAN_COMPLETE" }, @@ -138,9 +136,23 @@ const bcmevent_name_t bcmevent_names[] = { #ifdef WLTDLS { WLC_E_TDLS_PEER_EVENT, "TDLS_PEER_EVENT" }, #endif /* WLTDLS */ + { WLC_E_NATIVE, "NATIVE" }, +#ifdef WLPKTDLYSTAT + { WLC_E_PKTDELAY_IND, "PKTDELAY_IND" }, +#endif /* WLPKTDLYSTAT */ { WLC_E_SERVICE_FOUND, "SERVICE_FOUND" }, + { WLC_E_GAS_FRAGMENT_RX, "GAS_FRAGMENT_RX" }, + { WLC_E_GAS_COMPLETE, "GAS_COMPLETE" }, { WLC_E_P2PO_ADD_DEVICE, "P2PO_DEV_FOUND" }, { WLC_E_P2PO_DEL_DEVICE, "P2PO_DEV_LOST" }, +#ifdef WLWNM + { WLC_E_WNM_STA_SLEEP, "WMM_STA_SLEEP" }, +#endif /* WLWNM */ +#if defined(WL_PROXDETECT) + { WLC_E_PROXD, "WLC_E_PROXD" }, +#endif + { WLC_E_CCA_CHAN_QUAL, "CCA_BASED_CHANNEL_QUALITY" }, + { WLC_E_CCX_S69_RESP_RX, "CCX_S69_RESPONSE"}, }; const int bcmevent_names_size = ARRAYSIZE(bcmevent_names); diff --git a/drivers/net/wireless/bcmdhd/bcmsdh.c b/drivers/net/wireless/bcmdhd/bcmsdh.c index de4902fec4db..b2ffb18d64e1 100644..100755 --- a/drivers/net/wireless/bcmdhd/bcmsdh.c +++ b/drivers/net/wireless/bcmdhd/bcmsdh.c @@ -2,7 +2,7 @@ * BCMSDH interface glue * implement bcmsdh API for SDIOH driver * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -22,7 +22,7 @@ * 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: bcmsdh.c 373330 2012-12-07 04:46:17Z $ + * $Id: bcmsdh.c 373331 2012-12-07 04:46:22Z $ */ /** @@ -728,10 +728,10 @@ bcmsdh_gpioout(void *sdh, uint32 gpio, bool enab) #ifdef BCMSDIOH_TXGLOM void -bcmsdh_glom_post(void *sdh, uint8 *frame, uint len) +bcmsdh_glom_post(void *sdh, uint8 *frame, void *pkt, uint len) { bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; - sdioh_glom_post(bcmsdh->sdioh, frame, len); + sdioh_glom_post(bcmsdh->sdioh, frame, pkt, len); } void diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_linux.c b/drivers/net/wireless/bcmdhd/bcmsdh_linux.c index f44f84d15419..95691d9c58d4 100644..100755 --- a/drivers/net/wireless/bcmdhd/bcmsdh_linux.c +++ b/drivers/net/wireless/bcmdhd/bcmsdh_linux.c @@ -1,7 +1,7 @@ /* * SDIO access interface for drivers - linux specific (pci only) * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -21,7 +21,7 @@ * 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: bcmsdh_linux.c 384890 2013-02-13 13:38:48Z $ + * $Id: bcmsdh_linux.c 414953 2013-07-26 17:36:27Z $ */ /** @@ -35,7 +35,6 @@ #include <linux/pci.h> #include <linux/completion.h> -#include <linux/mmc/sdio_func.h> #include <osl.h> #include <pcicfg.h> @@ -50,7 +49,6 @@ extern void dhdsdio_isr(void * args); #include <dhd.h> #endif - /** * SDIO Host Controller info */ @@ -77,6 +75,8 @@ struct bcmsdh_hc { }; static bcmsdh_hc_t *sdhcinfo = NULL; +struct device *pm_dev; + /* driver info, initialized when bcmsdh_register is called */ static bcmsdh_driver_t drvinfo = {NULL, NULL}; @@ -136,28 +136,27 @@ bcmsdh_chipmatch(uint16 vendor, uint16 device) #if defined(BCMPLATFORM_BUS) #if defined(BCMLXSDMMC) /* forward declarations */ -int bcmsdh_probe_bcmdhd(struct device *dev); -int bcmsdh_remove_bcmdhd(struct device *dev); +int bcmsdh_probe(struct device *dev); +int bcmsdh_remove(struct device *dev); -EXPORT_SYMBOL(bcmsdh_probe_bcmdhd); -EXPORT_SYMBOL(bcmsdh_remove_bcmdhd); +EXPORT_SYMBOL(bcmsdh_probe); +EXPORT_SYMBOL(bcmsdh_remove); #else /* forward declarations */ -static int __devinit bcmsdh_probe_bcmdhd(struct device *dev); -static int __devexit bcmsdh_remove_bcmdhd(struct device *dev); +static int __devinit bcmsdh_probe(struct device *dev); +static int __devexit bcmsdh_remove(struct device *dev); #endif #if !defined(BCMLXSDMMC) static #endif -int bcmsdh_probe_bcmdhd(struct device *dev) +int bcmsdh_probe(struct device *dev) { osl_t *osh = NULL; bcmsdh_hc_t *sdhc = NULL, *sdhc_org = sdhcinfo; ulong regs = 0; bcmsdh_info_t *sdh = NULL; - struct sdio_func *func = container_of(dev, struct sdio_func, dev); #if !defined(BCMLXSDMMC) && defined(BCMPLATFORM_BUS) struct platform_device *pdev; struct resource *r; @@ -170,7 +169,7 @@ int bcmsdh_probe_bcmdhd(struct device *dev) pdev = to_platform_device(dev); r = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq = platform_get_irq(pdev, 0); - if (!r || irq == NO_IRQ) + if (!r || irq < 0) return -ENXIO; #endif @@ -186,7 +185,7 @@ int bcmsdh_probe_bcmdhd(struct device *dev) irq = dhd_customer_oob_irq_map(&irq_flags); if (irq < 0) { SDLX_MSG(("%s: Host irq is not defined\n", __FUNCTION__)); - return 1; + goto err; } #endif /* allocate SDIO Host Controller state info */ @@ -231,13 +230,17 @@ int bcmsdh_probe_bcmdhd(struct device *dev) sdhc->next = sdhcinfo; sdhcinfo = sdhc; +#if !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) + if (!device_init_wakeup(dev, 1)) + pm_dev = dev; +#endif /* !CONFIG_HAS_WAKELOCK */ /* Read the vendor/device ID from the CIS */ vendevid = bcmsdh_query_device(sdh); /* try to attach to the target device */ if (!(sdhc->ch = drvinfo.attach((vendevid >> 16), - func->device, 0, 0, 0, 0, - (void *)regs, NULL, sdh, dev))) { + (vendevid & 0xFFFF), 0, 0, 0, 0, + (void *)regs, NULL, sdh, dev))) { SDLX_MSG(("%s: device attach failed\n", __FUNCTION__)); goto err; } @@ -260,13 +263,12 @@ err: #if !defined(BCMLXSDMMC) static #endif -int bcmsdh_remove_bcmdhd(struct device *dev) +int bcmsdh_remove(struct device *dev) { bcmsdh_hc_t *sdhc, *prev; osl_t *osh; int sdhcinfo_null = false; - /* find the SDIO Host Controller state for this pdev and take it out from the list */ for (sdhc = sdhcinfo, prev = NULL; sdhc; sdhc = sdhc->next) { if (sdhc->dev == (void *)dev) { @@ -288,9 +290,16 @@ int bcmsdh_remove_bcmdhd(struct device *dev) return 0; } + /* detach ch & sdhc if dev is valid */ drvinfo.detach(sdhc->ch); bcmsdh_detach(sdhc->osh, sdhc->sdh); - /* detach ch & sdhc if dev is valid */ + +#if !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) + if (pm_dev) { + device_init_wakeup(pm_dev, 0); + pm_dev = NULL; + } +#endif /* !CONFIG_HAS_WAKELOCK */ if (sdhcinfo_null == true) sdhcinfo = NULL; @@ -419,6 +428,10 @@ bcmsdh_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* match this pci device with what we support */ /* we can't solely rely on this to believe it is our SDIO Host Controller! */ if (!bcmsdh_chipmatch(pdev->vendor, pdev->device)) { + if (pdev->vendor == VENDOR_BROADCOM) { + SDLX_MSG(("%s: Unknown Broadcom device (vendor: %#x, device: %#x).\n", + __FUNCTION__, pdev->vendor, pdev->device)); + } return -ENODEV; } @@ -722,6 +735,10 @@ module_param(sd_f2_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); #endif #ifdef BCMSDIOH_TXGLOM diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c index d638b82a2a90..1f9c08b0b4fb 100644..100755 --- a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c +++ b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c @@ -1,7 +1,7 @@ /* * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -21,7 +21,7 @@ * 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: bcmsdh_sdmmc.c 379078 2013-01-16 00:41:36Z $ + * $Id: bcmsdh_sdmmc.c 427054 2013-10-02 03:38:35Z $ */ #include <typedefs.h> @@ -77,6 +77,18 @@ 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; + +#ifdef BCMSDIOH_TXGLOM +#ifndef CUSTOM_TXGLOM +#define CUSTOM_TXGLOM 0 +#endif +uint sd_txglom = CUSTOM_TXGLOM; +#endif /* BCMSDIOH_TXGLOM */ + +#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); @@ -155,7 +167,7 @@ sdioh_attach(osl_t *osh, void *bar0, uint irq) sd->sd_blockmode = TRUE; sd->use_client_ints = TRUE; sd->client_block_size[0] = 64; - sd->use_rxchain = FALSE; + sd->use_rxchain = CUSTOM_RXCHAIN; gInstance->sd = sd; @@ -165,12 +177,14 @@ sdioh_attach(osl_t *osh, void *bar0, uint irq) sd->client_block_size[1] = 64; err_ret = sdio_set_block_size(gInstance->func[1], 64); + /* Release host controller F1 */ + sdio_release_host(gInstance->func[1]); if (err_ret) { sd_err(("bcmsdh_sdmmc: Failed to set F1 blocksize\n")); + MFREE(sd->osh, sd, sizeof(sdioh_info_t)); + return NULL; } - /* Release host controller F1 */ - sdio_release_host(gInstance->func[1]); } else { sd_err(("%s:gInstance->func[1] is null\n", __FUNCTION__)); MFREE(sd->osh, sd, sizeof(sdioh_info_t)); @@ -183,13 +197,15 @@ sdioh_attach(osl_t *osh, void *bar0, uint irq) sd->client_block_size[2] = sd_f2_blocksize; err_ret = sdio_set_block_size(gInstance->func[2], sd_f2_blocksize); + /* Release host controller F2 */ + sdio_release_host(gInstance->func[2]); if (err_ret) { sd_err(("bcmsdh_sdmmc: Failed to set F2 blocksize to %d\n", sd_f2_blocksize)); + MFREE(sd->osh, sd, sizeof(sdioh_info_t)); + return NULL; } - /* Release host controller F2 */ - sdio_release_host(gInstance->func[2]); } else { sd_err(("%s:gInstance->func[2] is null\n", __FUNCTION__)); MFREE(sd->osh, sd, sizeof(sdioh_info_t)); @@ -791,10 +807,11 @@ sdioh_cis_read(sdioh_info_t *sd, uint func, uint8 *cisd, uint32 length) extern SDIOH_API_RC sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *byte) { - int err_ret; + int err_ret = 0; #if defined(MMC_SDIO_ABORT) int sdio_abort_retry = MMC_SDIO_ABORT_RETRY_LIMIT; #endif + sd_info(("%s: rw=%d, func=%d, addr=0x%05x\n", __FUNCTION__, rw, func, regaddr)); DHD_PM_RESUME_WAIT(sdioh_request_byte_wait); @@ -828,18 +845,14 @@ sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *by #if defined(MMC_SDIO_ABORT) /* to allow abort command through F1 */ else if (regaddr == SDIOD_CCCR_IOABORT) { - /* Because of SDIO3.0 host issue on Manta, - * sometimes the abort fails. - * Retrying again will fix this issue. - */ while (sdio_abort_retry--) { if (gInstance->func[func]) { sdio_claim_host(gInstance->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 - */ + * 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(gInstance->func[func], *byte, regaddr, &err_ret); sdio_release_host(gInstance->func[func]); @@ -882,8 +895,11 @@ sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *by } if (err_ret) { - 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 ((regaddr == 0x1001F) && (err_ret == -110)) { + } 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)); + } } return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL); @@ -911,7 +927,7 @@ sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func, uint add /* Claim host controller */ sdio_claim_host(gInstance->func[func]); - if(rw) { /* CMD53 Write */ + if(rw) { /* CMD52 Write */ if (nbytes == 4) { sdio_writel(gInstance->func[func], *word, addr, &err_ret); } else if (nbytes == 2) { @@ -939,10 +955,10 @@ sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func, uint add if (gInstance->func[0]) { sdio_claim_host(gInstance->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 - */ + * 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(gInstance->func[0], func, SDIOD_CCCR_IOABORT, &err_ret); sdio_release_host(gInstance->func[0]); @@ -953,14 +969,103 @@ sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func, uint add if (err_ret) #endif /* MMC_SDIO_ABORT */ { - sd_err(("bcmsdh_sdmmc: Failed to %s word, Err: 0x%08x\n", - rw ? "Write" : "Read", err_ret)); + sd_err(("bcmsdh_sdmmc: Failed to %s word, Err: 0x%08x", + rw ? "Write" : "Read", err_ret)); } } return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL); } +#ifdef BCMSDIOH_TXGLOM +void +sdioh_glom_post(sdioh_info_t *sd, uint8 *frame, void *pkt, uint len) +{ + void *phead = sd->glom_info.glom_pkt_head; + void *ptail = sd->glom_info.glom_pkt_tail; + + BCM_REFERENCE(frame); + + ASSERT(!PKTLINK(pkt)); + if (!phead) { + ASSERT(!phead); + sd->glom_info.glom_pkt_head = sd->glom_info.glom_pkt_tail = pkt; + } + else { + ASSERT(ptail); + PKTSETNEXT(sd->osh, ptail, pkt); + sd->glom_info.glom_pkt_tail = pkt; + } + sd->glom_info.count++; +} + +void +sdioh_glom_clear(sdioh_info_t *sd) +{ + void *pnow, *pnext; + + pnext = sd->glom_info.glom_pkt_head; + + if (!pnext) { + sd_err(("sdioh_glom_clear: no first packet to clear!\n")); + return; + } + + while (pnext) { + pnow = pnext; + pnext = PKTNEXT(sd->osh, pnow); + PKTSETNEXT(sd->osh, pnow, NULL); + sd->glom_info.count--; + } + + sd->glom_info.glom_pkt_head = NULL; + sd->glom_info.glom_pkt_tail = NULL; + if (sd->glom_info.count != 0) { + sd_err(("sdioh_glom_clear: glom count mismatch!\n")); + sd->glom_info.count = 0; + } +} + +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); +} + +bool +sdioh_glom_enabled(void) +{ + return sd_txglom; +} +#endif /* BCMSDIOH_TXGLOM */ + +static INLINE int sdioh_request_packet_align(uint pkt_len, uint write, uint func, int blk_size) +{ + /* Align Patch */ + if (!write || pkt_len < 32) + pkt_len = (pkt_len + 3) & 0xFFFFFFFC; + else if ((pkt_len > blk_size) && (pkt_len % blk_size)) { + if (func == SDIO_FUNC_2) { + sd_err(("%s: [%s] dhd_sdio must align %d bytes" + " packet larger than a %d bytes blk size by a blk size\n", + __FUNCTION__, write ? "W" : "R", pkt_len, blk_size)); + } + pkt_len += blk_size - (pkt_len % blk_size); + } +#ifdef CONFIG_MMC_MSM7X00A + if ((pkt_len % 64) == 32) { + sd_err(("%s: Rounding up TX packet +=32\n", __FUNCTION__)); + pkt_len += 32; + } +#endif /* CONFIG_MMC_MSM7X00A */ + return pkt_len; +} + static SDIOH_API_RC sdioh_request_packet(sdioh_info_t *sd, uint fix_inc, uint write, uint func, uint addr, void *pkt) @@ -968,13 +1073,20 @@ sdioh_request_packet(sdioh_info_t *sd, uint fix_inc, uint write, uint func, bool fifo = (fix_inc == SDIOH_DATA_FIX); uint32 SGCount = 0; int err_ret = 0; - void *pnext, *pprev; + void *pnext; uint ttl_len, dma_len, lft_len, xfred_len, pkt_len; uint blk_num; int blk_size; struct mmc_request mmc_req; struct mmc_command mmc_cmd; struct mmc_data mmc_dat; +#ifdef BCMSDIOH_TXGLOM + uint8 *localbuf = NULL; + uint local_plen = 0; + bool need_txglom = write && sdioh_glom_enabled() && + (pkt == sd->glom_info.glom_pkt_tail) && + (sd->glom_info.glom_pkt_head != sd->glom_info.glom_pkt_tail); +#endif /* BCMSDIOH_TXGLOM */ sd_trace(("%s: Enter\n", __FUNCTION__)); @@ -983,18 +1095,29 @@ sdioh_request_packet(sdioh_info_t *sd, uint fix_inc, uint write, uint func, DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL); ttl_len = xfred_len = 0; +#ifdef BCMSDIOH_TXGLOM + if (need_txglom) { + pkt = sd->glom_info.glom_pkt_head; + } +#endif /* BCMSDIOH_TXGLOM */ + /* at least 4 bytes alignment of skb buff is guaranteed */ for (pnext = pkt; pnext; pnext = PKTNEXT(sd->osh, pnext)) ttl_len += PKTLEN(sd->osh, pnext); blk_size = sd->client_block_size[func]; - if (!sd->use_rxchain || ttl_len <= blk_size) { - blk_num = 0; - dma_len = 0; - } else { + if (((!write && sd->use_rxchain) || +#ifdef BCMSDIOH_TXGLOM + (need_txglom && sd->txglom_mode == SDPCM_TXGLOM_MDESC) || +#endif + 0) && (ttl_len >= blk_size)) { blk_num = ttl_len / blk_size; dma_len = blk_num * blk_size; + } else { + blk_num = 0; + dma_len = 0; } + lft_len = ttl_len - dma_len; sd_trace(("%s: %s %dB to func%d:%08x, %d blks with DMA, %dB leftover\n", @@ -1007,7 +1130,6 @@ sdioh_request_packet(sdioh_info_t *sd, uint fix_inc, uint write, uint func, memset(&mmc_dat, 0, sizeof(struct mmc_data)); /* Set up DMA descriptors */ - pprev = pkt; for (pnext = pkt; pnext && dma_len; pnext = PKTNEXT(sd->osh, pnext)) { @@ -1061,12 +1183,8 @@ sdioh_request_packet(sdioh_info_t *sd, uint fix_inc, uint write, uint func, __FUNCTION__, write ? "write" : "read", err_ret)); - sd_err(("%s:Disabling rxchain and fire it with PIO\n", - __FUNCTION__)); - sd->use_rxchain = FALSE; - pkt = pprev; - lft_len = ttl_len; - } else if (!fifo) { + } + if (!fifo) { addr = addr + ttl_len - lft_len - dma_len; } } @@ -1078,27 +1196,79 @@ sdioh_request_packet(sdioh_info_t *sd, uint fix_inc, uint write, uint func, for (pnext = pkt; pnext; pnext = PKTNEXT(sd->osh, pnext)) { uint8 *buf = (uint8*)PKTDATA(sd->osh, pnext) + xfred_len; + int pad = 0; pkt_len = PKTLEN(sd->osh, pnext); if (0 != xfred_len) { pkt_len -= xfred_len; xfred_len = 0; } +#ifdef BCMSDIOH_TXGLOM + if (need_txglom) { + if (!localbuf) { + uint prev_lft_len = lft_len; + lft_len = sdioh_request_packet_align(lft_len, write, + func, blk_size); + + if (lft_len > prev_lft_len) { + sd_err(("%s: padding is unexpected! lft_len %d," + " prev_lft_len %d %s\n", + __FUNCTION__, lft_len, prev_lft_len, + write ? "Write" : "Read")); + } - /* Align Patch - * read or small packet(ex:BDC header) skip 32 byte align - * otherwise, padding DHD_SDALIGN for performance - */ - if (write == 0 || pkt_len < 32) - pkt_len = (pkt_len + 3) & 0xFFFFFFFC; - else if (pkt_len % blk_size) - pkt_len += blk_size - (pkt_len % blk_size); + localbuf = (uint8 *)MALLOC(sd->osh, lft_len); + if (localbuf == NULL) { + sd_err(("%s: %s TXGLOM: localbuf malloc FAILED\n", + __FUNCTION__, (write) ? "TX" : "RX")); + need_txglom = FALSE; + goto txglomfail; + } + } + bcopy(buf, (localbuf + local_plen), pkt_len); + local_plen += pkt_len; -#ifdef CONFIG_MMC_MSM7X00A - if ((pkt_len % 64) == 32) { - sd_trace(("%s: Rounding up TX packet +=32\n", __FUNCTION__)); - pkt_len += 32; + if (PKTNEXT(sd->osh, pnext)) { + continue; + } + + buf = localbuf; + pkt_len = local_plen; + } + +txglomfail: +#endif /* BCMSDIOH_TXGLOM */ + + if ( +#ifdef BCMSDIOH_TXGLOM + !need_txglom && +#endif + TRUE) { + int align_pkt_len = 0; + align_pkt_len = sdioh_request_packet_align(pkt_len, write, + func, blk_size); + + pad = align_pkt_len - pkt_len; + if (pad > 0) { + if (func == SDIO_FUNC_2) { + sd_err(("%s: padding is unexpected! pkt_len %d," + " PKTLEN %d lft_len %d %s\n", + __FUNCTION__, pkt_len, PKTLEN(sd->osh, pnext), + lft_len, write ? "Write" : "Read")); + } + if (PKTTAILROOM(sd->osh, pkt) < pad) { + sd_info(("%s: insufficient tailroom %d, pad %d," + " lft_len %d pktlen %d, func %d %s\n", + __FUNCTION__, (int)PKTTAILROOM(sd->osh, pkt), + pad, lft_len, PKTLEN(sd->osh, pnext), func, + write ? "W" : "R")); + if (PKTPADTAILROOM(sd->osh, pkt, pad)) { + sd_err(("%s: padding error size %d.\n", + __FUNCTION__, pad)); + return SDIOH_API_RC_FAIL; + } + } + } } -#endif /* CONFIG_MMC_MSM7X00A */ if ((write) && (!fifo)) err_ret = sdio_memcpy_toio( @@ -1134,6 +1304,10 @@ sdioh_request_packet(sdioh_info_t *sd, uint fix_inc, uint write, uint func, } sdio_release_host(gInstance->func[func]); } +#ifdef BCMSDIOH_TXGLOM + if (localbuf) + MFREE(sd->osh, localbuf, lft_len); +#endif /* BCMSDIOH_TXGLOM */ sd_trace(("%s: Exit\n", __FUNCTION__)); return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL); @@ -1153,87 +1327,51 @@ sdioh_request_packet(sdioh_info_t *sd, uint fix_inc, uint write, uint func, */ 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 buflen_u, uint8 *buffer, void *pkt) + uint addr, uint reg_width, uint buflen_u, uint8 *buffer, void *pkt) { SDIOH_API_RC Status; - void *mypkt = NULL; + void *tmppkt; + void *orig_buf = NULL; + uint copylen = 0; sd_trace(("%s: Enter\n", __FUNCTION__)); DHD_PM_RESUME_WAIT(sdioh_request_buffer_wait); DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL); - /* Case 1: we don't have a packet. */ - if (pkt == NULL) { - sd_data(("%s: Creating new %s Packet, len=%d\n", - __FUNCTION__, write ? "TX" : "RX", buflen_u)); -#ifdef CONFIG_DHD_USE_STATIC_BUF - if (!(mypkt = PKTGET_STATIC(sd->osh, buflen_u, write ? TRUE : FALSE))) { -#else - if (!(mypkt = PKTGET(sd->osh, buflen_u, write ? TRUE : FALSE))) { -#endif /* CONFIG_DHD_USE_STATIC_BUF */ - sd_err(("%s: PKTGET failed: len %d\n", - __FUNCTION__, buflen_u)); - return SDIOH_API_RC_FAIL; - } - - /* For a write, copy the buffer data into the packet. */ - if (write) { - bcopy(buffer, PKTDATA(sd->osh, mypkt), buflen_u); - } - - Status = sdioh_request_packet(sd, fix_inc, write, func, addr, mypkt); - - /* For a read, copy the packet data back to the buffer. */ - if (!write) { - bcopy(PKTDATA(sd->osh, mypkt), buffer, buflen_u); - } -#ifdef CONFIG_DHD_USE_STATIC_BUF - PKTFREE_STATIC(sd->osh, mypkt, write ? TRUE : FALSE); -#else - PKTFREE(sd->osh, mypkt, write ? TRUE : FALSE); -#endif /* CONFIG_DHD_USE_STATIC_BUF */ - } else if (((uint32)(PKTDATA(sd->osh, pkt)) & DMA_ALIGN_MASK) != 0) { - /* Case 2: We have a packet, but it is unaligned. */ - /* In this case, we cannot have a chain. */ + if (pkt == NULL) { + /* Case 1: we don't have a packet. */ + orig_buf = buffer; + copylen = buflen_u; + } else if ((ulong)PKTDATA(sd->osh, pkt) & DMA_ALIGN_MASK) { + /* Case 2: We have a packet, but it is unaligned. + * in this case, we cannot have a chain. + */ ASSERT(PKTNEXT(sd->osh, pkt) == NULL); - sd_data(("%s: Creating aligned %s Packet, len=%d\n", - __FUNCTION__, write ? "TX" : "RX", PKTLEN(sd->osh, pkt))); -#ifdef CONFIG_DHD_USE_STATIC_BUF - if (!(mypkt = PKTGET_STATIC(sd->osh, PKTLEN(sd->osh, pkt), write ? TRUE : FALSE))) { -#else - if (!(mypkt = PKTGET(sd->osh, PKTLEN(sd->osh, pkt), write ? TRUE : FALSE))) { -#endif /* CONFIG_DHD_USE_STATIC_BUF */ - sd_err(("%s: PKTGET failed: len %d\n", - __FUNCTION__, PKTLEN(sd->osh, pkt))); + orig_buf = PKTDATA(sd->osh, pkt); + copylen = PKTLEN(sd->osh, pkt); + } + + tmppkt = pkt; + if (copylen) { + tmppkt = PKTGET_STATIC(sd->osh, copylen, write ? TRUE : FALSE); + if (tmppkt == NULL) { + sd_err(("%s: PKTGET failed: len %d\n", __FUNCTION__, copylen)); return SDIOH_API_RC_FAIL; } - /* For a write, copy the buffer data into the packet. */ - if (write) { - bcopy(PKTDATA(sd->osh, pkt), - PKTDATA(sd->osh, mypkt), - PKTLEN(sd->osh, pkt)); - } + if (write) + bcopy(orig_buf, PKTDATA(sd->osh, tmppkt), copylen); + } - Status = sdioh_request_packet(sd, fix_inc, write, func, addr, mypkt); + Status = sdioh_request_packet(sd, fix_inc, write, func, addr, tmppkt); + if (copylen) { /* For a read, copy the packet data back to the buffer. */ - if (!write) { - bcopy(PKTDATA(sd->osh, mypkt), - PKTDATA(sd->osh, pkt), - PKTLEN(sd->osh, mypkt)); - } -#ifdef CONFIG_DHD_USE_STATIC_BUF - PKTFREE_STATIC(sd->osh, mypkt, write ? TRUE : FALSE); -#else - PKTFREE(sd->osh, mypkt, write ? TRUE : FALSE); -#endif /* CONFIG_DHD_USE_STATIC_BUF */ - } else { /* case 3: We have a packet and it is aligned. */ - sd_data(("%s: Aligned %s Packet, direct DMA\n", - __FUNCTION__, write ? "Tx" : "Rx")); - Status = sdioh_request_packet(sd, fix_inc, write, func, addr, pkt); + if (!write) + bcopy(PKTDATA(sd->osh, tmppkt), orig_buf, PKTLEN(sd->osh, tmppkt)); + PKTFREE_STATIC(sd->osh, tmppkt, write ? TRUE : FALSE); } return (Status); @@ -1380,7 +1518,10 @@ sdioh_start(sdioh_info_t *si, int stage) int ret; sdioh_info_t *sd = gInstance->sd; - if (!sd) return (0); + 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 @@ -1397,7 +1538,9 @@ sdioh_start(sdioh_info_t *si, int stage) 2.6.27. The implementation prior to that is buggy, and needs broadcom's patch for it */ - if ((ret = mmc_power_restore_host((gInstance->func[0])->card->host))) { + ret = mmc_power_restore_host((gInstance->func[0])->card->host); + + if (ret) { sd_err(("%s Failed, error = %d\n", __FUNCTION__, ret)); return ret; } @@ -1483,7 +1626,7 @@ sdioh_stop(sdioh_info_t *si) bcmsdh_oob_intr_set(FALSE); #endif /* !defined(OOB_INTR_ONLY) */ if (mmc_power_save_host((gInstance->func[0])->card->host)) - sd_err(("%s card power save fail\n", __FUNCTION__)); + sd_err(("%s card power save fail\n", __func__)); } else sd_err(("%s Failed\n", __FUNCTION__)); diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c index 5e2487dd404f..0970b9d9b7e6 100644..100755 --- a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c +++ b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c @@ -1,7 +1,7 @@ /* * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -21,7 +21,7 @@ * 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: bcmsdh_sdmmc_linux.c 381548 2013-01-28 17:25:38Z $ + * $Id: bcmsdh_sdmmc_linux.c 425711 2013-09-25 06:40:41Z $ */ #include <typedefs.h> @@ -50,6 +50,9 @@ #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) */ @@ -66,6 +69,7 @@ #define SDIO_DEVICE_ID_BROADCOM_43239 43239 #endif /* !defined(SDIO_DEVICE_ID_BROADCOM_43239) */ + #include <bcmsdh_sdmmc.h> #include <dhd_dbg.h> @@ -97,8 +101,8 @@ PBCMSDH_SDMMC_INSTANCE gInstance; /* Maximum number of bcmsdh_sdmmc devices supported by driver */ #define BCMSDH_SDMMC_MAX_DEVICES 1 -extern int bcmsdh_probe_bcmdhd(struct device *dev); -extern int bcmsdh_remove_bcmdhd(struct device *dev); +extern int bcmsdh_probe(struct device *dev); +extern int bcmsdh_remove(struct device *dev); extern volatile bool dhd_mmc_suspend; static int bcmsdh_sdmmc_probe(struct sdio_func *func, @@ -107,6 +111,9 @@ static int bcmsdh_sdmmc_probe(struct sdio_func *func, int ret = 0; static struct sdio_func sdio_func_0; + if (!gInstance) + return -EINVAL; + if (func) { sd_trace(("bcmsdh_sdmmc: %s Enter\n", __FUNCTION__)); sd_trace(("sdio_bcmsdh: func->class=%x\n", func->class)); @@ -120,8 +127,8 @@ static int bcmsdh_sdmmc_probe(struct sdio_func *func, gInstance->func[0] = &sdio_func_0; if(func->device == 0x4) { /* 4318 */ gInstance->func[2] = NULL; - sd_trace(("NIC found, calling bcmsdh_probe_bcmdhd...\n")); - ret = bcmsdh_probe_bcmdhd(&func->dev); + sd_trace(("NIC found, calling bcmsdh_probe...\n")); + ret = bcmsdh_probe(&func->dev); } } @@ -131,12 +138,13 @@ static int bcmsdh_sdmmc_probe(struct sdio_func *func, #ifdef WL_CFG80211 wl_cfg80211_set_parent_dev(&func->dev); #endif - sd_trace(("F2 found, calling bcmsdh_probe_bcmdhd...\n")); - ret = bcmsdh_probe_bcmdhd(&func->dev); - if (ret < 0 && gInstance) + sd_trace(("F2 found, calling bcmsdh_probe...\n")); + ret = bcmsdh_probe(&func->dev); + if (ret < 0) gInstance->func[2] = NULL; + if (mmc_power_save_host(func->card->host)) - sd_err(("%s: card power save fail", __FUNCTION__)); + sd_err(("%s: card power save fail", __func__)); } } else { ret = -ENODEV; @@ -155,8 +163,8 @@ static void bcmsdh_sdmmc_remove(struct sdio_func *func) sd_info(("Function#: 0x%04x\n", func->num)); if (gInstance->func[2]) { - sd_trace(("F2 found, calling bcmsdh_remove_bcmdhd...\n")); - bcmsdh_remove_bcmdhd(&func->dev); + sd_trace(("F2 found, calling bcmsdh_remove...\n")); + bcmsdh_remove(&func->dev); gInstance->func[2] = NULL; } if (func->num == 1) { @@ -169,67 +177,35 @@ static void bcmsdh_sdmmc_remove(struct sdio_func *func) } /* devices we support, null terminated */ -static const struct sdio_device_id bcmsdh_sdmmc_claim_ids[] = { +static const struct sdio_device_id bcmsdh_sdmmc_ids[] = { { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_DEFAULT) }, -#ifdef CONFIG_BCMDHD_CLAIM_BCM4325_SDGWB { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4325_SDGWB) }, -#endif -#ifdef CONFIG_BCMDHD_CLAIM_BCM4325 { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4325) }, -#endif -#ifdef CONFIG_BCMDHD_CLAIM_BCM4319 + { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4329) }, { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4319) }, -#endif -#ifdef CONFIG_BCMDHD_CLAIM_BCM4330 { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4330) }, -#endif -#ifdef CONFIG_BCMDHD_CLAIM_BCM4334 { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4334) }, -#endif -#ifdef CONFIG_BCMDHD_CLAIM_BCM4324 { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4324) }, -#endif -#ifdef CONFIG_BCMDHD_CLAIM_BCM43239 { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_43239) }, -#endif -#ifdef CONFIG_BCMDHD_CLAIM_SDIO_CLASS_NONE - { SDIO_DEVICE_CLASS(SDIO_CLASS_NONE) }, -#endif + { SDIO_DEVICE_CLASS(SDIO_CLASS_NONE) }, { /* end: all zeroes */ }, }; -static const struct sdio_device_id bcmsdh_sdmmc_support_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_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) }, -#ifdef CONFIG_BCMDHD_CLAIM_SDIO_CLASS_NONE - { SDIO_DEVICE_CLASS(SDIO_CLASS_NONE) }, -#endif - { /* end: all zeroes */ }, -}; - -MODULE_DEVICE_TABLE(sdio, bcmsdh_sdmmc_claim_ids); +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) { struct sdio_func *func = dev_to_sdio_func(pdev); mmc_pm_flag_t sdio_flags; - int ret = 0; + int ret; if (func->num != 2) return 0; - sd_trace_hw4(("%s Enter\n", __FUNCTION__)); - + sd_trace(("%s Enter\n", __FUNCTION__)); if (dhd_os_check_wakelock(bcmsdh_get_drvdata())) return -EBUSY; - sdio_flags = sdio_get_host_pm_caps(func); if (!(sdio_flags & MMC_PM_KEEP_POWER)) { @@ -243,46 +219,27 @@ static int bcmsdh_sdmmc_suspend(struct device *pdev) sd_err(("%s: error while trying to keep power\n", __FUNCTION__)); return ret; } - #if defined(OOB_INTR_ONLY) bcmsdh_oob_intr_set(0); -#endif /* defined(OOB_INTR_ONLY) */ - - sdio_flags = sdio_get_host_pm_caps(func); - - if (!(sdio_flags & MMC_PM_KEEP_POWER)) { - sd_err(("can't keep power while host " - "is suspended\n", __FUNCTION__)); - ret = -EINVAL; - goto out; - } - - /* keep power while host suspended */ - ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); - if (ret) { - sd_err(("error while trying to keep power\n", __FUNCTION__)); - goto out; - } - +#endif dhd_mmc_suspend = TRUE; smp_mb(); -out: - return ret; + return 0; } static int bcmsdh_sdmmc_resume(struct device *pdev) { #if defined(OOB_INTR_ONLY) struct sdio_func *func = dev_to_sdio_func(pdev); -#endif /* defined(OOB_INTR_ONLY) */ - sd_trace_hw4(("%s Enter\n", __FUNCTION__)); - +#endif + sd_trace(("%s Enter\n", __FUNCTION__)); dhd_mmc_suspend = FALSE; #if defined(OOB_INTR_ONLY) if ((func->num == 2) && dhd_os_check_if_up(bcmsdh_get_drvdata())) bcmsdh_oob_intr_set(1); -#endif /* (OOB_INTR_ONLY) */ +#endif + smp_mb(); return 0; } @@ -299,6 +256,10 @@ static struct semaphore *notify_semaphore = NULL; static int dummy_probe(struct sdio_func *func, const struct sdio_device_id *id) { + if (func && (func->num != 2)) { + return 0; + } + if (notify_semaphore) up(notify_semaphore); return 0; @@ -312,7 +273,7 @@ static struct sdio_driver dummy_sdmmc_driver = { .probe = dummy_probe, .remove = dummy_remove, .name = "dummy_sdmmc", - .id_table = bcmsdh_sdmmc_support_ids, + .id_table = bcmsdh_sdmmc_ids, }; int sdio_func_reg_notify(void* semaphore) @@ -323,6 +284,7 @@ int sdio_func_reg_notify(void* semaphore) void sdio_func_unreg_notify(void) { + OSL_SLEEP(15); sdio_unregister_driver(&dummy_sdmmc_driver); } @@ -332,7 +294,7 @@ static struct sdio_driver bcmsdh_sdmmc_driver = { .probe = bcmsdh_sdmmc_probe, .remove = bcmsdh_sdmmc_remove, .name = "bcmsdh_sdmmc", - .id_table = bcmsdh_sdmmc_support_ids, + .id_table = bcmsdh_sdmmc_ids, #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM) .drv = { .pm = &bcmsdh_sdmmc_pm_ops, @@ -448,9 +410,9 @@ int sdio_function_init(void) return -ENOMEM; error = sdio_register_driver(&bcmsdh_sdmmc_driver); - if (error && gInstance) { + if (error) { kfree(gInstance); - gInstance = 0; + gInstance = NULL; } return error; @@ -459,6 +421,7 @@ int sdio_function_init(void) /* * module cleanup */ +extern int bcmsdh_remove(struct device *dev); void sdio_function_cleanup(void) { sd_trace(("%s Enter\n", __FUNCTION__)); @@ -466,6 +429,8 @@ void sdio_function_cleanup(void) sdio_unregister_driver(&bcmsdh_sdmmc_driver); - if (gInstance) + if (gInstance) { kfree(gInstance); + gInstance = NULL; + } } diff --git a/drivers/net/wireless/bcmdhd/bcmutils.c b/drivers/net/wireless/bcmdhd/bcmutils.c index 951c57d8a2d8..a991b0cfc59b 100644..100755 --- a/drivers/net/wireless/bcmdhd/bcmutils.c +++ b/drivers/net/wireless/bcmdhd/bcmutils.c @@ -1,7 +1,7 @@ /* * Driver O/S-independent utility routines * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -20,7 +20,7 @@ * 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: bcmutils.c 384898 2013-02-13 14:20:11Z $ + * $Id: bcmutils.c 427979 2013-10-07 08:35:57Z $ */ #include <bcm_cfg.h> @@ -192,7 +192,7 @@ pktsegcnt_war(osl_t *osh, void *p) } uint8 * BCMFASTPATH -pktoffset(osl_t *osh, void *p, uint offset) +pktdataoffset(osl_t *osh, void *p, uint offset) { uint total = pkttotlen(osh, p); uint pkt_off = 0, len = 0; @@ -211,6 +211,25 @@ pktoffset(osl_t *osh, void *p, uint offset) 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; +} + /* * osl multiple-precedence packet queue * hi_prec is always >= the number of the highest non-empty precedence @@ -324,6 +343,44 @@ pktq_pdeq_prev(struct pktq *pq, int prec, void *prev_p) } void * BCMFASTPATH +pktq_pdeq_with_fn(struct pktq *pq, int prec, ifpkt_cb_t fn, int arg) +{ + struct pktq_prec *q; + void *p, *prev = NULL; + + ASSERT(prec >= 0 && prec < pq->num_prec); + + q = &pq->q[prec]; + p = q->head; + + while (p) { + if (fn == NULL || (*fn)(p, arg)) { + break; + } else { + prev = p; + p = PKTLINK(p); + } + } + if (p == NULL) + return NULL; + + if (prev == NULL) { + if ((q->head = PKTLINK(p)) == NULL) + q->tail = NULL; + } else { + PKTSETLINK(prev, PKTLINK(p)); + } + + q->len--; + + pq->len--; + + PKTSETLINK(p, NULL); + + return p; +} + +void * BCMFASTPATH pktq_pdeq_tail(struct pktq *pq, int prec) { struct pktq_prec *q; @@ -654,6 +711,7 @@ pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out) #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 */ @@ -968,6 +1026,22 @@ bcm_ether_atoe(const char *p, struct ether_addr *ea) 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: @@ -1078,7 +1152,7 @@ pktsetprio(void *pkt, bool update_vtag) eh = (struct ether_header *) pktdata; - if (ntoh16(eh->ether_type) == ETHER_TYPE_8021Q) { + if (eh->ether_type == hton16(ETHER_TYPE_8021Q)) { uint16 vlan_tag; int vlan_prio, dscp_prio = 0; @@ -1087,7 +1161,7 @@ pktsetprio(void *pkt, bool update_vtag) vlan_tag = ntoh16(evh->vlan_tag); vlan_prio = (int) (vlan_tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK; - if (ntoh16(evh->ether_type) == ETHER_TYPE_IP) { + if (evh->ether_type == hton16(ETHER_TYPE_IP)) { uint8 *ip_body = pktdata + sizeof(struct ethervlan_header); uint8 tos_tc = IP_TOS46(ip_body); dscp_prio = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT); @@ -1114,10 +1188,32 @@ pktsetprio(void *pkt, bool update_vtag) evh->vlan_tag = hton16(vlan_tag); rc |= PKTPRIO_UPD; } - } else if (ntoh16(eh->ether_type) == ETHER_TYPE_IP) { + } else if (eh->ether_type == hton16(ETHER_TYPE_IP)) { uint8 *ip_body = pktdata + sizeof(struct ether_header); uint8 tos_tc = IP_TOS46(ip_body); - priority = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT); + 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; } @@ -1223,6 +1319,7 @@ bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set) #endif /* BCMDRIVER */ +#if !defined(BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS) /******************************************************************************* * crc8 * @@ -1579,10 +1676,36 @@ bcm_parse_ordered_tlvs(void *buf, int buflen, uint key) } 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; @@ -1625,8 +1748,11 @@ bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char* buf, int len) } /* indicate the str was too short */ - if (flags != 0) + if (flags != 0) { + if (len < 2) + p -= 2 - len; /* overwrite last char */ p += snprintf(p, 2, ">"); + } return (int)(p - buf); } @@ -1998,6 +2124,39 @@ bcm_print_bytes(const char *name, const uchar *data, int len) } printf("\n"); } + +/* Look for vendor-specific IE with specified OUI and optional type */ +bcm_tlv_t * +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; +} + #if defined(WLTINYDUMP) || defined(WLMSG_INFORM) || defined(WLMSG_ASSOC) || \ defined(WLMSG_PRPKT) || defined(WLMSG_WSEC) #define SSID_FMT_BUF_LEN ((4 * DOT11_MAX_SSID_LEN) + 1) @@ -2085,3 +2244,93 @@ process_nvram_vars(char *varbuf, unsigned int len) 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 */ diff --git a/drivers/net/wireless/bcmdhd/bcmwifi_channels.c b/drivers/net/wireless/bcmdhd/bcmwifi_channels.c index b911e6aa3069..ccebc3bc3c26 100644..100755 --- a/drivers/net/wireless/bcmdhd/bcmwifi_channels.c +++ b/drivers/net/wireless/bcmdhd/bcmwifi_channels.c @@ -3,7 +3,7 @@ * Contents are wifi-specific, used by any kernel or app-level * software that might want wifi things as it grows. * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -27,10 +27,10 @@ #include <bcm_cfg.h> #include <typedefs.h> +#include <bcmutils.h> #ifdef BCMDRIVER #include <osl.h> -#include <bcmutils.h> #define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base)) #define tolower(c) (bcm_isupper((c)) ? ((c) + 'a' - 'A') : (c)) #else @@ -560,7 +560,7 @@ wf_chspec_aton(const char *a) return 0; /* if we are looking at a 'g', then the first number was a band */ - c = tolower(a[0]); + c = tolower((int)a[0]); if (c == 'g') { a ++; /* consume the char */ @@ -576,7 +576,7 @@ wf_chspec_aton(const char *a) if (!read_uint(&a, &ctl_ch)) return 0; - c = tolower(a[0]); + c = tolower((int)a[0]); } else { /* first number is channel, use default for band */ @@ -626,7 +626,7 @@ wf_chspec_aton(const char *a) * or '+80' if bw = 80, to make '80+80' bw. */ - c = tolower(a[0]); + 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) { @@ -1051,6 +1051,7 @@ wf_channel2chspec(uint ctl_ch, uint bw) return chspec; } + #endif /* D11AC_IOTYPES */ /* @@ -1180,3 +1181,106 @@ wf_channel2mhz(uint ch, uint start_factor) return freq; } + +/* These chan_info[] & lookup routines replicate those from wlc_phy.c because of BMAC split */ +static const struct chan_info { + uint16 chan; /* channel number */ + uint16 freq; /* in MHz */ +} chan_info[] = { + /* 11b/11g */ +/* 0 */ {1, 2412}, +/* 1 */ {2, 2417}, +/* 2 */ {3, 2422}, +/* 3 */ {4, 2427}, +/* 4 */ {5, 2432}, +/* 5 */ {6, 2437}, +/* 6 */ {7, 2442}, +/* 7 */ {8, 2447}, +/* 8 */ {9, 2452}, +/* 9 */ {10, 2457}, +/* 10 */ {11, 2462}, +/* 11 */ {12, 2467}, +/* 12 */ {13, 2472}, +/* 13 */ {14, 2484}, + +#ifdef BAND5G +/* 11a japan high */ +/* 14 */ {34, 5170}, +/* 15 */ {38, 5190}, +/* 16 */ {42, 5210}, +/* 17 */ {46, 5230}, + +/* 11a usa low */ +/* 18 */ {36, 5180}, +/* 19 */ {40, 5200}, +/* 20 */ {44, 5220}, +/* 21 */ {48, 5240}, +/* 22 */ {52, 5260}, +/* 23 */ {56, 5280}, +/* 24 */ {60, 5300}, +/* 25 */ {64, 5320}, + +/* 11a Europe */ +/* 26 */ {100, 5500}, +/* 27 */ {104, 5520}, +/* 28 */ {108, 5540}, +/* 29 */ {112, 5560}, +/* 30 */ {116, 5580}, +/* 31 */ {120, 5600}, +/* 32 */ {124, 5620}, +/* 33 */ {128, 5640}, +/* 34 */ {132, 5660}, +/* 35 */ {136, 5680}, +/* 36 */ {140, 5700}, + +/* 11a usa high, ref5 only */ +/* 37 */ {149, 5745}, +/* 38 */ {153, 5765}, +/* 39 */ {157, 5785}, +/* 40 */ {161, 5805}, +/* 41 */ {165, 5825}, + +/* 11a japan */ +/* 42 */ {184, 4920}, +/* 43 */ {188, 4940}, +/* 44 */ {192, 4960}, +/* 45 */ {196, 4980}, +/* 46 */ {200, 5000}, +/* 47 */ {204, 5020}, +/* 48 */ {208, 5040}, +/* 49 */ {212, 5060}, +/* 50 */ {216, 5080} +#endif /* BAND5G */ +}; + +/* + * Converts channel frequency to channel number. + * Returns 0 if the frequency does not match any channel definition. + */ +uint +wf_freq2channel(uint freq) +{ + uint i; + + for (i = 0; i < ARRAYSIZE(chan_info); i++) { + if (chan_info[i].freq == freq) + return (chan_info[i].chan); + } + return (0); +} + +/* + * Converts channel number to channel frequency. + * Returns 0 if the channel is out of range. + * Also used by some code in wlc_iw.c + */ +uint +wf_channel2freq(uint channel) +{ + uint i; + + for (i = 0; i < ARRAYSIZE(chan_info); i++) + if (chan_info[i].chan == channel) + return (chan_info[i].freq); + return (0); +} diff --git a/drivers/net/wireless/bcmdhd/dhd.h b/drivers/net/wireless/bcmdhd/dhd.h index 538a708407fa..3d5e2e19ccf4 100644..100755 --- a/drivers/net/wireless/bcmdhd/dhd.h +++ b/drivers/net/wireless/bcmdhd/dhd.h @@ -4,14 +4,14 @@ * Provides type definitions and function prototypes used to link the * DHD OS, bus, and protocol modules. * - * Copyright (C) 1999-2012, Broadcom Corporation - * + * Copyright (C) 1999-2013, 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 @@ -19,12 +19,12 @@ * 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.h 384647 2013-02-12 19:19:46Z $ + * $Id: dhd.h 432432 2013-10-28 15:52:47Z $ */ /**************** @@ -43,6 +43,7 @@ #include <linux/random.h> #include <linux/spinlock.h> #include <linux/ethtool.h> +#include <linux/string.h> #include <asm/uaccess.h> #include <asm/unaligned.h> #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_HAS_WAKELOCK) @@ -58,12 +59,22 @@ int setScheduler(struct task_struct *p, int policy, struct sched_param *param); #include <wlioctl.h> #include <wlfc_proto.h> +#if 0 && (0>= 0x0600) +#include <wdf.h> +#include <WdfMiniport.h> +#endif - +#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_cmn; /* The level of bus communication with the dongle */ enum dhd_bus_state { @@ -72,26 +83,41 @@ enum dhd_bus_state { DHD_BUS_DATA /* Ready for frame transfers */ }; +#if 0 && (0>= 0x0600) +/* Firmware requested operation mode */ +#define STA_MASK 0x0001 +#define HOSTAPD_MASK 0x0002 +#define WFD_MASK 0x0004 +#define SOFTAP_FW_MASK 0x0008 +#define P2P_GO_ENABLED 0x0010 +#define P2P_GC_ENABLED 0x0020 +#define CONCURENT_MASK 0x00F0 +#endif + enum dhd_op_flags { /* Firmware requested operation mode */ - DHD_FLAG_STA_MODE = BIT(0), /* STA only */ - DHD_FLAG_HOSTAP_MODE = BIT(1), /* SOFTAP only */ - DHD_FLAG_P2P_MODE = BIT(2), /* P2P Only */ + 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), - DHD_FLAG_CONCURR_MULTI_CHAN_MODE = BIT(4), /* STA + P2P */ + DHD_FLAG_CONCURR_MULTI_CHAN_MODE = (1 << (4)), /* STA + P2P */ /* Current P2P mode for P2P connection */ - DHD_FLAG_P2P_GC_MODE = BIT(5), - DHD_FLAG_P2P_GO_MODE = BIT(6), - DHD_FLAG_MBSS_MODE = BIT(7) /* MBSS in future */ + 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)) }; #define MANUFACTRING_FW "WLTEST" -/* max sequential rxcntl timeouts to set HANG event */ -#ifndef MAX_CNTL_TIMEOUT -#define MAX_CNTL_TIMEOUT 2 -#endif +/* Max sequential TX/RX Control timeouts to set HANG event */ +#ifndef MAX_CNTL_TX_TIMEOUT +#define MAX_CNTL_TX_TIMEOUT 5 +#endif /* MAX_CNTL_TX_TIMEOUT */ +#ifndef MAX_CNTL_RX_TIMEOUT +#define MAX_CNTL_RX_TIMEOUT 5 +#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 */ @@ -101,7 +127,7 @@ enum dhd_op_flags { #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 */ +#define POWERUP_WAIT_MS 2000 /* ms: time out in waiting wifi to come up */ #endif enum dhd_bus_wake_state { @@ -117,20 +143,18 @@ enum dhd_bus_wake_state { WAKE_LOCK_SOFTAP_SET, WAKE_LOCK_SOFTAP_STOP, WAKE_LOCK_SOFTAP_START, - WAKE_LOCK_SOFTAP_THREAD, - WAKE_LOCK_MAX + WAKE_LOCK_SOFTAP_THREAD }; enum dhd_prealloc_index { DHD_PREALLOC_PROT = 0, DHD_PREALLOC_RXBUF, DHD_PREALLOC_DATABUF, -#if defined(STATIC_WL_PRIV_STRUCT) DHD_PREALLOC_OSL_BUF, +#if defined(STATIC_WL_PRIV_STRUCT) DHD_PREALLOC_WIPHY_ESCAN0 = 5, -#else - DHD_PREALLOC_OSL_BUF #endif /* STATIC_WL_PRIV_STRUCT */ + DHD_PREALLOC_DHD_INFO = 7 }; typedef enum { @@ -142,6 +166,13 @@ typedef enum { } dhd_if_state_t; +typedef enum { + DHD_IPV6_ADDR_NONE = 0, + DHD_IPV6_ADDR_ADD, + DHD_IPV6_ADDR_DELETE +} dhd_ipv6_op_t; + + #if defined(CONFIG_DHD_USE_STATIC_BUF) uint8* dhd_os_prealloc(void *osh, int section, uint size); @@ -172,6 +203,19 @@ typedef struct reorder_info { uint8 pend_pkts; } reorder_info_t; +#ifdef DHDTCPACK_SUPPRESS +#define MAXTCPSTREAMS 4 /* Keep this to be power of 2 */ +typedef struct tcp_ack_info { + void *p_tcpackinqueue; + uint32 tcpack_number; + uint ip_tcp_ttllen; + uint8 ipaddrs[8]; /* Each 4bytes src and dst IP addrs */ + uint8 tcpports[4]; /* Each 2bytes src and dst port number */ +} tcp_ack_info_t; + +void dhd_onoff_tcpack_sup(void *pub, bool on); +#endif /* DHDTCPACK_SUPPRESS */ + /* Common structure for module and instance linkage */ typedef struct dhd_pub { /* Linkage ponters */ @@ -179,6 +223,7 @@ typedef struct dhd_pub { struct dhd_bus *bus; /* Bus module handle */ struct dhd_prot *prot; /* Protocol module handle */ struct dhd_info *info; /* Info module handle */ + struct dhd_cmn *cmn; /* dhd_common module handle */ /* Internal dhd items */ bool up; /* Driver up/down (to OS) */ @@ -227,10 +272,6 @@ typedef struct dhd_pub { /* 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) */ @@ -257,14 +298,25 @@ typedef struct dhd_pub { #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 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 +#endif -#ifdef WLBTAMP - uint16 maxdatablks; -#endif /* WLBTAMP */ #ifdef PROP_TXSTATUS - int wlfc_enabled; - void* wlfc_state; + int wlfc_enabled; + void* wlfc_state; + int ptx_opt_enabled; + bool pending_tx_pkts; + + /* + * implement below functions in each platform if needed. + */ + /* platform specific function whether to skip flow control */ + bool (*skip_fc)(void); + /* platform specific function for wlfc_enable and wlfc_deinit */ + void (*plat_enable)(void *dhd); + void (*plat_deinit)(void *dhd); +#endif +#ifdef PNO_SUPPORT + void *pno_state; #endif bool dongle_isolation; bool dongle_trap_occured; /* flag for sending HANG event to upper layer */ @@ -275,12 +327,32 @@ typedef struct dhd_pub { #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]; -#if defined(ARP_OFFLOAD_SUPPORT) + char fw_capabilities[WLC_IOCTL_SMLEN]; +#ifdef RXFRAME_THREAD +#define MAXSKBPEND 1024 + void *skbbuf[MAXSKBPEND]; + uint32 store_idx; + uint32 sent_idx; +#endif /* RXFRAME_THREAD */ +#ifdef DHDTCPACK_SUPPRESS + int tcp_ack_info_cnt; + tcp_ack_info_t tcp_ack_info_tbl[MAXTCPSTREAMS]; +#endif /* DHDTCPACK_SUPPRESS */ uint32 arp_version; -#endif +#ifdef PKT_FILTER_SUPPORT + uint pkt_filter_mode; + uint pkt_filter_ports_count; + uint16 pkt_filter_ports[WL_PKT_FILTER_PORTS_MAX]; +#endif /* PKT_FILTER_SUPPORT */ } dhd_pub_t; - +typedef struct dhd_cmn { + osl_t *osh; /* OSL handle */ + dhd_pub_t *dhd; +} dhd_cmn_t; #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) @@ -329,6 +401,11 @@ typedef struct dhd_pub { #undef SPINWAIT_SLEEP #define SPINWAIT_SLEEP(a, exp, us) SPINWAIT(exp, us) #endif /* DHDTHREAD */ + +#ifndef OSL_SLEEP +#define OSL_SLEEP(ms) OSL_DELAY(ms*1000) +#endif /* OSL_SLEEP */ + #define DHD_IF_VIF 0x01 /* Virtual IF (Hidden from user) */ unsigned long dhd_os_spin_lock(dhd_pub_t *pub); @@ -383,9 +460,6 @@ inline static void MUTEX_UNLOCK_SOFTAP_SET(dhd_pub_t * dhdp) void dhd_net_if_lock(struct net_device *dev); void dhd_net_if_unlock(struct net_device *dev); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 -extern struct mutex _dhd_sdio_mutex_lock_; -#endif typedef struct dhd_if_event { uint8 ifidx; @@ -443,6 +517,9 @@ extern void dhd_free(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); /* Receive frame for delivery to OS. Callee disposes of rxp. */ @@ -475,6 +552,11 @@ 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); +#ifdef DHDTCPACK_SUPPRESS +extern void dhd_os_tcpacklock(dhd_pub_t *pub); +extern void dhd_os_tcpackunlock(dhd_pub_t *pub); +#endif /* DHDTCPACK_SUPPRESS */ + extern void dhd_customer_gpio_wlan_ctrl(int onoff); extern int dhd_custom_get_mac_address(unsigned char *buf); extern void dhd_os_sdunlock_sndup_rxq(dhd_pub_t * pub); @@ -484,29 +566,32 @@ 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); -#ifdef PNO_SUPPORT -extern int dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled); -extern int dhd_pno_clean(dhd_pub_t *dhd); -extern int dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, - ushort scan_fr, int pno_repeat, int pno_freq_expo_max); -extern int dhd_pno_get_status(dhd_pub_t *dhd); -extern int dhd_dev_pno_reset(struct net_device *dev); -extern int dhd_dev_pno_set(struct net_device *dev, wlc_ssid_t* ssids_local, - int nssid, ushort scan_fr, int pno_repeat, int pno_freq_expo_max); -extern int dhd_dev_pno_enable(struct net_device *dev, int pfn_enabled); -extern int dhd_dev_get_pno_status(struct net_device *dev); -#endif /* PNO_SUPPORT */ +#if defined(KEEP_ALIVE) +extern int dhd_keep_alive_onoff(dhd_pub_t *dhd); +#endif /* KEEP_ALIVE */ + #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 -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 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); +#define DHD_MDNS_FILTER_NUM 4 +#define DHD_ARP_FILTER_NUM 5 + +/* Port based packet filtering command actions */ +#define PKT_FILTER_PORTS_CLEAR 0 +#define PKT_FILTER_PORTS_ADD 1 +#define PKT_FILTER_PORTS_DEL 2 +#define PKT_FILTER_PORTS_LOOPBACK 3 +#define PKT_FILTER_PORTS_MAX PKT_FILTER_PORTS_LOOPBACK + +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 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 void dhd_set_packet_filter_mode(struct net_device *dev, char *command); +extern int dhd_set_packet_filter_ports(struct net_device *dev, char *command); #endif /* PKT_FILTER_SUPPORT */ extern int dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd); @@ -517,7 +602,7 @@ extern int write_to_file(dhd_pub_t *dhd, uint8 *buf, int size); #endif /* DHD_DEBUG */ #if defined(OOB_INTR_ONLY) extern int dhd_customer_oob_irq_map(unsigned long *irq_flags_ptr); -#endif +#endif extern void dhd_os_sdtxlock(dhd_pub_t * pub); extern void dhd_os_sdtxunlock(dhd_pub_t * pub); @@ -542,8 +627,8 @@ extern void wl_event_to_host_order(wl_event_msg_t * evt); 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 void dhd_common_init(osl_t *osh); +extern void dhd_common_deinit(dhd_pub_t *dhd_pub, dhd_cmn_t *sa_cmn); extern int dhd_do_driver_init(struct net_device *net); extern int dhd_add_if(struct dhd_info *dhd, int ifidx, void *handle, @@ -579,7 +664,7 @@ extern int dhd_keep_alive_onoff(dhd_pub_t *dhd); #endif /* KEEP_ALIVE */ extern bool dhd_is_concurrent_mode(dhd_pub_t *dhd); - +extern int dhd_iovar(dhd_pub_t *pub, int ifidx, char *name, char *cmd_buf, uint cmd_len, int set); typedef enum cust_gpio_modes { WLAN_RESET_ON, WLAN_RESET_OFF, @@ -657,7 +742,7 @@ extern uint dhd_force_tx_queueing; #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 @@ -679,18 +764,43 @@ extern uint dhd_force_tx_queueing; #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 +#define DEFAULT_WIFI_TURNOFF_DELAY 0 +#define WIFI_TURNOFF_DELAY DEFAULT_WIFI_TURNOFF_DELAY + +#ifdef RXFRAME_THREAD +#ifndef CUSTOM_RXF_PRIO_SETTING +#define CUSTOM_RXF_PRIO_SETTING MAX((CUSTOM_DPC_PRIO_SETTING - 1), 1) +#endif +#endif /* RXFRAME_THREAD */ + +#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 */ + + #define MAX_DTIM_SKIP_BEACON_ITERVAL 100 /* max allowed associated AP beacon for dtim skip */ #ifdef SDTEST @@ -709,7 +819,6 @@ extern char fw_path[MOD_PARAM_PATHLEN]; extern char nv_path[MOD_PARAM_PATHLEN]; #define MOD_PARAM_INFOLEN 512 - #ifdef SOFTAP extern char fw_path2[MOD_PARAM_PATHLEN]; #endif @@ -722,13 +831,13 @@ extern uint dhd_download_fw_on_driverload; #define DHD_MAX_IFS 16 #define DHD_DEL_IF -0xe #define DHD_BAD_IF -0xf -#define WL_AUTO_ROAM_TRIGGER -75 - #ifdef PROP_TXSTATUS /* Please be mindful that total pkttag space is 32 octets only */ typedef struct dhd_pkttag { /* + b[14:13] - encryption exemption + b[12 ] - 1 = event channel b[11 ] - 1 = this packet was sent in response to one time packet request, do not increment credit on status for this one. [WLFC_CTL_TYPE_MAC_REQUEST_PACKET]. b[10 ] - 1 = signal-only-packet to firmware [i.e. nothing to piggyback on] @@ -779,6 +888,12 @@ typedef struct dhd_pkttag { #define DHD_PKTTAG_ONETIMEPKTRQST_MASK 0x1 #define DHD_PKTTAG_ONETIMEPKTRQST_SHIFT 11 +#define DHD_PKTTAG_EVENT_MASK 0x1 +#define DHD_PKTTAG_EVENT_SHIFT 12 + +#define DHD_PKTTAG_EXEMPT_MASK 0x3 +#define DHD_PKTTAG_EXEMPT_SHIFT 13 + #define DHD_PKTTAG_PKTDIR_MASK 0x1 #define DHD_PKTTAG_PKTDIR_SHIFT 9 @@ -832,11 +947,28 @@ typedef struct dhd_pkttag { #define DHD_PKTTAG_ONETIMEPKTRQST(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ DHD_PKTTAG_ONETIMEPKTRQST_SHIFT) & DHD_PKTTAG_ONETIMEPKTRQST_MASK) +#define DHD_PKTTAG_SETEVENT(tag, event) ((dhd_pkttag_t*)(tag))->if_flags = \ + (((dhd_pkttag_t*)(tag))->if_flags & \ + ~(DHD_PKTTAG_EVENT_MASK << DHD_PKTTAG_EVENT_SHIFT)) | \ + (((event) & DHD_PKTTAG_EVENT_MASK) << DHD_PKTTAG_EVENT_SHIFT) +#define DHD_PKTTAG_EVENT(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ + DHD_PKTTAG_EVENT_SHIFT) & DHD_PKTTAG_EVENT_MASK) + +#define DHD_PKTTAG_EXEMPT_SET(tag, value) ((dhd_pkttag_t*)(tag))->if_flags = \ + (((dhd_pkttag_t*)(tag))->if_flags & \ + ~(DHD_PKTTAG_EXEMPT_MASK << DHD_PKTTAG_EXEMPT_SHIFT)) | \ + (((value) & DHD_PKTTAG_EXEMPT_MASK) << DHD_PKTTAG_EXEMPT_SHIFT) +#define DHD_PKTTAG_EXEMPT(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ + DHD_PKTTAG_EXEMPT_SHIFT) & DHD_PKTTAG_EXEMPT_MASK) + #define DHD_PKTTAG_SETDSTN(tag, dstn_MAC_ea) memcpy(((dhd_pkttag_t*)((tag)))->dstn_ether, \ (dstn_MAC_ea), ETHER_ADDR_LEN) #define DHD_PKTTAG_DSTN(tag) ((dhd_pkttag_t*)(tag))->dstn_ether typedef int (*f_commitpkt_t)(void* ctx, void* p); +int dhd_os_wlfc_block(dhd_pub_t *pub); +int dhd_os_wlfc_unblock(dhd_pub_t *pub); +void dhd_schedule_tx(struct dhd_info *dhd); #ifdef PROP_TXSTATUS_DEBUG #define DHD_WLFC_CTRINC_MAC_CLOSE(entry) do { (entry)->closed_ct++; } while (0) @@ -846,12 +978,6 @@ typedef int (*f_commitpkt_t)(void* ctx, void* p); #define DHD_WLFC_CTRINC_MAC_OPEN(entry) do {} while (0) #endif -#ifdef QUEUE_BW -#define QUEUE_BW_SYSUPTIME() ((uint64)(jiffies_to_usecs(jiffies))) -extern int dhd_wlfc_queue_bw_iovar_getpercent(dhd_pub_t *dhdp); -extern int dhd_wlfc_queue_bw_iovar_thres(dhd_pub_t *dhdp, int set, int setval); -#endif - #endif /* PROP_TXSTATUS */ extern void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar); @@ -862,19 +988,7 @@ extern void dhd_wait_event_wakeup(dhd_pub_t*dhd); NdisStallExecution(1); #define IFUNLOCK(lock) InterlockedExchange((lock), 0) #define IFLOCK_FREE(lock) - -#ifdef PNO_SUPPORT -extern int dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled); -extern int dhd_pnoenable(dhd_pub_t *dhd, int pfn_enabled); -extern int dhd_pno_clean(dhd_pub_t *dhd); -extern int dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, - ushort scan_fr, int pno_repeat, int pno_freq_expo_max); -extern int dhd_pno_get_status(dhd_pub_t *dhd); -extern int dhd_pno_set_add(dhd_pub_t *dhd, wl_pfn_t *netinfo, int nssid, ushort scan_fr, - ushort slowscan_fr, uint8 pno_repeat, uint8 pno_freq_expo_max, int16 flags); -extern int dhd_pno_cfg(dhd_pub_t *dhd, wl_pfn_cfg_t *pcfg); -extern int dhd_pno_suspend(dhd_pub_t *dhd, int pfn_suspend); -#endif /* PNO_SUPPORT */ +#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); @@ -886,5 +1000,19 @@ 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_disable(dhd_pub_t *dhd, bool flag); +#endif +/* Neighbor Discovery Offload Support */ +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); +/* ioctl processing for nl80211 */ +int dhd_ioctl_process(dhd_pub_t *pub, int ifidx, struct dhd_ioctl *ioc); + +void dhd_set_bus_state(void *bus, uint32 state); + +/* Remove proper pkts(either one no-frag pkt or whole fragmented pkts) */ +extern bool dhd_prec_drop_pkts(osl_t *osh, struct pktq *pq, int prec); #endif /* _dhd_h_ */ diff --git a/drivers/net/wireless/bcmdhd/dhd_bta.c b/drivers/net/wireless/bcmdhd/dhd_bta.c index 15c605ea248f..8f870daca82a 100644..100755 --- a/drivers/net/wireless/bcmdhd/dhd_bta.c +++ b/drivers/net/wireless/bcmdhd/dhd_bta.c @@ -1,7 +1,7 @@ /* * BT-AMP support routines * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -21,11 +21,9 @@ * 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_bta.c 303834 2011-12-20 06:17:39Z $ + * $Id: dhd_bta.c 379512 2013-01-17 22:49:08Z $ */ -#ifndef WLBTAMP #error "WLBTAMP is not defined" -#endif /* WLBTAMP */ #include <typedefs.h> #include <osl.h> @@ -313,6 +311,9 @@ dhd_bta_doevt(dhd_pub_t *dhdp, void *data_buf, uint data_len) { amp_hci_event_t *evt = (amp_hci_event_t *)data_buf; + ASSERT(dhdp); + ASSERT(evt); + switch (evt->ecode) { case HCI_Command_Complete: { cmd_complete_parms_t *parms = (cmd_complete_parms_t *)evt->parms; diff --git a/drivers/net/wireless/bcmdhd/dhd_bta.h b/drivers/net/wireless/bcmdhd/dhd_bta.h index 0337f15d285a..73ccea1683f7 100644..100755 --- a/drivers/net/wireless/bcmdhd/dhd_bta.h +++ b/drivers/net/wireless/bcmdhd/dhd_bta.h @@ -1,7 +1,7 @@ /* * BT-AMP support routines * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd/dhd_bus.h b/drivers/net/wireless/bcmdhd/dhd_bus.h index fcb4bbd65c85..5b922ef0c371 100644..100755 --- a/drivers/net/wireless/bcmdhd/dhd_bus.h +++ b/drivers/net/wireless/bcmdhd/dhd_bus.h @@ -4,7 +4,7 @@ * Provides type definitions and function prototypes used to link the * DHD OS, bus, and protocol modules. * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -24,7 +24,7 @@ * 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_bus.h 347614 2012-07-27 10:24:51Z $ + * $Id: dhd_bus.h 335569 2012-05-29 12:04:43Z $ */ #ifndef _dhd_bus_h_ diff --git a/drivers/net/wireless/bcmdhd/dhd_cdc.c b/drivers/net/wireless/bcmdhd/dhd_cdc.c index 9e06a56a7e0b..056175c908b5 100644..100755 --- a/drivers/net/wireless/bcmdhd/dhd_cdc.c +++ b/drivers/net/wireless/bcmdhd/dhd_cdc.c @@ -1,14 +1,14 @@ /* * DHD Protocol Module for CDC and BDC. * - * Copyright (C) 1999-2012, Broadcom Corporation - * + * Copyright (C) 1999-2013, Broadcom Corporation + * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2 (the "GPL"), * available at http://www.broadcom.com/licenses/GPLv2.php, with the * following added to such license: - * + * * As a special exception, the copyright holders of this software give you * permission to link this software with independent modules, and to copy and * distribute the resulting executable under terms of your choice, provided that @@ -16,12 +16,12 @@ * 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_cdc.c 368762 2012-11-14 21:59:17Z $ + * $Id: dhd_cdc.c 424024 2013-09-15 14:00:46Z $ * * 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 @@ -57,19 +57,6 @@ * round off at the end of buffer */ -#define BUS_RETRIES 1 /* # of retries before aborting a bus tx operation */ - -#ifdef PROP_TXSTATUS -typedef struct dhd_wlfc_commit_info { - uint8 needs_hdr; - uint8 ac_fifo_credit_spent; - ewlfc_packet_state_t pkt_type; - wlfc_mac_descriptor_t* mac_entry; - void* p; -} dhd_wlfc_commit_info_t; -#endif /* PROP_TXSTATUS */ - - typedef struct dhd_prot { uint16 reqid; uint8 pending; @@ -130,7 +117,6 @@ dhdcdc_query_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uin { dhd_prot_t *prot = dhd->prot; cdc_ioctl_t *msg = &prot->msg; - void *info; int ret = 0, retries = 0; uint32 id, flags = 0; @@ -190,15 +176,12 @@ retry: goto done; } - /* Check info buffer */ - info = (void*)&msg[1]; - /* Copy info buffer */ if (buf) { if (ret < (int)len) len = ret; - memcpy(buf, info, len); + memcpy(buf, (void*) prot->buf, len); } /* Check the ERROR flag */ @@ -237,7 +220,6 @@ dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8 return -EIO; } - memset(msg, 0, sizeof(cdc_ioctl_t)); msg->cmd = htol32(cmd); @@ -289,26 +271,11 @@ 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; -#if defined(NDIS630) - bool acquired = FALSE; -#endif if ((dhd->busstate == DHD_BUS_DOWN) || dhd->hang_was_sent) { DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__)); goto done; } -#if defined(NDIS630) - if (dhd_os_proto_block(dhd)) - { - acquired = TRUE; - } - else - { - /* attempt to acquire protocol mutex timed out. */ - ret = -1; - return ret; - } -#endif /* NDIS630 */ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); @@ -359,10 +326,7 @@ dhd_prot_ioctl(dhd_pub_t *dhd, int ifidx, wl_ioctl_t * ioc, void * buf, int len) prot->pending = FALSE; done: -#if defined(NDIS630) - if (acquired) - dhd_os_proto_unblock(dhd); -#endif + return ret; } @@ -373,2474 +337,22 @@ dhd_prot_iovar_op(dhd_pub_t *dhdp, const char *name, return BCME_UNSUPPORTED; } -#ifdef PROP_TXSTATUS - -#ifdef QUEUE_BW -#define DHD_WLFC_QUEUE_BW_COMPLETE(entry) dhd_wlfc_queue_bw_complete(entry) -#define TRANSIT_COUNT(entry) entry->transitallq_count - -static void -dhd_wlfc_queue_bw_reset(wlfc_mac_descriptor_t* entry) -{ - entry->transitallq_count = 0; - entry->queued_time_cumul = 0; - entry->queued_time_cumul_last = 0; - entry->queued_time_last = 0; - entry->queued_time_last_io = 0; -} - -static void -dhd_wlfc_queue_bw_complete(wlfc_mac_descriptor_t* entry) -{ - uint64 now = QUEUE_BW_SYSUPTIME(); - entry->transitallq_count--; - if ((TRANSIT_COUNT(entry) <= entry->queued_time_thres) && - (entry->queued_time_last != 0)) { - /* Set timestamp when transit packet above a threshold */ - entry->queued_time_cumul += now - entry->queued_time_last; - entry->queued_time_last = 0; - } - else if (TRANSIT_COUNT(entry) > entry->queued_time_thres) { - entry->queued_time_cumul += now - entry->queued_time_last; - entry->queued_time_last = now; - } -} - -static wlfc_mac_descriptor_t * -dhd_wlfc_queue_bw_p2p_entry(dhd_pub_t *dhdp) -{ - wlfc_mac_descriptor_t* interfaces = - ((athost_wl_status_info_t*)dhdp->wlfc_state)->destination_entries.interfaces; - wlfc_mac_descriptor_t* nodes = - ((athost_wl_status_info_t*)dhdp->wlfc_state)->destination_entries.nodes; - uint8 i, j; - - ASSERT(interfaces != NULL); - ASSERT(nodes != NULL); - - for (i = 0; i < WLFC_MAX_IFNUM; i++) { - if (!interfaces[i].occupied) - continue; - - if (interfaces[i].iftype == WLC_E_IF_ROLE_P2P_CLIENT) - return &interfaces[i]; - else if (interfaces[i].iftype == WLC_E_IF_ROLE_P2P_GO) { - for (j = 0; j < WLFC_MAC_DESC_TABLE_SIZE; j++) { - if (nodes[j].occupied && - (nodes[j].iftype == WLC_E_IF_ROLE_P2P_GO)) - return &nodes[j]; - } - } - } - return NULL; -} - -int -dhd_wlfc_queue_bw_iovar_getpercent(dhd_pub_t *dhdp) -{ - int percent = 0; - wlfc_mac_descriptor_t *entry; - - entry = dhd_wlfc_queue_bw_p2p_entry(dhdp); - if (entry) { - uint64 queued_time_cumul = entry->queued_time_cumul; - uint64 queued_time_last = entry->queued_time_last; - uint64 now = QUEUE_BW_SYSUPTIME(); - uint64 time_cumul_adjust = 0; - - if (queued_time_last) - time_cumul_adjust = now - queued_time_last; - - percent = (uint32)((time_cumul_adjust + queued_time_cumul - - entry->queued_time_cumul_last) * 100) / - (uint32)(now - entry->queued_time_last_io); - - entry->queued_time_cumul_last = queued_time_cumul + time_cumul_adjust; - entry->queued_time_last_io = now; - } - return percent; -} - -int -dhd_wlfc_queue_bw_iovar_thres(dhd_pub_t *dhdp, int set, int setval) -{ - int val = 0; - wlfc_mac_descriptor_t *entry; - - entry = dhd_wlfc_queue_bw_p2p_entry(dhdp); - if (entry) { - if (set) - entry->queued_time_thres = setval; - else - val = entry->queued_time_thres; - } - return val; -} -#else -#define DHD_WLFC_QUEUE_BW_COMPLETE(entry) -#endif /* QUEUE_BW */ - -void -dhd_wlfc_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) -{ - int i; - uint8* ea; - athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) - dhdp->wlfc_state; - wlfc_hanger_t* h; - wlfc_mac_descriptor_t* mac_table; - wlfc_mac_descriptor_t* interfaces; - char* iftypes[] = {"STA", "AP", "WDS", "p2pGO", "p2pCL"}; - - if (wlfc == NULL) { - bcm_bprintf(strbuf, "wlfc not initialized yet\n"); - return; - } - h = (wlfc_hanger_t*)wlfc->hanger; - if (h == NULL) { - bcm_bprintf(strbuf, "wlfc-hanger not initialized yet\n"); - } - - mac_table = wlfc->destination_entries.nodes; - interfaces = wlfc->destination_entries.interfaces; - bcm_bprintf(strbuf, "---- wlfc stats ----\n"); - if (h) { - bcm_bprintf(strbuf, "wlfc hanger (pushed,popped,f_push," - "f_pop,f_slot, pending) = (%d,%d,%d,%d,%d,%d)\n", - h->pushed, - h->popped, - h->failed_to_push, - h->failed_to_pop, - h->failed_slotfind, - (h->pushed - h->popped)); - } - - bcm_bprintf(strbuf, "wlfc fail(tlv,credit_rqst,mac_update,psmode_update), " - "(dq_full,sendq_full, rollback_fail) = (%d,%d,%d,%d), (%d,%d,%d)\n", - wlfc->stats.tlv_parse_failed, - wlfc->stats.credit_request_failed, - wlfc->stats.mac_update_failed, - wlfc->stats.psmode_update_failed, - wlfc->stats.delayq_full_error, - wlfc->stats.sendq_full_error, - wlfc->stats.rollback_failed); - - bcm_bprintf(strbuf, "SENDQ (len,credit,sent) " - "(AC0[%d,%d,%d],AC1[%d,%d,%d],AC2[%d,%d,%d],AC3[%d,%d,%d],BC_MC[%d,%d,%d])\n", - wlfc->SENDQ.q[0].len, wlfc->FIFO_credit[0], wlfc->stats.sendq_pkts[0], - wlfc->SENDQ.q[1].len, wlfc->FIFO_credit[1], wlfc->stats.sendq_pkts[1], - wlfc->SENDQ.q[2].len, wlfc->FIFO_credit[2], wlfc->stats.sendq_pkts[2], - wlfc->SENDQ.q[3].len, wlfc->FIFO_credit[3], wlfc->stats.sendq_pkts[3], - wlfc->SENDQ.q[4].len, wlfc->FIFO_credit[4], wlfc->stats.sendq_pkts[4]); - -#ifdef PROP_TXSTATUS_DEBUG - bcm_bprintf(strbuf, "SENDQ dropped: AC[0-3]:(%d,%d,%d,%d), (bcmc,atim):(%d,%d)\n", - wlfc->stats.dropped_qfull[0], wlfc->stats.dropped_qfull[1], - wlfc->stats.dropped_qfull[2], wlfc->stats.dropped_qfull[3], - wlfc->stats.dropped_qfull[4], wlfc->stats.dropped_qfull[5]); -#endif - - bcm_bprintf(strbuf, "\n"); - for (i = 0; i < WLFC_MAX_IFNUM; i++) { - if (interfaces[i].occupied) { - char* iftype_desc; - - if (interfaces[i].iftype > WLC_E_IF_ROLE_P2P_CLIENT) - iftype_desc = "<Unknown"; - else - iftype_desc = iftypes[interfaces[i].iftype]; - - ea = interfaces[i].ea; - bcm_bprintf(strbuf, "INTERFACE[%d].ea = " - "[%02x:%02x:%02x:%02x:%02x:%02x], if:%d, type: %s" - "netif_flow_control:%s\n", i, - ea[0], ea[1], ea[2], ea[3], ea[4], ea[5], - interfaces[i].interface_id, - iftype_desc, ((wlfc->hostif_flow_state[i] == OFF) - ? " OFF":" ON")); - - bcm_bprintf(strbuf, "INTERFACE[%d].DELAYQ(len,state,credit)" - "= (%d,%s,%d)\n", - i, - interfaces[i].psq.len, - ((interfaces[i].state == - WLFC_STATE_OPEN) ? " OPEN":"CLOSE"), - interfaces[i].requested_credit); - - bcm_bprintf(strbuf, "INTERFACE[%d].DELAYQ" - "(sup,ac0),(sup,ac1),(sup,ac2),(sup,ac3) = " - "(%d,%d),(%d,%d),(%d,%d),(%d,%d)\n", - i, - interfaces[i].psq.q[0].len, - interfaces[i].psq.q[1].len, - interfaces[i].psq.q[2].len, - interfaces[i].psq.q[3].len, - interfaces[i].psq.q[4].len, - interfaces[i].psq.q[5].len, - interfaces[i].psq.q[6].len, - interfaces[i].psq.q[7].len); - } - } - - bcm_bprintf(strbuf, "\n"); - for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { - if (mac_table[i].occupied) { - ea = mac_table[i].ea; - bcm_bprintf(strbuf, "MAC_table[%d].ea = " - "[%02x:%02x:%02x:%02x:%02x:%02x], if:%d \n", i, - ea[0], ea[1], ea[2], ea[3], ea[4], ea[5], - mac_table[i].interface_id); - - bcm_bprintf(strbuf, "MAC_table[%d].DELAYQ(len,state,credit)" - "= (%d,%s,%d)\n", - i, - mac_table[i].psq.len, - ((mac_table[i].state == - WLFC_STATE_OPEN) ? " OPEN":"CLOSE"), - mac_table[i].requested_credit); -#ifdef PROP_TXSTATUS_DEBUG - bcm_bprintf(strbuf, "MAC_table[%d]: (opened, closed) = (%d, %d)\n", - i, mac_table[i].opened_ct, mac_table[i].closed_ct); -#endif - bcm_bprintf(strbuf, "MAC_table[%d].DELAYQ" - "(sup,ac0),(sup,ac1),(sup,ac2),(sup,ac3) = " - "(%d,%d),(%d,%d),(%d,%d),(%d,%d)\n", - i, - mac_table[i].psq.q[0].len, - mac_table[i].psq.q[1].len, - mac_table[i].psq.q[2].len, - mac_table[i].psq.q[3].len, - mac_table[i].psq.q[4].len, - mac_table[i].psq.q[5].len, - mac_table[i].psq.q[6].len, - mac_table[i].psq.q[7].len); - } - } - -#ifdef PROP_TXSTATUS_DEBUG - { - int avg; - int moving_avg = 0; - int moving_samples; - - if (wlfc->stats.latency_sample_count) { - moving_samples = sizeof(wlfc->stats.deltas)/sizeof(uint32); - - for (i = 0; i < moving_samples; i++) - moving_avg += wlfc->stats.deltas[i]; - moving_avg /= moving_samples; - - avg = (100 * wlfc->stats.total_status_latency) / - wlfc->stats.latency_sample_count; - bcm_bprintf(strbuf, "txstatus latency (average, last, moving[%d]) = " - "(%d.%d, %03d, %03d)\n", - moving_samples, avg/100, (avg - (avg/100)*100), - wlfc->stats.latency_most_recent, - moving_avg); - } - } - - bcm_bprintf(strbuf, "wlfc- fifo[0-5] credit stats: sent = (%d,%d,%d,%d,%d,%d), " - "back = (%d,%d,%d,%d,%d,%d)\n", - wlfc->stats.fifo_credits_sent[0], - wlfc->stats.fifo_credits_sent[1], - wlfc->stats.fifo_credits_sent[2], - wlfc->stats.fifo_credits_sent[3], - wlfc->stats.fifo_credits_sent[4], - wlfc->stats.fifo_credits_sent[5], - - wlfc->stats.fifo_credits_back[0], - wlfc->stats.fifo_credits_back[1], - wlfc->stats.fifo_credits_back[2], - wlfc->stats.fifo_credits_back[3], - wlfc->stats.fifo_credits_back[4], - wlfc->stats.fifo_credits_back[5]); - { - uint32 fifo_cr_sent = 0; - uint32 fifo_cr_acked = 0; - uint32 request_cr_sent = 0; - uint32 request_cr_ack = 0; - uint32 bc_mc_cr_ack = 0; - - for (i = 0; i < sizeof(wlfc->stats.fifo_credits_sent)/sizeof(uint32); i++) { - fifo_cr_sent += wlfc->stats.fifo_credits_sent[i]; - } - - for (i = 0; i < sizeof(wlfc->stats.fifo_credits_back)/sizeof(uint32); i++) { - fifo_cr_acked += wlfc->stats.fifo_credits_back[i]; - } - - for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { - if (wlfc->destination_entries.nodes[i].occupied) { - request_cr_sent += - wlfc->destination_entries.nodes[i].dstncredit_sent_packets; - } - } - for (i = 0; i < WLFC_MAX_IFNUM; i++) { - if (wlfc->destination_entries.interfaces[i].occupied) { - request_cr_sent += - wlfc->destination_entries.interfaces[i].dstncredit_sent_packets; - } - } - for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { - if (wlfc->destination_entries.nodes[i].occupied) { - request_cr_ack += - wlfc->destination_entries.nodes[i].dstncredit_acks; - } - } - for (i = 0; i < WLFC_MAX_IFNUM; i++) { - if (wlfc->destination_entries.interfaces[i].occupied) { - request_cr_ack += - wlfc->destination_entries.interfaces[i].dstncredit_acks; - } - } - bcm_bprintf(strbuf, "wlfc- (sent, status) => pq(%d,%d), vq(%d,%d)," - "other:%d, bc_mc:%d, signal-only, (sent,freed): (%d,%d)", - fifo_cr_sent, fifo_cr_acked, - request_cr_sent, request_cr_ack, - wlfc->destination_entries.other.dstncredit_acks, - bc_mc_cr_ack, - wlfc->stats.signal_only_pkts_sent, wlfc->stats.signal_only_pkts_freed); - } -#endif /* PROP_TXSTATUS_DEBUG */ - bcm_bprintf(strbuf, "\n"); - bcm_bprintf(strbuf, "wlfc- pkt((in,2bus,txstats,hdrpull),(dropped,hdr_only,wlc_tossed)" - "(freed,free_err,rollback)) = " - "((%d,%d,%d,%d),(%d,%d,%d),(%d,%d,%d))\n", - wlfc->stats.pktin, - wlfc->stats.pkt2bus, - wlfc->stats.txstatus_in, - wlfc->stats.dhd_hdrpulls, - - wlfc->stats.pktdropped, - wlfc->stats.wlfc_header_only_pkt, - wlfc->stats.wlc_tossed_pkts, - - wlfc->stats.pkt_freed, - wlfc->stats.pkt_free_err, wlfc->stats.rollback); - - bcm_bprintf(strbuf, "wlfc- suppress((d11,wlc,err),enq(d11,wl,hq,mac?),retx(d11,wlc,hq)) = " - "((%d,%d,%d),(%d,%d,%d,%d),(%d,%d,%d))\n", - - wlfc->stats.d11_suppress, - wlfc->stats.wl_suppress, - wlfc->stats.bad_suppress, - - wlfc->stats.psq_d11sup_enq, - wlfc->stats.psq_wlsup_enq, - wlfc->stats.psq_hostq_enq, - wlfc->stats.mac_handle_notfound, - - wlfc->stats.psq_d11sup_retx, - wlfc->stats.psq_wlsup_retx, - wlfc->stats.psq_hostq_retx); - return; -} - -/* Create a place to store all packet pointers submitted to the firmware until - a status comes back, suppress or otherwise. - - hang-er: noun, a contrivance on which things are hung, as a hook. -*/ -static void* -dhd_wlfc_hanger_create(osl_t *osh, int max_items) -{ - int i; - wlfc_hanger_t* hanger; - - /* allow only up to a specific size for now */ - ASSERT(max_items == WLFC_HANGER_MAXITEMS); - - if ((hanger = (wlfc_hanger_t*)MALLOC(osh, WLFC_HANGER_SIZE(max_items))) == NULL) - return NULL; - - memset(hanger, 0, WLFC_HANGER_SIZE(max_items)); - hanger->max_items = max_items; - - for (i = 0; i < hanger->max_items; i++) { - hanger->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; - } - return hanger; -} - -static int -dhd_wlfc_hanger_delete(osl_t *osh, void* hanger) -{ - wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; - - if (h) { - MFREE(osh, h, WLFC_HANGER_SIZE(h->max_items)); - return BCME_OK; - } - return BCME_BADARG; -} - -static uint16 -dhd_wlfc_hanger_get_free_slot(void* hanger) -{ - uint32 i; - wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; - - if (h) { - for (i = (h->slot_pos + 1); i != h->slot_pos;) { - if (h->items[i].state == WLFC_HANGER_ITEM_STATE_FREE) { - h->slot_pos = i; - return (uint16)i; - } - (i == h->max_items)? i = 0 : i++; - } - h->failed_slotfind++; - } - return WLFC_HANGER_MAXITEMS; -} - -static int -dhd_wlfc_hanger_get_genbit(void* hanger, void* pkt, uint32 slot_id, int* gen) -{ - int rc = BCME_OK; - wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; - - *gen = 0xff; - - /* this packet was not pushed at the time it went to the firmware */ - if (slot_id == WLFC_HANGER_MAXITEMS) - return BCME_NOTFOUND; - - if (h) { - if ((h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_INUSE) || - (h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED)) { - *gen = h->items[slot_id].gen; - } - else { - rc = BCME_NOTFOUND; - } - } - else - rc = BCME_BADARG; - return rc; -} - -static int -dhd_wlfc_hanger_pushpkt(void* hanger, void* pkt, uint32 slot_id) -{ - int rc = BCME_OK; - wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; - - if (h && (slot_id < WLFC_HANGER_MAXITEMS)) { - if (h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_FREE) { - h->items[slot_id].state = WLFC_HANGER_ITEM_STATE_INUSE; - h->items[slot_id].pkt = pkt; - h->items[slot_id].identifier = slot_id; - h->pushed++; - } - else { - h->failed_to_push++; - rc = BCME_NOTFOUND; - } - } - else - rc = BCME_BADARG; - return rc; -} - -static int -dhd_wlfc_hanger_poppkt(void* hanger, uint32 slot_id, void** pktout, int remove_from_hanger) -{ - int rc = BCME_OK; - wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; - - /* this packet was not pushed at the time it went to the firmware */ - if (slot_id == WLFC_HANGER_MAXITEMS) - return BCME_NOTFOUND; - - if (h) { - if (h->items[slot_id].state != WLFC_HANGER_ITEM_STATE_FREE) { - *pktout = h->items[slot_id].pkt; - if (remove_from_hanger) { - h->items[slot_id].state = - WLFC_HANGER_ITEM_STATE_FREE; - h->items[slot_id].pkt = NULL; - h->items[slot_id].identifier = 0; - h->items[slot_id].gen = 0xff; - h->popped++; - } - } - else { - h->failed_to_pop++; - rc = BCME_NOTFOUND; - } - } - else - rc = BCME_BADARG; - return rc; -} - -static int -dhd_wlfc_hanger_mark_suppressed(void* hanger, uint32 slot_id, uint8 gen) -{ - int rc = BCME_OK; - wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; - - /* this packet was not pushed at the time it went to the firmware */ - if (slot_id == WLFC_HANGER_MAXITEMS) - return BCME_NOTFOUND; - if (h) { - h->items[slot_id].gen = gen; - if (h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_INUSE) { - h->items[slot_id].state = WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED; - } - else - rc = BCME_BADARG; - } - else - rc = BCME_BADARG; - - return rc; -} - -static int -_dhd_wlfc_pushheader(athost_wl_status_info_t* ctx, void* p, bool tim_signal, - uint8 tim_bmp, uint8 mac_handle, uint32 htodtag) -{ - uint32 wl_pktinfo = 0; - uint8* wlh; - uint8 dataOffset; - uint8 fillers; - uint8 tim_signal_len = 0; - - struct bdc_header *h; - - if (tim_signal) { - tim_signal_len = 1 + 1 + WLFC_CTL_VALUE_LEN_PENDING_TRAFFIC_BMP; - } - - /* +2 is for Type[1] and Len[1] in TLV, plus TIM signal */ - dataOffset = WLFC_CTL_VALUE_LEN_PKTTAG + 2 + tim_signal_len; - fillers = ROUNDUP(dataOffset, 4) - dataOffset; - dataOffset += fillers; - - PKTPUSH(ctx->osh, p, dataOffset); - wlh = (uint8*) PKTDATA(ctx->osh, p); - - wl_pktinfo = htol32(htodtag); - - wlh[0] = WLFC_CTL_TYPE_PKTTAG; - wlh[1] = WLFC_CTL_VALUE_LEN_PKTTAG; - memcpy(&wlh[2], &wl_pktinfo, sizeof(uint32)); - - if (tim_signal_len) { - wlh[dataOffset - fillers - tim_signal_len ] = - WLFC_CTL_TYPE_PENDING_TRAFFIC_BMP; - wlh[dataOffset - fillers - tim_signal_len + 1] = - WLFC_CTL_VALUE_LEN_PENDING_TRAFFIC_BMP; - wlh[dataOffset - fillers - tim_signal_len + 2] = mac_handle; - wlh[dataOffset - fillers - tim_signal_len + 3] = tim_bmp; - } - if (fillers) - memset(&wlh[dataOffset - fillers], WLFC_CTL_TYPE_FILLER, fillers); - - PKTPUSH(ctx->osh, p, BDC_HEADER_LEN); - h = (struct bdc_header *)PKTDATA(ctx->osh, p); - h->flags = (BDC_PROTO_VER << BDC_FLAG_VER_SHIFT); - if (PKTSUMNEEDED(p)) - h->flags |= BDC_FLAG_SUM_NEEDED; - - - h->priority = (PKTPRIO(p) & BDC_PRIORITY_MASK); - h->flags2 = 0; - h->dataOffset = dataOffset >> 2; - BDC_SET_IF_IDX(h, DHD_PKTTAG_IF(PKTTAG(p))); - return BCME_OK; -} - -static int -_dhd_wlfc_pullheader(athost_wl_status_info_t* ctx, void* pktbuf) -{ - struct bdc_header *h; - - if (PKTLEN(ctx->osh, pktbuf) < BDC_HEADER_LEN) { - WLFC_DBGMESG(("%s: rx data too short (%d < %d)\n", __FUNCTION__, - PKTLEN(ctx->osh, pktbuf), BDC_HEADER_LEN)); - return BCME_ERROR; - } - h = (struct bdc_header *)PKTDATA(ctx->osh, pktbuf); - - /* pull BDC header */ - PKTPULL(ctx->osh, pktbuf, BDC_HEADER_LEN); - - if (PKTLEN(ctx->osh, pktbuf) < (h->dataOffset << 2)) { - WLFC_DBGMESG(("%s: rx data too short (%d < %d)\n", __FUNCTION__, - PKTLEN(ctx->osh, pktbuf), (h->dataOffset << 2))); - return BCME_ERROR; - } - /* pull wl-header */ - PKTPULL(ctx->osh, pktbuf, (h->dataOffset << 2)); - return BCME_OK; -} - -static wlfc_mac_descriptor_t* -_dhd_wlfc_find_table_entry(athost_wl_status_info_t* ctx, void* p) -{ - int i; - wlfc_mac_descriptor_t* table = ctx->destination_entries.nodes; - uint8 ifid = DHD_PKTTAG_IF(PKTTAG(p)); - uint8* dstn = DHD_PKTTAG_DSTN(PKTTAG(p)); - - if (((ctx->destination_entries.interfaces[ifid].iftype == WLC_E_IF_ROLE_STA) || - ETHER_ISMULTI(dstn) || - (ctx->destination_entries.interfaces[ifid].iftype == WLC_E_IF_ROLE_P2P_CLIENT)) && - (ctx->destination_entries.interfaces[ifid].occupied)) { - return &ctx->destination_entries.interfaces[ifid]; - } - - for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { - if (table[i].occupied) { - if (table[i].interface_id == ifid) { - if (!memcmp(table[i].ea, dstn, ETHER_ADDR_LEN)) - return &table[i]; - } - } - } - return &ctx->destination_entries.other; -} - -static int -_dhd_wlfc_rollback_packet_toq(athost_wl_status_info_t* ctx, - void* p, ewlfc_packet_state_t pkt_type, uint32 hslot) -{ - /* - put the packet back to the head of queue - - - a packet from send-q will need to go back to send-q and not delay-q - since that will change the order of packets. - - suppressed packet goes back to suppress sub-queue - - pull out the header, if new or delayed packet - - Note: hslot is used only when header removal is done. - */ - wlfc_mac_descriptor_t* entry; - void* pktout; - int rc = BCME_OK; - int prec; - - entry = _dhd_wlfc_find_table_entry(ctx, p); - prec = DHD_PKTTAG_FIFO(PKTTAG(p)); - if (entry != NULL) { - if (pkt_type == eWLFC_PKTTYPE_SUPPRESSED) { - /* wl-header is saved for suppressed packets */ - if (WLFC_PKTQ_PENQ_HEAD(&entry->psq, ((prec << 1) + 1), p) == NULL) { - WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - rc = BCME_ERROR; - } - } - else { - /* remove header first */ - rc = _dhd_wlfc_pullheader(ctx, p); - if (rc != BCME_OK) { - WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - /* free the hanger slot */ - dhd_wlfc_hanger_poppkt(ctx->hanger, hslot, &pktout, 1); - PKTFREE(ctx->osh, p, TRUE); - rc = BCME_ERROR; - return rc; - } - - if (pkt_type == eWLFC_PKTTYPE_DELAYED) { - /* delay-q packets are going to delay-q */ - if (WLFC_PKTQ_PENQ_HEAD(&entry->psq, (prec << 1), p) == NULL) { - WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - rc = BCME_ERROR; - } - } - else { - /* these are going to SENDQ */ - if (WLFC_PKTQ_PENQ_HEAD(&ctx->SENDQ, prec, p) == NULL) { - WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - rc = BCME_ERROR; - } - } - /* free the hanger slot */ - dhd_wlfc_hanger_poppkt(ctx->hanger, hslot, &pktout, 1); - - /* decrement sequence count */ - WLFC_DECR_SEQCOUNT(entry, prec); - } - /* - if this packet did not count against FIFO credit, it must have - taken a requested_credit from the firmware (for pspoll etc.) - */ - if (!DHD_PKTTAG_CREDITCHECK(PKTTAG(p))) { - entry->requested_credit++; - } - } - else { - WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - rc = BCME_ERROR; - } - if (rc != BCME_OK) - ctx->stats.rollback_failed++; - else - ctx->stats.rollback++; - - return rc; -} - -static void -_dhd_wlfc_flow_control_check(athost_wl_status_info_t* ctx, struct pktq* pq, uint8 if_id) -{ - if ((pq->len <= WLFC_FLOWCONTROL_LOWATER) && (ctx->hostif_flow_state[if_id] == ON)) { - /* start traffic */ - ctx->hostif_flow_state[if_id] = OFF; - /* - WLFC_DBGMESG(("qlen:%02d, if:%02d, ->OFF, start traffic %s()\n", - pq->len, if_id, __FUNCTION__)); - */ - WLFC_DBGMESG(("F")); - dhd_txflowcontrol(ctx->dhdp, if_id, OFF); - ctx->toggle_host_if = 0; - } - if ((pq->len >= WLFC_FLOWCONTROL_HIWATER) && (ctx->hostif_flow_state[if_id] == OFF)) { - /* stop traffic */ - ctx->hostif_flow_state[if_id] = ON; - /* - WLFC_DBGMESG(("qlen:%02d, if:%02d, ->ON, stop traffic %s()\n", - pq->len, if_id, __FUNCTION__)); - */ - WLFC_DBGMESG(("N")); - dhd_txflowcontrol(ctx->dhdp, if_id, ON); - ctx->host_ifidx = if_id; - ctx->toggle_host_if = 1; - } - return; -} - -static int -_dhd_wlfc_send_signalonly_packet(athost_wl_status_info_t* ctx, wlfc_mac_descriptor_t* entry, - uint8 ta_bmp) -{ - int rc = BCME_OK; - void* p = NULL; - int dummylen = ((dhd_pub_t *)ctx->dhdp)->hdrlen+ 12; - - /* allocate a dummy packet */ - p = PKTGET(ctx->osh, dummylen, TRUE); - if (p) { - PKTPULL(ctx->osh, p, dummylen); - DHD_PKTTAG_SET_H2DTAG(PKTTAG(p), 0); - _dhd_wlfc_pushheader(ctx, p, TRUE, ta_bmp, entry->mac_handle, 0); - DHD_PKTTAG_SETSIGNALONLY(PKTTAG(p), 1); -#ifdef PROP_TXSTATUS_DEBUG - ctx->stats.signal_only_pkts_sent++; -#endif - rc = dhd_bus_txdata(((dhd_pub_t *)ctx->dhdp)->bus, p); - if (rc != BCME_OK) { - PKTFREE(ctx->osh, p, TRUE); - } - } - else { - DHD_ERROR(("%s: couldn't allocate new %d-byte packet\n", - __FUNCTION__, dummylen)); - rc = BCME_NOMEM; - } - return rc; -} - -/* Return TRUE if traffic availability changed */ -static bool -_dhd_wlfc_traffic_pending_check(athost_wl_status_info_t* ctx, wlfc_mac_descriptor_t* entry, - int prec) -{ - bool rc = FALSE; - - if (entry->state == WLFC_STATE_CLOSE) { - if ((pktq_plen(&entry->psq, (prec << 1)) == 0) && - (pktq_plen(&entry->psq, ((prec << 1) + 1)) == 0)) { - - if (entry->traffic_pending_bmp & NBITVAL(prec)) { - rc = TRUE; - entry->traffic_pending_bmp = - entry->traffic_pending_bmp & ~ NBITVAL(prec); - } - } - else { - if (!(entry->traffic_pending_bmp & NBITVAL(prec))) { - rc = TRUE; - entry->traffic_pending_bmp = - entry->traffic_pending_bmp | NBITVAL(prec); - } - } - } - if (rc) { - /* request a TIM update to firmware at the next piggyback opportunity */ - if (entry->traffic_lastreported_bmp != entry->traffic_pending_bmp) { - entry->send_tim_signal = 1; - _dhd_wlfc_send_signalonly_packet(ctx, entry, entry->traffic_pending_bmp); - entry->traffic_lastreported_bmp = entry->traffic_pending_bmp; - entry->send_tim_signal = 0; - } - else { - rc = FALSE; - } - } - return rc; -} - -static int -_dhd_wlfc_enque_suppressed(athost_wl_status_info_t* ctx, int prec, void* p) -{ - wlfc_mac_descriptor_t* entry; - - entry = _dhd_wlfc_find_table_entry(ctx, p); - if (entry == NULL) { - WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_NOTFOUND; - } - /* - - suppressed packets go to sub_queue[2*prec + 1] AND - - delayed packets go to sub_queue[2*prec + 0] to ensure - order of delivery. - */ - if (WLFC_PKTQ_PENQ(&entry->psq, ((prec << 1) + 1), p) == NULL) { - ctx->stats.delayq_full_error++; - /* WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); */ - WLFC_DBGMESG(("s")); - return BCME_ERROR; - } - /* A packet has been pushed, update traffic availability bitmap, if applicable */ - _dhd_wlfc_traffic_pending_check(ctx, entry, prec); - _dhd_wlfc_flow_control_check(ctx, &entry->psq, DHD_PKTTAG_IF(PKTTAG(p))); - return BCME_OK; -} - -static int -_dhd_wlfc_pretx_pktprocess(athost_wl_status_info_t* ctx, - wlfc_mac_descriptor_t* entry, void* p, int header_needed, uint32* slot) -{ - int rc = BCME_OK; - int hslot = WLFC_HANGER_MAXITEMS; - bool send_tim_update = FALSE; - uint32 htod = 0; - uint8 free_ctr; - - *slot = hslot; - - if (entry == NULL) { - entry = _dhd_wlfc_find_table_entry(ctx, p); - } - - if (entry == NULL) { - WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_ERROR; - } - if (entry->send_tim_signal) { - send_tim_update = TRUE; - entry->send_tim_signal = 0; - entry->traffic_lastreported_bmp = entry->traffic_pending_bmp; - } - if (header_needed) { - hslot = dhd_wlfc_hanger_get_free_slot(ctx->hanger); - free_ctr = WLFC_SEQCOUNT(entry, DHD_PKTTAG_FIFO(PKTTAG(p))); - DHD_PKTTAG_SET_H2DTAG(PKTTAG(p), htod); - WLFC_PKTFLAG_SET_GENERATION(htod, entry->generation); - entry->transit_count++; - } - else { - hslot = WLFC_PKTID_HSLOT_GET(DHD_PKTTAG_H2DTAG(PKTTAG(p))); - free_ctr = WLFC_PKTID_FREERUNCTR_GET(DHD_PKTTAG_H2DTAG(PKTTAG(p))); - } - WLFC_PKTID_HSLOT_SET(htod, hslot); - WLFC_PKTID_FREERUNCTR_SET(htod, free_ctr); - DHD_PKTTAG_SETPKTDIR(PKTTAG(p), 1); - WL_TXSTATUS_SET_FLAGS(htod, WLFC_PKTFLAG_PKTFROMHOST); - WL_TXSTATUS_SET_FIFO(htod, DHD_PKTTAG_FIFO(PKTTAG(p))); - - if (!DHD_PKTTAG_CREDITCHECK(PKTTAG(p))) { - /* - Indicate that this packet is being sent in response to an - explicit request from the firmware side. - */ - WLFC_PKTFLAG_SET_PKTREQUESTED(htod); - } - else { - WLFC_PKTFLAG_CLR_PKTREQUESTED(htod); - } - if (header_needed) { - rc = _dhd_wlfc_pushheader(ctx, p, send_tim_update, - entry->traffic_lastreported_bmp, entry->mac_handle, htod); - if (rc == BCME_OK) { - DHD_PKTTAG_SET_H2DTAG(PKTTAG(p), htod); - /* - a new header was created for this packet. - push to hanger slot and scrub q. Since bus - send succeeded, increment seq number as well. - */ - rc = dhd_wlfc_hanger_pushpkt(ctx->hanger, p, hslot); - if (rc == BCME_OK) { - /* increment free running sequence count */ - WLFC_INCR_SEQCOUNT(entry, DHD_PKTTAG_FIFO(PKTTAG(p))); -#ifdef PROP_TXSTATUS_DEBUG - ((wlfc_hanger_t*)(ctx->hanger))->items[hslot].push_time = - OSL_SYSUPTIME(); -#endif - } - else { - WLFC_DBGMESG(("%s() hanger_pushpkt() failed, rc: %d\n", - __FUNCTION__, rc)); - } - } - } - else { - int gen; - - /* remove old header */ - rc = _dhd_wlfc_pullheader(ctx, p); - if (rc == BCME_OK) { - hslot = WLFC_PKTID_HSLOT_GET(DHD_PKTTAG_H2DTAG(PKTTAG(p))); - dhd_wlfc_hanger_get_genbit(ctx->hanger, p, hslot, &gen); - - WLFC_PKTFLAG_SET_GENERATION(htod, gen); - free_ctr = WLFC_PKTID_FREERUNCTR_GET(DHD_PKTTAG_H2DTAG(PKTTAG(p))); - /* push new header */ - _dhd_wlfc_pushheader(ctx, p, send_tim_update, - entry->traffic_lastreported_bmp, entry->mac_handle, htod); - } - } - *slot = hslot; - return rc; -} - -static int -_dhd_wlfc_is_destination_closed(athost_wl_status_info_t* ctx, - wlfc_mac_descriptor_t* entry, int prec) -{ - if (ctx->destination_entries.interfaces[entry->interface_id].iftype == - WLC_E_IF_ROLE_P2P_GO) { - /* - destination interface is of type p2p GO. - For a p2pGO interface, if the destination is OPEN but the interface is - CLOSEd, do not send traffic. But if the dstn is CLOSEd while there is - destination-specific-credit left send packets. This is because the - firmware storing the destination-specific-requested packet in queue. - */ - if ((entry->state == WLFC_STATE_CLOSE) && (entry->requested_credit == 0) && - (entry->requested_packet == 0)) - return 1; - } - /* AP, p2p_go -> unicast desc entry, STA/p2p_cl -> interface desc. entry */ - if (((entry->state == WLFC_STATE_CLOSE) && (entry->requested_credit == 0) && - (entry->requested_packet == 0)) || - (!(entry->ac_bitmap & (1 << prec)))) - return 1; - - return 0; -} - -static void* -_dhd_wlfc_deque_delayedq(athost_wl_status_info_t* ctx, - int prec, uint8* ac_credit_spent, uint8* needs_hdr, wlfc_mac_descriptor_t** entry_out) -{ - wlfc_mac_descriptor_t* entry; - wlfc_mac_descriptor_t* table; - uint8 token_pos; - int total_entries; - void* p = NULL; - int pout; - int i; - - *entry_out = NULL; - token_pos = ctx->token_pos[prec]; - /* most cases a packet will count against FIFO credit */ - *ac_credit_spent = 1; - *needs_hdr = 1; - - /* search all entries, include nodes as well as interfaces */ - table = (wlfc_mac_descriptor_t*)&ctx->destination_entries; - total_entries = sizeof(ctx->destination_entries)/sizeof(wlfc_mac_descriptor_t); - - for (i = 0; i < total_entries; i++) { - entry = &table[(token_pos + i) % total_entries]; - if (entry->occupied) { - if (!_dhd_wlfc_is_destination_closed(ctx, entry, prec)) { - p = pktq_mdeq(&entry->psq, - /* higher precedence will be picked up first, - * i.e. suppressed packets before delayed ones - */ - NBITVAL((prec << 1) + 1), &pout); - *needs_hdr = 0; - - if (p == NULL) { - if (entry->suppressed == TRUE) { - if ((entry->suppr_transit_count <= - entry->suppress_count)) { - entry->suppressed = FALSE; - } else { - return NULL; - } - } - /* De-Q from delay Q */ - p = pktq_mdeq(&entry->psq, - NBITVAL((prec << 1)), - &pout); - *needs_hdr = 1; - } - - if (p != NULL) { - /* did the packet come from suppress sub-queue? */ - if (entry->requested_credit > 0) { - entry->requested_credit--; -#ifdef PROP_TXSTATUS_DEBUG - entry->dstncredit_sent_packets++; -#endif - /* - if the packet was pulled out while destination is in - closed state but had a non-zero packets requested, - then this should not count against the FIFO credit. - That is due to the fact that the firmware will - most likely hold onto this packet until a suitable - time later to push it to the appropriate AC FIFO. - */ - if (entry->state == WLFC_STATE_CLOSE) - *ac_credit_spent = 0; - } - else if (entry->requested_packet > 0) { - entry->requested_packet--; - DHD_PKTTAG_SETONETIMEPKTRQST(PKTTAG(p)); - if (entry->state == WLFC_STATE_CLOSE) - *ac_credit_spent = 0; - } - /* move token to ensure fair round-robin */ - ctx->token_pos[prec] = - (token_pos + i + 1) % total_entries; - *entry_out = entry; - _dhd_wlfc_flow_control_check(ctx, &entry->psq, - DHD_PKTTAG_IF(PKTTAG(p))); - /* - A packet has been picked up, update traffic - availability bitmap, if applicable - */ - _dhd_wlfc_traffic_pending_check(ctx, entry, prec); - return p; - } - } - } - } - return NULL; -} - -static void* -_dhd_wlfc_deque_sendq(athost_wl_status_info_t* ctx, int prec) -{ - wlfc_mac_descriptor_t* entry; - void* p; - - - p = pktq_pdeq(&ctx->SENDQ, prec); - if (p != NULL) { - if (ETHER_ISMULTI(DHD_PKTTAG_DSTN(PKTTAG(p)))) - /* bc/mc packets do not have a delay queue */ - return p; - - entry = _dhd_wlfc_find_table_entry(ctx, p); - - if (entry == NULL) { - WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return p; - } - - while ((p != NULL)) { - /* - - suppressed packets go to sub_queue[2*prec + 1] AND - - delayed packets go to sub_queue[2*prec + 0] to ensure - order of delivery. - */ - if (WLFC_PKTQ_PENQ(&entry->psq, (prec << 1), p) == NULL) { - WLFC_DBGMESG(("D")); - /* dhd_txcomplete(ctx->dhdp, p, FALSE); */ - PKTFREE(ctx->osh, p, TRUE); - ctx->stats.delayq_full_error++; - } - /* - A packet has been pushed, update traffic availability bitmap, - if applicable - */ - _dhd_wlfc_traffic_pending_check(ctx, entry, prec); - - p = pktq_pdeq(&ctx->SENDQ, prec); - if (p == NULL) - break; - - entry = _dhd_wlfc_find_table_entry(ctx, p); - - if ((entry == NULL) || (ETHER_ISMULTI(DHD_PKTTAG_DSTN(PKTTAG(p))))) { - return p; - } - } - } - return p; -} - -static int -_dhd_wlfc_mac_entry_update(athost_wl_status_info_t* ctx, wlfc_mac_descriptor_t* entry, - ewlfc_mac_entry_action_t action, uint8 ifid, uint8 iftype, uint8* ea) -{ - int rc = BCME_OK; - -#ifdef QUEUE_BW - dhd_wlfc_queue_bw_reset(entry); -#endif - - if (action == eWLFC_MAC_ENTRY_ACTION_ADD) { - entry->occupied = 1; - entry->state = WLFC_STATE_OPEN; - entry->requested_credit = 0; - entry->interface_id = ifid; - entry->iftype = iftype; - entry->ac_bitmap = 0xff; /* update this when handling APSD */ - /* for an interface entry we may not care about the MAC address */ - if (ea != NULL) - memcpy(&entry->ea[0], ea, ETHER_ADDR_LEN); - pktq_init(&entry->psq, WLFC_PSQ_PREC_COUNT, WLFC_PSQ_LEN); - } - else if (action == eWLFC_MAC_ENTRY_ACTION_UPDATE) { - entry->occupied = 1; - entry->state = WLFC_STATE_OPEN; - entry->requested_credit = 0; - entry->interface_id = ifid; - entry->iftype = iftype; - entry->ac_bitmap = 0xff; /* update this when handling APSD */ - /* for an interface entry we may not care about the MAC address */ - if (ea != NULL) - memcpy(&entry->ea[0], ea, ETHER_ADDR_LEN); - } - else if (action == eWLFC_MAC_ENTRY_ACTION_DEL) { - entry->occupied = 0; - entry->state = WLFC_STATE_CLOSE; - entry->requested_credit = 0; - /* enable after packets are queued-deqeued properly. - pktq_flush(dhd->osh, &entry->psq, FALSE, NULL, 0); - */ - } - return rc; -} - -int -_dhd_wlfc_borrow_credit(athost_wl_status_info_t* ctx, uint8 available_credit_map, int borrower_ac) -{ - int lender_ac; - int rc = BCME_ERROR; - - if (ctx == NULL || available_credit_map == 0) { - WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - /* Borrow from lowest priority available AC (including BC/MC credits) */ - for (lender_ac = 0; lender_ac <= AC_COUNT; lender_ac++) { - if ((available_credit_map && (1 << lender_ac)) && - (ctx->FIFO_credit[lender_ac] > 0)) { - ctx->credits_borrowed[borrower_ac][lender_ac]++; - ctx->FIFO_credit[lender_ac]--; - rc = BCME_OK; - break; - } - } - - return rc; -} - -int -dhd_wlfc_interface_entry_update(void* state, - ewlfc_mac_entry_action_t action, uint8 ifid, uint8 iftype, uint8* ea) -{ - athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state; - wlfc_mac_descriptor_t* entry; - - if (ifid >= WLFC_MAX_IFNUM) - return BCME_BADARG; - - entry = &ctx->destination_entries.interfaces[ifid]; - return _dhd_wlfc_mac_entry_update(ctx, entry, action, ifid, iftype, ea); -} - -int -dhd_wlfc_FIFOcreditmap_update(void* state, uint8* credits) -{ - athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state; - - /* update the AC FIFO credit map */ - ctx->FIFO_credit[0] = credits[0]; - ctx->FIFO_credit[1] = credits[1]; - ctx->FIFO_credit[2] = credits[2]; - ctx->FIFO_credit[3] = credits[3]; - /* credit for bc/mc packets */ - ctx->FIFO_credit[4] = credits[4]; - /* credit for ATIM FIFO is not used yet. */ - ctx->FIFO_credit[5] = 0; - return BCME_OK; -} - -int -dhd_wlfc_enque_sendq(void* state, int prec, void* p) -{ - athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state; - - if ((state == NULL) || - /* prec = AC_COUNT is used for bc/mc queue */ - (prec > AC_COUNT) || - (p == NULL)) { - WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - if (FALSE == dhd_prec_enq(ctx->dhdp, &ctx->SENDQ, p, prec)) { - ctx->stats.sendq_full_error++; - /* - WLFC_DBGMESG(("Error: %s():%d, qlen:%d\n", - __FUNCTION__, __LINE__, ctx->SENDQ.len)); - */ - WLFC_HOST_FIFO_DROPPEDCTR_INC(ctx, prec); - WLFC_DBGMESG(("Q")); - PKTFREE(ctx->osh, p, TRUE); - return BCME_ERROR; - } - -#ifdef QUEUE_BW - wlfc_mac_descriptor_t* entry = _dhd_wlfc_find_table_entry(ctx, p); - if (entry) { - entry->transitallq_count++; - if ((TRANSIT_COUNT(entry) > entry->queued_time_thres) && - (entry->queued_time_last == 0)) { - /* Set timestamp when transit packet above a threshold */ - entry->queued_time_last = QUEUE_BW_SYSUPTIME(); - } - } -#endif - - ctx->stats.pktin++; - /* _dhd_wlfc_flow_control_check(ctx, &ctx->SENDQ, DHD_PKTTAG_IF(PKTTAG(p))); */ - return BCME_OK; -} - -int -_dhd_wlfc_handle_packet_commit(athost_wl_status_info_t* ctx, int ac, - dhd_wlfc_commit_info_t *commit_info, f_commitpkt_t fcommit, void* commit_ctx) -{ - uint32 hslot; - int rc; - - /* - if ac_fifo_credit_spent = 0 - - This packet will not count against the FIFO credit. - To ensure the txstatus corresponding to this packet - does not provide an implied credit (default behavior) - mark the packet accordingly. - - if ac_fifo_credit_spent = 1 - - This is a normal packet and it counts against the FIFO - credit count. - */ - DHD_PKTTAG_SETCREDITCHECK(PKTTAG(commit_info->p), commit_info->ac_fifo_credit_spent); - rc = _dhd_wlfc_pretx_pktprocess(ctx, commit_info->mac_entry, commit_info->p, - commit_info->needs_hdr, &hslot); - - if (rc == BCME_OK) - rc = fcommit(commit_ctx, commit_info->p); - else - ctx->stats.generic_error++; - - if (rc == BCME_OK) { - ctx->stats.pkt2bus++; - if (commit_info->ac_fifo_credit_spent) { - ctx->stats.sendq_pkts[ac]++; - WLFC_HOST_FIFO_CREDIT_INC_SENTCTRS(ctx, ac); - } - } else if (rc == BCME_NORESOURCE) - rc = BCME_ERROR; - else { - /* - bus commit has failed, rollback. - - remove wl-header for a delayed packet - - save wl-header header for suppressed packets - */ - rc = _dhd_wlfc_rollback_packet_toq(ctx, commit_info->p, - (commit_info->pkt_type), hslot); - if (rc != BCME_OK) - ctx->stats.rollback_failed++; - - rc = BCME_ERROR; - } - - return rc; -} - -int -dhd_wlfc_commit_packets(void* state, f_commitpkt_t fcommit, void* commit_ctx) -{ - int ac; - int credit; - int rc; - dhd_wlfc_commit_info_t commit_info; - athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state; - int credit_count = 0; - int bus_retry_count = 0; - uint8 ac_available = 0; /* Bitmask for 4 ACs + BC/MC */ - - if ((state == NULL) || - (fcommit == NULL)) { - WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - memset(&commit_info, 0, sizeof(commit_info)); - - /* - Commit packets for regular AC traffic. Higher priority first. - First, use up FIFO credits available to each AC. Based on distribution - and credits left, borrow from other ACs as applicable - - -NOTE: - If the bus between the host and firmware is overwhelmed by the - traffic from host, it is possible that higher priority traffic - starves the lower priority queue. If that occurs often, we may - have to employ weighted round-robin or ucode scheme to avoid - low priority packet starvation. - */ - - for (ac = AC_COUNT; ac >= 0; ac--) { - - int initial_credit_count = ctx->FIFO_credit[ac]; - - /* packets from SENDQ are fresh and they'd need header and have no MAC entry */ - commit_info.needs_hdr = 1; - commit_info.mac_entry = NULL; - commit_info.pkt_type = eWLFC_PKTTYPE_NEW; - - do { - commit_info.p = _dhd_wlfc_deque_sendq(ctx, ac); - if (commit_info.p == NULL) - break; - else if (ETHER_ISMULTI(DHD_PKTTAG_DSTN(PKTTAG(commit_info.p)))) { - ASSERT(ac == AC_COUNT); - - if (ctx->FIFO_credit[ac]) { - rc = _dhd_wlfc_handle_packet_commit(ctx, ac, &commit_info, - fcommit, commit_ctx); - - /* Bus commits may fail (e.g. flow control); abort after retries */ - if (rc == BCME_OK) { - if (commit_info.ac_fifo_credit_spent) { - (void) _dhd_wlfc_borrow_credit(ctx, - ac_available, ac); - credit_count--; - } - } else { - bus_retry_count++; - if (bus_retry_count >= BUS_RETRIES) { - DHD_ERROR((" %s: bus error\n", - __FUNCTION__)); - return rc; - } - } - } - } - - } while (commit_info.p); - - for (credit = 0; credit < ctx->FIFO_credit[ac];) { - commit_info.p = _dhd_wlfc_deque_delayedq(ctx, ac, - &(commit_info.ac_fifo_credit_spent), - &(commit_info.needs_hdr), - &(commit_info.mac_entry)); - - if (commit_info.p == NULL) - break; - - commit_info.pkt_type = (commit_info.needs_hdr) ? eWLFC_PKTTYPE_DELAYED : - eWLFC_PKTTYPE_SUPPRESSED; - - rc = _dhd_wlfc_handle_packet_commit(ctx, ac, &commit_info, - fcommit, commit_ctx); - - /* Bus commits may fail (e.g. flow control); abort after retries */ - if (rc == BCME_OK) { - if (commit_info.ac_fifo_credit_spent) { - credit++; - } - } - else { - bus_retry_count++; - if (bus_retry_count >= BUS_RETRIES) { - DHD_ERROR(("dhd_wlfc_commit_packets(): bus error\n")); - ctx->FIFO_credit[ac] -= credit; - return rc; - } - } - } - - ctx->FIFO_credit[ac] -= credit; - - - /* If no credits were used, the queue is idle and can be re-used - Note that resv credits cannot be borrowed - */ - if (initial_credit_count == ctx->FIFO_credit[ac]) { - ac_available |= (1 << ac); - credit_count += ctx->FIFO_credit[ac]; - } - } - - /* We borrow only for AC_BE and only if no other traffic seen for DEFER_PERIOD - - Note that (ac_available & WLFC_AC_BE_TRAFFIC_ONLY) is done to: - a) ignore BC/MC for deferring borrow - b) ignore AC_BE being available along with other ACs - (this should happen only for pure BC/MC traffic) - - i.e. AC_VI, AC_VO, AC_BK all MUST be available (i.e. no traffic) and - we do not care if AC_BE and BC/MC are available or not - */ - if ((ac_available & WLFC_AC_BE_TRAFFIC_ONLY) == WLFC_AC_BE_TRAFFIC_ONLY) { - - if (ctx->allow_credit_borrow) { - ac = 1; /* Set ac to AC_BE and borrow credits */ - } - else { - int delta; - int curr_t = OSL_SYSUPTIME(); - - if (curr_t > ctx->borrow_defer_timestamp) - delta = curr_t - ctx->borrow_defer_timestamp; - else - delta = 0xffffffff + curr_t - ctx->borrow_defer_timestamp; - - if (delta >= WLFC_BORROW_DEFER_PERIOD_MS) { - /* Reset borrow but defer to next iteration (defensive borrowing) */ - ctx->allow_credit_borrow = TRUE; - ctx->borrow_defer_timestamp = 0; - } - return BCME_OK; - } - } - else { - /* If we have multiple AC traffic, turn off borrowing, mark time and bail out */ - ctx->allow_credit_borrow = FALSE; - ctx->borrow_defer_timestamp = OSL_SYSUPTIME(); - return BCME_OK; - } - - /* At this point, borrow all credits only for "ac" (which should be set above to AC_BE) - Generically use "ac" only in case we extend to all ACs in future - */ - for (; (credit_count > 0);) { - - commit_info.p = _dhd_wlfc_deque_delayedq(ctx, ac, - &(commit_info.ac_fifo_credit_spent), - &(commit_info.needs_hdr), - &(commit_info.mac_entry)); - if (commit_info.p == NULL) - break; - - commit_info.pkt_type = (commit_info.needs_hdr) ? eWLFC_PKTTYPE_DELAYED : - eWLFC_PKTTYPE_SUPPRESSED; - - rc = _dhd_wlfc_handle_packet_commit(ctx, ac, &commit_info, - fcommit, commit_ctx); - - /* Bus commits may fail (e.g. flow control); abort after retries */ - if (rc == BCME_OK) { - if (commit_info.ac_fifo_credit_spent) { - (void) _dhd_wlfc_borrow_credit(ctx, ac_available, ac); - credit_count--; - } - } - else { - bus_retry_count++; - if (bus_retry_count >= BUS_RETRIES) { - DHD_ERROR(("dhd_wlfc_commit_packets(): bus error\n")); - return rc; - } - } - } - - return BCME_OK; -} - -static uint8 -dhd_wlfc_find_mac_desc_id_from_mac(dhd_pub_t *dhdp, uint8* ea) -{ - wlfc_mac_descriptor_t* table = - ((athost_wl_status_info_t*)dhdp->wlfc_state)->destination_entries.nodes; - uint8 table_index; - - if (ea != NULL) { - for (table_index = 0; table_index < WLFC_MAC_DESC_TABLE_SIZE; table_index++) { - if ((memcmp(ea, &table[table_index].ea[0], ETHER_ADDR_LEN) == 0) && - table[table_index].occupied) - return table_index; - } - } - return WLFC_MAC_DESC_ID_INVALID; -} - -void -dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success) -{ - athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) - dhd->wlfc_state; - void* p; - int fifo_id; - - dhd_os_wlfc_block(dhd); - - if (DHD_PKTTAG_SIGNALONLY(PKTTAG(txp))) { -#ifdef PROP_TXSTATUS_DEBUG - wlfc->stats.signal_only_pkts_freed++; -#endif - if (success) - /* is this a signal-only packet? */ - PKTFREE(wlfc->osh, txp, TRUE); - dhd_os_wlfc_unblock(dhd); - return; - } - if (!success) { - WLFC_DBGMESG(("At: %s():%d, bus_complete() failure for %p, htod_tag:0x%08x\n", - __FUNCTION__, __LINE__, txp, DHD_PKTTAG_H2DTAG(PKTTAG(txp)))); - dhd_wlfc_hanger_poppkt(wlfc->hanger, WLFC_PKTID_HSLOT_GET(DHD_PKTTAG_H2DTAG - (PKTTAG(txp))), &p, 1); - - /* indicate failure and free the packet */ - dhd_txcomplete(dhd, txp, FALSE); - - /* return the credit, if necessary */ - if (DHD_PKTTAG_CREDITCHECK(PKTTAG(txp))) { - int lender, credit_returned = 0; /* Note that borrower is fifo_id */ - - fifo_id = DHD_PKTTAG_FIFO(PKTTAG(txp)); - - /* Return credits to highest priority lender first */ - for (lender = AC_COUNT; lender >= 0; lender--) { - if (wlfc->credits_borrowed[fifo_id][lender] > 0) { - wlfc->FIFO_credit[lender]++; - wlfc->credits_borrowed[fifo_id][lender]--; - credit_returned = 1; - break; - } - } - - if (!credit_returned) { - wlfc->FIFO_credit[fifo_id]++; - } - } - - PKTFREE(wlfc->osh, txp, TRUE); - } - dhd_os_wlfc_unblock(dhd); - return; -} - -static int -dhd_wlfc_compressed_txstatus_update(dhd_pub_t *dhd, uint8* pkt_info, uint8 len) -{ - uint8 status_flag; - uint32 status; - int ret; - int remove_from_hanger = 1; - void* pktbuf; - uint8 fifo_id; - uint8 count = 0; - uint32 status_g; - uint32 hslot, hcnt; - wlfc_mac_descriptor_t* entry = NULL; - athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) - dhd->wlfc_state; - - memcpy(&status, pkt_info, sizeof(uint32)); - status_flag = WL_TXSTATUS_GET_FLAGS(status); - status_g = status & 0xff000000; - hslot = (status & 0x00ffff00) >> 8; - hcnt = status & 0xff; - len = pkt_info[4]; - - wlfc->stats.txstatus_in++; - - if (status_flag == WLFC_CTL_PKTFLAG_DISCARD) { - wlfc->stats.pkt_freed++; - } - - else if (status_flag == WLFC_CTL_PKTFLAG_D11SUPPRESS) { - wlfc->stats.d11_suppress++; - remove_from_hanger = 0; - } - - else if (status_flag == WLFC_CTL_PKTFLAG_WLSUPPRESS) { - wlfc->stats.wl_suppress++; - remove_from_hanger = 0; - } - - else if (status_flag == WLFC_CTL_PKTFLAG_TOSSED_BYWLC) { - wlfc->stats.wlc_tossed_pkts++; - } - while (count < len) { - status = (status_g << 24) | (hslot << 8) | (hcnt); - count++; - hslot++; - hcnt++; - - ret = dhd_wlfc_hanger_poppkt(wlfc->hanger, - WLFC_PKTID_HSLOT_GET(status), &pktbuf, remove_from_hanger); - if (ret != BCME_OK) { - /* do something */ - continue; - } - - entry = _dhd_wlfc_find_table_entry(wlfc, pktbuf); - - if (!remove_from_hanger) { - /* this packet was suppressed */ - if (!entry->suppressed || entry->generation != WLFC_PKTID_GEN(status)) { - entry->suppressed = TRUE; - entry->suppress_count = pktq_mlen(&entry->psq, - NBITVAL((WL_TXSTATUS_GET_FIFO(status) << 1) + 1)); - entry->suppr_transit_count = entry->transit_count; - } - entry->generation = WLFC_PKTID_GEN(status); - } - -#ifdef PROP_TXSTATUS_DEBUG - { - uint32 new_t = OSL_SYSUPTIME(); - uint32 old_t; - uint32 delta; - old_t = ((wlfc_hanger_t*)(wlfc->hanger))->items[ - WLFC_PKTID_HSLOT_GET(status)].push_time; - - - wlfc->stats.latency_sample_count++; - if (new_t > old_t) - delta = new_t - old_t; - else - delta = 0xffffffff + new_t - old_t; - wlfc->stats.total_status_latency += delta; - wlfc->stats.latency_most_recent = delta; - - wlfc->stats.deltas[wlfc->stats.idx_delta++] = delta; - if (wlfc->stats.idx_delta == sizeof(wlfc->stats.deltas)/sizeof(uint32)) - wlfc->stats.idx_delta = 0; - } -#endif /* PROP_TXSTATUS_DEBUG */ - - fifo_id = DHD_PKTTAG_FIFO(PKTTAG(pktbuf)); - - /* pick up the implicit credit from this packet */ - if (DHD_PKTTAG_CREDITCHECK(PKTTAG(pktbuf))) { - if (wlfc->proptxstatus_mode == WLFC_FCMODE_IMPLIED_CREDIT) { - - int lender, credit_returned = 0; /* Note that borrower is fifo_id */ - - /* Return credits to highest priority lender first */ - for (lender = AC_COUNT; lender >= 0; lender--) { - if (wlfc->credits_borrowed[fifo_id][lender] > 0) { - wlfc->FIFO_credit[lender]++; - wlfc->credits_borrowed[fifo_id][lender]--; - credit_returned = 1; - break; - } - } - - if (!credit_returned) { - wlfc->FIFO_credit[fifo_id]++; - } - } - } - else { - /* - if this packet did not count against FIFO credit, it must have - taken a requested_credit from the destination entry (for pspoll etc.) - */ - if (!entry) { - - entry = _dhd_wlfc_find_table_entry(wlfc, pktbuf); - } - if (!DHD_PKTTAG_ONETIMEPKTRQST(PKTTAG(pktbuf))) - entry->requested_credit++; -#ifdef PROP_TXSTATUS_DEBUG - entry->dstncredit_acks++; -#endif - } - if ((status_flag == WLFC_CTL_PKTFLAG_D11SUPPRESS) || - (status_flag == WLFC_CTL_PKTFLAG_WLSUPPRESS)) { - - ret = _dhd_wlfc_enque_suppressed(wlfc, fifo_id, pktbuf); - if (ret != BCME_OK) { - /* delay q is full, drop this packet */ - dhd_wlfc_hanger_poppkt(wlfc->hanger, WLFC_PKTID_HSLOT_GET(status), - &pktbuf, 1); - - /* indicate failure and free the packet */ - dhd_txcomplete(dhd, pktbuf, FALSE); - entry->transit_count--; - DHD_WLFC_QUEUE_BW_COMPLETE(entry); - /* packet is transmitted Successfully by dongle - * after first suppress. - */ - if (entry->suppressed) { - entry->suppr_transit_count--; - } - PKTFREE(wlfc->osh, pktbuf, TRUE); - } else { - /* Mark suppressed to avoid a double free during wlfc cleanup */ - - dhd_wlfc_hanger_mark_suppressed(wlfc->hanger, - WLFC_PKTID_HSLOT_GET(status), WLFC_PKTID_GEN(status)); - entry->suppress_count++; - } - } - else { - dhd_txcomplete(dhd, pktbuf, TRUE); - entry->transit_count--; - DHD_WLFC_QUEUE_BW_COMPLETE(entry); - - /* This packet is transmitted Successfully by dongle - * even after first suppress. - */ - if (entry->suppressed) { - entry->suppr_transit_count--; - } - /* free the packet */ - PKTFREE(wlfc->osh, pktbuf, TRUE); - } - } - return BCME_OK; -} - -/* Handle discard or suppress indication */ -static int -dhd_wlfc_txstatus_update(dhd_pub_t *dhd, uint8* pkt_info) -{ - uint8 status_flag; - uint32 status; - int ret; - int remove_from_hanger = 1; - void* pktbuf; - uint8 fifo_id; - wlfc_mac_descriptor_t* entry = NULL; - athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) - dhd->wlfc_state; - - memcpy(&status, pkt_info, sizeof(uint32)); - status_flag = WL_TXSTATUS_GET_FLAGS(status); - wlfc->stats.txstatus_in++; - - if (status_flag == WLFC_CTL_PKTFLAG_DISCARD) { - wlfc->stats.pkt_freed++; - } - - else if (status_flag == WLFC_CTL_PKTFLAG_D11SUPPRESS) { - wlfc->stats.d11_suppress++; - remove_from_hanger = 0; - } - - else if (status_flag == WLFC_CTL_PKTFLAG_WLSUPPRESS) { - wlfc->stats.wl_suppress++; - remove_from_hanger = 0; - } - - else if (status_flag == WLFC_CTL_PKTFLAG_TOSSED_BYWLC) { - wlfc->stats.wlc_tossed_pkts++; - } - - ret = dhd_wlfc_hanger_poppkt(wlfc->hanger, - WLFC_PKTID_HSLOT_GET(status), &pktbuf, remove_from_hanger); - if (ret != BCME_OK) { - /* do something */ - return ret; - } - - entry = _dhd_wlfc_find_table_entry(wlfc, pktbuf); - - if (!remove_from_hanger) { - /* this packet was suppressed */ - if (!entry->suppressed || entry->generation != WLFC_PKTID_GEN(status)) { - entry->suppressed = TRUE; - entry->suppress_count = pktq_mlen(&entry->psq, - NBITVAL((WL_TXSTATUS_GET_FIFO(status) << 1) + 1)); - entry->suppr_transit_count = entry->transit_count; - } - entry->generation = WLFC_PKTID_GEN(status); - } - -#ifdef PROP_TXSTATUS_DEBUG - { - uint32 new_t = OSL_SYSUPTIME(); - uint32 old_t; - uint32 delta; - old_t = ((wlfc_hanger_t*)(wlfc->hanger))->items[ - WLFC_PKTID_HSLOT_GET(status)].push_time; - - - wlfc->stats.latency_sample_count++; - if (new_t > old_t) - delta = new_t - old_t; - else - delta = 0xffffffff + new_t - old_t; - wlfc->stats.total_status_latency += delta; - wlfc->stats.latency_most_recent = delta; - - wlfc->stats.deltas[wlfc->stats.idx_delta++] = delta; - if (wlfc->stats.idx_delta == sizeof(wlfc->stats.deltas)/sizeof(uint32)) - wlfc->stats.idx_delta = 0; - } -#endif /* PROP_TXSTATUS_DEBUG */ - - fifo_id = DHD_PKTTAG_FIFO(PKTTAG(pktbuf)); - - /* pick up the implicit credit from this packet */ - if (DHD_PKTTAG_CREDITCHECK(PKTTAG(pktbuf))) { - if (wlfc->proptxstatus_mode == WLFC_FCMODE_IMPLIED_CREDIT) { - - int lender, credit_returned = 0; /* Note that borrower is fifo_id */ - - /* Return credits to highest priority lender first */ - for (lender = AC_COUNT; lender >= 0; lender--) { - if (wlfc->credits_borrowed[fifo_id][lender] > 0) { - wlfc->FIFO_credit[lender]++; - wlfc->credits_borrowed[fifo_id][lender]--; - credit_returned = 1; - break; - } - } - - if (!credit_returned) { - wlfc->FIFO_credit[fifo_id]++; - } - } - } - else { - /* - if this packet did not count against FIFO credit, it must have - taken a requested_credit from the destination entry (for pspoll etc.) - */ - if (!entry) { - - entry = _dhd_wlfc_find_table_entry(wlfc, pktbuf); - } - if (!DHD_PKTTAG_ONETIMEPKTRQST(PKTTAG(pktbuf))) - entry->requested_credit++; -#ifdef PROP_TXSTATUS_DEBUG - entry->dstncredit_acks++; -#endif - } - if ((status_flag == WLFC_CTL_PKTFLAG_D11SUPPRESS) || - (status_flag == WLFC_CTL_PKTFLAG_WLSUPPRESS)) { - - ret = _dhd_wlfc_enque_suppressed(wlfc, fifo_id, pktbuf); - if (ret != BCME_OK) { - /* delay q is full, drop this packet */ - dhd_wlfc_hanger_poppkt(wlfc->hanger, WLFC_PKTID_HSLOT_GET(status), - &pktbuf, 1); - - /* indicate failure and free the packet */ - dhd_txcomplete(dhd, pktbuf, FALSE); - entry->transit_count--; - DHD_WLFC_QUEUE_BW_COMPLETE(entry); - /* This packet is transmitted Successfully by - * dongle even after first suppress. - */ - if (entry->suppressed) { - entry->suppr_transit_count--; - } - PKTFREE(wlfc->osh, pktbuf, TRUE); - } else { - /* Mark suppressed to avoid a double free during wlfc cleanup */ - dhd_wlfc_hanger_mark_suppressed(wlfc->hanger, - WLFC_PKTID_HSLOT_GET(status), WLFC_PKTID_GEN(status)); - entry->suppress_count++; - } - } - else { - dhd_txcomplete(dhd, pktbuf, TRUE); - entry->transit_count--; - DHD_WLFC_QUEUE_BW_COMPLETE(entry); - - /* This packet is transmitted Successfully by dongle even after first suppress. */ - if (entry->suppressed) { - entry->suppr_transit_count--; - } - /* free the packet */ - PKTFREE(wlfc->osh, pktbuf, TRUE); - } - return BCME_OK; -} - -static int -dhd_wlfc_fifocreditback_indicate(dhd_pub_t *dhd, uint8* credits) -{ - int i; - athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) - dhd->wlfc_state; - for (i = 0; i < WLFC_CTL_VALUE_LEN_FIFO_CREDITBACK; i++) { -#ifdef PROP_TXSTATUS_DEBUG - wlfc->stats.fifo_credits_back[i] += credits[i]; -#endif - /* update FIFO credits */ - if (wlfc->proptxstatus_mode == WLFC_FCMODE_EXPLICIT_CREDIT) - { - int lender; /* Note that borrower is i */ - - /* Return credits to highest priority lender first */ - for (lender = AC_COUNT; (lender >= 0) && (credits[i] > 0); lender--) { - if (wlfc->credits_borrowed[i][lender] > 0) { - if (credits[i] >= wlfc->credits_borrowed[i][lender]) { - credits[i] -= wlfc->credits_borrowed[i][lender]; - wlfc->FIFO_credit[lender] += - wlfc->credits_borrowed[i][lender]; - wlfc->credits_borrowed[i][lender] = 0; - } - else { - wlfc->credits_borrowed[i][lender] -= credits[i]; - wlfc->FIFO_credit[lender] += credits[i]; - credits[i] = 0; - } - } - } - - /* If we have more credits left over, these must belong to the AC */ - if (credits[i] > 0) { - wlfc->FIFO_credit[i] += credits[i]; - } - } - } - - return BCME_OK; -} - -static int -dhd_wlfc_dbg_senum_check(dhd_pub_t *dhd, uint8 *value) -{ - uint32 timestamp; - - (void)dhd; - - bcopy(&value[2], ×tamp, sizeof(uint32)); - DHD_INFO(("RXPKT: SEQ: %d, timestamp %d\n", value[1], timestamp)); - return BCME_OK; -} - - -static int -dhd_wlfc_rssi_indicate(dhd_pub_t *dhd, uint8* rssi) -{ - (void)dhd; - (void)rssi; - return BCME_OK; -} - -static int -dhd_wlfc_mac_table_update(dhd_pub_t *dhd, uint8* value, uint8 type) -{ - int rc; - athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) - dhd->wlfc_state; - wlfc_mac_descriptor_t* table; - uint8 existing_index; - uint8 table_index; - uint8 ifid; - uint8* ea; - - WLFC_DBGMESG(("%s(), mac [%02x:%02x:%02x:%02x:%02x:%02x],%s,idx:%d,id:0x%02x\n", - __FUNCTION__, value[2], value[3], value[4], value[5], value[6], value[7], - ((type == WLFC_CTL_TYPE_MACDESC_ADD) ? "ADD":"DEL"), - WLFC_MAC_DESC_GET_LOOKUP_INDEX(value[0]), value[0])); - - table = wlfc->destination_entries.nodes; - table_index = WLFC_MAC_DESC_GET_LOOKUP_INDEX(value[0]); - ifid = value[1]; - ea = &value[2]; - - if (type == WLFC_CTL_TYPE_MACDESC_ADD) { - existing_index = dhd_wlfc_find_mac_desc_id_from_mac(dhd, &value[2]); - if (existing_index == WLFC_MAC_DESC_ID_INVALID) { - /* this MAC entry does not exist, create one */ - if (!table[table_index].occupied) { - table[table_index].mac_handle = value[0]; - rc = _dhd_wlfc_mac_entry_update(wlfc, &table[table_index], - eWLFC_MAC_ENTRY_ACTION_ADD, ifid, - wlfc->destination_entries.interfaces[ifid].iftype, - ea); - } - else { - /* the space should have been empty, but it's not */ - wlfc->stats.mac_update_failed++; - } - } - else { - /* - there is an existing entry, move it to new index - if necessary. - */ - if (existing_index != table_index) { - /* if we already have an entry, free the old one */ - table[existing_index].occupied = 0; - table[existing_index].state = WLFC_STATE_CLOSE; - table[existing_index].requested_credit = 0; - table[existing_index].interface_id = 0; - /* enable after packets are queued-deqeued properly. - pktq_flush(dhd->osh, &table[existing_index].psq, FALSE, NULL, 0); - */ - } - } - } - if (type == WLFC_CTL_TYPE_MACDESC_DEL) { - if (table[table_index].occupied) { - rc = _dhd_wlfc_mac_entry_update(wlfc, &table[table_index], - eWLFC_MAC_ENTRY_ACTION_DEL, ifid, - wlfc->destination_entries.interfaces[ifid].iftype, - ea); - } - else { - /* the space should have been occupied, but it's not */ - wlfc->stats.mac_update_failed++; - } - } - BCM_REFERENCE(rc); - return BCME_OK; -} - -static int -dhd_wlfc_psmode_update(dhd_pub_t *dhd, uint8* value, uint8 type) -{ - /* Handle PS on/off indication */ - athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) - dhd->wlfc_state; - wlfc_mac_descriptor_t* table; - wlfc_mac_descriptor_t* desc; - uint8 mac_handle = value[0]; - int i; - - table = wlfc->destination_entries.nodes; - desc = &table[WLFC_MAC_DESC_GET_LOOKUP_INDEX(mac_handle)]; - if (desc->occupied) { - /* a fresh PS mode should wipe old ps credits? */ - desc->requested_credit = 0; - if (type == WLFC_CTL_TYPE_MAC_OPEN) { - desc->state = WLFC_STATE_OPEN; - DHD_WLFC_CTRINC_MAC_OPEN(desc); - } - else { - desc->state = WLFC_STATE_CLOSE; - DHD_WLFC_CTRINC_MAC_CLOSE(desc); - /* - Indicate to firmware if there is any traffic pending. - */ - for (i = AC_BE; i < AC_COUNT; i++) { - _dhd_wlfc_traffic_pending_check(wlfc, desc, i); - } - } - } - else { - wlfc->stats.psmode_update_failed++; - } - return BCME_OK; -} - -static int -dhd_wlfc_interface_update(dhd_pub_t *dhd, uint8* value, uint8 type) -{ - /* Handle PS on/off indication */ - athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) - dhd->wlfc_state; - wlfc_mac_descriptor_t* table; - uint8 if_id = value[0]; - - if (if_id < WLFC_MAX_IFNUM) { - table = wlfc->destination_entries.interfaces; - if (table[if_id].occupied) { - if (type == WLFC_CTL_TYPE_INTERFACE_OPEN) { - table[if_id].state = WLFC_STATE_OPEN; - /* WLFC_DBGMESG(("INTERFACE[%d] OPEN\n", if_id)); */ - } - else { - table[if_id].state = WLFC_STATE_CLOSE; - /* WLFC_DBGMESG(("INTERFACE[%d] CLOSE\n", if_id)); */ - } - return BCME_OK; - } - } - wlfc->stats.interface_update_failed++; - - return BCME_OK; -} - -static int -dhd_wlfc_credit_request(dhd_pub_t *dhd, uint8* value) -{ - athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) - dhd->wlfc_state; - wlfc_mac_descriptor_t* table; - wlfc_mac_descriptor_t* desc; - uint8 mac_handle; - uint8 credit; - - table = wlfc->destination_entries.nodes; - mac_handle = value[1]; - credit = value[0]; - - desc = &table[WLFC_MAC_DESC_GET_LOOKUP_INDEX(mac_handle)]; - if (desc->occupied) { - desc->requested_credit = credit; - - desc->ac_bitmap = value[2]; - } - else { - wlfc->stats.credit_request_failed++; - } - return BCME_OK; -} - -static int -dhd_wlfc_packet_request(dhd_pub_t *dhd, uint8* value) -{ - athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) - dhd->wlfc_state; - wlfc_mac_descriptor_t* table; - wlfc_mac_descriptor_t* desc; - uint8 mac_handle; - uint8 packet_count; - - table = wlfc->destination_entries.nodes; - mac_handle = value[1]; - packet_count = value[0]; - - desc = &table[WLFC_MAC_DESC_GET_LOOKUP_INDEX(mac_handle)]; - if (desc->occupied) { - desc->requested_packet = packet_count; - - desc->ac_bitmap = value[2]; - } - else { - wlfc->stats.packet_request_failed++; - } - return BCME_OK; -} - -static void -dhd_wlfc_reorderinfo_indicate(uint8 *val, uint8 len, uchar *info_buf, uint *info_len) -{ - if (info_len) { - if (info_buf) { - bcopy(val, info_buf, len); - *info_len = len; - } - else - *info_len = 0; - } -} - -static int -dhd_wlfc_parse_header_info(dhd_pub_t *dhd, void* pktbuf, int tlv_hdr_len, uchar *reorder_info_buf, - uint *reorder_info_len) -{ - uint8 type, len; - uint8* value; - uint8* tmpbuf; - uint16 remainder = tlv_hdr_len; - uint16 processed = 0; - athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) - dhd->wlfc_state; - tmpbuf = (uint8*)PKTDATA(dhd->osh, pktbuf); - if (remainder) { - while ((processed < (WLFC_MAX_PENDING_DATALEN * 2)) && (remainder > 0)) { - type = tmpbuf[processed]; - if (type == WLFC_CTL_TYPE_FILLER) { - remainder -= 1; - processed += 1; - continue; - } - - len = tmpbuf[processed + 1]; - value = &tmpbuf[processed + 2]; - - if (remainder < (2 + len)) - break; - - remainder -= 2 + len; - processed += 2 + len; - if (type == WLFC_CTL_TYPE_TXSTATUS) - dhd_wlfc_txstatus_update(dhd, value); - if (type == WLFC_CTL_TYPE_COMP_TXSTATUS) - dhd_wlfc_compressed_txstatus_update(dhd, value, len); - - else if (type == WLFC_CTL_TYPE_HOST_REORDER_RXPKTS) - dhd_wlfc_reorderinfo_indicate(value, len, reorder_info_buf, - reorder_info_len); - else if (type == WLFC_CTL_TYPE_FIFO_CREDITBACK) - dhd_wlfc_fifocreditback_indicate(dhd, value); - - else if (type == WLFC_CTL_TYPE_RSSI) - dhd_wlfc_rssi_indicate(dhd, value); - - else if (type == WLFC_CTL_TYPE_MAC_REQUEST_CREDIT) - dhd_wlfc_credit_request(dhd, value); - - else if (type == WLFC_CTL_TYPE_MAC_REQUEST_PACKET) - dhd_wlfc_packet_request(dhd, value); - - else if ((type == WLFC_CTL_TYPE_MAC_OPEN) || - (type == WLFC_CTL_TYPE_MAC_CLOSE)) - dhd_wlfc_psmode_update(dhd, value, type); - - else if ((type == WLFC_CTL_TYPE_MACDESC_ADD) || - (type == WLFC_CTL_TYPE_MACDESC_DEL)) - dhd_wlfc_mac_table_update(dhd, value, type); - - else if (type == WLFC_CTL_TYPE_TRANS_ID) - dhd_wlfc_dbg_senum_check(dhd, value); - - else if ((type == WLFC_CTL_TYPE_INTERFACE_OPEN) || - (type == WLFC_CTL_TYPE_INTERFACE_CLOSE)) { - dhd_wlfc_interface_update(dhd, value, type); - } - } - if (remainder != 0) { - /* trouble..., something is not right */ - wlfc->stats.tlv_parse_failed++; - } - } - return BCME_OK; -} - -int -dhd_wlfc_init(dhd_pub_t *dhd) -{ - char iovbuf[12]; /* Room for "tlv" + '\0' + parameter */ - uint32 tlv; - - if (!dhd) { - DHD_ERROR(("dhd_wlfc_init(): dhd == NULL\n")); - return -ENODEV; - } - - /* enable all signals & indicate host proptxstatus logic is active */ - tlv = dhd->wlfc_enabled ? - WLFC_FLAGS_RSSI_SIGNALS | - WLFC_FLAGS_XONXOFF_SIGNALS | - WLFC_FLAGS_CREDIT_STATUS_SIGNALS | - WLFC_FLAGS_HOST_PROPTXSTATUS_ACTIVE | - WLFC_FLAGS_HOST_RXRERODER_ACTIVE : 0; - /* WLFC_FLAGS_HOST_PROPTXSTATUS_ACTIVE | WLFC_FLAGS_HOST_RXRERODER_ACTIVE : 0; */ - - /* - try to enable/disable signaling by sending "tlv" iovar. if that fails, - fallback to no flow control? Print a message for now. - */ - - /* enable proptxtstatus signaling by default */ - bcm_mkiovar("tlv", (char *)&tlv, 4, iovbuf, sizeof(iovbuf)); - if (dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0) < 0) { - DHD_ERROR(("dhd_wlfc_init(): failed to enable/disable bdcv2 tlv signaling\n")); - } - else { - /* - Leaving the message for now, it should be removed after a while; once - the tlv situation is stable. - */ - DHD_ERROR(("dhd_wlfc_init(): successfully %s bdcv2 tlv signaling, %d\n", - dhd->wlfc_enabled?"enabled":"disabled", tlv)); - } - return BCME_OK; -} - -int -dhd_wlfc_enable(dhd_pub_t *dhd) -{ - int i; - athost_wl_status_info_t* wlfc; - - DHD_TRACE(("Enter %s\n", __FUNCTION__)); - - if (!dhd->wlfc_enabled || dhd->wlfc_state) - return BCME_OK; - - /* allocate space to track txstatus propagated from firmware */ - dhd->wlfc_state = MALLOC(dhd->osh, sizeof(athost_wl_status_info_t)); - if (dhd->wlfc_state == NULL) - return BCME_NOMEM; - - /* initialize state space */ - wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; - memset(wlfc, 0, sizeof(athost_wl_status_info_t)); - - /* remember osh & dhdp */ - wlfc->osh = dhd->osh; - wlfc->dhdp = dhd; - - wlfc->hanger = - dhd_wlfc_hanger_create(dhd->osh, WLFC_HANGER_MAXITEMS); - if (wlfc->hanger == NULL) { - MFREE(dhd->osh, dhd->wlfc_state, sizeof(athost_wl_status_info_t)); - dhd->wlfc_state = NULL; - return BCME_NOMEM; - } - - /* initialize all interfaces to accept traffic */ - for (i = 0; i < WLFC_MAX_IFNUM; i++) { - wlfc->hostif_flow_state[i] = OFF; - } - - /* - create the SENDQ containing - sub-queues for all AC precedences + 1 for bc/mc traffic - */ - pktq_init(&wlfc->SENDQ, (AC_COUNT + 1), WLFC_SENDQ_LEN); - - wlfc->destination_entries.other.state = WLFC_STATE_OPEN; - /* bc/mc FIFO is always open [credit aside], i.e. b[5] */ - wlfc->destination_entries.other.ac_bitmap = 0x1f; - wlfc->destination_entries.other.interface_id = 0; - - wlfc->proptxstatus_mode = WLFC_FCMODE_EXPLICIT_CREDIT; - - wlfc->allow_credit_borrow = TRUE; - wlfc->borrow_defer_timestamp = 0; - - return BCME_OK; -} - -/* release all packet resources */ -void -dhd_wlfc_cleanup(dhd_pub_t *dhd) -{ - int i; - int total_entries; - athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) - dhd->wlfc_state; - wlfc_mac_descriptor_t* table; - wlfc_hanger_t* h; - int prec; - void *pkt = NULL; - struct pktq *txq = NULL; - - DHD_TRACE(("Enter %s\n", __FUNCTION__)); - if (dhd->wlfc_state == NULL) - return; - /* flush bus->txq */ - txq = dhd_bus_txq(dhd->bus); - - /* any in the hanger? */ - h = (wlfc_hanger_t*)wlfc->hanger; - total_entries = sizeof(wlfc->destination_entries)/sizeof(wlfc_mac_descriptor_t); - /* search all entries, include nodes as well as interfaces */ - table = (wlfc_mac_descriptor_t*)&wlfc->destination_entries; - - for (i = 0; i < total_entries; i++) { - if (table[i].occupied) { - if (table[i].psq.len) { - WLFC_DBGMESG(("%s(): DELAYQ[%d].len = %d\n", - __FUNCTION__, i, table[i].psq.len)); - /* release packets held in DELAYQ */ - pktq_flush(wlfc->osh, &table[i].psq, TRUE, NULL, 0); - } - table[i].occupied = 0; - } - } - /* release packets held in SENDQ */ - if (wlfc->SENDQ.len) - pktq_flush(wlfc->osh, &wlfc->SENDQ, TRUE, NULL, 0); - for (prec = 0; prec < txq->num_prec; prec++) { - pkt = pktq_pdeq(txq, prec); - while (pkt) { - for (i = 0; i < h->max_items; i++) { - if (pkt == h->items[i].pkt) { - if (h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE) { - PKTFREE(wlfc->osh, h->items[i].pkt, TRUE); - h->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; - h->items[i].pkt = NULL; - h->items[i].identifier = 0; - } else if (h->items[i].state == - WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED) { - /* These are already freed from the psq */ - h->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; - } - break; - } - } - pkt = pktq_pdeq(txq, prec); - } - } - /* flush remained pkt in hanger queue, not in bus->txq */ - for (i = 0; i < h->max_items; i++) { - if (h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE) { - PKTFREE(wlfc->osh, h->items[i].pkt, TRUE); - h->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; - } else if (h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED) { - /* These are freed from the psq so no need to free again */ - h->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; - } - } - - return; -} - -void -dhd_wlfc_deinit(dhd_pub_t *dhd) -{ - /* cleanup all psq related resources */ - athost_wl_status_info_t* wlfc = NULL; - - if (dhd == NULL) - return; - - wlfc = (athost_wl_status_info_t*) - dhd->wlfc_state; - - DHD_TRACE(("Enter %s\n", __FUNCTION__)); - - dhd_os_wlfc_block(dhd); - if (dhd->wlfc_state == NULL) { - dhd_os_wlfc_unblock(dhd); - return; - } - -#ifdef PROP_TXSTATUS_DEBUG - { - int i; - wlfc_hanger_t* h = (wlfc_hanger_t*)wlfc->hanger; - for (i = 0; i < h->max_items; i++) { - if (h->items[i].state != WLFC_HANGER_ITEM_STATE_FREE) { - WLFC_DBGMESG(("%s() pkt[%d] = 0x%p, FIFO_credit_used:%d\n", - __FUNCTION__, i, h->items[i].pkt, - DHD_PKTTAG_CREDITCHECK(PKTTAG(h->items[i].pkt)))); - } - } - } -#endif - /* delete hanger */ - dhd_wlfc_hanger_delete(dhd->osh, wlfc->hanger); - - /* free top structure */ - MFREE(dhd->osh, dhd->wlfc_state, sizeof(athost_wl_status_info_t)); - dhd->wlfc_state = NULL; - dhd_os_wlfc_unblock(dhd); - - - return; -} -#endif /* PROP_TXSTATUS */ - void dhd_prot_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) { bcm_bprintf(strbuf, "Protocol CDC: reqid %d\n", dhdp->prot->reqid); #ifdef PROP_TXSTATUS - dhd_os_wlfc_block(dhdp); if (dhdp->wlfc_state) dhd_wlfc_dump(dhdp, strbuf); - dhd_os_wlfc_unblock(dhdp); #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) +dhd_prot_hdrpush(dhd_pub_t *dhd, int ifidx, void *PKTBUF) { #ifdef BDC struct bdc_header *h; @@ -2851,21 +363,22 @@ dhd_prot_hdrpush(dhd_pub_t *dhd, int ifidx, void *pktbuf) #ifdef BDC /* Push BDC header used to convey priority for buses that don't */ - PKTPUSH(dhd->osh, pktbuf, BDC_HEADER_LEN); + PKTPUSH(dhd->osh, PKTBUF, BDC_HEADER_LEN); - h = (struct bdc_header *)PKTDATA(dhd->osh, pktbuf); + h = (struct bdc_header *)PKTDATA(dhd->osh, PKTBUF); h->flags = (BDC_PROTO_VER << BDC_FLAG_VER_SHIFT); - if (PKTSUMNEEDED(pktbuf)) + if (PKTSUMNEEDED(PKTBUF)) h->flags |= BDC_FLAG_SUM_NEEDED; - h->priority = (PKTPRIO(pktbuf) & BDC_PRIORITY_MASK); + 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 */ int dhd_prot_hdrpull(dhd_pub_t *dhd, int *ifidx, void *pktbuf, uchar *reorder_buf_info, @@ -2891,10 +404,6 @@ dhd_prot_hdrpull(dhd_pub_t *dhd, int *ifidx, void *pktbuf, uchar *reorder_buf_in h = (struct bdc_header *)PKTDATA(dhd->osh, pktbuf); -#if defined(NDIS630) - h->dataOffset = 0; -#endif - if (!ifidx) { /* for tx packet, skip the analysis */ data_offset = h->dataOffset; @@ -2928,14 +437,8 @@ dhd_prot_hdrpull(dhd_pub_t *dhd, int *ifidx, void *pktbuf, uchar *reorder_buf_in PKTPULL(dhd->osh, pktbuf, BDC_HEADER_LEN); #endif /* BDC */ -#if !defined(NDIS630) - if (PKTLEN(dhd->osh, pktbuf) < (uint32) (data_offset << 2)) { - DHD_ERROR(("%s: rx data too short (%d < %d)\n", __FUNCTION__, - PKTLEN(dhd->osh, pktbuf), (data_offset * 4))); - return BCME_ERROR; - } -#endif #ifdef PROP_TXSTATUS + dhd_os_wlfc_block(dhd); if (dhd->wlfc_state && ((athost_wl_status_info_t*)dhd->wlfc_state)->proptxstatus_mode != WLFC_FCMODE_NONE && @@ -2943,18 +446,16 @@ dhd_prot_hdrpull(dhd_pub_t *dhd, int *ifidx, void *pktbuf, uchar *reorder_buf_in /* - parse txstatus only for packets that came from the firmware */ - dhd_os_wlfc_block(dhd); dhd_wlfc_parse_header_info(dhd, pktbuf, (data_offset << 2), reorder_buf_info, reorder_info_len); ((athost_wl_status_info_t*)dhd->wlfc_state)->stats.dhd_hdrpulls++; - dhd_os_wlfc_unblock(dhd); + } + dhd_os_wlfc_unblock(dhd); #endif /* PROP_TXSTATUS */ exit: -#if !defined(NDIS630) PKTPULL(dhd->osh, pktbuf, (data_offset << 2)); -#endif return 0; } @@ -2962,14 +463,14 @@ exit: void dhd_wlfc_trigger_pktcommit(dhd_pub_t *dhd) { + dhd_os_wlfc_block(dhd); if (dhd->wlfc_state && (((athost_wl_status_info_t*)dhd->wlfc_state)->proptxstatus_mode != WLFC_FCMODE_NONE)) { - dhd_os_wlfc_block(dhd); dhd_wlfc_commit_packets(dhd->wlfc_state, (f_commitpkt_t)dhd_bus_txdata, - (void *)dhd->bus); - dhd_os_wlfc_unblock(dhd); + (void *)dhd->bus, NULL); } + dhd_os_wlfc_unblock(dhd); } #endif @@ -3013,6 +514,8 @@ dhd_prot_detach(dhd_pub_t *dhd) { #ifdef PROP_TXSTATUS dhd_wlfc_deinit(dhd); + if (dhd->plat_deinit) + dhd->plat_deinit((void *)dhd); #endif #ifndef CONFIG_DHD_USE_STATIC_BUF MFREE(dhd->osh, dhd->prot, sizeof(dhd_prot_t)); @@ -3052,11 +555,6 @@ dhd_prot_init(dhd_pub_t *dhd) if (dhd_download_fw_on_driverload) #endif /* defined(WL_CFG80211) */ ret = dhd_preinit_ioctls(dhd); - -#ifdef PROP_TXSTATUS - ret = dhd_wlfc_init(dhd); -#endif - /* Always assumes wl for now */ dhd->iswl = TRUE; @@ -3157,7 +655,7 @@ dhd_process_pkt_reorder_info(dhd_pub_t *dhd, uchar *reorder_info_buf, uint reord __FUNCTION__, flow_id)); if (ptr == NULL) { - DHD_ERROR(("%s: received flags to cleanup, but no flow (%d) yet\n", + DHD_REORDER(("%s: received flags to cleanup, but no flow (%d) yet\n", __FUNCTION__, flow_id)); *pkt_count = 1; *pkt = cur_pkt; diff --git a/drivers/net/wireless/bcmdhd/dhd_cfg80211.c b/drivers/net/wireless/bcmdhd/dhd_cfg80211.c index 94d1b629ddc0..e4984c6a6e3d 100644..100755 --- a/drivers/net/wireless/bcmdhd/dhd_cfg80211.c +++ b/drivers/net/wireless/bcmdhd/dhd_cfg80211.c @@ -1,7 +1,7 @@ /* * Linux cfg80211 driver - Dongle Host Driver (DHD) related * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -152,6 +152,43 @@ default_conf_out: } +#ifdef CONFIG_NL80211_TESTMODE +int dhd_cfg80211_testmode_cmd(struct wiphy *wiphy, void *data, int len) +{ + struct sk_buff *reply; + struct wl_priv *wl; + dhd_pub_t *dhd; + dhd_ioctl_t *ioc = data; + int err = 0; + + WL_TRACE(("entry: cmd = %d\n", ioc->cmd)); + wl = wiphy_priv(wiphy); + dhd = wl->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); + } + + /* currently there is only one wiphy for ifidx 0 */ + err = dhd_ioctl_process(dhd, 0, ioc); + if (err) + goto done; + + /* response data is in ioc->buf so return ioc here */ + reply = cfg80211_testmode_alloc_reply_skb(wiphy, sizeof(*ioc)); + nla_put(reply, NL80211_ATTR_TESTDATA, sizeof(*ioc), ioc); + err = cfg80211_testmode_reply(reply); +done: + DHD_OS_WAKE_UNLOCK(dhd); + return err; +} +#endif /* CONFIG_NL80211_TESTMODE */ /* TODO: clean up the BT-Coex code, it still have some legacy ioctl/iovar functions */ #define COEX_DHCP @@ -255,7 +292,7 @@ static bool btcoex_is_sco_active(struct net_device *dev) break; } - msleep(5); + OSL_SLEEP(5); } return res; @@ -419,6 +456,7 @@ static void wl_cfg80211_bt_handler(struct work_struct *work) * provide OPPORTUNITY window to get DHCP address */ WL_TRACE(("bt_dhcp stm: started \n")); + btcx_inf->bt_state = BT_DHCP_OPPR_WIN; mod_timer(&btcx_inf->timer, jiffies + msecs_to_jiffies(BT_DHCP_OPPR_WIN_TIME)); @@ -461,7 +499,7 @@ btc_coex_idle: break; default: - WL_ERR(("error g_status=%d !!!\n", btcx_inf->bt_state)); + WL_ERR(("error g_status=%d !!!\n", btcx_inf->bt_state)); if (btcx_inf->dev) wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE); btcx_inf->bt_state = BT_DHCP_IDLE; @@ -512,7 +550,6 @@ void wl_cfg80211_btcoex_deinit(struct wl_priv *wl) kfree(wl->btcoex_info); wl->btcoex_info = NULL; } -#endif int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, char *command) { @@ -544,10 +581,6 @@ int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, char *command) if (strnicmp((char *)&powermode_val, "1", strlen("1")) == 0) { WL_TRACE_HW4(("DHCP session starts\n")); -#if defined(DHCP_SCAN_SUPPRESS) - /* Suppress scan during the DHCP */ - wl_cfg80211_scan_suppress(dev, 1); -#endif /* OEM_ANDROID */ #ifdef PKT_FILTER_SUPPORT dhd->dhcp_in_progress = 1; @@ -601,15 +634,11 @@ int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, char *command) else if (strnicmp((char *)&powermode_val, "2", strlen("2")) == 0) { + #ifdef PKT_FILTER_SUPPORT dhd->dhcp_in_progress = 0; WL_TRACE_HW4(("DHCP is complete \n")); -#if defined(DHCP_SCAN_SUPPRESS) - /* Since DHCP is complete, enable the scan back */ - wl_cfg80211_scan_suppress(dev, 0); -#endif /* OEM_ANDROID */ - /* Enable packet filtering */ if (dhd->early_suspended) { WL_TRACE_HW4(("DHCP is complete , enable packet filter!!!\n")); @@ -666,3 +695,4 @@ int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, char *command) return (strlen("OK")); } +#endif diff --git a/drivers/net/wireless/bcmdhd/dhd_cfg80211.h b/drivers/net/wireless/bcmdhd/dhd_cfg80211.h index 922d6edde00e..c5c8c215f995 100644..100755 --- a/drivers/net/wireless/bcmdhd/dhd_cfg80211.h +++ b/drivers/net/wireless/bcmdhd/dhd_cfg80211.h @@ -1,7 +1,7 @@ /* * Linux cfg80211 driver - Dongle Host Driver (DHD) related * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -38,6 +38,15 @@ s32 dhd_cfg80211_set_p2p_info(struct wl_priv *wl, int val); s32 dhd_cfg80211_clean_p2p_info(struct wl_priv *wl); s32 dhd_config_dongle(struct wl_priv *wl, bool need_lock); +#ifdef CONFIG_NL80211_TESTMODE +int dhd_cfg80211_testmode_cmd(struct wiphy *wiphy, void *data, int len); +#else +static inline int dhd_cfg80211_testmode_cmd(struct wiphy *wiphy, void *data, int len) +{ + return 0; +} +#endif + int wl_cfg80211_btcoex_init(struct wl_priv *wl); void wl_cfg80211_btcoex_deinit(struct wl_priv *wl); diff --git a/drivers/net/wireless/bcmdhd/dhd_common.c b/drivers/net/wireless/bcmdhd/dhd_common.c index 188d8359fdd6..62c924c9cdaa 100644..100755 --- a/drivers/net/wireless/bcmdhd/dhd_common.c +++ b/drivers/net/wireless/bcmdhd/dhd_common.c @@ -1,14 +1,14 @@ /* * Broadcom Dongle Host Driver (DHD), common DHD core. * - * Copyright (C) 1999-2012, Broadcom Corporation - * + * Copyright (C) 1999-2013, Broadcom Corporation + * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2 (the "GPL"), * available at http://www.broadcom.com/licenses/GPLv2.php, with the * following added to such license: - * + * * As a special exception, the copyright holders of this software give you * permission to link this software with independent modules, and to copy and * distribute the resulting executable under terms of your choice, provided that @@ -16,12 +16,12 @@ * 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_common.c 386753 2013-02-21 20:37:53Z $ + * $Id: dhd_common.c 419132 2013-08-19 21:33:05Z $ */ #include <typedefs.h> #include <osl.h> @@ -33,8 +33,10 @@ #include <dngl_stats.h> #include <wlioctl.h> #include <dhd.h> +#include <dhd_ip.h> #include <proto/bcmevent.h> +#include <proto/bcmip.h> #include <dhd_bus.h> #include <dhd_proto.h> @@ -44,9 +46,8 @@ #ifdef WL_CFG80211 #include <wl_cfg80211.h> #endif -#ifdef WLBTAMP -#include <proto/bt_amp_hci.h> -#include <dhd_bta.h> +#ifdef PNO_SUPPORT +#include <dhd_pno.h> #endif #ifdef SET_RANDOM_MAC_SOFTAP #include <linux/random.h> @@ -65,7 +66,6 @@ #include <dhd_wlfc.h> #endif - #ifdef WLMEDIA_HTSF extern void htsf_update(struct dhd_info *dhd, void *data); #endif @@ -123,10 +123,6 @@ enum { IOV_LOGSTAMP, IOV_GPIOOB, IOV_IOCTLTIMEOUT, -#ifdef WLBTAMP - IOV_HCI_CMD, /* HCI command */ - IOV_HCI_ACL_DATA, /* HCI data packet */ -#endif #if defined(DHD_DEBUG) IOV_CONS, IOV_DCONSOLE_POLL, @@ -134,11 +130,12 @@ enum { #ifdef PROP_TXSTATUS IOV_PROPTXSTATUS_ENABLE, IOV_PROPTXSTATUS_MODE, -#ifdef QUEUE_BW - IOV_QUEUED_TIME_THRES, - IOV_QUEUED_TIME_PERCENT, -#endif /* QUEUE_BW */ -#endif + IOV_PROPTXSTATUS_OPT, +#ifdef QMONITOR + IOV_QMON_TIME_THRES, + IOV_QMON_TIME_PERCENT, +#endif /* QMONITOR */ +#endif /* PROP_TXSTATUS */ IOV_BUS_TYPE, #ifdef WLMEDIA_HTSF IOV_WLPKTDLYSTAT_SZ, @@ -164,10 +161,6 @@ const bcm_iovar_t dhd_iovars[] = { {"clearcounts", IOV_CLEARCOUNTS, 0, IOVT_VOID, 0 }, {"gpioob", IOV_GPIOOB, 0, IOVT_UINT32, 0 }, {"ioctl_timeout", IOV_IOCTLTIMEOUT, 0, IOVT_UINT32, 0 }, -#ifdef WLBTAMP - {"HCI_cmd", IOV_HCI_CMD, 0, IOVT_BUFFER, 0}, - {"HCI_ACL_data", IOV_HCI_ACL_DATA, 0, IOVT_BUFFER, 0}, -#endif #ifdef PROP_TXSTATUS {"proptx", IOV_PROPTXSTATUS_ENABLE, 0, IOVT_UINT32, 0 }, /* @@ -177,11 +170,12 @@ const bcm_iovar_t dhd_iovars[] = { 2 - Use explicit credit */ {"ptxmode", IOV_PROPTXSTATUS_MODE, 0, IOVT_UINT32, 0 }, -#ifdef QUEUE_BW - {"qtime_thres", IOV_QUEUED_TIME_THRES, 0, IOVT_UINT32, 0 }, - {"qtime_percent", IOV_QUEUED_TIME_PERCENT, 0, IOVT_UINT32, 0 }, -#endif /* QUEUE_BW */ -#endif + {"proptx_opt", IOV_PROPTXSTATUS_OPT, 0, IOVT_UINT32, 0 }, +#ifdef QMONITOR + {"qtime_thres", IOV_QMON_TIME_THRES, 0, IOVT_UINT32, 0 }, + {"qtime_percent", IOV_QMON_TIME_PERCENT, 0, IOVT_UINT32, 0 }, +#endif /* QMONITOR */ +#endif /* PROP_TXSTATUS */ {"bustype", IOV_BUS_TYPE, 0, IOVT_UINT32, 0}, #ifdef WLMEDIA_HTSF {"pktdlystatsz", IOV_WLPKTDLYSTAT_SZ, 0, IOVT_UINT8, 0 }, @@ -191,6 +185,7 @@ const bcm_iovar_t dhd_iovars[] = { (WLHOST_REORDERDATA_MAXFLOWS + 1) }, {NULL, 0, 0, 0, 0 } }; +#define DHD_IOVAR_BUF_SIZE 128 void dhd_common_init(osl_t *osh) @@ -208,7 +203,28 @@ dhd_common_init(osl_t *osh) #ifdef SOFTAP fw_path2[0] = '\0'; #endif - DHD_ERROR(("bcmdhd: fw_path: %s nvram_path: %s\n", fw_path, nv_path)); +} + +void +dhd_common_deinit(dhd_pub_t *dhd_pub, dhd_cmn_t *sa_cmn) +{ + osl_t *osh; + dhd_cmn_t *cmn; + + if (dhd_pub != NULL) + cmn = dhd_pub->cmn; + else + cmn = sa_cmn; + + if (!cmn) + return; + + osh = cmn->osh; + + if (dhd_pub != NULL) + dhd_pub->cmn = NULL; + + MFREE(osh, cmn, sizeof(dhd_cmn_t)); } static int @@ -226,31 +242,31 @@ dhd_dump(dhd_pub_t *dhdp, char *buf, int buflen) 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 %d pub.maxctl %d pub.rxsz %d\n", + 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 %d\n", dhdp->bcmerror, dhdp->tickcnt); + bcm_bprintf(strbuf, "pub.bcmerror %d tickcnt %u\n", dhdp->bcmerror, dhdp->tickcnt); bcm_bprintf(strbuf, "dongle stats:\n"); - bcm_bprintf(strbuf, "tx_packets %ld tx_bytes %ld tx_errors %ld tx_dropped %ld\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 %ld rx_bytes %ld rx_errors %ld rx_dropped %ld\n", + 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 %ld\n", dhdp->dstats.multicast); + bcm_bprintf(strbuf, "multicast %lu\n", dhdp->dstats.multicast); bcm_bprintf(strbuf, "bus stats:\n"); - bcm_bprintf(strbuf, "tx_packets %ld tx_multicast %ld tx_errors %ld\n", + bcm_bprintf(strbuf, "tx_packets %lu tx_multicast %lu tx_errors %lu\n", dhdp->tx_packets, dhdp->tx_multicast, dhdp->tx_errors); - bcm_bprintf(strbuf, "tx_ctlpkts %ld tx_ctlerrs %ld\n", + bcm_bprintf(strbuf, "tx_ctlpkts %lu tx_ctlerrs %lu\n", dhdp->tx_ctlpkts, dhdp->tx_ctlerrs); - bcm_bprintf(strbuf, "rx_packets %ld rx_multicast %ld rx_errors %ld \n", + 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 %ld rx_ctlerrs %ld rx_dropped %ld\n", + 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 %ld tx_realloc %ld\n", + bcm_bprintf(strbuf, "rx_readahead_cnt %lu tx_realloc %lu\n", dhdp->rx_readahead_cnt, dhdp->tx_realloc); bcm_bprintf(strbuf, "\n"); @@ -281,18 +297,27 @@ dhd_wl_ioctl_cmd(dhd_pub_t *dhd_pub, int cmd, void *arg, int len, uint8 set, int int dhd_wl_ioctl(dhd_pub_t *dhd_pub, int ifindex, wl_ioctl_t *ioc, void *buf, int len) { - int ret; + int ret = 0; - dhd_os_proto_block(dhd_pub); + if (dhd_os_proto_block(dhd_pub)) + { + + ret = dhd_prot_ioctl(dhd_pub, ifindex, ioc, buf, len); + if ((ret) && (dhd_pub->up)) + /* Send hang event only if dhd_open() was success */ + dhd_os_check_hang(dhd_pub, ifindex, ret); - ret = dhd_prot_ioctl(dhd_pub, ifindex, ioc, buf, len); - if ((ret) && (dhd_pub->up)) - /* Send hang event only if dhd_open() was success */ - dhd_os_check_hang(dhd_pub, ifindex, 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_os_proto_unblock(dhd_pub); + dhd_os_proto_unblock(dhd_pub); + } return ret; } @@ -422,37 +447,6 @@ dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const ch break; } -#ifdef WLBTAMP - case IOV_SVAL(IOV_HCI_CMD): { - amp_hci_cmd_t *cmd = (amp_hci_cmd_t *)arg; - - /* sanity check: command preamble present */ - if (len < HCI_CMD_PREAMBLE_SIZE) - return BCME_BUFTOOSHORT; - - /* sanity check: command parameters are present */ - if (len < (int)(HCI_CMD_PREAMBLE_SIZE + cmd->plen)) - return BCME_BUFTOOSHORT; - - dhd_bta_docmd(dhd_pub, cmd, len); - break; - } - - case IOV_SVAL(IOV_HCI_ACL_DATA): { - amp_hci_ACL_data_t *ACL_data = (amp_hci_ACL_data_t *)arg; - - /* sanity check: HCI header present */ - if (len < HCI_ACL_DATA_PREAMBLE_SIZE) - return BCME_BUFTOOSHORT; - - /* sanity check: ACL data is present */ - if (len < (int)(HCI_ACL_DATA_PREAMBLE_SIZE + ACL_data->dlen)) - return BCME_BUFTOOSHORT; - - dhd_bta_tx_hcidata(dhd_pub, ACL_data, len); - break; - } -#endif /* WLBTAMP */ #ifdef PROP_TXSTATUS case IOV_GVAL(IOV_PROPTXSTATUS_ENABLE): @@ -479,22 +473,24 @@ dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const ch wlfc->proptxstatus_mode = int_val & 0xff; } break; - -#ifdef QUEUE_BW - case IOV_GVAL(IOV_QUEUED_TIME_THRES): - int_val = dhd_wlfc_queue_bw_iovar_thres(dhd_pub, FALSE, int_val); +#ifdef QMONITOR + case IOV_GVAL(IOV_QMON_TIME_THRES): { + int_val = dhd_qmon_thres(dhd_pub, FALSE, 0); bcopy(&int_val, arg, val_size); break; + } - case IOV_SVAL(IOV_QUEUED_TIME_THRES): - dhd_wlfc_queue_bw_iovar_thres(dhd_pub, TRUE, int_val); + case IOV_SVAL(IOV_QMON_TIME_THRES): { + dhd_qmon_thres(dhd_pub, TRUE, int_val); break; + } - case IOV_GVAL(IOV_QUEUED_TIME_PERCENT): - int_val = dhd_wlfc_queue_bw_iovar_getpercent(dhd_pub); + case IOV_GVAL(IOV_QMON_TIME_PERCENT): { + int_val = dhd_qmon_getpercent(dhd_pub); bcopy(&int_val, arg, val_size); break; -#endif /* QUEUE_BW */ + } +#endif /* QMONITOR */ #endif /* PROP_TXSTATUS */ case IOV_GVAL(IOV_BUS_TYPE): @@ -587,7 +583,8 @@ dhd_prec_enq(dhd_pub_t *dhdp, struct pktq *q, void *pkt, int prec) if (pktq_pfull(q, prec)) eprec = prec; else if (pktq_full(q)) { - pktq_peek_tail(q, &eprec); + p = pktq_peek_tail(q, &eprec); + ASSERT(p); if (eprec > prec || eprec < 0) return FALSE; } @@ -607,7 +604,91 @@ dhd_prec_enq(dhd_pub_t *dhdp, struct pktq *q, void *pkt, int prec) } /* Enqueue */ - pktq_penq(q, prec, pkt); + 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(osl_t *osh, struct pktq *pq, int prec) +{ + struct pktq_prec *q = NULL; + void *p, *prev = NULL, *next = NULL, *first = NULL, *last = NULL, *prev_first = NULL; + pkt_frag_t frag_info; + + ASSERT(osh && 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(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; + } 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); + + PKTFREE(osh, 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); + } return TRUE; } @@ -922,6 +1003,7 @@ wl_show_host_event(wl_event_msg_t *event, void *event_data) case WLC_E_TRACE: { static uint32 seqnum_prev = 0; + static uint32 logtrace_seqnum_prev = 0; msgtrace_hdr_t hdr; uint32 nblost; char *s, *p; @@ -938,35 +1020,72 @@ wl_show_host_event(wl_event_msg_t *event, void *event_data) break; } - /* There are 2 bytes available at the end of data */ - buf[MSGTRACE_HDRLEN + ntoh16(hdr.len)] = '\0'; + if (hdr.trace_type == MSGTRACE_HDR_TYPE_MSG) { + /* There are 2 bytes available at the end of data */ + buf[MSGTRACE_HDRLEN + ntoh16(hdr.len)] = '\0'; - if (ntoh32(hdr.discarded_bytes) || ntoh32(hdr.discarded_printf)) { - printf("\nWLC_E_TRACE: [Discarded traces in dongle -->" - "discarded_bytes %d discarded_printf %d]\n", - ntoh32(hdr.discarded_bytes), ntoh32(hdr.discarded_printf)); - } + if (ntoh32(hdr.discarded_bytes) || ntoh32(hdr.discarded_printf)) { + printf("\nWLC_E_TRACE: [Discarded traces in dongle -->" + "discarded_bytes %d discarded_printf %d]\n", + ntoh32(hdr.discarded_bytes), ntoh32(hdr.discarded_printf)); + } - nblost = ntoh32(hdr.seqnum) - seqnum_prev - 1; - if (nblost > 0) { - printf("\nWLC_E_TRACE: [Event lost --> seqnum %d nblost %d\n", - ntoh32(hdr.seqnum), nblost); - } - seqnum_prev = ntoh32(hdr.seqnum); - - /* Display the trace buffer. Advance from \n to \n to avoid display big - * printf (issue with Linux printk ) - */ - p = (char *)&buf[MSGTRACE_HDRLEN]; - while ((s = strstr(p, "\n")) != NULL) { - *s = '\0'; - printf("%s\n", p); - p = s+1; + nblost = ntoh32(hdr.seqnum) - seqnum_prev - 1; + if (nblost > 0) { + printf("\nWLC_E_TRACE: [Event lost (msg) --> seqnum %d nblost %d\n", + ntoh32(hdr.seqnum), nblost); + } + seqnum_prev = ntoh32(hdr.seqnum); + + /* Display the trace buffer. Advance from \n to \n to avoid display big + * printf (issue with Linux printk ) + */ + p = (char *)&buf[MSGTRACE_HDRLEN]; + while (*p != '\0' && (s = strstr(p, "\n")) != NULL) { + *s = '\0'; + printf("%s\n", p); + p = s+1; + } + if (*p) printf("%s", p); + + /* Reset datalen to avoid display below */ + datalen = 0; + + } else if (hdr.trace_type == MSGTRACE_HDR_TYPE_LOG) { + /* Let the standard event printing work for now */ + uint32 timestamp, w; + if (ntoh32(hdr.seqnum) == logtrace_seqnum_prev) { + printf("\nWLC_E_TRACE: [Event duplicate (log) %d", + logtrace_seqnum_prev); + } else { + nblost = ntoh32(hdr.seqnum) - logtrace_seqnum_prev - 1; + if (nblost > 0) { + printf("\nWLC_E_TRACE: [Event lost (log)" + " --> seqnum %d nblost %d\n", + ntoh32(hdr.seqnum), nblost); + } + logtrace_seqnum_prev = ntoh32(hdr.seqnum); + + p = (char *)&buf[MSGTRACE_HDRLEN]; + datalen -= MSGTRACE_HDRLEN; + w = ntoh32((uint32) *p); + p += 4; + datalen -= 4; + timestamp = ntoh32((uint32) *p); + printf("Logtrace %x timestamp %x %x", + logtrace_seqnum_prev, timestamp, w); + + while (datalen > 4) { + p += 4; + datalen -= 4; + /* Print each word. DO NOT ntoh it. */ + printf(" %8.8x", *((uint32 *) p)); + } + printf("\n"); + } + datalen = 0; } - printf("%s\n", p); - /* Reset datalen to avoid display below */ - datalen = 0; break; } @@ -978,7 +1097,7 @@ wl_show_host_event(wl_event_msg_t *event, void *event_data) 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)); + DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); break; default: @@ -989,7 +1108,7 @@ wl_show_host_event(wl_event_msg_t *event, void *event_data) } /* show any appended data */ - if (datalen) { + if (DHD_BYTES_ON() && DHD_EVENT_ON() && datalen) { buf = (uchar *) event_data; DHD_EVENT((" data (%d) : ", datalen)); for (i = 0; i < datalen; i++) @@ -1036,8 +1155,10 @@ wl_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata, switch (type) { #ifdef PROP_TXSTATUS case WLC_E_FIFO_CREDIT_MAP: + dhd_os_wlfc_block(dhd_pub); dhd_wlfc_event(dhd_pub->info); dhd_wlfc_FIFOcreditmap_event(dhd_pub->info, event_data); + dhd_os_wlfc_unblock(dhd_pub); 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], @@ -1065,6 +1186,8 @@ wl_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata, ((ifevent->is_AP == 0) ? "STA":"AP "), ea[0], ea[1], ea[2], ea[3], ea[4], ea[5])); (void)ea; + + dhd_os_wlfc_block(dhd_pub); if (ifevent->action == WLC_E_IF_CHANGE) dhd_wlfc_interface_event(dhd_pub->info, eWLFC_MAC_ENTRY_ACTION_UPDATE, @@ -1074,7 +1197,7 @@ wl_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata, ((ifevent->action == WLC_E_IF_ADD) ? eWLFC_MAC_ENTRY_ACTION_ADD : eWLFC_MAC_ENTRY_ACTION_DEL), ifevent->ifidx, ifevent->is_AP, ea); - + dhd_os_wlfc_unblock(dhd_pub); /* dhd already has created an interface by default, for 0 */ if (ifevent->ifidx == 0) @@ -1128,17 +1251,22 @@ wl_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata, htsf_update(dhd_pub->info, event_data); break; #endif /* WLMEDIA_HTSF */ -#if defined(NDIS630) - case WLC_E_NDIS_LINK: - break; -#else /* defined(NDIS630) && defined(BCMDONGLEHOST) */ case WLC_E_NDIS_LINK: { uint32 temp = hton32(WLC_E_LINK); memcpy((void *)(&pvt_data->event.event_type), &temp, sizeof(pvt_data->event.event_type)); } + case WLC_E_PFN_NET_FOUND: + case WLC_E_PFN_NET_LOST: + break; + case WLC_E_PFN_BSSID_NET_FOUND: + case WLC_E_PFN_BSSID_NET_LOST: + case WLC_E_PFN_BEST_BATCHING: +#ifdef PNO_SUPPORT + dhd_pno_event_handler(dhd_pub, event, (void *)event_data); #endif + break; /* These are what external supplicant/authenticator wants */ /* fall through */ case WLC_E_LINK: @@ -1458,6 +1586,19 @@ fail: if (buf) MFREE(dhd->osh, buf, BUF_SIZE); } + +void dhd_pktfilter_offload_delete(dhd_pub_t *dhd, int id) +{ + char iovbuf[32]; + int ret; + + bcm_mkiovar("pkt_filter_delete", (char *)&id, 4, iovbuf, sizeof(iovbuf)); + ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + if (ret < 0) { + DHD_ERROR(("%s: Failed to delete filter ID:%d, ret=%d\n", + __FUNCTION__, id, ret)); + } +} #endif /* PKT_FILTER_SUPPORT */ /* ========================== */ @@ -1518,7 +1659,7 @@ dhd_aoe_arp_clr(dhd_pub_t *dhd, int idx) { int ret = 0; int iov_len = 0; - char iovbuf[128]; + char iovbuf[DHD_IOVAR_BUF_SIZE]; if (dhd == NULL) return; if (dhd->arp_version == 1) @@ -1534,7 +1675,7 @@ dhd_aoe_hostip_clr(dhd_pub_t *dhd, int idx) { int ret = 0; int iov_len = 0; - char iovbuf[128]; + char iovbuf[DHD_IOVAR_BUF_SIZE]; if (dhd == NULL) return; if (dhd->arp_version == 1) @@ -1549,7 +1690,7 @@ void dhd_arp_offload_add_ip(dhd_pub_t *dhd, uint32 ipaddr, int idx) { int iov_len = 0; - char iovbuf[32]; + char iovbuf[DHD_IOVAR_BUF_SIZE]; int retcode; @@ -1607,16 +1748,90 @@ dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen, int idx) 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) +{ + char iovbuf[DHD_IOVAR_BUF_SIZE]; + int retcode; + + if (dhd == NULL) + return -1; + + bcm_mkiovar("ndoe", (char *)&ndo_enable, 4, iovbuf, sizeof(iovbuf)); + retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), 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: add host ipv6 ip into firmware + * 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]; + int retcode; + + if (dhd == NULL || ipv6addr == NULL) + return -1; + + iov_len = bcm_mkiovar("nd_hostip", ipv6addr, + IPV6_ADDR_LEN, iovbuf, sizeof(iovbuf)); + 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_ERROR(("%s: ndo ipaddr entry added \n", + __FUNCTION__)); + return retcode; +} +/* + * Neighbor Discover Offload: disable 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]; + int retcode; + + if (dhd == NULL) + return -1; + + iov_len = bcm_mkiovar("nd_hostip_clear", (char *)NULL, + 0, iovbuf, sizeof(iovbuf)); + 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; +} /* send up locally generated event */ void dhd_sendup_event_common(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data) { switch (ntoh32(event->event_type)) { -#ifdef WLBTAMP - case WLC_E_BTA_HCI_EVENT: - break; -#endif /* WLBTAMP */ default: break; } @@ -1709,22 +1924,22 @@ dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd) bcn_li_dtim = dhd->suspend_bcn_li_dtim; /* check if sta listen interval fits into AP dtim */ - if (dtim_assoc > LISTEN_INTERVAL) { + if (dtim_assoc > CUSTOM_LISTEN_INTERVAL) { /* AP DTIM to big for our Listen Interval : no dtim skiping */ bcn_li_dtim = 1; DHD_ERROR(("%s DTIM=%d > Listen=%d : too big ...\n", - __FUNCTION__, dtim_assoc, LISTEN_INTERVAL)); + __FUNCTION__, dtim_assoc, CUSTOM_LISTEN_INTERVAL)); goto exit; } - if ((bcn_li_dtim * dtim_assoc) > LISTEN_INTERVAL) { + if ((bcn_li_dtim * dtim_assoc) > CUSTOM_LISTEN_INTERVAL) { /* Round up dtim_skip to fit into STAs Listen Interval */ - bcn_li_dtim = (int)(LISTEN_INTERVAL / dtim_assoc); + bcn_li_dtim = (int)(CUSTOM_LISTEN_INTERVAL / dtim_assoc); 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__, ap_beacon, bcn_li_dtim, dtim_assoc, LISTEN_INTERVAL)); + __FUNCTION__, ap_beacon, bcn_li_dtim, dtim_assoc, CUSTOM_LISTEN_INTERVAL)); exit: return bcn_li_dtim; @@ -1742,213 +1957,12 @@ bool dhd_support_sta_mode(dhd_pub_t *dhd) return TRUE; } -#if defined(PNO_SUPPORT) -int -dhd_pno_clean(dhd_pub_t *dhd) -{ - char iovbuf[128]; - int pfn_enabled = 0; - int iov_len = 0; - int ret; - - /* Disable pfn */ - iov_len = bcm_mkiovar("pfn", (char *)&pfn_enabled, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) >= 0) { - /* clear pfn */ - iov_len = bcm_mkiovar("pfnclear", 0, 0, iovbuf, sizeof(iovbuf)); - if (iov_len) { - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, - iov_len, TRUE, 0)) < 0) { - DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret)); - } - } - else { - ret = -1; - DHD_ERROR(("%s failed code %d\n", __FUNCTION__, iov_len)); - } - } - else - DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret)); - - return ret; -} - -int -dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled) -{ - char iovbuf[128]; - int ret = -1; - - if ((!dhd) && ((pfn_enabled != 0) || (pfn_enabled != 1))) { - DHD_ERROR(("%s error exit\n", __FUNCTION__)); - return ret; - } - -#ifndef WL_SCHED_SCAN - if (!dhd_support_sta_mode(dhd)) - return (ret); - - memset(iovbuf, 0, sizeof(iovbuf)); - - if ((pfn_enabled) && (dhd_is_associated(dhd, NULL, NULL) == TRUE)) { - DHD_ERROR(("%s pno is NOT enable : called in assoc mode , ignore\n", __FUNCTION__)); - return ret; - } -#endif /* !WL_SCHED_SCAN */ - - /* Enable/disable PNO */ - if ((ret = bcm_mkiovar("pfn", (char *)&pfn_enabled, 4, iovbuf, sizeof(iovbuf))) > 0) { - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, - iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) { - DHD_ERROR(("%s failed for error=%d\n", __FUNCTION__, ret)); - return ret; - } - else { - dhd->pno_enable = pfn_enabled; - DHD_TRACE(("%s set pno as %s\n", - __FUNCTION__, dhd->pno_enable ? "Enable" : "Disable")); - } - } - else DHD_ERROR(("%s failed err=%d\n", __FUNCTION__, ret)); - - return ret; -} - -/* Function to execute combined scan */ -int -dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, ushort scan_fr, - int pno_repeat, int pno_freq_expo_max) -{ - int err = -1; - char iovbuf[128]; - int k, i; - wl_pfn_param_t pfn_param; - wl_pfn_t pfn_element; - uint len = 0; - - DHD_TRACE(("%s nssid=%d nchan=%d\n", __FUNCTION__, nssid, scan_fr)); - - if ((!dhd) || (!ssids_local)) { - DHD_ERROR(("%s error exit(%s %s)\n", __FUNCTION__, - (!dhd)?"dhd is null":"", (!ssids_local)?"ssid is null":"")); - err = -1; - return err; - } -#ifndef WL_SCHED_SCAN - if (!dhd_support_sta_mode(dhd)) - return err; -#endif /* !WL_SCHED_SCAN */ - - /* Check for broadcast ssid */ - for (k = 0; k < nssid; k++) { - if (!ssids_local[k].SSID_len) { - DHD_ERROR(("%d: Broadcast SSID is ilegal for PNO setting\n", k)); - return err; - } - } -/* #define PNO_DUMP 1 */ -#ifdef PNO_DUMP - { - int j; - for (j = 0; j < nssid; j++) { - DHD_ERROR(("%d: scan for %s size =%d\n", j, - ssids_local[j].SSID, ssids_local[j].SSID_len)); - } - } -#endif /* PNO_DUMP */ - - /* clean up everything */ - if ((err = dhd_pno_clean(dhd)) < 0) { - DHD_ERROR(("%s failed error=%d\n", __FUNCTION__, err)); - return err; - } - memset(iovbuf, 0, sizeof(iovbuf)); - memset(&pfn_param, 0, sizeof(pfn_param)); - memset(&pfn_element, 0, sizeof(pfn_element)); - - /* set pfn parameters */ - pfn_param.version = htod32(PFN_VERSION); - pfn_param.flags = htod16((PFN_LIST_ORDER << SORT_CRITERIA_BIT)); - - /* check and set extra pno params */ - if ((pno_repeat != 0) || (pno_freq_expo_max != 0)) { - pfn_param.flags |= htod16(ENABLE << ENABLE_ADAPTSCAN_BIT); - pfn_param.repeat = (uchar) (pno_repeat); - pfn_param.exp = (uchar) (pno_freq_expo_max); - } - /* set up pno scan fr */ - if (scan_fr != 0) - pfn_param.scan_freq = htod32(scan_fr); - - if (pfn_param.scan_freq > PNO_SCAN_MAX_FW_SEC) { - DHD_ERROR(("%s pno freq above %d sec\n", __FUNCTION__, PNO_SCAN_MAX_FW_SEC)); - return err; - } - if (pfn_param.scan_freq < PNO_SCAN_MIN_FW_SEC) { - DHD_ERROR(("%s pno freq less %d sec\n", __FUNCTION__, PNO_SCAN_MIN_FW_SEC)); - return err; - } - - len = bcm_mkiovar("pfn_set", (char *)&pfn_param, sizeof(pfn_param), iovbuf, sizeof(iovbuf)); - if ((err = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, len, TRUE, 0)) < 0) { - DHD_ERROR(("%s pfn_set failed for error=%d\n", - __FUNCTION__, err)); - return err; - } - - /* set all pfn ssid */ - for (i = 0; i < nssid; i++) { - - pfn_element.infra = htod32(DOT11_BSSTYPE_INFRASTRUCTURE); - pfn_element.auth = (DOT11_OPEN_SYSTEM); - pfn_element.wpa_auth = htod32(WPA_AUTH_PFN_ANY); - pfn_element.wsec = htod32(0); - pfn_element.infra = htod32(1); - pfn_element.flags = htod32(ENABLE << WL_PFN_HIDDEN_BIT); - memcpy((char *)pfn_element.ssid.SSID, ssids_local[i].SSID, ssids_local[i].SSID_len); - pfn_element.ssid.SSID_len = ssids_local[i].SSID_len; - - if ((len = - bcm_mkiovar("pfn_add", (char *)&pfn_element, - sizeof(pfn_element), iovbuf, sizeof(iovbuf))) > 0) { - if ((err = - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, len, TRUE, 0)) < 0) { - DHD_ERROR(("%s failed for i=%d error=%d\n", - __FUNCTION__, i, err)); - return err; - } - else - DHD_TRACE(("%s set OK with PNO time=%d repeat=%d max_adjust=%d\n", - __FUNCTION__, pfn_param.scan_freq, - pfn_param.repeat, pfn_param.exp)); - } - else DHD_ERROR(("%s failed err=%d\n", __FUNCTION__, err)); - } - - /* Enable PNO */ - /* dhd_pno_enable(dhd, 1); */ - return err; -} - -int -dhd_pno_get_status(dhd_pub_t *dhd) -{ - int ret = -1; - - if (!dhd) - return ret; - else - return (dhd->pno_enable); -} - -#endif /* OEM_ANDROID && PNO_SUPPORT */ - #if defined(KEEP_ALIVE) int dhd_keep_alive_onoff(dhd_pub_t *dhd) { char buf[256]; const char *str; - wl_mkeep_alive_pkt_t mkeep_alive_pkt; + wl_mkeep_alive_pkt_t mkeep_alive_pkt = {0}; wl_mkeep_alive_pkt_t *mkeep_alive_pktp; int buf_len; int str_len; diff --git a/drivers/net/wireless/bcmdhd/dhd_custom_gpio.c b/drivers/net/wireless/bcmdhd/dhd_custom_gpio.c index 891c071c2ee6..075c84980a42 100644..100755 --- a/drivers/net/wireless/bcmdhd/dhd_custom_gpio.c +++ b/drivers/net/wireless/bcmdhd/dhd_custom_gpio.c @@ -1,6 +1,6 @@ /* * Customer code to add GPIO control during WLAN start/stop -* Copyright (C) 1999-2012, Broadcom Corporation +* Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -20,7 +20,7 @@ * 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_custom_gpio.c 353167 2012-08-24 22:11:30Z $ +* $Id: dhd_custom_gpio.c 417465 2013-08-09 11:47:27Z $ */ #include <typedefs.h> @@ -42,6 +42,8 @@ extern void bcm_wlan_power_off(int); extern void bcm_wlan_power_on(int); #endif /* CUSTOMER_HW */ #if defined(CUSTOMER_HW2) + + #ifdef CONFIG_WIFI_CONTROL_FUNC int wifi_set_power(int on, unsigned long msec); int wifi_get_irq_number(unsigned long *irq_flags_ptr); @@ -61,7 +63,7 @@ void *wifi_get_country_code(char *ccode) { return NULL; } extern int sdioh_mmc_irq(int irq); #endif /* (BCMLXSDMMC) */ -#ifdef CUSTOMER_HW3 +#if defined(CUSTOMER_HW3) #include <mach/gpio.h> #endif @@ -130,7 +132,7 @@ dhd_customer_gpio_wlan_ctrl(int onoff) bcm_wlan_power_off(2); #endif /* CUSTOMER_HW */ #if defined(CUSTOMER_HW2) - wifi_set_power(0, 300); + wifi_set_power(0, WIFI_TURNOFF_DELAY); #endif WL_ERROR(("=========== WLAN placed in RESET ========\n")); break; @@ -142,7 +144,7 @@ dhd_customer_gpio_wlan_ctrl(int onoff) bcm_wlan_power_on(2); #endif /* CUSTOMER_HW */ #if defined(CUSTOMER_HW2) - wifi_set_power(1, 0); + wifi_set_power(1, 200); #endif WL_ERROR(("=========== WLAN going back to live ========\n")); break; diff --git a/drivers/net/wireless/bcmdhd/dhd_dbg.h b/drivers/net/wireless/bcmdhd/dhd_dbg.h index b3733df495d2..0ee773f6ad38 100644..100755 --- a/drivers/net/wireless/bcmdhd/dhd_dbg.h +++ b/drivers/net/wireless/bcmdhd/dhd_dbg.h @@ -1,14 +1,14 @@ /* * Debug/trace/assert driver definitions for Dongle Host Driver. * - * Copyright (C) 1999-2012, Broadcom Corporation - * + * Copyright (C) 1999-2013, Broadcom Corporation + * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2 (the "GPL"), * available at http://www.broadcom.com/licenses/GPLv2.php, with the * following added to such license: - * + * * As a special exception, the copyright holders of this software give you * permission to link this software with independent modules, and to copy and * distribute the resulting executable under terms of your choice, provided that @@ -16,12 +16,12 @@ * the license of that module. An independent module is a module which is not * derived from this software. The special exception does not apply to any * modifications of the software. - * + * * Notwithstanding the above, under no circumstances may you combine this * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd_dbg.h 353490 2012-08-27 21:10:02Z $ + * $Id: dhd_dbg.h 419132 2013-08-19 21:33:05Z $ */ #ifndef _dhd_dbg_ @@ -47,6 +47,7 @@ #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_TRACE_HW4 DHD_TRACE @@ -65,6 +66,8 @@ #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) #else /* defined(BCMDBG) || defined(DHD_DEBUG) */ @@ -83,6 +86,7 @@ #define DHD_ISCAN(args) #define DHD_ARPOE(args) #define DHD_REORDER(args) +#define DHD_PNO(args) #define DHD_TRACE_HW4 DHD_TRACE @@ -101,7 +105,10 @@ #define DHD_ISCAN_ON() 0 #define DHD_ARPOE_ON() 0 #define DHD_REORDER_ON() 0 -#endif +#define DHD_NOCHECKDIED_ON() 0 +#define DHD_PNO_ON() 0 + +#endif #define DHD_LOG(args) diff --git a/drivers/net/wireless/bcmdhd/dhd_ip.c b/drivers/net/wireless/bcmdhd/dhd_ip.c new file mode 100755 index 000000000000..b4fb5e3c36f1 --- /dev/null +++ b/drivers/net/wireless/bcmdhd/dhd_ip.c @@ -0,0 +1,111 @@ +/* + * IP Packet Parser Module. + * + * Copyright (C) 1999-2013, 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$ + */ +#include <typedefs.h> +#include <osl.h> + +#include <proto/ethernet.h> +#include <proto/vlan.h> +#include <proto/802.3.h> +#include <proto/bcmip.h> +#include <bcmendian.h> + +#include <dhd_dbg.h> + +#include <dhd_ip.h> + +/* 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 = 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; + } +} diff --git a/drivers/net/wireless/bcmdhd/dhd_ip.h b/drivers/net/wireless/bcmdhd/dhd_ip.h new file mode 100755 index 000000000000..ceb3877549c5 --- /dev/null +++ b/drivers/net/wireless/bcmdhd/dhd_ip.h @@ -0,0 +1,42 @@ +/* + * Header file describing the common ip parser function. + * + * Provides type definitions and function prototypes used to parse ip packet. + * + * Copyright (C) 1999-2013, 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$ + */ + +#ifndef _dhd_ip_h_ +#define _dhd_ip_h_ + +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); + +#endif /* _dhd_ip_h_ */ diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c index 546d98b6964c..a0c81c95fff7 100644..100755 --- a/drivers/net/wireless/bcmdhd/dhd_linux.c +++ b/drivers/net/wireless/bcmdhd/dhd_linux.c @@ -1,16 +1,15 @@ - /* * Broadcom Dongle Host Driver (DHD), Linux-specific network interface * Basically selected code segments from usb-cdc.c and usb-rndis.c * - * Copyright (C) 1999-2012, Broadcom Corporation - * + * Copyright (C) 1999-2013, Broadcom Corporation + * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2 (the "GPL"), * available at http://www.broadcom.com/licenses/GPLv2.php, with the * following added to such license: - * + * * As a special exception, the copyright holders of this software give you * permission to link this software with independent modules, and to copy and * distribute the resulting executable under terms of your choice, provided that @@ -18,12 +17,12 @@ * 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_linux.c 385321 2013-02-14 21:26:49Z $ + * $Id: dhd_linux.c 432432 2013-10-28 15:52:47Z $ */ #include <typedefs.h> @@ -32,7 +31,6 @@ #include <linux/init.h> #include <linux/kernel.h> -#include <linux/kthread.h> #include <linux/slab.h> #include <linux/skbuff.h> #include <linux/netdevice.h> @@ -44,7 +42,12 @@ #include <linux/ethtool.h> #include <linux/fcntl.h> #include <linux/fs.h> +#include <linux/ip.h> #include <linux/device.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> @@ -55,6 +58,7 @@ #include <bcmdevs.h> #include <proto/ethernet.h> +#include <proto/bcmip.h> #include <dngl_stats.h> #include <dhd.h> #include <dhd_bus.h> @@ -66,11 +70,8 @@ #ifdef WL_CFG80211 #include <wl_cfg80211.h> #endif - -#ifdef WLBTAMP -#include <proto/802.11_bta.h> -#include <proto/bt_amp_hci.h> -#include <dhd_bta.h> +#ifdef PNO_SUPPORT +#include <dhd_pno.h> #endif #ifdef WLMEDIA_HTSF @@ -81,6 +82,7 @@ #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; @@ -98,14 +100,20 @@ typedef struct histo_ { static histo_t vi_d1, vi_d2, vi_d3, vi_d4; #endif /* WLMEDIA_HTSF */ -#if defined(PKT_FILTER_SUPPORT) -#endif /* PKT_FILTER_SUPPORT */ #if defined(SOFTAP) extern bool ap_cfg_running; extern bool ap_fw_loaded; #endif + +#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 @@ -130,6 +138,13 @@ static struct notifier_block dhd_notifier = { .notifier_call = dhd_device_event }; #endif /* ARP_OFFLOAD_SUPPORT */ +static int dhd_device_ipv6_event(struct notifier_block *this, + unsigned long event, + void *ptr); + +static struct notifier_block dhd_notifier_ipv6 = { + .notifier_call = dhd_device_ipv6_event +}; #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) #include <linux/suspend.h> @@ -139,10 +154,10 @@ DECLARE_WAIT_QUEUE_HEAD(dhd_dpc_wait); #if defined(OOB_INTR_ONLY) extern void dhd_enable_oob_intr(struct dhd_bus *bus, bool enable); -#endif +#endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (1) static void dhd_hang_process(struct work_struct *work); -#endif +#endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) MODULE_LICENSE("GPL v2"); #endif /* LinuxVer */ @@ -159,6 +174,12 @@ MODULE_LICENSE("GPL v2"); #endif #endif /* BCM_FD_AGGR */ +#ifdef PROP_TXSTATUS +extern bool dhd_wlfc_skip_fc(void); +extern void dhd_wlfc_plat_enable(void *dhd); +extern void dhd_wlfc_plat_deinit(void *dhd); +#endif /* PROP_TXSTATUS */ + #if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15) const char * print_tainted() @@ -173,33 +194,34 @@ print_tainted() extern wl_iw_extra_params_t g_wl_iw_params; #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) */ + extern int dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd); #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 + #ifdef READ_MACADDR -extern int dhd_read_macaddr(struct dhd_info *dhd, struct ether_addr *mac); -#endif -#ifdef RDWR_MACADDR -extern int dhd_check_rdwr_macaddr(struct dhd_info *dhd, dhd_pub_t *dhdp, struct ether_addr *mac); -extern int dhd_write_rdwr_macaddr(struct ether_addr *mac); +extern int dhd_read_macaddr(struct dhd_info *dhd); +#else +static inline int dhd_read_macaddr(struct dhd_info *dhd) { return 0; } #endif #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 -#ifdef GET_MAC_FROM_OTP -extern int dhd_check_module_mac(dhd_pub_t *dhd, struct ether_addr *mac); -#endif -#ifdef MIMO_ANT_SETTING -extern int dhd_sel_ant_from_file(dhd_pub_t *dhd); -#endif - -#ifdef GLOBALCONFIG_WLAN_COUNTRY_CODE -int dhd_customer_set_country(dhd_pub_t *dhd); -#endif +struct ipv6_addr { + char ipv6_addr[IPV6_ADDR_LEN]; + dhd_ipv6_op_t ipv6_oper; + struct list_head list; +}; /* Interface control information */ typedef struct dhd_if { @@ -216,6 +238,8 @@ typedef struct dhd_if { char name[IFNAMSIZ+1]; /* linux interface name */ uint8 bssidx; /* bsscfg index for the interface */ bool set_multicast; + struct list_head ipv6_list; + spinlock_t ipv6_lock; bool event2cfg80211; /* To determine if pass event to cfg80211 */ } dhd_if_t; @@ -247,7 +271,6 @@ static uint32 maxdelay = 0, tspktcnt = 0, maxdelaypktno = 0; #endif /* WLMEDIA_HTSF */ - /* Local private structure (extension of pub) */ typedef struct dhd_info { #if defined(WL_WIRELESS_EXT) @@ -267,6 +290,8 @@ typedef struct dhd_info { htsf_t htsf; #endif wait_queue_head_t ioctl_resp_wait; + uint32 default_wd_interval; + struct timer_list timer; bool wd_timer_valid; struct tasklet_struct tasklet; @@ -280,6 +305,10 @@ typedef struct dhd_info { tsk_ctl_t thr_dpc_ctl; tsk_ctl_t thr_wdt_ctl; +#ifdef RXFRAME_THREAD + tsk_ctl_t thr_rxf_ctl; + spinlock_t rxf_lock; +#endif /* RXFRAME_THREAD */ #endif /* DHDTHREAD */ bool dhd_tasklet_create; tsk_ctl_t thr_sysioc_ctl; @@ -315,6 +344,10 @@ typedef struct dhd_info { atomic_t pend_8021x_cnt; dhd_attach_states_t dhd_state; +#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 */ @@ -325,6 +358,9 @@ typedef struct dhd_info { bool rpcth_timer_active; bool fdaggr; #endif +#ifdef DHDTCPACK_SUPPRESS + spinlock_t tcpack_lock; +#endif /* DHDTCPACK_SUPPRESS */ } dhd_info_t; /* Flag to indicate if we should download firmware on driver load */ @@ -339,7 +375,6 @@ char nvram_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); @@ -350,6 +385,7 @@ struct semaphore dhd_registration_sem; struct semaphore dhd_init_sem; bool init_power_off = TRUE; #endif +struct semaphore dhd_chipup_sem; int dhd_registration_check = FALSE; #define DHD_REGISTRATION_TIMEOUT 12000 /* msec : allowed time to finished dhd registration */ @@ -362,13 +398,32 @@ module_param(dhd_sysioc, uint, 0); /* Error bits */ module_param(dhd_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 */ + +uint dhd_arp_mode = ARP_OL_AGENT | ARP_OL_PEER_AUTO_REPLY; + +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, 0); + /* Watchdog interval */ + +/* extend watchdog expiration to 2 seconds when DPC is running */ +#define WATCHDOG_EXTEND_INTERVAL (2000) + uint dhd_watchdog_ms = 10; module_param(dhd_watchdog_ms, uint, 0); @@ -378,23 +433,9 @@ uint dhd_console_ms = 0; module_param(dhd_console_ms, uint, 0644); #endif /* defined(DHD_DEBUG) */ -extern uint dhd_doflow; -/* tunable paramter to update tx credit in each dpc */ -extern uint dhd_dpcpoll; -module_param(dhd_doflow, uint, 0644); -module_param(dhd_dpcpoll, uint, 0644); uint dhd_slpauto = TRUE; module_param(dhd_slpauto, uint, 0); -/* ARP offload agent mode : Enable ARP Host Auto-Reply and ARP Peer Auto-Reply */ -uint dhd_arp_mode = ARP_OL_AGENT | ARP_OL_PEER_AUTO_REPLY; - -module_param(dhd_arp_mode, uint, 0); - -/* ARP offload enable */ -uint dhd_arp_enable = TRUE; -module_param(dhd_arp_enable, uint, 0); - #ifdef PKT_FILTER_SUPPORT /* Global Pkt filter enable control */ uint dhd_pkt_filter_enable = TRUE; @@ -406,11 +447,7 @@ 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 uint dhd_master_mode = TRUE; -#endif /* GAL_LITE_NAT_KEEPALIVE_FILTER */ module_param(dhd_master_mode, uint, 0); #ifdef DHDTHREAD @@ -421,12 +458,18 @@ module_param(dhd_watchdog_prio, int, 0); int dhd_dpc_prio = CUSTOM_DPC_PRIO_SETTING; module_param(dhd_dpc_prio, int, 0); +#ifdef RXFRAME_THREAD +/* RX frame thread priority */ +int dhd_rxf_prio = CUSTOM_RXF_PRIO_SETTING; +module_param(dhd_rxf_prio, int, 0); +#endif /* RXFRAME_THREAD */ + /* DPC thread priority, -1 to use tasklet */ -extern int dhd_dongle_memsize; -module_param(dhd_dongle_memsize, int, 0); +extern int dhd_dongle_ramsize; +module_param(dhd_dongle_ramsize, int, 0); #endif /* DHDTHREAD */ /* Control fw roaming */ -uint dhd_roam_disable = 1; +uint dhd_roam_disable = 0; /* Control radio state */ uint dhd_radio_up = 1; @@ -519,10 +562,7 @@ static void dhd_dump_htsfhisto(histo_t *his, char *s); int dhd_monitor_init(void *dhd_pub); int dhd_monitor_uninit(void); -#ifdef SYSFS_IDLETIME -int dhd_sysfs_init(dhd_pub_t *dhdp); -int dhd_sysfs_deinit(void); -#endif /* SYSFS_IDLETIME */ + #if defined(WL_WIRELESS_EXT) struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev); @@ -531,6 +571,7 @@ struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev); static void dhd_dpc(ulong data); /* 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 @@ -543,12 +584,12 @@ static int dhd_toe_set(dhd_info_t *dhd, int idx, uint32 toe_ol); static int dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata, wl_event_msg_t *event_ptr, void **data_ptr); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (LINUX_VERSION_CODE <= \ + KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM_SLEEP) static int dhd_sleep_pm_callback(struct notifier_block *nfb, unsigned long action, void *ignored) { int ret = NOTIFY_DONE; -#if 0 || 0 || (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) switch (action) { case PM_HIBERNATION_PREPARE: case PM_SUSPEND_PREPARE: @@ -562,7 +603,6 @@ static int dhd_sleep_pm_callback(struct notifier_block *nfb, unsigned long actio break; } smp_mb(); -#endif return ret; } @@ -572,7 +612,266 @@ static struct notifier_block dhd_sleep_pm_notifier = { }; extern int register_pm_notifier(struct notifier_block *nb); extern int unregister_pm_notifier(struct notifier_block *nb); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ +#endif /* (LINUX_VERSION >= 2.6.27 && LINUX_VERSION <= 2.6.39 && CONFIG_PM_SLEEP */ + +#if defined(DHDTHREAD) && defined(RXFRAME_THREAD) +/* 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); + +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 */ + /* Do I need to make this context sleep here? Definitely in Single processor case */ + dhd_os_rxfunlock(dhdp); + DHD_ERROR(("dhd_rxf_enqueue: pktbuf not consumed %p, store idx %d sent idx %d\n", + skb, store_idx, sent_idx)); + msleep(1); + return BCME_ERROR; + } + 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; +} +#endif /* defined(DHDTHREAD) && defined(RXFRAME_THREAD) */ + +static int dhd_process_cid_mac(dhd_pub_t *dhdp, bool prepost) +{ + dhd_info_t *dhd = (dhd_info_t *)dhdp->info; + + if (prepost) { /* pre process */ + dhd_read_macaddr(dhd); + } else { /* post process */ + dhd_write_macaddr(&dhd->pub.mac); + } + + return 0; +} + +#if defined(PKT_FILTER_SUPPORT) && !defined(GAN_LITE_NAT_KEEPALIVE_FILTER) +static bool +_turn_on_arp_filter(dhd_pub_t *dhd, int op_mode) +{ + bool _apply = FALSE; + /* In case of IBSS mode, apply arp pkt filter */ + if (op_mode & 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 ((dhd->arp_version == 1) && + (op_mode & (DHD_FLAG_P2P_GC_MODE | DHD_FLAG_P2P_GO_MODE))) { + _apply = TRUE; + goto exit; + } + +exit: + return _apply; +} +#endif /* PKT_FILTER_SUPPORT && !GAN_LITE_NAT_KEEPALIVE_FILTER */ + +#ifdef PKT_FILTER_SUPPORT +void +dhd_set_packet_filter_mode(struct net_device *dev, char *command) +{ + dhd_info_t *dhdi = *(dhd_info_t **)netdev_priv(dev); + + dhdi->pub.pkt_filter_mode = bcm_strtoul(command, &command, 0); +} + +int +dhd_set_packet_filter_ports(struct net_device *dev, char *command) +{ + int i = 0, error = BCME_OK, count = 0, get_count = 0, action = 0; + uint16 portnum = 0, *ports = NULL, get_ports[WL_PKT_FILTER_PORTS_MAX]; + dhd_info_t *dhdi = *(dhd_info_t **)netdev_priv(dev); + dhd_pub_t *dhdp = &dhdi->pub; + char iovbuf[WLC_IOCTL_SMLEN]; + + /* get action */ + action = bcm_strtoul(command, &command, 0); + if (action > PKT_FILTER_PORTS_MAX) + return BCME_BADARG; + + if (action == PKT_FILTER_PORTS_LOOPBACK) { + /* echo the loopback value if port filter is supported else error */ + bcm_mkiovar("cap", NULL, 0, iovbuf, sizeof(iovbuf)); + error = dhd_wl_ioctl_cmd(dhdp, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0); + if (error < 0) { + DHD_ERROR(("%s: Get Capability failed (error=%d)\n", __FUNCTION__, error)); + return error; + } + + if (strstr(iovbuf, "pktfltr2")) + return bcm_strtoul(command, &command, 0); + else { + DHD_ERROR(("%s: pktfltr2 is not supported\n", __FUNCTION__)); + return BCME_UNSUPPORTED; + } + } + + if (action == PKT_FILTER_PORTS_CLEAR) { + /* action 0 is clear all ports */ + dhdp->pkt_filter_ports_count = 0; + bzero(dhdp->pkt_filter_ports, sizeof(dhdp->pkt_filter_ports)); + } + else { + portnum = bcm_strtoul(command, &command, 0); + if (portnum == 0) { + /* no ports to add or remove */ + return BCME_BADARG; + } + + /* get configured ports */ + count = dhdp->pkt_filter_ports_count; + ports = dhdp->pkt_filter_ports; + + if (action == PKT_FILTER_PORTS_ADD) { + /* action 1 is add ports */ + + /* copy new ports */ + while ((portnum != 0) && (count < WL_PKT_FILTER_PORTS_MAX)) { + for (i = 0; i < count; i++) { + /* duplicate port */ + if (portnum == ports[i]) + break; + } + if (portnum != ports[i]) + ports[count++] = portnum; + portnum = bcm_strtoul(command, &command, 0); + } + } else if ((action == PKT_FILTER_PORTS_DEL) && (count > 0)) { + /* action 2 is remove ports */ + bcopy(dhdp->pkt_filter_ports, get_ports, count * sizeof(uint16)); + get_count = count; + + while (portnum != 0) { + count = 0; + for (i = 0; i < get_count; i++) { + if (portnum != get_ports[i]) + ports[count++] = get_ports[i]; + } + get_count = count; + bcopy(ports, get_ports, count * sizeof(uint16)); + portnum = bcm_strtoul(command, &command, 0); + } + } + dhdp->pkt_filter_ports_count = count; + } + return error; +} + +static void +dhd_enable_packet_filter_ports(dhd_pub_t *dhd, bool enable) +{ + int error = 0; + wl_pkt_filter_ports_t *portlist = NULL; + const uint pkt_filter_ports_buf_len = sizeof("pkt_filter_ports") + + WL_PKT_FILTER_PORTS_FIXED_LEN + (WL_PKT_FILTER_PORTS_MAX * sizeof(uint16)); + char pkt_filter_ports_buf[pkt_filter_ports_buf_len]; + char iovbuf[pkt_filter_ports_buf_len]; + + DHD_TRACE(("%s: enable %d, in_suspend %d, mode %d, port count %d\n", + __FUNCTION__, enable, dhd->in_suspend, + dhd->pkt_filter_mode, dhd->pkt_filter_ports_count)); + + bzero(pkt_filter_ports_buf, sizeof(pkt_filter_ports_buf)); + portlist = (wl_pkt_filter_ports_t*)pkt_filter_ports_buf; + portlist->version = WL_PKT_FILTER_PORTS_VERSION; + portlist->reserved = 0; + + if (enable) { + if (!(dhd->pkt_filter_mode & PKT_FILTER_MODE_PORTS_ONLY)) + return; + + /* enable port filter */ + dhd_master_mode |= PKT_FILTER_MODE_PORTS_ONLY; + if (dhd->pkt_filter_mode & PKT_FILTER_MODE_FORWARD_ON_MATCH) + /* whitelist mode: FORWARD_ON_MATCH */ + dhd_master_mode |= PKT_FILTER_MODE_FORWARD_ON_MATCH; + else + /* blacklist mode: DISCARD_ON_MATCH */ + dhd_master_mode &= ~PKT_FILTER_MODE_FORWARD_ON_MATCH; + + portlist->count = dhd->pkt_filter_ports_count; + bcopy(dhd->pkt_filter_ports, + portlist->ports, dhd->pkt_filter_ports_count * sizeof(uint16)); + } else { + /* disable port filter */ + portlist->count = 0; + dhd_master_mode &= ~PKT_FILTER_MODE_PORTS_ONLY; + dhd_master_mode |= PKT_FILTER_MODE_FORWARD_ON_MATCH; + } + + DHD_INFO(("%s: update: mode %d, port count %d\n", + __FUNCTION__, dhd_master_mode, portlist->count)); + + /* update ports */ + bcm_mkiovar("pkt_filter_ports", + (char*)portlist, + (WL_PKT_FILTER_PORTS_FIXED_LEN + (portlist->count * sizeof(uint16))), + iovbuf, sizeof(iovbuf)); + error = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + if (error < 0) + DHD_ERROR(("%s: set pkt_filter_ports failed %d\n", __FUNCTION__, error)); + + /* update mode */ + bcm_mkiovar("pkt_filter_mode", (char*)&dhd_master_mode, + sizeof(dhd_master_mode), iovbuf, sizeof(iovbuf)); + error = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + if (error < 0) + DHD_ERROR(("%s: set pkt_filter_mode failed %d\n", __FUNCTION__, error)); + + return; +} +#endif /* PKT_FILTER_SUPPORT */ void dhd_set_packet_filter(dhd_pub_t *dhd) { @@ -594,21 +893,24 @@ void dhd_enable_packet_filter(int value, dhd_pub_t *dhd) int i; DHD_TRACE(("%s: enter, value = %d\n", __FUNCTION__, value)); + + dhd_enable_packet_filter_ports(dhd, value); + /* 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++) { -#ifdef PASS_ARP_PACKET - if (value && (i == dhd->pktfilter_count -1) && - !(dhd->op_mode & (DHD_FLAG_P2P_GC_MODE | DHD_FLAG_P2P_GO_MODE))) { - DHD_TRACE_HW4(("Do not turn on ARP white list pkt filter:" +#ifndef 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 +#endif /* !GAN_LITE_NAT_KEEPALIVE_FILTER */ dhd_pktfilter_offload_enable(dhd, dhd->pktfilter[i], value, dhd_master_mode); } @@ -618,54 +920,39 @@ void dhd_enable_packet_filter(int value, dhd_pub_t *dhd) static int dhd_set_suspend(int value, dhd_pub_t *dhd) { -#if !defined(SUPPORT_PM2_ONLY) +#ifndef SUPPORT_PM2_ONLY int power_mode = PM_MAX; -#endif +#endif /* SUPPORT_PM2_ONLY */ /* wl_pkt_filter_enable_t enable_parm; */ char iovbuf[32]; int bcn_li_dtim = 0; /* Default bcn_li_dtim in resume mode is 0 */ #ifndef ENABLE_FW_ROAM_SUSPEND uint roamvar = 1; #endif /* ENABLE_FW_ROAM_SUSPEND */ -#ifdef ENABLE_BCN_LI_BCN_WAKEUP - int bcn_li_bcn; -#endif /* ENABLE_BCN_LI_BCN_WAKEUP */ -#ifdef PASS_ALL_MCAST_PKTS - struct dhd_info *dhdinfo = dhd->info; - uint32 allmulti; - uint i; -#endif /* PASS_ALL_MCAST_PKTS */ + + if (!dhd) + return -ENODEV; DHD_TRACE(("%s: enter, value = %d in_suspend=%d\n", __FUNCTION__, value, dhd->in_suspend)); dhd_suspend_lock(dhd); - if (dhd && dhd->up) { + 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__)); + DHD_ERROR(("%s: force extra Suspend setting \n", __FUNCTION__)); -#if !defined(SUPPORT_PM2_ONLY) +#ifndef SUPPORT_PM2_ONLY dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, sizeof(power_mode), TRUE, 0); -#endif +#endif /* SUPPORT_PM2_ONLY */ /* Enable packet filter, only allow unicast packet to send up */ dhd_enable_packet_filter(1, dhd); -#ifdef PASS_ALL_MCAST_PKTS - allmulti = 0; - bcm_mkiovar("allmulti", (char *)&allmulti, - 4, iovbuf, sizeof(iovbuf)); - for (i = 0; i < DHD_MAX_IFS; i++) { - if (dhdinfo->iflist[i] && dhdinfo->iflist[i]->net) - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, - sizeof(iovbuf), TRUE, i); - } -#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 @@ -674,7 +961,9 @@ static int dhd_set_suspend(int value, dhd_pub_t *dhd) bcn_li_dtim = dhd_get_suspend_bcn_li_dtim(dhd); bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim, 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + if (dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), + TRUE, 0) < 0) + DHD_ERROR(("%s: set dtim failed\n", __FUNCTION__)); #ifndef ENABLE_FW_ROAM_SUSPEND /* Disable firmware roaming during suspend */ @@ -682,39 +971,22 @@ static int dhd_set_suspend(int value, dhd_pub_t *dhd) iovbuf, sizeof(iovbuf)); dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); #endif /* ENABLE_FW_ROAM_SUSPEND */ -#ifdef ENABLE_BCN_LI_BCN_WAKEUP - bcn_li_bcn = 0; - bcm_mkiovar("bcn_li_bcn", (char *)&bcn_li_bcn, - 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -#endif /* ENABLE_BCN_LI_BCN_WAKEUP */ - } else { #ifdef PKT_FILTER_SUPPORT dhd->early_suspended = 0; #endif /* Kernel resumed */ - DHD_ERROR(("%s: Remove extra suspend setting\n", __FUNCTION__)); + DHD_ERROR(("%s: Remove extra suspend setting \n", __FUNCTION__)); -#if !defined(SUPPORT_PM2_ONLY) +#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 - +#endif /* SUPPORT_PM2_ONLY */ +#ifdef PKT_FILTER_SUPPORT /* disable pkt filter */ dhd_enable_packet_filter(0, dhd); - -#ifdef PASS_ALL_MCAST_PKTS - allmulti = 1; - bcm_mkiovar("allmulti", (char *)&allmulti, - 4, iovbuf, sizeof(iovbuf)); - for (i = 0; i < DHD_MAX_IFS; i++) { - if (dhdinfo->iflist[i] && dhdinfo->iflist[i]->net) - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, - sizeof(iovbuf), TRUE, i); - } -#endif /* PASS_ALL_MCAST_PKTS */ +#endif /* PKT_FILTER_SUPPORT */ /* restore pre-suspend setting for dtim_skip */ bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim, @@ -727,17 +999,10 @@ static int dhd_set_suspend(int value, dhd_pub_t *dhd) sizeof(iovbuf)); dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); #endif /* ENABLE_FW_ROAM_SUSPEND */ -#ifdef ENABLE_BCN_LI_BCN_WAKEUP - bcn_li_bcn = 1; - bcm_mkiovar("bcn_li_bcn", (char *)&bcn_li_bcn, - 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -#endif /* ENABLE_BCN_LI_BCN_WAKEUP */ - } } - dhd_suspend_unlock(dhd); + return 0; } @@ -759,6 +1024,26 @@ static int dhd_suspend_resume_helper(struct dhd_info *dhd, int val, int force) 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: @@ -915,33 +1200,26 @@ _dhd_set_multicast_list(dhd_info_t *dhd, int ifidx) uint buflen; int ret; - ASSERT(dhd && dhd->iflist[ifidx]); - dev = dhd->iflist[ifidx]->net; - if (!dev) - return; + ASSERT(dhd && dhd->iflist[ifidx]); + dev = dhd->iflist[ifidx]->net; + if (!dev) + return; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) - netif_addr_lock_bh(dev); + netif_addr_lock_bh(dev); #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) - cnt = netdev_mc_count(dev); + cnt = netdev_mc_count(dev); #else - cnt = dev->mc_count; + cnt = dev->mc_count; #endif /* LINUX_VERSION_CODE */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) - netif_addr_unlock_bh(dev); + netif_addr_unlock_bh(dev); #endif - /* Determine initial value of allmulti flag */ + /* 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. */ @@ -962,26 +1240,26 @@ _dhd_set_multicast_list(dhd_info_t *dhd, int ifidx) #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) - netif_addr_lock_bh(dev); + netif_addr_lock_bh(dev); #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) - netdev_for_each_mc_addr(ha, dev) { - if (!cnt) - break; - memcpy(bufp, ha->addr, ETHER_ADDR_LEN); - bufp += ETHER_ADDR_LEN; - cnt--; + netdev_for_each_mc_addr(ha, dev) { + if (!cnt) + break; + memcpy(bufp, ha->addr, ETHER_ADDR_LEN); + bufp += ETHER_ADDR_LEN; + cnt--; } #else 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; - } + memcpy(bufp, (void *)mclist->dmi_addr, ETHER_ADDR_LEN); + bufp += ETHER_ADDR_LEN; + } #endif /* LINUX_VERSION_CODE */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) - netif_addr_unlock_bh(dev); + netif_addr_unlock_bh(dev); #endif memset(&ioc, 0, sizeof(ioc)); @@ -1206,23 +1484,23 @@ dhd_op_if(dhd_if_t *ifp) } } +#ifdef DHDTCPACK_SUPPRESS +uint dhd_use_tcpack_suppress = TRUE; +module_param(dhd_use_tcpack_suppress, uint, FALSE); +extern bool dhd_tcpack_suppress(dhd_pub_t *dhdp, void *pkt); +#endif /* DHDTCPACK_SUPPRESS */ + static int _dhd_sysioc_thread(void *data) { tsk_ctl_t *tsk = (tsk_ctl_t *)data; dhd_info_t *dhd = (dhd_info_t *)tsk->parent; - - - int i; + struct ipv6_addr *iter, *next; + int i, ret; #ifdef SOFTAP bool in_ap = FALSE; unsigned long flags; #endif -#ifndef USE_KTHREAD_API - DAEMONIZE("dhd_sysioc"); - - complete(&tsk->completed); -#endif while (down_interruptible(&tsk->sema) == 0) { @@ -1272,14 +1550,45 @@ _dhd_sysioc_thread(void *data) _dhd_set_multicast_list(dhd, i); } + list_for_each_entry_safe(iter, next, + &dhd->iflist[i]->ipv6_list, list) { + spin_lock_bh(&dhd->iflist[i]->ipv6_lock); + list_del(&iter->list); + spin_unlock_bh(&dhd->iflist[i]->ipv6_lock); + if (iter->ipv6_oper == DHD_IPV6_ADDR_ADD) { + ret = dhd_ndo_enable(&dhd->pub, TRUE); + if (ret < 0) { + DHD_ERROR(("%s: Enabling NDO Failed %d\n", + __FUNCTION__, ret)); + continue; + } + ret = dhd_ndo_add_ip(&dhd->pub, + (char*)&iter->ipv6_addr[0], i); + if (ret < 0) { + DHD_ERROR(("%s: Adding host ip fail %d\n", + __FUNCTION__, ret)); + continue; + } + } else { + ret = dhd_ndo_remove_ip(&dhd->pub, i); + if (ret < 0) { + DHD_ERROR(("%s: Removing host ip fail %d\n", + __FUNCTION__, ret)); + continue; + } + } + NATIVE_MFREE(dhd->pub.osh, iter, sizeof(struct ipv6_addr)); + } if (dhd->set_macaddress == i+1) { dhd->set_macaddress = 0; if (_dhd_set_mac_address(dhd, i, &dhd->macvalue) == 0) { DHD_INFO(( - "dhd_sysioc_thread: MACID is overwritten\n")); + "%s: MACID is overwritten\n", + __FUNCTION__)); } else { DHD_ERROR(( - "dhd_sysioc_thread: _dhd_set_mac_address() failed\n")); + "%s: _dhd_set_mac_address() failed\n", + __FUNCTION__)); } } } @@ -1356,7 +1665,7 @@ uint8 prio2fifo[8] = { 1, 0, 0, 1, 2, 2, 3, 3 }; int dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf) { - int ret; + int ret = BCME_OK; dhd_info_t *dhd = (dhd_info_t *)(dhdp->info); struct ether_header *eh = NULL; @@ -1384,7 +1693,7 @@ dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf) /* Look into the packet and update the packet priority */ #ifndef PKTPRIO_OVERRIDE if (PKTPRIO(pktbuf) == 0) -#endif +#endif pktsetprio(pktbuf, FALSE); #ifdef PROP_TXSTATUS @@ -1410,14 +1719,18 @@ dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf) #ifdef WLMEDIA_HTSF dhd_htsf_addtxts(dhdp, pktbuf); #endif +#ifdef DHDTCPACK_SUPPRESS + if (dhd_use_tcpack_suppress && dhd_tcpack_suppress(dhdp, pktbuf)) + ret = BCME_OK; + else +#endif /* DHDTCPACK_SUPPRESS */ #ifdef PROP_TXSTATUS + { dhd_os_wlfc_block(dhdp); if (dhdp->wlfc_state && ((athost_wl_status_info_t*)dhdp->wlfc_state)->proptxstatus_mode != WLFC_FCMODE_NONE) { - ret = dhd_wlfc_enque_sendq(dhdp->wlfc_state, DHD_PKTTAG_FIFO(PKTTAG(pktbuf)), - pktbuf); dhd_wlfc_commit_packets(dhdp->wlfc_state, (f_commitpkt_t)dhd_bus_txdata, - dhdp->bus); + dhdp->bus, pktbuf); if (((athost_wl_status_info_t*)dhdp->wlfc_state)->toggle_host_if) { ((athost_wl_status_info_t*)dhdp->wlfc_state)->toggle_host_if = 0; } @@ -1428,6 +1741,7 @@ dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf) /* non-proptxstatus way */ ret = dhd_bus_txdata(dhdp->bus, pktbuf); } + } #else ret = dhd_bus_txdata(dhdp->bus, pktbuf); #endif /* PROP_TXSTATUS */ @@ -1439,8 +1753,10 @@ int dhd_start_xmit(struct sk_buff *skb, struct net_device *net) { int ret; + uint datalen; void *pktbuf; - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); + dhd_if_t *ifp = NULL; int ifidx; #ifdef WLMEDIA_HTSF uint8 htsfdlystat_sz = dhd->pub.htsfdlystat_sz; @@ -1482,6 +1798,9 @@ dhd_start_xmit(struct sk_buff *skb, struct net_device *net) #endif } + ifp = dhd->iflist[ifidx]; + datalen = PKTLEN(dhdp->osh, skb); + /* Make sure there's enough room for any header */ if (skb_headroom(skb) < dhd->pub.hdrlen + htsfdlystat_sz) { @@ -1524,12 +1843,15 @@ dhd_start_xmit(struct sk_buff *skb, struct net_device *net) ret = dhd_sendpkt(&dhd->pub, ifidx, pktbuf); - done: - if (ret) - dhd->pub.dstats.tx_dropped++; - else - dhd->pub.tx_packets++; + if (ret) { + ifp->stats.tx_dropped++; + } + else { + dhd->pub.tx_packets++; + ifp->stats.tx_packets++; + ifp->stats.tx_bytes += datalen; + } DHD_OS_WAKE_UNLOCK(&dhd->pub); @@ -1619,22 +1941,18 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) wl_event_msg_t event; int tout_rx = 0; int tout_ctrl = 0; - -#ifdef DHD_RX_DUMP -#ifdef DHD_RX_FULL_DUMP - int k; -#endif /* DHD_RX_FULL_DUMP */ +#if defined(DHDTHREAD) && defined(RXFRAME_THREAD) + void *skbhead = NULL; + void *skbprev = NULL; +#endif /* defined(DHDTHREAD) && defined(RXFRAME_THREAD) */ +#if defined(DHD_RX_DUMP) || defined(DHD_8021X_DUMP) char *dump_data; uint16 protocol; -#endif /* DHD_RX_DUMP */ +#endif /* DHD_RX_DUMP || DHD_8021X_DUMP */ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); for (i = 0; pktbuf && i < numpkt; i++, pktbuf = pnext) { -#ifdef WLBTAMP - struct ether_header *eh; - struct dot11_llc_snap_header *lsh; -#endif pnext = PKTNEXT(dhdp->osh, pktbuf); PKTSETNEXT(wl->sh.osh, pktbuf, NULL); @@ -1660,19 +1978,6 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) } #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */ -#ifdef WLBTAMP - eh = (struct ether_header *)PKTDATA(wl->sh.osh, pktbuf); - lsh = (struct dot11_llc_snap_header *)&eh[1]; - - if ((ntoh16(eh->ether_type) < ETHER_TYPE_MIN) && - (PKTLEN(wl->sh.osh, pktbuf) >= RFC1042_HDR_LEN) && - bcmp(lsh, BT_SIG_SNAP_MPROT, DOT11_LLC_SNAP_HDR_LEN - 2) == 0 && - lsh->type == HTON16(BTA_PROT_L2CAP)) { - amp_hci_ACL_data_t *ACL_data = (amp_hci_ACL_data_t *) - ((uint8 *)eh + RFC1042_HDR_LEN); - ACL_data = NULL; - } -#endif /* WLBTAMP */ #ifdef PROP_TXSTATUS if (dhdp->wlfc_state && PKTLEN(wl->sh.osh, pktbuf) == 0) { @@ -1700,22 +2005,19 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) eth = skb->data; len = skb->len; -#ifdef DHD_RX_DUMP +#if defined(DHD_RX_DUMP) || defined(DHD_8021X_DUMP) dump_data = skb->data; protocol = (dump_data[12] << 8) | dump_data[13]; - DHD_ERROR(("RX DUMP - %s\n", _get_packet_type_str(protocol))); -#ifdef DHD_RX_FULL_DUMP - if (protocol != ETHER_TYPE_BRCM) { - for (k = 0; k < skb->len; k++) { - DHD_ERROR(("%02X ", dump_data[k])); - if ((k & 15) == 15) - DHD_ERROR(("\n")); - } - DHD_ERROR(("\n")); + if (protocol == ETHER_TYPE_802_1X) { + DHD_ERROR(("ETHER_TYPE_802_1X: " + "ver %d, type %d, replay %d\n", + dump_data[14], dump_data[15], + dump_data[30])); } -#endif /* DHD_RX_FULL_DUMP */ - +#endif /* DHD_RX_DUMP || DHD_8021X_DUMP */ +#if defined(DHD_RX_DUMP) + DHD_ERROR(("RX DUMP - %s\n", _get_packet_type_str(protocol))); if (protocol != ETHER_TYPE_BRCM) { if (dump_data[0] == 0xFF) { DHD_ERROR(("%s: BROADCAST\n", __FUNCTION__)); @@ -1729,15 +2031,18 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) DHD_ERROR(("%s: MULTICAST: " MACDBG "\n", __FUNCTION__, MAC2STRDBG(dump_data))); } - - if (protocol == ETHER_TYPE_802_1X) { - DHD_ERROR(("ETHER_TYPE_802_1X: " - "ver %d, type %d, replay %d\n", - dump_data[14], dump_data[15], - dump_data[30])); +#ifdef DHD_RX_FULL_DUMP + { + int k; + for (k = 0; k < skb->len; k++) { + DHD_ERROR(("%02X ", dump_data[k])); + if ((k & 15) == 15) + DHD_ERROR(("\n")); + } + DHD_ERROR(("\n")); } +#endif /* DHD_RX_FULL_DUMP */ } - #endif /* DHD_RX_DUMP */ ifp = dhd->iflist[ifidx]; @@ -1762,10 +2067,11 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) 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) { dhd_wl_host_event(dhd, &ifidx, #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) - skb->mac_header, + skb_mac_header(skb), #else skb->mac.raw, #endif @@ -1773,16 +2079,9 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) &data); wl_event_to_host_order(&event); - if (!tout_ctrl) tout_ctrl = DHD_PACKET_TIMEOUT_MS; -#ifdef WLBTAMP - if (event.event_type == WLC_E_BTA_HCI_EVENT) { - dhd_bta_doevt(dhdp, data, event.datalen); - } -#endif /* WLBTAMP */ - #if defined(PNO_SUPPORT) if (event.event_type == WLC_E_PFN_NET_FOUND) { /* enforce custom wake lock to garantee that Kernel not suspended */ @@ -1793,7 +2092,7 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) #ifdef DHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT PKTFREE(dhdp->osh, pktbuf, TRUE); continue; -#endif +#endif /* DHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT */ } else { tout_rx = DHD_PACKET_TIMEOUT_MS; } @@ -1807,6 +2106,8 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) dhdp->dstats.rx_bytes += skb->len; dhdp->rx_packets++; /* Local count */ + ifp->stats.rx_bytes += skb->len; + ifp->stats.rx_packets++; if (in_interrupt()) { netif_rx(skb); @@ -1817,6 +2118,13 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) * by netif_rx_ni(), but in earlier kernels, we need * to do it manually. */ +#if defined(DHDTHREAD) && defined(RXFRAME_THREAD) + if (!skbhead) + skbhead = skb; + else + PKTSETNEXT(wl->sh.osh, skbprev, skb); + skbprev = skb; +#else #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) netif_rx_ni(skb); #else @@ -1826,9 +2134,13 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) RAISE_RX_SOFTIRQ(); local_irq_restore(flags); #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */ +#endif /* defined(DHDTHREAD) && defined(RXFRAME_THREAD) */ } } - +#if defined(DHDTHREAD) && defined(RXFRAME_THREAD) + if (skbhead) + dhd_sched_rxf(dhdp, skbhead); +#endif DHD_OS_WAKE_LOCK_RX_TIMEOUT_ENABLE(dhdp, tout_rx); DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(dhdp, tout_ctrl); } @@ -1846,9 +2158,6 @@ 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; -#ifdef WLBTAMP - uint len; -#endif dhd_prot_hdrpull(dhdp, NULL, txp, NULL, NULL); @@ -1858,23 +2167,6 @@ dhd_txcomplete(dhd_pub_t *dhdp, void *txp, bool success) if (type == ETHER_TYPE_802_1X) atomic_dec(&dhd->pend_8021x_cnt); -#ifdef WLBTAMP - /* Crack open the packet and check to see if it is BT HCI ACL data packet. - * If yes generate packet completion event. - */ - len = PKTLEN(dhdp->osh, txp); - - /* Generate ACL data tx completion event locally to avoid SDIO bus transaction */ - if ((type < ETHER_TYPE_MIN) && (len >= RFC1042_HDR_LEN)) { - struct dot11_llc_snap_header *lsh = (struct dot11_llc_snap_header *)&eh[1]; - - if (bcmp(lsh, BT_SIG_SNAP_MPROT, DOT11_LLC_SNAP_HDR_LEN - 2) == 0 && - ntoh16(lsh->type) == BTA_PROT_L2CAP) { - - dhd_bta_tx_hcidata_complete(dhdp, txp, success); - } - } -#endif /* WLBTAMP */ } static struct net_device_stats * @@ -1929,12 +2221,6 @@ dhd_watchdog_thread(void *data) dhd_watchdog_prio:(MAX_RT_PRIO-1); setScheduler(current, SCHED_FIFO, ¶m); } -#ifndef USE_KTHREAD_API - DAEMONIZE("dhd_watchdog"); - - /* Run until signal received */ - complete(&tsk->completed); -#endif while (1) if (down_interruptible (&tsk->sema) == 0) { @@ -1951,7 +2237,6 @@ dhd_watchdog_thread(void *data) if (dhd->pub.dongle_reset == FALSE) { DHD_TIMER(("%s:\n", __FUNCTION__)); - /* Call the bus module watchdog */ dhd_bus_watchdog(&dhd->pub); @@ -2009,12 +2294,28 @@ static void dhd_watchdog(ulong data) } #ifdef DHDTHREAD + +#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 { + param.sched_priority = (prio < MAX_RT_PRIO)? prio : (MAX_RT_PRIO-1); + setScheduler(current, SCHED_FIFO, ¶m); + } +} +#endif /* ENABLE_ADAPTIVE_SCHED */ + + 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 */ @@ -2024,18 +2325,17 @@ dhd_dpc_thread(void *data) param.sched_priority = (dhd_dpc_prio < MAX_RT_PRIO)?dhd_dpc_prio:(MAX_RT_PRIO-1); setScheduler(current, SCHED_FIFO, ¶m); } -#ifndef USE_KTHREAD_API - DAEMONIZE("dhd_dpc"); - /* DHD_OS_WAKE_LOCK is called in dhd_sched_dpc[dhd_linux.c] down below */ - /* signal: thread has started */ - complete(&tsk->completed); -#endif +#ifdef CUSTOM_DPC_CPUCORE + set_cpus_allowed_ptr(current, cpumask_of(CUSTOM_DPC_CPUCORE)); +#endif /* CUSTOM_DPC_CPUCORE */ /* Run until signal received */ while (1) { - if (down_interruptible(&tsk->sema) == 0) { - + 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; @@ -2043,12 +2343,12 @@ dhd_dpc_thread(void *data) /* Call bus dpc unless it indicated down (then clean stop) */ if (dhd->pub.busstate != DHD_BUS_DOWN) { - if (dhd_bus_dpc(dhd->pub.bus)) { - up(&tsk->sema); - } - else { - DHD_OS_WAKE_UNLOCK(&dhd->pub); + dhd_os_wd_timer_extend(&dhd->pub, TRUE); + while (dhd_bus_dpc(dhd->pub.bus)) { + /* process all data */ } + 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); @@ -2061,6 +2361,77 @@ dhd_dpc_thread(void *data) complete_and_exit(&tsk->completed, 0); } + +#ifdef RXFRAME_THREAD +static int +dhd_rxf_thread(void *data) +{ + tsk_ctl_t *tsk = (tsk_ctl_t *)data; + dhd_info_t *dhd = (dhd_info_t *)tsk->parent; + 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); + } + + DAEMONIZE("dhd_rxf"); + /* DHD_OS_WAKE_LOCK is called in dhd_sched_dpc[dhd_linux.c] down below */ + + /* signal: thread has started */ + complete(&tsk->completed); + + /* Run until signal received */ + while (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); + +#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; + } + + DHD_OS_WAKE_UNLOCK(pub); + } + else + break; + } + + complete_and_exit(&tsk->completed, 0); +} +#endif /* RXFRAME_THREAD */ #endif /* DHDTHREAD */ static void @@ -2094,7 +2465,11 @@ dhd_sched_dpc(dhd_pub_t *dhdp) DHD_OS_WAKE_LOCK(dhdp); #ifdef DHDTHREAD if (dhd->thr_dpc_ctl.thr_pid >= 0) { - up(&dhd->thr_dpc_ctl.sema); + /* 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; } #endif /* DHDTHREAD */ @@ -2103,6 +2478,27 @@ dhd_sched_dpc(dhd_pub_t *dhdp) tasklet_schedule(&dhd->tasklet); } +#if defined(DHDTHREAD) && defined(RXFRAME_THREAD) +static void +dhd_sched_rxf(dhd_pub_t *dhdp, void *skb) +{ + dhd_info_t *dhd = (dhd_info_t *)dhdp->info; + + DHD_OS_WAKE_LOCK(dhdp); + + DHD_TRACE(("dhd_sched_rxf: Enter\n")); + + 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 /* defined(DHDTHREAD) && defined(RXFRAME_THREAD) */ + #ifdef TOE /* Retrieve current toe component enables, which are kept as a bitmap in toe_ol iovar */ static int @@ -2310,9 +2706,14 @@ dhd_ethtool(dhd_info_t *dhd, void *uaddr) static bool dhd_check_hang(struct net_device *net, dhd_pub_t *dhdp, int error) { - dhd_info_t * dhd; + dhd_info_t *dhd; - if (!dhdp) + if (!dhdp) { + DHD_ERROR(("%s: dhdp is NULL\n", __FUNCTION__)); + return FALSE; + } + + if (!dhdp->up) return FALSE; dhd = (dhd_info_t *)dhdp->info; @@ -2331,128 +2732,61 @@ static bool dhd_check_hang(struct net_device *net, dhd_pub_t *dhdp, int error) return FALSE; } -static int -dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd) +int dhd_ioctl_process(dhd_pub_t *pub, int ifidx, dhd_ioctl_t *ioc) { - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); - dhd_ioctl_t ioc; - int bcmerror = 0; + int bcmerror = BCME_OK; int buflen = 0; void *buf = NULL; - uint driver = 0; - int ifidx; - int ret; - - DHD_OS_WAKE_LOCK(&dhd->pub); - - /* send to dongle only if we are not waiting for reload already */ - if (dhd->pub.hang_was_sent) { - DHD_ERROR(("%s: HANG was sent up earlier\n", __FUNCTION__)); - DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(&dhd->pub, DHD_EVENT_TIMEOUT_MS); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - return OSL_ERROR(BCME_DONGLE_DOWN); - } - - 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_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_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_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_OS_WAKE_UNLOCK(&dhd->pub); - return ret; - } - - if (cmd != SIOCDEVPRIVATE) { - DHD_OS_WAKE_UNLOCK(&dhd->pub); - return -EOPNOTSUPP; - } - - memset(&ioc, 0, sizeof(ioc)); + struct net_device *net; - /* Copy the ioc control structure part of ioctl request */ - if (copy_from_user(&ioc, ifr->ifr_data, sizeof(wl_ioctl_t))) { - bcmerror = BCME_BADADDR; + net = dhd_idx2net(pub, ifidx); + if (!net) { + bcmerror = BCME_BADARG; goto done; } /* Copy out any buffer passed */ - if (ioc.buf) { - if (ioc.len == 0) { - DHD_TRACE(("%s: ioc.len=0, returns BCME_BADARG \n", __FUNCTION__)); + if (ioc->buf) { + if (ioc->len == 0) { + DHD_TRACE(("%s: ioc->len=0, returns BCME_BADARG \n", __FUNCTION__)); bcmerror = BCME_BADARG; goto done; } - buflen = MIN(ioc.len, DHD_IOCTL_MAXLEN); + buflen = MIN(ioc->len, DHD_IOCTL_MAXLEN); /* optimization for direct ioctl calls from kernel */ /* if (segment_eq(get_fs(), KERNEL_DS)) { - buf = ioc.buf; + buf = ioc->buf; } else { */ { - if (!(buf = (char*)MALLOC(dhd->pub.osh, buflen))) { + if (!(buf = MALLOC(pub->osh, buflen + 1))) { bcmerror = BCME_NOMEM; goto done; } - if (copy_from_user(buf, ioc.buf, buflen)) { + if (copy_from_user(buf, ioc->buf, buflen)) { bcmerror = BCME_BADADDR; goto done; } + *(char *)(buf + buflen) = '\0'; } } - /* To differentiate between wl and dhd read 4 more byes */ - if ((copy_from_user(&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; - } - /* check for local dhd ioctl and handle it */ - if (driver == DHD_IOCTL_MAGIC) { - bcmerror = dhd_ioctl((void *)&dhd->pub, &ioc, buf, buflen); + if (ioc->driver == DHD_IOCTL_MAGIC) { + bcmerror = dhd_ioctl((void *)pub, ioc, buf, buflen); if (bcmerror) - dhd->pub.bcmerror = bcmerror; + pub->bcmerror = bcmerror; goto done; } /* send to dongle (must be up, and wl). */ - if (dhd->pub.busstate != DHD_BUS_DATA) { + if (pub->busstate != DHD_BUS_DATA) { bcmerror = BCME_DONGLE_DOWN; goto done; } - if (!dhd->pub.iswl) { + if (!pub->iswl) { bcmerror = BCME_DONGLE_DOWN; goto done; } @@ -2464,24 +2798,24 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd) * 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 && ioc.buf != NULL && - strncmp("wsec_key", ioc.buf, 9) == 0) || - (ioc.cmd == WLC_SET_VAR && ioc.buf != NULL && - strncmp("bsscfg:wsec_key", ioc.buf, 15) == 0) || - ioc.cmd == WLC_DISASSOC) + if (ioc->cmd == WLC_SET_KEY || + (ioc->cmd == WLC_SET_VAR && ioc->buf != NULL && + strncmp("wsec_key", ioc->buf, 9) == 0) || + (ioc->cmd == WLC_SET_VAR && ioc->buf != NULL && + strncmp("bsscfg:wsec_key", ioc->buf, 15) == 0) || + ioc->cmd == WLC_DISASSOC) dhd_wait_pend8021x(net); #ifdef WLMEDIA_HTSF - if (ioc.buf) { + if (ioc->buf) { /* short cut wl ioctl calls here */ - if (strcmp("htsf", ioc.buf) == 0) { + if (strcmp("htsf", ioc->buf) == 0) { dhd_ioctl_htsf_get(dhd, 0); return BCME_OK; } - if (strcmp("htsflate", ioc.buf) == 0) { - if (ioc.set) { + if (strcmp("htsflate", ioc->buf) == 0) { + if (ioc->set) { memset(ts, 0, sizeof(tstamp_t)*TSMAX); memset(&maxdelayts, 0, sizeof(tstamp_t)); maxdelay = 0; @@ -2496,7 +2830,7 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd) } return BCME_OK; } - if (strcmp("htsfclear", ioc.buf) == 0) { + if (strcmp("htsfclear", ioc->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); @@ -2504,16 +2838,16 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd) htsf_seqnum = 0; return BCME_OK; } - if (strcmp("htsfhis", ioc.buf) == 0) { + if (strcmp("htsfhis", ioc->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", ioc.buf) == 0) { - if (ioc.set) { - memcpy(&tsport, ioc.buf + 7, 4); + if (strcmp("tsport", ioc->buf) == 0) { + if (ioc->set) { + memcpy(&tsport, ioc->buf + 7, 4); } else { DHD_ERROR(("current timestamp port: %d \n", tsport)); } @@ -2522,28 +2856,112 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd) } #endif /* WLMEDIA_HTSF */ - if ((ioc.cmd == WLC_SET_VAR || ioc.cmd == WLC_GET_VAR) && - ioc.buf != NULL && strncmp("rpc_", ioc.buf, 4) == 0) { + if ((ioc->cmd == WLC_SET_VAR || ioc->cmd == WLC_GET_VAR) && + ioc->buf != NULL && strncmp("rpc_", ioc->buf, 4) == 0) { #ifdef BCM_FD_AGGR - bcmerror = dhd_fdaggr_ioctl(&dhd->pub, ifidx, (wl_ioctl_t *)&ioc, buf, buflen); + bcmerror = dhd_fdaggr_ioctl(pub, ifidx, (wl_ioctl_t *)ioc, buf, buflen); #else bcmerror = BCME_UNSUPPORTED; #endif goto done; } - bcmerror = dhd_wl_ioctl(&dhd->pub, ifidx, (wl_ioctl_t *)&ioc, buf, buflen); + bcmerror = dhd_wl_ioctl(pub, ifidx, (wl_ioctl_t *)ioc, buf, buflen); done: - dhd_check_hang(net, &dhd->pub, bcmerror); + dhd_check_hang(net, pub, bcmerror); - if (!bcmerror && buf && ioc.buf) { - if (copy_to_user(ioc.buf, buf, buflen)) + if (!bcmerror && buf && ioc->buf) { + if (copy_to_user(ioc->buf, buf, buflen)) bcmerror = -EFAULT; } if (buf) - MFREE(dhd->pub.osh, buf, buflen); + MFREE(pub->osh, buf, buflen + 1); + + return bcmerror; +} + +static int +dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); + dhd_ioctl_t ioc; + int bcmerror = 0; + int ifidx; + int ret; + + DHD_OS_WAKE_LOCK(&dhd->pub); + + /* send to dongle only if we are not waiting for reload already */ + if (dhd->pub.hang_was_sent) { + DHD_ERROR(("%s: HANG was sent up earlier\n", __FUNCTION__)); + DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(&dhd->pub, DHD_EVENT_TIMEOUT_MS); + DHD_OS_WAKE_UNLOCK(&dhd->pub); + return OSL_ERROR(BCME_DONGLE_DOWN); + } + + 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_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_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_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_OS_WAKE_UNLOCK(&dhd->pub); + return ret; + } + + if (cmd != SIOCDEVPRIVATE) { + DHD_OS_WAKE_UNLOCK(&dhd->pub); + return -EOPNOTSUPP; + } + + memset(&ioc, 0, sizeof(ioc)); + + /* 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; + } + bcmerror = dhd_ioctl_process(&dhd->pub, ifidx, &ioc); + +done: DHD_OS_WAKE_UNLOCK(&dhd->pub); return OSL_ERROR(bcmerror); @@ -2599,6 +3017,8 @@ dhd_stop(struct net_device *net) dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); DHD_OS_WAKE_LOCK(&dhd->pub); DHD_TRACE(("%s: Enter %p\n", __FUNCTION__, net)); + + if (dhd->pub.up == 0) { goto exit; } @@ -2617,30 +3037,29 @@ dhd_stop(struct net_device *net) * For CFG80211: Clean up all the left over virtual interfaces * when the primary Interface is brought down. [ifconfig wlan0 down] */ - if ((dhd->dhd_state & DHD_ATTACH_STATE_ADD_IF) && - (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211)) { - dhd_cleanup_virt_ifaces(dhd); + if (!dhd_download_fw_on_driverload) { + if ((dhd->dhd_state & DHD_ATTACH_STATE_ADD_IF) && + (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211)) { + dhd_cleanup_virt_ifaces(dhd); + } } } #endif #ifdef PROP_TXSTATUS dhd_os_wlfc_block(&dhd->pub); - dhd_wlfc_cleanup(&dhd->pub); + dhd_wlfc_cleanup(&dhd->pub, NULL, 0); dhd_os_wlfc_unblock(&dhd->pub); #endif - /* Stop the protocol module */ dhd_prot_stop(&dhd->pub); OLD_MOD_DEC_USE_COUNT; exit: #if defined(WL_CFG80211) - if (ifidx == 0) { - if (!dhd_download_fw_on_driverload) - wl_android_wifi_off(net); - } -#endif + if (ifidx == 0 && !dhd_download_fw_on_driverload) + wl_android_wifi_off(net); +#endif dhd->pub.rxcnt_timeout = 0; dhd->pub.txcnt_timeout = 0; @@ -2650,6 +3069,8 @@ exit: return 0; } +/* (USE_INITIAL_2G_SCAN || USE_INITIAL_SHORT_DWELL_TIME) */ + static int dhd_open(struct net_device *net) { @@ -2660,30 +3081,21 @@ dhd_open(struct net_device *net) int ifidx; int32 ret = 0; - /* 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__)); - return -1; - } -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 - if (mutex_is_locked(&_dhd_sdio_mutex_lock_) != 0) { - DHD_ERROR(("%s : dhd_open: call dev open before insmod complete!\n", __FUNCTION__)); - } - mutex_lock(&_dhd_sdio_mutex_lock_); -#endif DHD_OS_WAKE_LOCK(&dhd->pub); /* Update FW path if it was changed */ if (strlen(firmware_path) != 0) { if (firmware_path[strlen(firmware_path)-1] == '\n') firmware_path[strlen(firmware_path)-1] = '\0'; + bzero(fw_path, MOD_PARAM_PATHLEN); strncpy(fw_path, firmware_path, sizeof(fw_path)-1); - fw_path[sizeof(fw_path)-1] = '\0'; firmware_path[0] = '\0'; } + + dhd->pub.dongle_trap_occured = 0; dhd->pub.hang_was_sent = 0; #if !defined(WL_CFG80211) @@ -2699,7 +3111,7 @@ dhd_open(struct net_device *net) goto exit; } -#endif +#endif ifidx = dhd_net2idx(dhd, net); DHD_TRACE(("%s: ifidx %d\n", __FUNCTION__, ifidx)); @@ -2732,13 +3144,13 @@ dhd_open(struct net_device *net) if (!dhd_download_fw_on_driverload) { ret = wl_android_wifi_on(net); if (ret != 0) { - DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret)); + DHD_ERROR(("%s : wl_android_wifi_on failed (%d)\n", + __FUNCTION__, ret)); ret = -1; goto exit; } - } else { } -#endif +#endif if (dhd->pub.busstate != DHD_BUS_DATA) { @@ -2786,9 +3198,7 @@ exit: DHD_OS_WAKE_UNLOCK(&dhd->pub); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 - mutex_unlock(&_dhd_sdio_mutex_lock_); -#endif + return ret; } @@ -2801,15 +3211,8 @@ int dhd_do_driver_init(struct net_device *net) return -EINVAL; } -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 -#ifdef MULTIPLE_SUPPLICANT - if (mutex_is_locked(&_dhd_sdio_mutex_lock_) != 0) { - DHD_ERROR(("%s : dhdsdio_probe is already running!\n", __FUNCTION__)); - return 0; - } -#endif /* MULTIPLE_SUPPLICANT */ -#endif + /* && defined(OEM_ANDROID) && defined(BCMSDIO) */ dhd = *(dhd_info_t **)netdev_priv(net); /* If driver is already initialized, do nothing @@ -2843,7 +3246,10 @@ dhd_osl_detach(osl_t *osh) #if 1 && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) dhd_registration_check = FALSE; up(&dhd_registration_sem); +#if defined(BCMLXSDMMC) + up(&dhd_chipup_sem); #endif +#endif } int @@ -2875,6 +3281,8 @@ dhd_add_if(dhd_info_t *dhd, int ifidx, void *handle, char *name, dhd->iflist[ifidx] = ifp; strncpy(ifp->name, name, IFNAMSIZ); ifp->name[IFNAMSIZ] = '\0'; + INIT_LIST_HEAD(&ifp->ipv6_list); + spin_lock_init(&ifp->ipv6_lock); if (mac_addr != NULL) memcpy(&ifp->mac_addr, mac_addr, ETHER_ADDR_LEN); @@ -2953,12 +3361,12 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen, void *dev) /* updates firmware nvram path if it was provided as module parameters */ if (strlen(firmware_path) != 0) { + bzero(fw_path, MOD_PARAM_PATHLEN); strncpy(fw_path, firmware_path, sizeof(fw_path) - 1); - fw_path[sizeof(fw_path) - 1] = '\0'; } if (strlen(nvram_path) != 0) { + bzero(nv_path, MOD_PARAM_PATHLEN); strncpy(nv_path, nvram_path, sizeof(nv_path) -1); - nv_path[sizeof(nv_path) -1] = '\0'; } /* Allocate etherdev, including space for private structure */ @@ -2970,10 +3378,18 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen, void *dev) SET_NETDEV_DEV(net, (struct device *)dev); /* Allocate primary dhd_info */ +#if defined(CONFIG_DHD_USE_STATIC_BUF) + dhd = (void *)dhd_os_prealloc(osh, DHD_PREALLOC_DHD_INFO, sizeof(dhd_info_t)); + if (!dhd) { + DHD_INFO(("%s: OOM - Pre-alloc dhd_info\n", __FUNCTION__)); +#endif /* CONFIG_DHD_USE_STATIC_BUF */ if (!(dhd = MALLOC(osh, sizeof(dhd_info_t)))) { DHD_ERROR(("%s: OOM - alloc dhd_info\n", __FUNCTION__)); goto fail; } +#if defined(CONFIG_DHD_USE_STATIC_BUF) + } +#endif /* CONFIG_DHD_USE_STATIC_BUF */ memset(dhd, 0, sizeof(dhd_info_t)); #ifdef DHDTHREAD @@ -3025,11 +3441,15 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen, void *dev) #ifdef PROP_TXSTATUS_VSDB dhd->pub.wlfc_enabled = FALSE; #else - if (disable_proptx) - dhd->pub.wlfc_enabled = FALSE; - else + if (!disable_proptx) dhd->pub.wlfc_enabled = TRUE; + else + dhd->pub.wlfc_enabled = FALSE; #endif /* PROP_TXSTATUS_VSDB */ + dhd->pub.ptx_opt_enabled = FALSE; + dhd->pub.skip_fc = dhd_wlfc_skip_fc; + dhd->pub.plat_enable = dhd_wlfc_plat_enable; + dhd->pub.plat_deinit = dhd_wlfc_plat_deinit; #endif /* PROP_TXSTATUS */ /* Initialize other structure content */ @@ -3040,6 +3460,12 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen, void *dev) spin_lock_init(&dhd->sdlock); spin_lock_init(&dhd->txqlock); spin_lock_init(&dhd->dhd_lock); +#if defined(DHDTHREAD) && defined(RXFRAME_THREAD) + spin_lock_init(&dhd->rxf_lock); +#endif /* defined(DHDTHREAD) && defined(RXFRAME_THREAD) */ +#ifdef DHDTCPACK_SUPPRESS + spin_lock_init(&dhd->tcpack_lock); +#endif /* DHDTCPACK_SUPPRESS */ /* Initialize Wakelock stuff */ spin_lock_init(&dhd->wakelock_spinlock); @@ -3092,6 +3518,7 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen, void *dev) init_timer(&dhd->timer); dhd->timer.data = (ulong)dhd; dhd->timer.function = dhd_watchdog; + dhd->default_wd_interval = dhd_watchdog_ms; #ifdef DHDTHREAD /* Initialize thread based operation and lock */ @@ -3105,11 +3532,8 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen, void *dev) if (dhd_watchdog_prio >= 0) { /* Initialize watchdog thread */ -#ifdef USE_KTHREAD_API - PROC_START2(dhd_watchdog_thread, dhd, &dhd->thr_wdt_ctl, 0, "dhd_watchdog_thread"); -#else - PROC_START(dhd_watchdog_thread, dhd, &dhd->thr_wdt_ctl, 0); -#endif + PROC_START(dhd_watchdog_thread, dhd, &dhd->thr_wdt_ctl, 0, "dhd_watchdog_thread"); + } else { dhd->thr_wdt_ctl.thr_pid = -1; } @@ -3117,16 +3541,17 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen, void *dev) /* Set up the bottom half handler */ if (dhd_dpc_prio >= 0) { /* Initialize DPC thread */ -#ifdef USE_KTHREAD_API - PROC_START2(dhd_dpc_thread, dhd, &dhd->thr_dpc_ctl, 0, "dhd_dpc"); -#else - PROC_START(dhd_dpc_thread, dhd, &dhd->thr_dpc_ctl, 0); -#endif + PROC_START(dhd_dpc_thread, dhd, &dhd->thr_dpc_ctl, 0, "dhd_dpc"); } else { /* use tasklet for dpc */ tasklet_init(&dhd->tasklet, dhd_dpc, (ulong)dhd); dhd->thr_dpc_ctl.thr_pid = -1; } +#ifdef RXFRAME_THREAD + bzero(&dhd->pub.skbbuf[0], sizeof(void *) * MAXSKBPEND); + /* Initialize RXF thread */ + PROC_START(dhd_rxf_thread, dhd, &dhd->thr_rxf_ctl, 0, "dhd_rxf"); +#endif #else /* Set up the bottom half handler */ tasklet_init(&dhd->tasklet, dhd_dpc, (ulong)dhd); @@ -3134,35 +3559,44 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen, void *dev) #endif /* DHDTHREAD */ if (dhd_sysioc) { -#ifdef USE_KTHREAD_API - PROC_START2(_dhd_sysioc_thread, dhd, &dhd->thr_sysioc_ctl, 0, "dhd_sysioc"); -#else - PROC_START(_dhd_sysioc_thread, dhd, &dhd->thr_sysioc_ctl, 0); -#endif + PROC_START(_dhd_sysioc_thread, dhd, &dhd->thr_sysioc_ctl, 0, "dhd_sysioc"); } else { dhd->thr_sysioc_ctl.thr_pid = -1; } dhd_state |= DHD_ATTACH_STATE_THREADS_CREATED; + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (1) INIT_WORK(&dhd->work_hang, dhd_hang_process); #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ -#ifdef SYSFS_IDLETIME - dhd_sysfs_init(&dhd->pub); -#endif /* SYSFS_IDLETIME */ /* * Save the dhd_info into the priv */ memcpy(netdev_priv(net), &dhd, sizeof(dhd)); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (LINUX_VERSION_CODE <= \ + KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM_SLEEP) register_pm_notifier(&dhd_sleep_pm_notifier); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ +#endif /* (LINUX_VERSION >= 2.6.27 && LINUX_VERSION <= 2.6.39 && 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; register_inetaddr_notifier(&dhd_notifier); #endif /* ARP_OFFLOAD_SUPPORT */ + register_inet6addr_notifier(&dhd_notifier_ipv6); + +#ifdef DHDTCPACK_SUPPRESS + dhd->pub.tcp_ack_info_cnt = 0; + bzero(dhd->pub.tcp_ack_info_tbl, sizeof(struct tcp_ack_info)*MAXTCPSTREAMS); +#endif /* DHDTCPACK_SUPPRESS */ dhd_state |= DHD_ATTACH_STATE_DONE; dhd->dhd_state = dhd_state; @@ -3201,8 +3635,19 @@ dhd_bus_start(dhd_pub_t *dhdp) /* try to download image and nvram to the dongle */ if ((dhd->pub.busstate == DHD_BUS_DOWN) && - (fw_path != NULL) && (fw_path[0] != '\0') && - (nv_path != NULL) && (nv_path[0] != '\0')) { + (fw_path[0] != '\0') && (nv_path[0] != '\0')) { +#ifdef SHOW_NVRAM_TYPE + { /* Show nvram type in the kernel log */ + int i; + for (i = 0; nv_path[i] != '\0'; ++i) { + if (nv_path[i] == '.') { + ++i; + break; + } + } + DHD_ERROR(("%s: nvram_type = [%s]\n", __FUNCTION__, &nv_path[i])); + } +#endif /* SHOW_NVRAM_TYPE */ /* wake lock moved to dhdsdio_download_firmware */ if (!(dhd_bus_download_firmware(dhd->pub.bus, dhd->pub.osh, fw_path, nv_path))) { @@ -3258,7 +3703,7 @@ dhd_bus_start(dhd_pub_t *dhdp) /* Enable oob at firmware */ dhd_enable_oob_intr(dhd->pub.bus, TRUE); -#endif +#endif /* If bus is not ready, can't come up */ if (dhd->pub.busstate != DHD_BUS_DATA) { @@ -3280,23 +3725,13 @@ dhd_bus_start(dhd_pub_t *dhdp) dhd_os_sdunlock(dhdp); #endif /* DHDTHREAD */ -#ifdef BCMSDIOH_TXGLOM - if ((dhd->pub.busstate == DHD_BUS_DATA) && bcmsdh_glom_enabled()) { - dhd_txglom_enable(dhdp, TRUE); - } -#endif - -#ifdef READ_MACADDR - dhd_read_macaddr(dhd); -#endif + dhd_process_cid_mac(dhdp, TRUE); /* Bus is ready, do any protocol initialization */ if ((ret = dhd_prot_init(&dhd->pub)) < 0) return ret; -#ifdef WRITE_MACADDR - dhd_write_macaddr(dhd->pub.mac.octet); -#endif + dhd_process_cid_mac(dhdp, FALSE); #ifdef ARP_OFFLOAD_SUPPORT if (dhd->pend_ipaddr) { @@ -3309,6 +3744,45 @@ dhd_bus_start(dhd_pub_t *dhdp) return 0; } +#ifdef WLTDLS +int dhd_tdls_enable_disable(dhd_pub_t *dhd, bool flag) +{ + char iovbuf[WLC_IOCTL_SMLEN]; + uint32 tdls = flag; + int ret; +#ifdef WLTDLS_AUTO_ENABLE + uint32 tdls_auto_op = 1; + uint32 tdls_idle_time = CUSTOM_TDLS_IDLE_MODE_SETTING; +#endif /* WLTDLS_AUTO_ENABLE */ + if (!FW_SUPPORTED(dhd, tdls)) + return BCME_ERROR; + + bcm_mkiovar("tdls_enable", (char *)&tdls, sizeof(tdls), iovbuf, sizeof(iovbuf)); + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) { + DHD_ERROR(("%s: tdls %d failed %d\n", __FUNCTION__, tdls, ret)); + goto exit; + } + dhd->tdls_enable = flag; + if (!flag) + goto exit; +#ifdef WLTDLS_AUTO_ENABLE + bcm_mkiovar("tdls_auto_op", (char *)&tdls_auto_op, sizeof(tdls_auto_op), + iovbuf, sizeof(iovbuf)); + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) { + DHD_ERROR(("%s: tdls_auto_op failed %d\n", __FUNCTION__, ret)); + goto exit; + } + bcm_mkiovar("tdls_idle_time", (char *)&tdls_idle_time, sizeof(tdls_idle_time), + iovbuf, sizeof(iovbuf)); + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) { + DHD_ERROR(("%s: tdls_idle_time failed %d\n", __FUNCTION__, ret)); + goto exit; + } +#endif /* WLTDLS_AUTO_ENABLE */ +exit: + return ret; +} +#endif /* WLTDLS */ bool dhd_is_concurrent_mode(dhd_pub_t *dhd) { @@ -3323,7 +3797,6 @@ bool dhd_is_concurrent_mode(dhd_pub_t *dhd) 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 @@ -3341,18 +3814,10 @@ dhd_get_concurrent_capabilites(dhd_pub_t *dhd) */ if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) return 0; - memset(buf, 0, sizeof(buf)); - bcm_mkiovar("cap", 0, 0, buf, sizeof(buf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf), - FALSE, 0)) < 0) { - DHD_ERROR(("%s: Get Capability failed (error=%d)\n", - __FUNCTION__, ret)); - return 0; - } - if (strstr(buf, "vsdb")) { + if (FW_SUPPORTED(dhd, vsdb)) { mchan_supported = TRUE; } - if (strstr(buf, "p2p") == NULL) { + if (!FW_SUPPORTED(dhd, p2p)) { DHD_TRACE(("Chip does not support p2p\n")); return 0; } @@ -3373,41 +3838,37 @@ dhd_get_concurrent_capabilites(dhd_pub_t *dhd) ret = DHD_FLAG_CONCURR_SINGLE_CHAN_MODE; if (mchan_supported) ret |= DHD_FLAG_CONCURR_MULTI_CHAN_MODE; -#if defined(WL_ENABLE_P2P_IF) +#if defined(WL_ENABLE_P2P_IF) || defined(WL_CFG80211_P2P_DEV_IF) /* For customer_hw4, although ICS, * we still support concurrent mode */ return ret; #else return 0; -#endif +#endif } } } return 0; } -#endif +#endif 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 */ - -#if !defined(WL_CFG80211) - uint up = 0; -#endif /* !defined(WL_CFG80211) */ + uint32 buf_key_b4_m4 = 1; +#if defined(CUSTOM_AMPDU_BA_WSIZE) + uint32 ampdu_ba_wsize = 0; +#endif +#ifdef DHD_ENABLE_LPC + uint32 lpc = 1; +#endif /* DHD_ENABLE_LPC */ uint power_mode = PM_FAST; uint32 dongle_align = DHD_SDALIGN; uint32 glom = CUSTOM_GLOM_SETTING; -#if defined(VSDB) || defined(ROAM_ENABLE) - uint bcn_timeout = 8; -#else uint bcn_timeout = 4; -#endif -#ifdef ENABLE_BCN_LI_BCN_WAKEUP - uint32 bcn_li_bcn = 1; -#endif /* ENABLE_BCN_LI_BCN_WAKEUP */ uint retry_max = 3; #if defined(ARP_OFFLOAD_SUPPORT) int arpoe = 1; @@ -3417,7 +3878,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) int scan_passive_time = DHD_SCAN_PASSIVE_TIME; char buf[WLC_IOCTL_SMLEN]; char *ptr; - uint32 listen_interval = LISTEN_INTERVAL; /* Default Listen Interval in Beacons */ + uint32 listen_interval = CUSTOM_LISTEN_INTERVAL; /* Default Listen Interval in Beacons */ #ifdef ROAM_ENABLE uint roamvar = 0; int roam_trigger[2] = {CUSTOM_ROAM_TRIGGER_SETTING, WLC_BAND_ALL}; @@ -3448,25 +3909,40 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #ifdef GET_CUSTOM_MAC_ENABLE struct ether_addr ea_addr; #endif /* GET_CUSTOM_MAC_ENABLE */ + #ifdef DISABLE_11N uint32 nmode = 0; -#else -#ifdef AMPDU_HOSTREORDER - uint32 hostreorder = 1; -#endif #endif /* DISABLE_11N */ - dhd->suspend_bcn_li_dtim = CUSTOM_SUSPEND_BCN_LI_DTIM; +#ifdef USE_WL_TXBF + uint32 txbf = 1; +#endif /* USE_WL_TXBF */ +#ifdef USE_WL_FRAMEBURST + uint32 frameburst = 1; +#endif /* USE_WL_FRAMEBURST */ +#ifdef DHD_SET_FW_HIGHSPEED + uint32 ack_ratio = 250; + uint32 ack_ratio_depth = 64; +#endif /* DHD_SET_FW_HIGHSPEED */ +#ifdef SUPPORT_2G_VHT + uint32 vht_features = 0x3; /* 2G enable | rates all */ +#endif /* SUPPORT_2G_VHT */ #ifdef PROP_TXSTATUS #ifdef PROP_TXSTATUS_VSDB + /* In case the host does not support proptxstatus, hostreorder in dongle should be off */ + uint32 hostreorder = 0; dhd->wlfc_enabled = FALSE; /* enable WLFC only if the firmware is VSDB */ #else - if (disable_proptx) - dhd->wlfc_enabled = FALSE; - else + if (!disable_proptx) dhd->wlfc_enabled = TRUE; + else + dhd->wlfc_enabled = FALSE; #endif /* PROP_TXSTATUS_VSDB */ #endif /* PROP_TXSTATUS */ +#ifdef PKT_FILTER_SUPPORT + dhd_pkt_filter_enable = TRUE; +#endif + dhd->suspend_bcn_li_dtim = CUSTOM_SUSPEND_BCN_LI_DTIM; DHD_TRACE(("Enter %s\n", __FUNCTION__)); dhd->op_mode = 0; #ifdef GET_CUSTOM_MAC_ENABLE @@ -3498,7 +3974,15 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #endif /* GET_CUSTOM_MAC_ENABLE */ DHD_TRACE(("Firmware = %s\n", fw_path)); - + /* get a capabilities from firmware */ + memset(dhd->fw_capabilities, 0, sizeof(dhd->fw_capabilities)); + bcm_mkiovar("cap", 0, 0, dhd->fw_capabilities, sizeof(dhd->fw_capabilities)); + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, dhd->fw_capabilities, + sizeof(dhd->fw_capabilities), FALSE, 0)) < 0) { + DHD_ERROR(("%s: Get Capability failed (error=%d)\n", + __FUNCTION__, ret)); + return 0; + } if ((!op_mode && strstr(fw_path, "_apsta") != NULL) || (op_mode == DHD_FLAG_HOSTAP_MODE)) { #ifdef SET_RANDOM_MAC_SOFTAP @@ -3512,8 +3996,8 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) dhd_pkt_filter_enable = FALSE; #endif #ifdef SET_RANDOM_MAC_SOFTAP - srandom32((uint)jiffies); - rand_mac = random32(); + SRANDOM32((uint)jiffies); + rand_mac = RANDOM32(); iovbuf[0] = 0x02; /* locally administered bit */ iovbuf[1] = 0x1A; iovbuf[2] = 0x11; @@ -3536,7 +4020,6 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) DHD_ERROR(("%s mpc for HostAPD failed %d\n", __FUNCTION__, ret)); } #endif - } else { uint32 concurrent_mode = 0; @@ -3549,11 +4032,21 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) dhd_pkt_filter_enable = FALSE; #endif dhd->op_mode = DHD_FLAG_P2P_MODE; - } - else + } else if (op_mode == DHD_FLAG_IBSS_MODE || + (!op_mode && strstr(fw_path, "_ibss") != NULL)) { + dhd->op_mode = DHD_FLAG_IBSS_MODE; +#ifdef PROP_TXSTATUS_VSDB + if (!disable_proptx) { + hostreorder = 1; + dhd->wlfc_enabled = TRUE; + } +#endif /* PROP_TXSTATUS_VSDB */ + } else { dhd->op_mode = DHD_FLAG_STA_MODE; + } #if !defined(AP) && defined(WLP2P) - if ((concurrent_mode = dhd_get_concurrent_capabilites(dhd))) { + if (dhd->op_mode != DHD_FLAG_IBSS_MODE && + (concurrent_mode = dhd_get_concurrent_capabilites(dhd))) { #if defined(ARP_OFFLOAD_SUPPORT) arpoe = 1; #endif @@ -3581,7 +4074,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) } #else (void)concurrent_mode; -#endif +#endif } DHD_ERROR(("Firmware up: op_mode=0x%04x, " @@ -3606,7 +4099,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf)); dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); #endif /* ROAM_ENABLE || DISABLE_BUILTIN_ROAM */ -#ifdef ROAM_ENABLE +#if defined(ROAM_ENABLE) 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)); @@ -3621,23 +4114,18 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) DHD_ERROR(("%s: roam fullscan period set failed %d\n", __FUNCTION__, ret)); #endif /* ROAM_ENABLE */ -#ifdef SET_LOW_LATENCY - struct ampdu_tid_control atc; - int ampdu_ba_wsize = 32; - - atc.tid = 5; - atc.enable = 0; - bcm_mkiovar("ampdu_rx_tid", (char *)&atc, sizeof(atc), iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); +#ifdef WLTDLS + dhd_tdls_enable_disable(dhd, 1); +#endif /* WLTDLS */ - atc.tid = 7; - atc.enable = 0; - bcm_mkiovar("ampdu_rx_tid", (char *)&atc, sizeof(atc), iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); - - bcm_mkiovar("ampdu_ba_wsize", (char *)&du_ba_wsize, sizeof(ampdu_ba_wsize), iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -#endif /* SET_LOW_LATENCY */ +#ifdef DHD_ENABLE_LPC + /* Set lpc 1 */ + bcm_mkiovar("lpc", (char *)&lpc, 4, iovbuf, sizeof(iovbuf)); + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, + sizeof(iovbuf), TRUE, 0)) < 0) { + DHD_ERROR(("%s Set lpc failed %d\n", __FUNCTION__, ret)); + } +#endif /* DHD_ENABLE_LPC */ /* Set PowerSave mode */ dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, sizeof(power_mode), TRUE, 0); @@ -3671,7 +4159,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) if (ap_fw_loaded == TRUE) { dhd_wl_ioctl_cmd(dhd, WLC_SET_DTIMPRD, (char *)&dtim, sizeof(dtim), TRUE, 0); } -#endif +#endif #if defined(KEEP_ALIVE) { @@ -3680,7 +4168,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #if defined(SOFTAP) if (ap_fw_loaded == FALSE) -#endif +#endif if (!(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) { if ((res = dhd_keep_alive_onoff(dhd)) < 0) DHD_ERROR(("%s set keeplive failed %d\n", @@ -3688,6 +4176,61 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) } } #endif /* defined(KEEP_ALIVE) */ +#ifdef USE_WL_TXBF + bcm_mkiovar("txbf", (char *)&txbf, 4, iovbuf, sizeof(iovbuf)); + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, + sizeof(iovbuf), TRUE, 0)) < 0) { + DHD_ERROR(("%s Set txbf failed %d\n", __FUNCTION__, ret)); + } +#endif /* USE_WL_TXBF */ +#ifdef USE_WL_FRAMEBURST + /* Set frameburst to value */ + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_FAKEFRAG, (char *)&frameburst, + sizeof(frameburst), TRUE, 0)) < 0) { + DHD_ERROR(("%s Set frameburst failed %d\n", __FUNCTION__, ret)); + } +#endif /* USE_WL_FRAMEBURST */ +#ifdef DHD_SET_FW_HIGHSPEED + /* Set ack_ratio */ + bcm_mkiovar("ack_ratio", (char *)&ack_ratio, 4, iovbuf, sizeof(iovbuf)); + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, + sizeof(iovbuf), TRUE, 0)) < 0) { + DHD_ERROR(("%s Set ack_ratio failed %d\n", __FUNCTION__, ret)); + } + + /* Set ack_ratio_depth */ + bcm_mkiovar("ack_ratio_depth", (char *)&ack_ratio_depth, 4, iovbuf, sizeof(iovbuf)); + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, + sizeof(iovbuf), TRUE, 0)) < 0) { + DHD_ERROR(("%s Set ack_ratio_depth failed %d\n", __FUNCTION__, ret)); + } +#endif /* DHD_SET_FW_HIGHSPEED */ +#if defined(CUSTOM_AMPDU_BA_WSIZE) || defined(CUSTOM_IBSS_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) { + bcm_mkiovar("ampdu_ba_wsize", (char *)&du_ba_wsize, 4, iovbuf, sizeof(iovbuf)); + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, + sizeof(iovbuf), TRUE, 0)) < 0) { + DHD_ERROR(("%s Set ampdu_ba_wsize to %d failed %d\n", + __FUNCTION__, CUSTOM_AMPDU_BA_WSIZE, ret)); + } + } +#endif /* CUSTOM_AMPDU_BA_WSIZE || CUSTOM_IBSS_AMPDU_BA_WSIZE */ +#ifdef SUPPORT_2G_VHT + bcm_mkiovar("vht_features", (char *)&vht_features, 4, iovbuf, sizeof(iovbuf)); + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) { + DHD_ERROR(("%s vht_features set failed %d\n", __FUNCTION__, ret)); + } +#endif /* SUPPORT_2G_VHT */ + + bcm_mkiovar("buf_key_b4_m4", (char *)&buf_key_b4_m4, 4, iovbuf, sizeof(iovbuf)); + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, + sizeof(iovbuf), TRUE, 0)) < 0) { + DHD_ERROR(("%s buf_key_b4_m4 set failed %d\n", __FUNCTION__, ret)); + } /* Read event_msgs mask */ bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf)); @@ -3709,6 +4252,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) setbit(eventmask, WLC_E_DISASSOC_IND); setbit(eventmask, WLC_E_DISASSOC); setbit(eventmask, WLC_E_JOIN); + setbit(eventmask, WLC_E_START); setbit(eventmask, WLC_E_ASSOC_IND); setbit(eventmask, WLC_E_PSK_SUP); setbit(eventmask, WLC_E_LINK); @@ -3727,9 +4271,18 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #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 BCMCCX_S69 + setbit(eventmask, WLC_E_CCX_S69_RESP_RX); +#endif +#ifdef WLTDLS + setbit(eventmask, WLC_E_TDLS_PEER_EVENT); +#endif /* WLTDLS */ #ifdef WL_CFG80211 setbit(eventmask, WLC_E_ESCAN_RESULT); if (dhd->op_mode & DHD_FLAG_P2P_MODE) { @@ -3758,7 +4311,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) if (arpoe && !ap_fw_loaded) { #else if (arpoe) { -#endif +#endif dhd_arp_offload_enable(dhd, TRUE); dhd_arp_offload_set(dhd, dhd_arp_mode); } else { @@ -3770,49 +4323,38 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #ifdef PKT_FILTER_SUPPORT /* Setup default defintions for pktfilter , enable in suspend */ - dhd->pktfilter_count = 5; + dhd->pktfilter_count = 6; /* Setup filter to allow only unicast */ - dhd->pktfilter[0] = "100 0 0 0 0x01 0x00"; - dhd->pktfilter[1] = NULL; - dhd->pktfilter[2] = NULL; - dhd->pktfilter[3] = NULL; + dhd->pktfilter[DHD_UNICAST_FILTER_NUM] = "100 0 0 0 0x01 0x00"; + dhd->pktfilter[DHD_BROADCAST_FILTER_NUM] = NULL; + dhd->pktfilter[DHD_MULTICAST4_FILTER_NUM] = NULL; + dhd->pktfilter[DHD_MULTICAST6_FILTER_NUM] = NULL; /* Add filter to pass multicastDNS packet and NOT filter out as Broadcast */ - dhd->pktfilter[4] = "104 0 0 0 0xFFFFFFFFFFFF 0x01005E0000FB"; + dhd->pktfilter[DHD_MDNS_FILTER_NUM] = "104 0 0 0 0xFFFFFFFFFFFF 0x01005E0000FB"; + /* apply APP pktfilter */ + dhd->pktfilter[DHD_ARP_FILTER_NUM] = "105 0 0 12 0xFFFF 0x0806"; - dhd_set_packet_filter(dhd); #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 bcm_mkiovar("nmode", (char *)&nmode, 4, iovbuf, sizeof(iovbuf)); if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) DHD_ERROR(("%s wl nmode 0 failed %d\n", __FUNCTION__, ret)); #else -#ifdef AMPDU_HOSTREORDER +#if defined(PROP_TXSTATUS) && defined(PROP_TXSTATUS_VSDB) bcm_mkiovar("ampdu_hostreorder", (char *)&hostreorder, 4, buf, sizeof(buf)); dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0); -#endif /* AMPDU_HOSTREORDER */ +#endif #endif /* DISABLE_11N */ -#if !defined(WL_CFG80211) - /* Force STA UP */ - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_UP, (char *)&up, sizeof(up), TRUE, 0)) < 0) { - DHD_ERROR(("%s Setting WL UP failed %d\n", __FUNCTION__, ret)); - goto done; - } -#endif -#ifdef ENABLE_BCN_LI_BCN_WAKEUP - bcm_mkiovar("bcn_li_bcn", (char *)&bcn_li_bcn, 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -#endif /* ENABLE_BCN_LI_BCN_WAKEUP */ - /* query for 'ver' to get version info from firmware */ memset(buf, 0, sizeof(buf)); ptr = buf; @@ -3823,12 +4365,8 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) bcmstrtok(&ptr, "\n", 0); /* Print fw version info */ DHD_ERROR(("Firmware version = %s\n", buf)); - dhd_set_version_info(dhd, buf); - DHD_BLOG(buf, strlen(buf) + 1); - DHD_BLOG(dhd_version, strlen(dhd_version) + 1); - /* Check and adjust IOCTL response timeout for Manufactring firmware */ if (strstr(buf, MANUFACTRING_FW) != NULL) { dhd_os_set_ioctl_resp_timeout(20000); @@ -3837,6 +4375,27 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) } } +#ifdef BCMSDIOH_TXGLOM + if (bcmsdh_glom_enabled()) { + dhd_txglom_enable(dhd, TRUE); + } +#endif /* BCMSDIOH_TXGLOM */ + +#if defined(PROP_TXSTATUS) +#ifdef PROP_TXSTATUS_VSDB + if (dhd->op_mode == DHD_FLAG_IBSS_MODE) + dhd_wlfc_init(dhd); +#else + dhd_wlfc_init(dhd); +#endif /* PROP_TXSTATUS_VSDB */ +#endif /* PROP_TXSTATUS */ + +#ifdef PNO_SUPPORT + if (!dhd->pno_state) { + dhd_pno_init(dhd); + } +#endif + done: return ret; } @@ -3875,7 +4434,7 @@ dhd_iovar(dhd_pub_t *pub, int ifidx, char *name, char *cmd_buf, uint cmd_len, in ioc.cmd = set? WLC_SET_VAR : WLC_GET_VAR; ioc.buf = buf; ioc.len = len; - ioc.set = TRUE; + ioc.set = set; ret = dhd_wl_ioctl(pub, ifidx, &ioc, ioc.buf, ioc.len); if (!set && ret >= 0) @@ -3986,9 +4545,9 @@ static int dhd_device_event(struct notifier_block *this, /* 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)) { -#ifdef WLP2P +#if defined(WL_ENABLE_P2P_IF) if (!wl_cfgp2p_is_ifops(ifa->ifa_dev->dev->netdev_ops)) -#endif +#endif /* WL_ENABLE_P2P_IF */ return NOTIFY_DONE; } #endif /* LINUX_VERSION_CODE */ @@ -4035,7 +4594,7 @@ static int dhd_device_event(struct notifier_block *this, 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 +#endif /* AOE_IP_ALIAS_SUPPORT */ break; case NETDEV_DOWN: @@ -4061,6 +4620,69 @@ static int dhd_device_event(struct notifier_block *this, } #endif /* ARP_OFFLOAD_SUPPORT */ +/* + * Neighbor Discovery Offload: Called when an interface + * is assigned with ipv6 address. + * Handles only primary interface + */ +static int dhd_device_ipv6_event(struct notifier_block *this, + unsigned long event, + void *ptr) +{ + dhd_info_t *dhd; + dhd_pub_t *dhd_pub; + struct ipv6_addr *_ipv6_addr = NULL; + struct inet6_ifaddr *inet6_ifa = ptr; + int idx = 0; +#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) { + goto exit; + } +#endif /* LINUX_VERSION_CODE */ + + dhd = *(dhd_info_t **)netdev_priv(inet6_ifa->idev->dev); + if (!dhd) + goto exit; + + idx = dhd_net2idx(dhd, inet6_ifa->idev->dev); + if (idx == DHD_BAD_IF) { + DHD_ERROR(("Cannot find ifidx")); + goto exit; + } + dhd_pub = &dhd->pub; + if (!FW_SUPPORTED(dhd_pub, ndoe)) + goto exit; + if (event == NETDEV_UP || event == NETDEV_DOWN) { + _ipv6_addr = NATIVE_MALLOC(dhd_pub->osh, sizeof(struct ipv6_addr)); + if (_ipv6_addr == NULL) { + DHD_ERROR(("Failed to allocate ipv6\n")); + goto exit; + } + memcpy(&_ipv6_addr->ipv6_addr[0], &inet6_ifa->addr, IPV6_ADDR_LEN); + DHD_TRACE(("IPV6 address : %pI6\n", &inet6_ifa->addr)); + } + switch (event) { + case NETDEV_UP: + DHD_TRACE(("%s: Enable NDO and add ipv6 into table \n ", __FUNCTION__)); + _ipv6_addr->ipv6_oper = DHD_IPV6_ADDR_ADD; + break; + case NETDEV_DOWN: + DHD_TRACE(("%s: clear ipv6 table \n", __FUNCTION__)); + _ipv6_addr->ipv6_oper = DHD_IPV6_ADDR_DELETE; + break; + default: + DHD_ERROR(("%s: unknown notifier event \n", __FUNCTION__)); + goto exit; + } + spin_lock_bh(&dhd->iflist[idx]->ipv6_lock); + list_add_tail(&_ipv6_addr->list, &dhd->iflist[idx]->ipv6_list); + spin_unlock_bh(&dhd->iflist[idx]->ipv6_lock); + up(&dhd->thr_sysioc_ctl.sema); +exit: + return NOTIFY_DONE; +} + int dhd_net_attach(dhd_pub_t *dhdp, int ifidx) { @@ -4138,6 +4760,7 @@ dhd_net_attach(dhd_pub_t *dhdp, int ifidx) memcpy(net->dev_addr, temp_addr, ETHER_ADDR_LEN); + net->ifindex = 0; if ((err = register_netdev(net)) != 0) { DHD_ERROR(("couldn't register the net device, err %d\n", err)); goto fail; @@ -4156,7 +4779,7 @@ dhd_net_attach(dhd_pub_t *dhdp, int ifidx) dhd_registration_check = TRUE; up(&dhd_registration_sem); } -#endif +#endif return 0; fail: @@ -4193,7 +4816,7 @@ dhd_bus_detach(dhd_pub_t *dhdp) #if defined(OOB_INTR_ONLY) bcmsdh_unregister_oob_intr(); -#endif +#endif } } } @@ -4213,13 +4836,17 @@ void dhd_detach(dhd_pub_t *dhdp) return; DHD_TRACE(("%s: Enter state 0x%x\n", __FUNCTION__, dhd->dhd_state)); +#ifdef ARP_OFFLOAD_SUPPORT + unregister_inetaddr_notifier(&dhd_notifier); +#endif /* ARP_OFFLOAD_SUPPORT */ + unregister_inet6addr_notifier(&dhd_notifier_ipv6); 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_delay(1000*100); + OSL_SLEEP(100); } if (dhd->dhd_state & DHD_ATTACH_STATE_PROT_ATTACH) { @@ -4228,10 +4855,12 @@ void dhd_detach(dhd_pub_t *dhdp) if (dhdp->prot) dhd_prot_detach(dhdp); } - -#ifdef ARP_OFFLOAD_SUPPORT - unregister_inetaddr_notifier(&dhd_notifier); -#endif /* ARP_OFFLOAD_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 (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) cancel_work_sync(&dhd->work_hang); @@ -4301,11 +4930,15 @@ void dhd_detach(dhd_pub_t *dhdp) if (dhd->thr_dpc_ctl.thr_pid >= 0) { PROC_STOP(&dhd->thr_dpc_ctl); } +#ifdef RXFRAME_THREAD + if (dhd->thr_rxf_ctl.thr_pid >= 0) { + PROC_STOP(&dhd->thr_rxf_ctl); + } +#endif else #endif /* DHDTHREAD */ tasklet_kill(&dhd->tasklet); } - #ifdef WL_CFG80211 if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) { wl_cfg80211_detach(NULL); @@ -4313,13 +4946,17 @@ void dhd_detach(dhd_pub_t *dhdp) } #endif - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) +#ifdef PNO_SUPPORT + if (dhdp->pno_state) + dhd_pno_deinit(dhdp); +#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (LINUX_VERSION_CODE <= \ + KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM_SLEEP) unregister_pm_notifier(&dhd_sleep_pm_notifier); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ - /* && defined(CONFIG_PM_SLEEP) */ +#endif /* (LINUX_VERSION >= 2.6.27 && LINUX_VERSION <= 2.6.39 && CONFIG_PM_SLEEP */ if (dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT) { + DHD_TRACE(("wd wakelock count:%d\n", dhd->wakelock_wd_counter)); #ifdef CONFIG_HAS_WAKELOCK dhd->wakelock_counter = 0; dhd->wakelock_wd_counter = 0; @@ -4331,10 +4968,6 @@ void dhd_detach(dhd_pub_t *dhdp) wake_lock_destroy(&dhd->wl_wdwake); #endif /* CONFIG_HAS_WAKELOCK */ } - -#ifdef SYSFS_IDLETIME - dhd_sysfs_deinit(); -#endif /* SYSFS_IDLETIME */ } @@ -4362,8 +4995,19 @@ dhd_free(dhd_pub_t *dhdp) } } dhd = (dhd_info_t *)dhdp->info; - if (dhd) - MFREE(dhd->pub.osh, dhd, sizeof(*dhd)); +#if defined(CONFIG_DHD_USE_STATIC_BUF) + /* If pointer is allocated by dhd_os_prealloc then avoid MFREE */ + if (dhd != (dhd_info_t *)dhd_os_prealloc(NULL, DHD_PREALLOC_DHD_INFO, 0)) { +#endif /* CONFIG_DHD_USE_STATIC_BUF */ + if (dhd) + MFREE(dhd->pub.osh, dhd, sizeof(*dhd)); +#if defined(CONFIG_DHD_USE_STATIC_BUF) + } + else { + if (dhd) + dhd = NULL; + } +#endif /* CONFIG_DHD_USE_STATIC_BUF */ } } @@ -4372,6 +5016,7 @@ dhd_module_cleanup(void) { DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + dhd_bus_unregister(); #if defined(CONFIG_WIFI_CONTROL_FUNC) @@ -4384,11 +5029,20 @@ dhd_module_cleanup(void) } +#if defined(CONFIG_WIFI_CONTROL_FUNC) +extern bool g_wifi_poweron; +#endif /* CONFIG_WIFI_CONTROL_FUNC */ + static int __init dhd_module_init(void) { int error = 0; +#if 1 && defined(BCMLXSDMMC) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) + int retry = POWERUP_MAX_RETRY; + int chip_up = 0; +#endif + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); wl_android_init(); @@ -4405,14 +5059,65 @@ dhd_module_init(void) break; DHD_ERROR(("Invalid module parameters.\n")); - return -EINVAL; + error = -EINVAL; } while (0); -#endif +#endif + if (error) + goto fail_0; + +#if 1 && defined(BCMLXSDMMC) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) + do { + sema_init(&dhd_chipup_sem, 0); + error = dhd_bus_reg_sdio_notify(&dhd_chipup_sem); + if (error) { + DHD_ERROR(("n%s dhd_bus_reg_sdio_notify fail(%d)\n\n", __func__, error)); + goto fail_1; + } + dhd_customer_gpio_wlan_ctrl(WLAN_POWER_ON); +#if defined(CONFIG_WIFI_CONTROL_FUNC) + if (wl_android_wifictrl_func_add() < 0) { + dhd_bus_unreg_sdio_notify(); + goto fail_1; + } +#endif /* defined(CONFIG_WIFI_CONTROL_FUNC) */ + if (down_timeout(&dhd_chipup_sem, + msecs_to_jiffies(POWERUP_WAIT_MS)) == 0) { + dhd_bus_unreg_sdio_notify(); + chip_up = 1; + break; + } + DHD_ERROR(("\nfailed to power up wifi chip, retry again (%d left) **\n\n", + retry+1)); + dhd_bus_unreg_sdio_notify(); +#if defined(CONFIG_WIFI_CONTROL_FUNC) + wl_android_wifictrl_func_del(); +#endif /* defined(CONFIG_WIFI_CONTROL_FUNC) */ + dhd_customer_gpio_wlan_ctrl(WLAN_POWER_OFF); + } while (retry-- > 0); + + if (!chip_up) { + DHD_ERROR(("\nfailed to power up wifi chip, max retry reached, exits **\n\n")); + error = -ENODEV; + goto fail_0; + } +#else dhd_customer_gpio_wlan_ctrl(WLAN_POWER_ON); #if defined(CONFIG_WIFI_CONTROL_FUNC) if (wl_android_wifictrl_func_add() < 0) goto fail_1; #endif /* defined(CONFIG_WIFI_CONTROL_FUNC) */ +#endif + +#if defined(CONFIG_WIFI_CONTROL_FUNC) && defined(BCMLXSDMMC) + /* If the wifi_set_power() is failed, + * we need to jump error handling routines. + */ + if (!g_wifi_poweron) { + printk("%s: wifi_set_power() failed\n", __FUNCTION__); + error = -ENODEV; + goto fail_1; + } +#endif /* defined(CONFIG_WIFI_CONTROL_FUNC) */ #if 1 && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) sema_init(&dhd_registration_sem, 0); @@ -4420,6 +5125,8 @@ dhd_module_init(void) sema_init(&dhd_init_sem, 1); #endif #endif + + error = dhd_bus_register(); if (!error) @@ -4429,7 +5136,7 @@ dhd_module_init(void) goto fail_1; } -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(BCMLXSDMMC) /* * Wait till MMC sdio_register_driver callback called and made driver attach. * It's needed to make sync up exit from dhd insmod and @@ -4457,7 +5164,7 @@ dhd_module_init(void) return error; -#if 1 && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) +#if 1 && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(BCMLXSDMMC) fail_2: dhd_bus_unregister(); #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ @@ -4466,19 +5173,27 @@ fail_1: #if defined(CONFIG_WIFI_CONTROL_FUNC) wl_android_wifictrl_func_del(); -#endif +#endif /* Call customer gpio to turn off power with WL_REG_ON signal */ dhd_customer_gpio_wlan_ctrl(WLAN_POWER_OFF); +fail_0: + + wl_android_exit(); + return error; } #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) +#ifdef 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 +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */ module_exit(dhd_module_cleanup); @@ -4553,6 +5268,19 @@ dhd_os_ioctl_resp_wake(dhd_pub_t *pub) } void +dhd_os_wd_timer_extend(void *bus, bool extend) +{ + 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); +} + + +void dhd_os_wd_timer(void *bus, uint wdtick) { dhd_pub_t *pub = bus; @@ -4561,8 +5289,10 @@ dhd_os_wd_timer(void *bus, uint wdtick) DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - if (!dhd) + if (!dhd) { + DHD_ERROR(("%s: dhd NULL\n", __FUNCTION__)); return; + } flags = dhd_os_spin_lock(pub); @@ -4574,7 +5304,7 @@ dhd_os_wd_timer(void *bus, uint wdtick) return; } - /* totally stop the timer */ + /* Totally stop the timer */ if (!wdtick && dhd->wd_timer_valid == TRUE) { dhd->wd_timer_valid = FALSE; dhd_os_spin_unlock(pub, flags); @@ -4583,7 +5313,6 @@ dhd_os_wd_timer(void *bus, uint wdtick) #else del_timer(&dhd->timer); #endif /* DHDTHREAD */ - /* Unlock when timer deleted */ DHD_OS_WD_WAKE_UNLOCK(pub); return; } @@ -4710,6 +5439,48 @@ dhd_os_sdtxunlock(dhd_pub_t *pub) dhd_os_sdunlock(pub); } +#if defined(DHDTHREAD) && defined(RXFRAME_THREAD) +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); +} +#endif /* defined(DHDTHREAD) && defined(RXFRAME_THREAD) */ + +#ifdef DHDTCPACK_SUPPRESS +void +dhd_os_tcpacklock(dhd_pub_t *pub) +{ + dhd_info_t *dhd; + + dhd = (dhd_info_t *)(pub->info); + spin_lock_bh(&dhd->tcpack_lock); + +} + +void +dhd_os_tcpackunlock(dhd_pub_t *pub) +{ + dhd_info_t *dhd; + + dhd = (dhd_info_t *)(pub->info); + spin_unlock_bh(&dhd->tcpack_lock); +} +#endif /* DHDTCPACK_SUPPRESS */ + #if defined(CONFIG_DHD_USE_STATIC_BUF) uint8* dhd_os_prealloc(void *osh, int section, uint size) { @@ -4799,102 +5570,6 @@ void dhd_sendup_event(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data) { switch (ntoh32(event->event_type)) { -#ifdef WLBTAMP - /* Send up locally generated AMP HCI Events */ - case WLC_E_BTA_HCI_EVENT: { - struct sk_buff *p, *skb; - bcm_event_t *msg; - wl_event_msg_t *p_bcm_event; - char *ptr; - uint32 len; - uint32 pktlen; - dhd_if_t *ifp; - dhd_info_t *dhd; - uchar *eth; - int ifidx; - - len = ntoh32(event->datalen); - pktlen = sizeof(bcm_event_t) + len + 2; - dhd = dhdp->info; - ifidx = dhd_ifname2idx(dhd, event->ifname); - - if ((p = PKTGET(dhdp->osh, pktlen, FALSE))) { - ASSERT(ISALIGNED((uintptr)PKTDATA(dhdp->osh, p), sizeof(uint32))); - - msg = (bcm_event_t *) PKTDATA(dhdp->osh, p); - - bcopy(&dhdp->mac, &msg->eth.ether_dhost, ETHER_ADDR_LEN); - bcopy(&dhdp->mac, &msg->eth.ether_shost, ETHER_ADDR_LEN); - ETHER_TOGGLE_LOCALADDR(&msg->eth.ether_shost); - - msg->eth.ether_type = hton16(ETHER_TYPE_BRCM); - - /* BCM Vendor specific header... */ - msg->bcm_hdr.subtype = hton16(BCMILCP_SUBTYPE_VENDOR_LONG); - msg->bcm_hdr.version = BCMILCP_BCM_SUBTYPEHDR_VERSION; - bcopy(BRCM_OUI, &msg->bcm_hdr.oui[0], DOT11_OUI_LEN); - - /* vendor spec header length + pvt data length (private indication - * hdr + actual message itself) - */ - msg->bcm_hdr.length = hton16(BCMILCP_BCM_SUBTYPEHDR_MINLENGTH + - BCM_MSG_LEN + sizeof(wl_event_msg_t) + (uint16)len); - msg->bcm_hdr.usr_subtype = hton16(BCMILCP_BCM_SUBTYPE_EVENT); - - PKTSETLEN(dhdp->osh, p, (sizeof(bcm_event_t) + len + 2)); - - /* copy wl_event_msg_t into sk_buf */ - - /* pointer to wl_event_msg_t in sk_buf */ - p_bcm_event = &msg->event; - bcopy(event, p_bcm_event, sizeof(wl_event_msg_t)); - - /* copy hci event into sk_buf */ - bcopy(data, (p_bcm_event + 1), len); - - msg->bcm_hdr.length = hton16(sizeof(wl_event_msg_t) + - ntoh16(msg->bcm_hdr.length)); - PKTSETLEN(dhdp->osh, p, (sizeof(bcm_event_t) + len + 2)); - - ptr = (char *)(msg + 1); - /* Last 2 bytes of the message are 0x00 0x00 to signal that there - * are no ethertypes which are following this - */ - ptr[len+0] = 0x00; - ptr[len+1] = 0x00; - - skb = PKTTONATIVE(dhdp->osh, p); - eth = skb->data; - len = skb->len; - - 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 = eth; - skb->len = len; - - /* Strip header, count, deliver upward */ - skb_pull(skb, ETH_HLEN); - - /* 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", __FUNCTION__)); - } - break; - } /* case WLC_E_BTA_HCI_EVENT */ -#endif /* WLBTAMP */ default: break; @@ -4915,7 +5590,7 @@ void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar) dhd_os_sdunlock(dhd); wait_event_timeout(dhdinfo->ctrl_wait, (*lockvar == FALSE), timeout); dhd_os_sdlock(dhd); -#endif +#endif return; } @@ -4936,14 +5611,29 @@ dhd_dev_reset(struct net_device *dev, uint8 flag) dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - if (dhd == NULL) - return -1; - 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__)); } +#if defined(PROP_TXSTATUS) +#ifdef PROP_TXSTATUS_VSDB + if (dhd->pub.op_mode == DHD_FLAG_IBSS_MODE) { + dhd_wlfc_deinit(&dhd->pub); + if (dhd->pub.plat_deinit) + dhd->pub.plat_deinit((void *)&dhd->pub); + } +#else + dhd_wlfc_deinit(&dhd->pub); + if (dhd->pub.plat_deinit) + dhd->pub.plat_deinit((void *)&dhd->pub); +#endif /* PROP_TXSTATUS_VSDB */ +#endif /* PROP_TXSTATUS */ + +#ifdef PNO_SUPPORT + if (dhd->pub.pno_state) + dhd_pno_deinit(&dhd->pub); +#endif } ret = dhd_bus_devreset(&dhd->pub, flag); @@ -4973,7 +5663,11 @@ int net_os_set_suspend(struct net_device *dev, int val, int force) dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); if (dhd) { +#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 @@ -4994,37 +5688,44 @@ int net_os_set_suspend_bcn_li_dtim(struct net_device *dev, int val) #ifdef PKT_FILTER_SUPPORT int net_os_rxfilter_add_remove(struct net_device *dev, int add_remove, int num) { -#ifndef GAN_LITE_NAT_KEEPALIVE_FILTER dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); char *filterp = NULL; + int filter_id = 0; int ret = 0; if (!dhd || (num == DHD_UNICAST_FILTER_NUM) || - (num == DHD_MDNS_FILTER_NUM)) + (num == DHD_MDNS_FILTER_NUM)) return ret; if (num >= dhd->pub.pktfilter_count) return -EINVAL; - if (add_remove) { - switch (num) { + switch (num) { case DHD_BROADCAST_FILTER_NUM: filterp = "101 0 0 0 0xFFFFFFFFFFFF 0xFFFFFFFFFFFF"; + filter_id = 101; break; case DHD_MULTICAST4_FILTER_NUM: filterp = "102 0 0 0 0xFFFFFF 0x01005E"; + filter_id = 102; break; case DHD_MULTICAST6_FILTER_NUM: filterp = "103 0 0 0 0xFFFF 0x3333"; + filter_id = 103; break; default: return -EINVAL; + } + + /* Add filter */ + if (add_remove) { + dhd->pub.pktfilter[num] = filterp; + dhd_pktfilter_offload_set(&dhd->pub, dhd->pub.pktfilter[num]); + } else { /* Delete filter */ + if (dhd->pub.pktfilter[num] != NULL) { + dhd_pktfilter_offload_delete(&dhd->pub, filter_id); + dhd->pub.pktfilter[num] = NULL; } } - dhd->pub.pktfilter[num] = filterp; - dhd_pktfilter_offload_set(&dhd->pub, dhd->pub.pktfilter[num]); return ret; -#else - return 0; -#endif /* GAN_LITE_NAT_KEEPALIVE_FILTER */ } int dhd_os_enable_packet_filter(dhd_pub_t *dhdp, int val) @@ -5059,49 +5760,77 @@ int dhd_dev_init_ioctl(struct net_device *dev) { dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - return dhd_preinit_ioctls(&dhd->pub); + int ret; + + dhd_process_cid_mac(&dhd->pub, TRUE); + + if ((ret = dhd_preinit_ioctls(&dhd->pub)) < 0) + goto done; + + dhd_process_cid_mac(&dhd->pub, FALSE); + +done: + return ret; } #ifdef PNO_SUPPORT -/* Linux wrapper to call common dhd_pno_clean */ +/* Linux wrapper to call common dhd_pno_stop_for_ssid */ int -dhd_dev_pno_reset(struct net_device *dev) +dhd_dev_pno_stop_for_ssid(struct net_device *dev) { dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - return (dhd_pno_clean(&dhd->pub)); + 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_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_info_t **)netdev_priv(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 pfn_enabled) +dhd_dev_pno_enable(struct net_device *dev, int enable) { dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - return (dhd_pno_enable(&dhd->pub, pfn_enabled)); + return (dhd_pno_enable(&dhd->pub, enable)); } - -/* Linux wrapper to call common dhd_pno_set */ +/* Linux wrapper to call common dhd_pno_set_for_hotlist */ int -dhd_dev_pno_set(struct net_device *dev, wlc_ssid_t* ssids_local, int nssid, - ushort scan_fr, int pno_repeat, int pno_freq_expo_max) +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_info_t **)netdev_priv(dev); - - return (dhd_pno_set(&dhd->pub, ssids_local, nssid, scan_fr, pno_repeat, pno_freq_expo_max)); + return (dhd_pno_set_for_hotlist(&dhd->pub, p_pfn_bssid, hotlist_params)); } - -/* Linux wrapper to get pno status */ +/* Linux wrapper to call common dhd_dev_pno_stop_for_batch */ int -dhd_dev_get_pno_status(struct net_device *dev) +dhd_dev_pno_stop_for_batch(struct net_device *dev) { dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_pno_get_status(&dhd->pub)); + 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_info_t **)netdev_priv(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_info_t **)netdev_priv(dev); + return (dhd_pno_get_for_batch(&dhd->pub, buf, bufsize, PNO_STATUS_NORMAL)); } - #endif /* PNO_SUPPORT */ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (1) @@ -5160,7 +5889,7 @@ int net_os_send_hang_message(struct net_device *dev) } return ret; } -#endif /* (OEM_ANDROID) */ +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) && OEM_ANDROID */ void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec, bool notify) { @@ -5172,6 +5901,7 @@ void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec, bool notif #endif } } + void dhd_bus_band_set(struct net_device *dev, uint band) { dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); @@ -5182,7 +5912,6 @@ void dhd_bus_band_set(struct net_device *dev, uint band) } } - void dhd_net_if_lock(struct net_device *dev) { dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); @@ -5254,7 +5983,7 @@ dhd_get_pend_8021x_cnt(dhd_info_t *dhd) return (atomic_read(&dhd->pend_8021x_cnt)); } -#define MAX_WAIT_FOR_8021X_TX 25 +#define MAX_WAIT_FOR_8021X_TX 50 int dhd_wait_pend8021x(struct net_device *dev) @@ -5274,7 +6003,10 @@ dhd_wait_pend8021x(struct net_device *dev) 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; } @@ -5409,6 +6141,9 @@ int dhd_os_wake_lock(dhd_pub_t *pub) #ifdef CONFIG_HAS_WAKELOCK if (!dhd->wakelock_counter) wake_lock(&dhd->wl_wifi); +#elif 1 && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) + if (pm_dev) + pm_stay_awake(pm_dev); #endif dhd->wakelock_counter++; ret = dhd->wakelock_counter; @@ -5441,6 +6176,9 @@ int dhd_os_wake_unlock(dhd_pub_t *pub) #ifdef CONFIG_HAS_WAKELOCK if (!dhd->wakelock_counter) wake_unlock(&dhd->wl_wifi); +#elif 1 && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) + if (pm_dev) + pm_relax(pm_dev); #endif ret = dhd->wakelock_counter; } @@ -5451,18 +6189,24 @@ int dhd_os_wake_unlock(dhd_pub_t *pub) int dhd_os_check_wakelock(void *dhdp) { -#ifdef CONFIG_HAS_WAKELOCK +#if defined(CONFIG_HAS_WAKELOCK) || (1 && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, \ + 36))) dhd_pub_t *pub = (dhd_pub_t *)dhdp; 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 1 && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) + if (dhd && (dhd->wakelock_counter > 0) && pm_dev) + return 1; #endif return 0; } @@ -5522,7 +6266,6 @@ int dhd_os_check_if_up(void *dhdp) return 0; return pub->up; } - /* function to collect firmware, chip id and chip version info */ void dhd_set_version_info(dhd_pub_t *dhdp, char *fw) { @@ -5538,7 +6281,6 @@ void dhd_set_version_info(dhd_pub_t *dhdp, char *fw) "\n Chip: %x Rev %x Pkg %x", dhd_bus_chip_id(dhdp), dhd_bus_chiprev_id(dhdp), dhd_bus_chippkg_id(dhdp)); } - int dhd_ioctl_entry_local(struct net_device *net, wl_ioctl_t *ioc, int cmd) { int ifidx; @@ -5551,6 +6293,9 @@ int dhd_ioctl_entry_local(struct net_device *net, wl_ioctl_t *ioc, int cmd) } dhd = *(dhd_info_t **)netdev_priv(net); + if (!dhd) + return -EINVAL; + ifidx = dhd_net2idx(dhd, net); if (ifidx == DHD_BAD_IF) { DHD_ERROR(("%s bad ifidx\n", __FUNCTION__)); @@ -5582,42 +6327,46 @@ extern int dhd_wlfc_FIFOcreditmap_update(void* state, uint8* credits); int dhd_wlfc_interface_event(struct dhd_info *dhd, ewlfc_mac_entry_action_t action, uint8 ifid, uint8 iftype, uint8* ea) { - int status; - - dhd_os_wlfc_block(&dhd->pub); - if (dhd->pub.wlfc_state == NULL) { - dhd_os_wlfc_unblock(&dhd->pub); + if (dhd->pub.wlfc_state == NULL) return BCME_OK; - } - status = dhd_wlfc_interface_entry_update(dhd->pub.wlfc_state, action, ifid, iftype, ea); - dhd_os_wlfc_unblock(&dhd->pub); - return status; + return dhd_wlfc_interface_entry_update(dhd->pub.wlfc_state, action, ifid, iftype, ea); } int dhd_wlfc_FIFOcreditmap_event(struct dhd_info *dhd, uint8* event_data) { - int status; - - dhd_os_wlfc_block(&dhd->pub); - if (dhd->pub.wlfc_state == NULL) { - dhd_os_wlfc_unblock(&dhd->pub); + if (dhd->pub.wlfc_state == NULL) return BCME_OK; - } - status = dhd_wlfc_FIFOcreditmap_update(dhd->pub.wlfc_state, event_data); - dhd_os_wlfc_unblock(&dhd->pub); - return status; + return dhd_wlfc_FIFOcreditmap_update(dhd->pub.wlfc_state, event_data); } int dhd_wlfc_event(struct dhd_info *dhd) { - int status; + return dhd_wlfc_enable(&dhd->pub); +} - dhd_os_wlfc_block(&dhd->pub); - status = dhd_wlfc_enable(&dhd->pub); - dhd_os_wlfc_unblock(&dhd->pub); - return status; +void dhd_wlfc_plat_enable(void *dhd) +{ + return; +} + +void dhd_wlfc_plat_deinit(void *dhd) +{ + return; +} + +bool dhd_wlfc_skip_fc(void) +{ + +#ifdef WL_CFG80211 + extern struct wl_priv *wlcfg_drv_priv; + + /* enable flow control in vsdb mode */ + return !(wlcfg_drv_priv && wlcfg_drv_priv->vsdb_mode); +#else + return TRUE; /* skip flow control */ +#endif /* WL_CFG80211 */ } #endif /* PROP_TXSTATUS */ diff --git a/drivers/net/wireless/bcmdhd/dhd_linux_sched.c b/drivers/net/wireless/bcmdhd/dhd_linux_sched.c index 290caf7e658c..3486c7b215e5 100644..100755 --- a/drivers/net/wireless/bcmdhd/dhd_linux_sched.c +++ b/drivers/net/wireless/bcmdhd/dhd_linux_sched.c @@ -1,7 +1,7 @@ /* * Expose some of the kernel scheduler routines * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd/dhd_pno.c b/drivers/net/wireless/bcmdhd/dhd_pno.c new file mode 100755 index 000000000000..165df802e41d --- /dev/null +++ b/drivers/net/wireless/bcmdhd/dhd_pno.c @@ -0,0 +1,1872 @@ +/* + * Broadcom Dongle Host Driver (DHD) + * Prefered Network Offload and Wi-Fi Location Service(WLS) code. + * + * Copyright (C) 1999-2013, 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_pno.c 427050 2013-10-02 03:31:11Z $ + */ +#include <typedefs.h> +#include <osl.h> + +#include <epivers.h> +#include <bcmutils.h> + +#include <bcmendian.h> +#include <linuxver.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/sort.h> +#include <dngl_stats.h> +#include <wlioctl.h> + +#include <proto/bcmevent.h> +#include <dhd.h> +#include <dhd_pno.h> +#include <dhd_dbg.h> + +#ifdef __BIG_ENDIAN +#include <bcmendian.h> +#define htod32(i) (bcmswap32(i)) +#define htod16(i) (bcmswap16(i)) +#define dtoh32(i) (bcmswap32(i)) +#define dtoh16(i) (bcmswap16(i)) +#define htodchanspec(i) htod16(i) +#define dtohchanspec(i) dtoh16(i) +#else +#define htod32(i) (i) +#define htod16(i) (i) +#define dtoh32(i) (i) +#define dtoh16(i) (i) +#define htodchanspec(i) (i) +#define dtohchanspec(i) (i) +#endif /* IL_BIGENDINA */ + +#define NULL_CHECK(p, s, err) \ + do { \ + if (!(p)) { \ + printf("NULL POINTER (%s) : %s\n", __FUNCTION__, (s)); \ + err = BCME_ERROR; \ + return err; \ + } \ + } while (0) +#define PNO_GET_PNOSTATE(dhd) ((dhd_pno_status_info_t *)dhd->pno_state) +#define PNO_BESTNET_LEN 1024 +#define PNO_ON 1 +#define PNO_OFF 0 +#define CHANNEL_2G_MAX 14 +#define MAX_NODE_CNT 5 +#define WLS_SUPPORTED(pno_state) (pno_state->wls_supported == TRUE) +#define TIME_DIFF(timestamp1, timestamp2) (abs((uint32)(timestamp1/1000) \ + - (uint32)(timestamp2/1000))) + +#define ENTRY_OVERHEAD strlen("bssid=\nssid=\nfreq=\nlevel=\nage=\ndist=\ndistSd=\n====") +#define TIME_MIN_DIFF 5 +static inline bool +is_dfs(uint16 channel) +{ + if (channel >= 52 && channel <= 64) /* class 2 */ + return TRUE; + else if (channel >= 100 && channel <= 140) /* class 4 */ + return TRUE; + else + return FALSE; +} +int +dhd_pno_clean(dhd_pub_t *dhd) +{ + int pfn = 0; + int err; + dhd_pno_status_info_t *_pno_state; + NULL_CHECK(dhd, "dhd is NULL", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + _pno_state = PNO_GET_PNOSTATE(dhd); + DHD_PNO(("%s enter\n", __FUNCTION__)); + /* Disable PNO */ + err = dhd_iovar(dhd, 0, "pfn", (char *)&pfn, sizeof(pfn), 1); + if (err < 0) { + DHD_ERROR(("%s : failed to execute pfn(error : %d)\n", + __FUNCTION__, err)); + goto exit; + } + _pno_state->pno_status = DHD_PNO_DISABLED; + err = dhd_iovar(dhd, 0, "pfnclear", NULL, 0, 1); + if (err < 0) { + DHD_ERROR(("%s : failed to execute pfnclear(error : %d)\n", + __FUNCTION__, err)); + } +exit: + return err; +} + +static int +_dhd_pno_suspend(dhd_pub_t *dhd) +{ + int err; + int suspend = 1; + dhd_pno_status_info_t *_pno_state; + NULL_CHECK(dhd, "dhd is NULL", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + + DHD_PNO(("%s enter\n", __FUNCTION__)); + _pno_state = PNO_GET_PNOSTATE(dhd); + err = dhd_iovar(dhd, 0, "pfn_suspend", (char *)&suspend, sizeof(suspend), 1); + if (err < 0) { + DHD_ERROR(("%s : failed to suspend pfn(error :%d)\n", __FUNCTION__, err)); + goto exit; + + } + _pno_state->pno_status = DHD_PNO_SUSPEND; +exit: + return err; +} +static int +_dhd_pno_enable(dhd_pub_t *dhd, int enable) +{ + int err = BCME_OK; + dhd_pno_status_info_t *_pno_state; + NULL_CHECK(dhd, "dhd is NULL", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + _pno_state = PNO_GET_PNOSTATE(dhd); + DHD_PNO(("%s enter\n", __FUNCTION__)); + + if (enable & 0xfffe) { + DHD_ERROR(("%s invalid value\n", __FUNCTION__)); + err = BCME_BADARG; + goto exit; + } + if (!dhd_support_sta_mode(dhd)) { + DHD_ERROR(("PNO is not allowed for non-STA mode")); + err = BCME_BADOPTION; + goto exit; + } + if (enable) { + if ((_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) && + dhd_is_associated(dhd, NULL, NULL)) { + DHD_ERROR(("%s Legacy PNO mode cannot be enabled " + "in assoc mode , ignore it\n", __FUNCTION__)); + err = BCME_BADOPTION; + goto exit; + } + } + /* Enable/Disable PNO */ + err = dhd_iovar(dhd, 0, "pfn", (char *)&enable, sizeof(enable), 1); + if (err < 0) { + DHD_ERROR(("%s : failed to execute pfn_set\n", __FUNCTION__)); + goto exit; + } + _pno_state->pno_status = (enable)? + DHD_PNO_ENABLED : DHD_PNO_DISABLED; + if (!enable) + _pno_state->pno_mode = DHD_PNO_NONE_MODE; + + DHD_PNO(("%s set pno as %s\n", + __FUNCTION__, enable ? "Enable" : "Disable")); +exit: + return err; +} + +static int +_dhd_pno_set(dhd_pub_t *dhd, const dhd_pno_params_t *pno_params, dhd_pno_mode_t mode) +{ + int err = BCME_OK; + wl_pfn_param_t pfn_param; + dhd_pno_params_t *_params; + dhd_pno_status_info_t *_pno_state; + bool combined_scan = FALSE; + DHD_PNO(("%s enter\n", __FUNCTION__)); + + NULL_CHECK(dhd, "dhd is NULL", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + _pno_state = PNO_GET_PNOSTATE(dhd); + + memset(&pfn_param, 0, sizeof(pfn_param)); + + /* set pfn parameters */ + pfn_param.version = htod32(PFN_VERSION); + pfn_param.flags = ((PFN_LIST_ORDER << SORT_CRITERIA_BIT) | + (ENABLE << IMMEDIATE_SCAN_BIT) | (ENABLE << REPORT_SEPERATELY_BIT)); + if (mode == DHD_PNO_LEGACY_MODE) { + /* check and set extra pno params */ + if ((pno_params->params_legacy.pno_repeat != 0) || + (pno_params->params_legacy.pno_freq_expo_max != 0)) { + pfn_param.flags |= htod16(ENABLE << ENABLE_ADAPTSCAN_BIT); + pfn_param.repeat = (uchar) (pno_params->params_legacy.pno_repeat); + pfn_param.exp = (uchar) (pno_params->params_legacy.pno_freq_expo_max); + } + /* set up pno scan fr */ + if (pno_params->params_legacy.scan_fr != 0) + pfn_param.scan_freq = htod32(pno_params->params_legacy.scan_fr); + if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) { + DHD_PNO(("will enable combined scan with BATCHIG SCAN MODE\n")); + mode |= DHD_PNO_BATCH_MODE; + combined_scan = TRUE; + } else if (_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE) { + DHD_PNO(("will enable combined scan with HOTLIST SCAN MODE\n")); + mode |= DHD_PNO_HOTLIST_MODE; + combined_scan = TRUE; + } + } + if (mode & (DHD_PNO_BATCH_MODE | DHD_PNO_HOTLIST_MODE)) { + /* Scan frequency of 30 sec */ + pfn_param.scan_freq = htod32(30); + /* slow adapt scan is off by default */ + pfn_param.slow_freq = htod32(0); + /* RSSI margin of 30 dBm */ + pfn_param.rssi_margin = htod16(30); + /* Network timeout 60 sec */ + pfn_param.lost_network_timeout = htod32(60); + /* best n = 2 by default */ + pfn_param.bestn = DEFAULT_BESTN; + /* mscan m=0 by default, so not record best networks by default */ + pfn_param.mscan = DEFAULT_MSCAN; + /* default repeat = 10 */ + pfn_param.repeat = DEFAULT_REPEAT; + /* by default, maximum scan interval = 2^2 + * scan_freq when adaptive scan is turned on + */ + pfn_param.exp = DEFAULT_EXP; + if (mode == DHD_PNO_BATCH_MODE) { + /* In case of BATCH SCAN */ + if (pno_params->params_batch.bestn) + pfn_param.bestn = pno_params->params_batch.bestn; + if (pno_params->params_batch.scan_fr) + pfn_param.scan_freq = htod32(pno_params->params_batch.scan_fr); + if (pno_params->params_batch.mscan) + pfn_param.mscan = pno_params->params_batch.mscan; + /* enable broadcast scan */ + pfn_param.flags |= (ENABLE << ENABLE_BD_SCAN_BIT); + } else if (mode == DHD_PNO_HOTLIST_MODE) { + /* In case of HOTLIST SCAN */ + if (pno_params->params_hotlist.scan_fr) + pfn_param.scan_freq = htod32(pno_params->params_hotlist.scan_fr); + pfn_param.bestn = 0; + pfn_param.repeat = 0; + /* enable broadcast scan */ + pfn_param.flags |= (ENABLE << ENABLE_BD_SCAN_BIT); + } + if (combined_scan) { + /* Disable Adaptive Scan */ + pfn_param.flags &= ~(htod16(ENABLE << ENABLE_ADAPTSCAN_BIT)); + pfn_param.flags |= (ENABLE << ENABLE_BD_SCAN_BIT); + pfn_param.repeat = 0; + pfn_param.exp = 0; + if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) { + /* In case of Legacy PNO + BATCH SCAN */ + _params = &(_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]); + if (_params->params_batch.bestn) + pfn_param.bestn = _params->params_batch.bestn; + if (_params->params_batch.scan_fr) + pfn_param.scan_freq = htod32(_params->params_batch.scan_fr); + if (_params->params_batch.mscan) + pfn_param.mscan = _params->params_batch.mscan; + } else if (_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE) { + /* In case of Legacy PNO + HOTLIST SCAN */ + _params = &(_pno_state->pno_params_arr[INDEX_OF_HOTLIST_PARAMS]); + if (_params->params_hotlist.scan_fr) + pfn_param.scan_freq = htod32(_params->params_hotlist.scan_fr); + pfn_param.bestn = 0; + pfn_param.repeat = 0; + } + } + } + if (pfn_param.scan_freq < htod32(PNO_SCAN_MIN_FW_SEC) || + pfn_param.scan_freq > htod32(PNO_SCAN_MAX_FW_SEC)) { + DHD_ERROR(("%s pno freq(%d sec) is not valid \n", + __FUNCTION__, PNO_SCAN_MIN_FW_SEC)); + err = BCME_BADARG; + goto exit; + } + if (mode == DHD_PNO_BATCH_MODE) { + int _tmp = pfn_param.bestn; + /* set bestn to calculate the max mscan which firmware supports */ + err = dhd_iovar(dhd, 0, "pfnmem", (char *)&_tmp, sizeof(_tmp), 1); + if (err < 0) { + DHD_ERROR(("%s : failed to set pfnmscan\n", __FUNCTION__)); + goto exit; + } + /* get max mscan which the firmware supports */ + err = dhd_iovar(dhd, 0, "pfnmem", (char *)&_tmp, sizeof(_tmp), 0); + if (err < 0) { + DHD_ERROR(("%s : failed to get pfnmscan\n", __FUNCTION__)); + goto exit; + } + DHD_PNO((" returned mscan : %d, set bestn : %d\n", _tmp, pfn_param.bestn)); + pfn_param.mscan = MIN(pfn_param.mscan, _tmp); + } + err = dhd_iovar(dhd, 0, "pfn_set", (char *)&pfn_param, sizeof(pfn_param), 1); + if (err < 0) { + DHD_ERROR(("%s : failed to execute pfn_set\n", __FUNCTION__)); + goto exit; + } + /* need to return mscan if this is for batch scan instead of err */ + err = (mode == DHD_PNO_BATCH_MODE)? pfn_param.mscan : err; +exit: + return err; +} +static int +_dhd_pno_add_ssid(dhd_pub_t *dhd, wlc_ssid_t* ssids_list, int nssid) +{ + int err = BCME_OK; + int i = 0; + wl_pfn_t pfn_element; + NULL_CHECK(dhd, "dhd is NULL", err); + if (nssid) { + NULL_CHECK(ssids_list, "ssid list is NULL", err); + } + memset(&pfn_element, 0, sizeof(pfn_element)); + { + int j; + for (j = 0; j < nssid; j++) { + DHD_PNO(("%d: scan for %s size = %d\n", j, + ssids_list[j].SSID, ssids_list[j].SSID_len)); + } + } + /* Check for broadcast ssid */ + for (i = 0; i < nssid; i++) { + if (!ssids_list[i].SSID_len) { + DHD_ERROR(("%d: Broadcast SSID is ilegal for PNO setting\n", i)); + err = BCME_ERROR; + goto exit; + } + } + /* set all pfn ssid */ + for (i = 0; i < nssid; i++) { + pfn_element.infra = htod32(DOT11_BSSTYPE_INFRASTRUCTURE); + pfn_element.auth = (DOT11_OPEN_SYSTEM); + pfn_element.wpa_auth = htod32(WPA_AUTH_PFN_ANY); + pfn_element.wsec = htod32(0); + pfn_element.infra = htod32(1); + pfn_element.flags = htod32(ENABLE << WL_PFN_HIDDEN_BIT); + memcpy((char *)pfn_element.ssid.SSID, ssids_list[i].SSID, + ssids_list[i].SSID_len); + pfn_element.ssid.SSID_len = ssids_list[i].SSID_len; + err = dhd_iovar(dhd, 0, "pfn_add", (char *)&pfn_element, + sizeof(pfn_element), 1); + if (err < 0) { + DHD_ERROR(("%s : failed to execute pfn_add\n", __FUNCTION__)); + goto exit; + } + } +exit: + return err; +} +/* qsort compare function */ +static int +_dhd_pno_cmpfunc(const void *a, const void *b) +{ + return (*(uint16*)a - *(uint16*)b); +} +static int +_dhd_pno_chan_merge(uint16 *d_chan_list, int *nchan, + uint16 *chan_list1, int nchan1, uint16 *chan_list2, int nchan2) +{ + int err = BCME_OK; + int i = 0, j = 0, k = 0; + uint16 tmp; + NULL_CHECK(d_chan_list, "d_chan_list is NULL", err); + NULL_CHECK(nchan, "nchan is NULL", err); + NULL_CHECK(chan_list1, "chan_list1 is NULL", err); + NULL_CHECK(chan_list2, "chan_list2 is NULL", err); + /* chan_list1 and chan_list2 should be sorted at first */ + while (i < nchan1 && j < nchan2) { + tmp = chan_list1[i] < chan_list2[j]? + chan_list1[i++] : chan_list2[j++]; + for (; i < nchan1 && chan_list1[i] == tmp; i++); + for (; j < nchan2 && chan_list2[j] == tmp; j++); + d_chan_list[k++] = tmp; + } + + while (i < nchan1) { + tmp = chan_list1[i++]; + for (; i < nchan1 && chan_list1[i] == tmp; i++); + d_chan_list[k++] = tmp; + } + + while (j < nchan2) { + tmp = chan_list2[j++]; + for (; j < nchan2 && chan_list2[j] == tmp; j++); + d_chan_list[k++] = tmp; + + } + *nchan = k; + return err; +} +static int +_dhd_pno_get_channels(dhd_pub_t *dhd, uint16 *d_chan_list, + int *nchan, uint8 band, bool skip_dfs) +{ + int err = BCME_OK; + int i, j; + uint32 chan_buf[WL_NUMCHANNELS + 1]; + wl_uint32_list_t *list; + NULL_CHECK(dhd, "dhd is NULL", err); + if (*nchan) { + NULL_CHECK(d_chan_list, "d_chan_list is NULL", err); + } + list = (wl_uint32_list_t *) (void *)chan_buf; + list->count = htod32(WL_NUMCHANNELS); + err = dhd_wl_ioctl_cmd(dhd, WLC_GET_VALID_CHANNELS, chan_buf, sizeof(chan_buf), FALSE, 0); + if (err < 0) { + DHD_ERROR(("failed to get channel list (err: %d)\n", err)); + goto exit; + } + for (i = 0, j = 0; i < dtoh32(list->count) && i < *nchan; i++) { + if (band == WLC_BAND_2G) { + if (dtoh32(list->element[i]) > CHANNEL_2G_MAX) + continue; + } else if (band == WLC_BAND_5G) { + if (dtoh32(list->element[i]) <= CHANNEL_2G_MAX) + continue; + if (skip_dfs && is_dfs(dtoh32(list->element[i]))) + continue; + + } else { /* All channels */ + if (skip_dfs && is_dfs(dtoh32(list->element[i]))) + continue; + } + d_chan_list[j++] = dtoh32(list->element[i]); + } + *nchan = j; +exit: + return err; +} +static int +_dhd_pno_convert_format(dhd_pub_t *dhd, struct dhd_pno_batch_params *params_batch, + char *buf, int nbufsize) +{ + int err = BCME_OK; + int bytes_written = 0, nreadsize = 0; + int t_delta = 0; + int nleftsize = nbufsize; + uint8 cnt = 0; + char *bp = buf; + char eabuf[ETHER_ADDR_STR_LEN]; +#ifdef PNO_DEBUG + char *_base_bp; + char msg[150]; +#endif + dhd_pno_bestnet_entry_t *iter, *next; + dhd_pno_scan_results_t *siter, *snext; + dhd_pno_best_header_t *phead, *pprev; + NULL_CHECK(params_batch, "params_batch is NULL", err); + if (nbufsize > 0) + NULL_CHECK(buf, "buf is NULL", err); + /* initialize the buffer */ + memset(buf, 0, nbufsize); + DHD_PNO(("%s enter \n", __FUNCTION__)); + /* # of scans */ + if (!params_batch->get_batch.batch_started) { + bp += nreadsize = sprintf(bp, "scancount=%d\n", + params_batch->get_batch.expired_tot_scan_cnt); + nleftsize -= nreadsize; + params_batch->get_batch.batch_started = TRUE; + } + DHD_PNO(("%s scancount %d\n", __FUNCTION__, params_batch->get_batch.expired_tot_scan_cnt)); + /* preestimate scan count until which scan result this report is going to end */ + list_for_each_entry_safe(siter, snext, + ¶ms_batch->get_batch.expired_scan_results_list, list) { + phead = siter->bestnetheader; + while (phead != NULL) { + /* if left_size is less than bestheader total size , stop this */ + if (nleftsize <= + (phead->tot_size + phead->tot_cnt * ENTRY_OVERHEAD)) + goto exit; + /* increase scan count */ + cnt++; + /* # best of each scan */ + DHD_PNO(("\n<loop : %d, apcount %d>\n", cnt - 1, phead->tot_cnt)); + /* attribute of the scan */ + if (phead->reason & PNO_STATUS_ABORT_MASK) { + bp += nreadsize = sprintf(bp, "trunc\n"); + nleftsize -= nreadsize; + } + list_for_each_entry_safe(iter, next, + &phead->entry_list, list) { + t_delta = jiffies_to_msecs(jiffies - iter->recorded_time); +#ifdef PNO_DEBUG + _base_bp = bp; + memset(msg, 0, sizeof(msg)); +#endif + /* BSSID info */ + bp += nreadsize = sprintf(bp, "bssid=%s\n", + bcm_ether_ntoa((const struct ether_addr *)&iter->BSSID, eabuf)); + nleftsize -= nreadsize; + /* SSID */ + bp += nreadsize = sprintf(bp, "ssid=%s\n", iter->SSID); + nleftsize -= nreadsize; + /* channel */ + bp += nreadsize = sprintf(bp, "freq=%d\n", + wf_channel2mhz(iter->channel, + iter->channel <= CH_MAX_2G_CHANNEL? + WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G)); + nleftsize -= nreadsize; + /* RSSI */ + bp += nreadsize = sprintf(bp, "level=%d\n", iter->RSSI); + nleftsize -= nreadsize; + /* add the time consumed in Driver to the timestamp of firmware */ + iter->timestamp += t_delta; + bp += nreadsize = sprintf(bp, "age=%d\n", iter->timestamp); + nleftsize -= nreadsize; + /* RTT0 */ + bp += nreadsize = sprintf(bp, "dist=%d\n", + (iter->rtt0 == 0)? -1 : iter->rtt0); + nleftsize -= nreadsize; + /* RTT1 */ + bp += nreadsize = sprintf(bp, "distSd=%d\n", + (iter->rtt0 == 0)? -1 : iter->rtt1); + nleftsize -= nreadsize; + bp += nreadsize = sprintf(bp, "%s", AP_END_MARKER); + nleftsize -= nreadsize; + list_del(&iter->list); + MFREE(dhd->osh, iter, BESTNET_ENTRY_SIZE); +#ifdef PNO_DEBUG + memcpy(msg, _base_bp, bp - _base_bp); + DHD_PNO(("Entry : \n%s", msg)); +#endif + } + bp += nreadsize = sprintf(bp, "%s", SCAN_END_MARKER); + DHD_PNO(("%s", SCAN_END_MARKER)); + nleftsize -= nreadsize; + pprev = phead; + /* reset the header */ + siter->bestnetheader = phead = phead->next; + MFREE(dhd->osh, pprev, BEST_HEADER_SIZE); + + siter->cnt_header--; + } + if (phead == NULL) { + /* we store all entry in this scan , so it is ok to delete */ + list_del(&siter->list); + MFREE(dhd->osh, siter, SCAN_RESULTS_SIZE); + } + } +exit: + if (cnt < params_batch->get_batch.expired_tot_scan_cnt) { + DHD_ERROR(("Buffer size is small to save all batch entry," + " cnt : %d (remained_scan_cnt): %d\n", + cnt, params_batch->get_batch.expired_tot_scan_cnt - cnt)); + } + params_batch->get_batch.expired_tot_scan_cnt -= cnt; + /* set FALSE only if the link list is empty after returning the data */ + if (list_empty(¶ms_batch->get_batch.expired_scan_results_list)) { + params_batch->get_batch.batch_started = FALSE; + bp += sprintf(bp, "%s", RESULTS_END_MARKER); + DHD_PNO(("%s", RESULTS_END_MARKER)); + DHD_PNO(("%s : Getting the batching data is complete\n", __FUNCTION__)); + } + /* return used memory in buffer */ + bytes_written = (int32)(bp - buf); + return bytes_written; +} +static int +_dhd_pno_clear_all_batch_results(dhd_pub_t *dhd, struct list_head *head, bool only_last) +{ + int err = BCME_OK; + int removed_scan_cnt = 0; + dhd_pno_scan_results_t *siter, *snext; + dhd_pno_best_header_t *phead, *pprev; + dhd_pno_bestnet_entry_t *iter, *next; + NULL_CHECK(dhd, "dhd is NULL", err); + NULL_CHECK(head, "head is NULL", err); + NULL_CHECK(head->next, "head->next is NULL", err); + DHD_PNO(("%s enter\n", __FUNCTION__)); + list_for_each_entry_safe(siter, snext, + head, list) { + if (only_last) { + /* in case that we need to delete only last one */ + if (!list_is_last(&siter->list, head)) { + /* skip if the one is not last */ + continue; + } + } + /* delete all data belong if the one is last */ + phead = siter->bestnetheader; + while (phead != NULL) { + removed_scan_cnt++; + list_for_each_entry_safe(iter, next, + &phead->entry_list, list) { + list_del(&iter->list); + MFREE(dhd->osh, iter, BESTNET_ENTRY_SIZE); + } + pprev = phead; + phead = phead->next; + MFREE(dhd->osh, pprev, BEST_HEADER_SIZE); + } + if (phead == NULL) { + /* it is ok to delete top node */ + list_del(&siter->list); + MFREE(dhd->osh, siter, SCAN_RESULTS_SIZE); + } + } + return removed_scan_cnt; +} + +static int +_dhd_pno_cfg(dhd_pub_t *dhd, uint16 *channel_list, int nchan) +{ + int err = BCME_OK; + int i = 0; + wl_pfn_cfg_t pfncfg_param; + NULL_CHECK(dhd, "dhd is NULL", err); + if (nchan) { + NULL_CHECK(channel_list, "nchan is NULL", err); + } + DHD_PNO(("%s enter : nchan : %d\n", __FUNCTION__, nchan)); + memset(&pfncfg_param, 0, sizeof(wl_pfn_cfg_t)); + /* Setup default values */ + pfncfg_param.reporttype = htod32(WL_PFN_REPORT_ALLNET); + pfncfg_param.channel_num = htod32(0); + + for (i = 0; i < nchan && nchan < WL_NUMCHANNELS; i++) + pfncfg_param.channel_list[i] = channel_list[i]; + + pfncfg_param.channel_num = htod32(nchan); + err = dhd_iovar(dhd, 0, "pfn_cfg", (char *)&pfncfg_param, sizeof(pfncfg_param), 1); + if (err < 0) { + DHD_ERROR(("%s : failed to execute pfn_cfg\n", __FUNCTION__)); + goto exit; + } +exit: + return err; +} +static int +_dhd_pno_reinitialize_prof(dhd_pub_t *dhd, dhd_pno_params_t *params, dhd_pno_mode_t mode) +{ + int err = BCME_OK; + dhd_pno_status_info_t *_pno_state; + NULL_CHECK(dhd, "dhd is NULL\n", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL\n", err); + DHD_PNO(("%s enter\n", __FUNCTION__)); + _pno_state = PNO_GET_PNOSTATE(dhd); + mutex_lock(&_pno_state->pno_mutex); + switch (mode) { + case DHD_PNO_LEGACY_MODE: { + struct dhd_pno_ssid *iter, *next; + if (params->params_legacy.nssid > 0) { + list_for_each_entry_safe(iter, next, + ¶ms->params_legacy.ssid_list, list) { + list_del(&iter->list); + kfree(iter); + } + } + params->params_legacy.scan_fr = 0; + params->params_legacy.pno_freq_expo_max = 0; + params->params_legacy.pno_repeat = 0; + params->params_legacy.nchan = 0; + memset(params->params_legacy.chan_list, 0, + sizeof(params->params_legacy.chan_list)); + break; + } + case DHD_PNO_BATCH_MODE: { + params->params_batch.scan_fr = 0; + params->params_batch.mscan = 0; + params->params_batch.nchan = 0; + params->params_batch.rtt = 0; + params->params_batch.bestn = 0; + params->params_batch.nchan = 0; + params->params_batch.band = WLC_BAND_AUTO; + memset(params->params_batch.chan_list, 0, + sizeof(params->params_batch.chan_list)); + params->params_batch.get_batch.batch_started = FALSE; + params->params_batch.get_batch.buf = NULL; + params->params_batch.get_batch.bufsize = 0; + params->params_batch.get_batch.reason = 0; + _dhd_pno_clear_all_batch_results(dhd, + ¶ms->params_batch.get_batch.scan_results_list, FALSE); + _dhd_pno_clear_all_batch_results(dhd, + ¶ms->params_batch.get_batch.expired_scan_results_list, FALSE); + params->params_batch.get_batch.tot_scan_cnt = 0; + params->params_batch.get_batch.expired_tot_scan_cnt = 0; + params->params_batch.get_batch.top_node_cnt = 0; + INIT_LIST_HEAD(¶ms->params_batch.get_batch.scan_results_list); + INIT_LIST_HEAD(¶ms->params_batch.get_batch.expired_scan_results_list); + break; + } + case DHD_PNO_HOTLIST_MODE: { + struct dhd_pno_bssid *iter, *next; + if (params->params_hotlist.nbssid > 0) { + list_for_each_entry_safe(iter, next, + ¶ms->params_hotlist.bssid_list, list) { + list_del(&iter->list); + kfree(iter); + } + } + params->params_hotlist.scan_fr = 0; + params->params_hotlist.nbssid = 0; + params->params_hotlist.nchan = 0; + params->params_batch.band = WLC_BAND_AUTO; + memset(params->params_hotlist.chan_list, 0, + sizeof(params->params_hotlist.chan_list)); + break; + } + default: + DHD_ERROR(("%s : unknown mode : %d\n", __FUNCTION__, mode)); + break; + } + mutex_unlock(&_pno_state->pno_mutex); + return err; +} +static int +_dhd_pno_add_bssid(dhd_pub_t *dhd, wl_pfn_bssid_t *p_pfn_bssid, int nbssid) +{ + int err = BCME_OK; + NULL_CHECK(dhd, "dhd is NULL", err); + if (nbssid) { + NULL_CHECK(p_pfn_bssid, "bssid list is NULL", err); + } + err = dhd_iovar(dhd, 0, "pfn_add_bssid", (char *)&p_pfn_bssid, + sizeof(wl_pfn_bssid_t) * nbssid, 1); + if (err < 0) { + DHD_ERROR(("%s : failed to execute pfn_cfg\n", __FUNCTION__)); + goto exit; + } +exit: + return err; +} +int +dhd_pno_stop_for_ssid(dhd_pub_t *dhd) +{ + int err = BCME_OK; + uint32 mode = 0; + dhd_pno_status_info_t *_pno_state; + dhd_pno_params_t *_params; + wl_pfn_bssid_t *p_pfn_bssid; + NULL_CHECK(dhd, "dev is NULL", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + _pno_state = PNO_GET_PNOSTATE(dhd); + if (!(_pno_state->pno_mode & DHD_PNO_LEGACY_MODE)) { + DHD_ERROR(("%s : LEGACY PNO MODE is not enabled\n", __FUNCTION__)); + goto exit; + } + DHD_PNO(("%s enter\n", __FUNCTION__)); + _pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE; + /* restart Batch mode if the batch mode is on */ + if (_pno_state->pno_mode & (DHD_PNO_BATCH_MODE | DHD_PNO_HOTLIST_MODE)) { + /* retrieve the batching data from firmware into host */ + dhd_pno_get_for_batch(dhd, NULL, 0, PNO_STATUS_DISABLE); + /* save current pno_mode before calling dhd_pno_clean */ + mode = _pno_state->pno_mode; + dhd_pno_clean(dhd); + /* restore previous pno_mode */ + _pno_state->pno_mode = mode; + if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) { + _params = &(_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]); + /* restart BATCH SCAN */ + err = dhd_pno_set_for_batch(dhd, &_params->params_batch); + if (err < 0) { + _pno_state->pno_mode &= ~DHD_PNO_BATCH_MODE; + DHD_ERROR(("%s : failed to restart batch scan(err: %d)\n", + __FUNCTION__, err)); + goto exit; + } + } else if (_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE) { + /* restart HOTLIST SCAN */ + struct dhd_pno_bssid *iter, *next; + _params = &(_pno_state->pno_params_arr[INDEX_OF_HOTLIST_PARAMS]); + p_pfn_bssid = kzalloc(sizeof(wl_pfn_bssid_t) * + _params->params_hotlist.nbssid, GFP_KERNEL); + if (p_pfn_bssid == NULL) { + DHD_ERROR(("%s : failed to allocate wl_pfn_bssid_t array" + " (count: %d)", + __FUNCTION__, _params->params_hotlist.nbssid)); + err = BCME_ERROR; + _pno_state->pno_mode &= ~DHD_PNO_HOTLIST_MODE; + goto exit; + } + /* convert dhd_pno_bssid to wl_pfn_bssid */ + list_for_each_entry_safe(iter, next, + &_params->params_hotlist.bssid_list, list) { + memcpy(&p_pfn_bssid->macaddr, + &iter->macaddr, ETHER_ADDR_LEN); + p_pfn_bssid->flags = iter->flags; + p_pfn_bssid++; + } + err = dhd_pno_set_for_hotlist(dhd, p_pfn_bssid, &_params->params_hotlist); + if (err < 0) { + _pno_state->pno_mode &= ~DHD_PNO_HOTLIST_MODE; + DHD_ERROR(("%s : failed to restart hotlist scan(err: %d)\n", + __FUNCTION__, err)); + goto exit; + } + } + } else { + err = dhd_pno_clean(dhd); + if (err < 0) { + DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n", + __FUNCTION__, err)); + goto exit; + } + } +exit: + return err; +} + +int +dhd_pno_enable(dhd_pub_t *dhd, int enable) +{ + int err = BCME_OK; + NULL_CHECK(dhd, "dhd is NULL", err); + DHD_PNO(("%s enter\n", __FUNCTION__)); + return (_dhd_pno_enable(dhd, enable)); +} + +int +dhd_pno_set_for_ssid(dhd_pub_t *dhd, wlc_ssid_t* ssid_list, int nssid, + uint16 scan_fr, int pno_repeat, int pno_freq_expo_max, uint16 *channel_list, int nchan) +{ + struct dhd_pno_ssid *_pno_ssid; + dhd_pno_params_t *_params; + dhd_pno_params_t *_params2; + dhd_pno_status_info_t *_pno_state; + uint16 _chan_list[WL_NUMCHANNELS]; + int32 tot_nchan = 0; + int err = BCME_OK; + int i; + int mode = 0; + NULL_CHECK(dhd, "dhd is NULL", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + _pno_state = PNO_GET_PNOSTATE(dhd); + + if (!dhd_support_sta_mode(dhd)) { + err = BCME_BADOPTION; + goto exit; + } + DHD_PNO(("%s enter : scan_fr :%d, pno_repeat :%d," + "pno_freq_expo_max: %d, nchan :%d\n", __FUNCTION__, + scan_fr, pno_repeat, pno_freq_expo_max, nchan)); + + _params = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]); + if (!(_pno_state->pno_mode & DHD_PNO_LEGACY_MODE)) { + _pno_state->pno_mode |= DHD_PNO_LEGACY_MODE; + err = _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_LEGACY_MODE); + if (err < 0) { + DHD_ERROR(("%s : failed to reinitialize profile (err %d)\n", + __FUNCTION__, err)); + goto exit; + } + } + memset(_chan_list, 0, sizeof(_chan_list)); + tot_nchan = nchan; + if (tot_nchan > 0 && channel_list) { + for (i = 0; i < nchan; i++) + _params->params_legacy.chan_list[i] = _chan_list[i] = channel_list[i]; + } + if (_pno_state->pno_mode & (DHD_PNO_BATCH_MODE | DHD_PNO_HOTLIST_MODE)) { + DHD_PNO(("BATCH SCAN is on progress in firmware\n")); + /* retrieve the batching data from firmware into host */ + dhd_pno_get_for_batch(dhd, NULL, 0, PNO_STATUS_DISABLE); + /* store current pno_mode before disabling pno */ + mode = _pno_state->pno_mode; + err = _dhd_pno_enable(dhd, PNO_OFF); + if (err < 0) { + DHD_ERROR(("%s : failed to disable PNO\n", __FUNCTION__)); + goto exit; + } + /* restore the previous mode */ + _pno_state->pno_mode = mode; + /* use superset of channel list between two mode */ + if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) { + _params2 = &(_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]); + if (_params2->params_batch.nchan > 0 && nchan > 0) { + err = _dhd_pno_chan_merge(_chan_list, &tot_nchan, + &_params2->params_batch.chan_list[0], + _params2->params_batch.nchan, + &channel_list[0], nchan); + if (err < 0) { + DHD_ERROR(("%s : failed to merge channel list" + " between legacy and batch\n", + __FUNCTION__)); + goto exit; + } + } else { + DHD_PNO(("superset channel will use" + " all channels in firmware\n")); + } + } else if (_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE) { + _params2 = &(_pno_state->pno_params_arr[INDEX_OF_HOTLIST_PARAMS]); + if (_params2->params_hotlist.nchan > 0 && nchan > 0) { + err = _dhd_pno_chan_merge(_chan_list, &tot_nchan, + &_params2->params_hotlist.chan_list[0], + _params2->params_hotlist.nchan, + &channel_list[0], nchan); + if (err < 0) { + DHD_ERROR(("%s : failed to merge channel list" + " between legacy and hotlist\n", + __FUNCTION__)); + goto exit; + } + } + } + } + _params->params_legacy.scan_fr = scan_fr; + _params->params_legacy.pno_repeat = pno_repeat; + _params->params_legacy.pno_freq_expo_max = pno_freq_expo_max; + _params->params_legacy.nchan = nchan; + _params->params_legacy.nssid = nssid; + INIT_LIST_HEAD(&_params->params_legacy.ssid_list); + if ((err = _dhd_pno_set(dhd, _params, DHD_PNO_LEGACY_MODE)) < 0) { + DHD_ERROR(("failed to set call pno_set (err %d) in firmware\n", err)); + goto exit; + } + if ((err = _dhd_pno_add_ssid(dhd, ssid_list, nssid)) < 0) { + DHD_ERROR(("failed to add ssid list (err %d) in firmware\n", err)); + goto exit; + } + for (i = 0; i < nssid; i++) { + _pno_ssid = kzalloc(sizeof(struct dhd_pno_ssid), GFP_KERNEL); + if (_pno_ssid == NULL) { + DHD_ERROR(("%s : failed to allocate struct dhd_pno_ssid\n", + __FUNCTION__)); + goto exit; + } + _pno_ssid->SSID_len = ssid_list[i].SSID_len; + memcpy(_pno_ssid->SSID, ssid_list[i].SSID, _pno_ssid->SSID_len); + list_add_tail(&_pno_ssid->list, &_params->params_legacy.ssid_list); + + } + if (tot_nchan > 0) { + if ((err = _dhd_pno_cfg(dhd, _chan_list, tot_nchan)) < 0) { + DHD_ERROR(("%s : failed to set call pno_cfg (err %d) in firmware\n", + __FUNCTION__, err)); + goto exit; + } + } + if (_pno_state->pno_status == DHD_PNO_DISABLED) { + if ((err = _dhd_pno_enable(dhd, PNO_ON)) < 0) + DHD_ERROR(("%s : failed to enable PNO\n", __FUNCTION__)); + } +exit: + /* clear mode in case of error */ + if (err < 0) + _pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE; + return err; +} +int +dhd_pno_set_for_batch(dhd_pub_t *dhd, struct dhd_pno_batch_params *batch_params) +{ + int err = BCME_OK; + uint16 _chan_list[WL_NUMCHANNELS]; + int rem_nchan = 0, tot_nchan = 0; + int mode = 0, mscan = 0; + int i = 0; + dhd_pno_params_t *_params; + dhd_pno_params_t *_params2; + dhd_pno_status_info_t *_pno_state; + wlc_ssid_t *p_ssid_list = NULL; + NULL_CHECK(dhd, "dhd is NULL", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + NULL_CHECK(batch_params, "batch_params is NULL", err); + _pno_state = PNO_GET_PNOSTATE(dhd); + DHD_PNO(("%s enter\n", __FUNCTION__)); + if (!dhd_support_sta_mode(dhd)) { + err = BCME_BADOPTION; + goto exit; + } + if (!WLS_SUPPORTED(_pno_state)) { + DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__)); + err = BCME_UNSUPPORTED; + goto exit; + } + _params = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]; + if (!(_pno_state->pno_mode & DHD_PNO_BATCH_MODE)) { + _pno_state->pno_mode |= DHD_PNO_BATCH_MODE; + err = _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_BATCH_MODE); + if (err < 0) { + DHD_ERROR(("%s : failed to call _dhd_pno_reinitialize_prof\n", + __FUNCTION__)); + goto exit; + } + } + _params->params_batch.scan_fr = batch_params->scan_fr; + _params->params_batch.bestn = batch_params->bestn; + _params->params_batch.mscan = (batch_params->mscan)? + batch_params->mscan : DEFAULT_BATCH_MSCAN; + _params->params_batch.nchan = batch_params->nchan; + memcpy(_params->params_batch.chan_list, batch_params->chan_list, + sizeof(_params->params_batch.chan_list)); + + memset(_chan_list, 0, sizeof(_chan_list)); + + rem_nchan = ARRAYSIZE(batch_params->chan_list) - batch_params->nchan; + if (batch_params->band == WLC_BAND_2G || batch_params->band == WLC_BAND_5G) { + /* get a valid channel list based on band B or A */ + err = _dhd_pno_get_channels(dhd, + &_params->params_batch.chan_list[batch_params->nchan], + &rem_nchan, batch_params->band, FALSE); + if (err < 0) { + DHD_ERROR(("%s: failed to get valid channel list(band : %d)\n", + __FUNCTION__, batch_params->band)); + goto exit; + } + /* now we need to update nchan because rem_chan has valid channel count */ + _params->params_batch.nchan += rem_nchan; + /* need to sort channel list */ + sort(_params->params_batch.chan_list, _params->params_batch.nchan, + sizeof(_params->params_batch.chan_list[0]), _dhd_pno_cmpfunc, NULL); + } +#ifdef PNO_DEBUG +{ + DHD_PNO(("Channel list : ")); + for (i = 0; i < _params->params_batch.nchan; i++) { + DHD_PNO(("%d ", _params->params_batch.chan_list[i])); + } + DHD_PNO(("\n")); +} +#endif + if (_params->params_batch.nchan) { + /* copy the channel list into local array */ + memcpy(_chan_list, _params->params_batch.chan_list, sizeof(_chan_list)); + tot_nchan = _params->params_batch.nchan; + } + if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { + struct dhd_pno_ssid *iter, *next; + DHD_PNO(("PNO SSID is on progress in firmware\n")); + /* store current pno_mode before disabling pno */ + mode = _pno_state->pno_mode; + err = _dhd_pno_enable(dhd, PNO_OFF); + if (err < 0) { + DHD_ERROR(("%s : failed to disable PNO\n", __FUNCTION__)); + goto exit; + } + /* restore the previous mode */ + _pno_state->pno_mode = mode; + /* Use the superset for channelist between two mode */ + _params2 = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]); + if (_params2->params_legacy.nchan > 0 && _params->params_batch.nchan > 0) { + err = _dhd_pno_chan_merge(_chan_list, &tot_nchan, + &_params2->params_legacy.chan_list[0], + _params2->params_legacy.nchan, + &_params->params_batch.chan_list[0], _params->params_batch.nchan); + if (err < 0) { + DHD_ERROR(("%s : failed to merge channel list" + " between legacy and batch\n", + __FUNCTION__)); + goto exit; + } + } else { + DHD_PNO(("superset channel will use all channels in firmware\n")); + } + p_ssid_list = kzalloc(sizeof(wlc_ssid_t) * + _params2->params_legacy.nssid, GFP_KERNEL); + if (p_ssid_list == NULL) { + DHD_ERROR(("%s : failed to allocate wlc_ssid_t array (count: %d)", + __FUNCTION__, _params2->params_legacy.nssid)); + err = BCME_ERROR; + _pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE; + goto exit; + } + i = 0; + /* convert dhd_pno_ssid to dhd_pno_ssid */ + list_for_each_entry_safe(iter, next, &_params2->params_legacy.ssid_list, list) { + p_ssid_list[i].SSID_len = iter->SSID_len; + memcpy(p_ssid_list->SSID, iter->SSID, p_ssid_list[i].SSID_len); + i++; + } + if ((err = _dhd_pno_add_ssid(dhd, p_ssid_list, + _params2->params_legacy.nssid)) < 0) { + DHD_ERROR(("failed to add ssid list (err %d) in firmware\n", err)); + goto exit; + } + } + if ((err = _dhd_pno_set(dhd, _params, DHD_PNO_BATCH_MODE)) < 0) { + DHD_ERROR(("%s : failed to set call pno_set (err %d) in firmware\n", + __FUNCTION__, err)); + goto exit; + } else { + /* we need to return mscan */ + mscan = err; + } + if (tot_nchan > 0) { + if ((err = _dhd_pno_cfg(dhd, _chan_list, tot_nchan)) < 0) { + DHD_ERROR(("%s : failed to set call pno_cfg (err %d) in firmware\n", + __FUNCTION__, err)); + goto exit; + } + } + if (_pno_state->pno_status == DHD_PNO_DISABLED) { + if ((err = _dhd_pno_enable(dhd, PNO_ON)) < 0) + DHD_ERROR(("%s : failed to enable PNO\n", __FUNCTION__)); + } +exit: + /* clear mode in case of error */ + if (err < 0) + _pno_state->pno_mode &= ~DHD_PNO_BATCH_MODE; + else { + /* return #max scan firmware can do */ + err = mscan; + } + if (p_ssid_list) + kfree(p_ssid_list); + return err; +} + +static int +_dhd_pno_get_for_batch(dhd_pub_t *dhd, char *buf, int bufsize, int reason) +{ + int err = BCME_OK; + int i, j; + uint32 timestamp = 0; + dhd_pno_params_t *_params = NULL; + dhd_pno_status_info_t *_pno_state = NULL; + wl_pfn_lscanresults_t *plbestnet = NULL; + wl_pfn_lnet_info_t *plnetinfo; + dhd_pno_bestnet_entry_t *pbestnet_entry; + dhd_pno_best_header_t *pbestnetheader = NULL; + dhd_pno_scan_results_t *pscan_results = NULL, *siter, *snext; + bool allocate_header = FALSE; + NULL_CHECK(dhd, "dhd is NULL", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + if (!dhd_support_sta_mode(dhd)) { + err = BCME_BADOPTION; + goto exit; + } + DHD_PNO(("%s enter\n", __FUNCTION__)); + _pno_state = PNO_GET_PNOSTATE(dhd); + + if (!WLS_SUPPORTED(_pno_state)) { + DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__)); + err = BCME_UNSUPPORTED; + goto exit; + } + if (!(_pno_state->pno_mode & DHD_PNO_BATCH_MODE)) { + DHD_ERROR(("%s: Batching SCAN mode is not enabled\n", __FUNCTION__)); + goto exit; + } + mutex_lock(&_pno_state->pno_mutex); + _params = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]; + if (buf && bufsize) { + if (!list_empty(&_params->params_batch.get_batch.expired_scan_results_list)) { + /* need to check whether we have cashed data or not */ + DHD_PNO(("%s: have cashed batching data in Driver\n", + __FUNCTION__)); + /* convert to results format */ + goto convert_format; + } else { + /* this is a first try to get batching results */ + if (!list_empty(&_params->params_batch.get_batch.scan_results_list)) { + /* move the scan_results_list to expired_scan_results_lists */ + list_for_each_entry_safe(siter, snext, + &_params->params_batch.get_batch.scan_results_list, list) { + list_move_tail(&siter->list, + &_params->params_batch.get_batch.expired_scan_results_list); + } + _params->params_batch.get_batch.top_node_cnt = 0; + _params->params_batch.get_batch.expired_tot_scan_cnt = + _params->params_batch.get_batch.tot_scan_cnt; + _params->params_batch.get_batch.tot_scan_cnt = 0; + goto convert_format; + } + } + } + /* create dhd_pno_scan_results_t whenever we got event WLC_E_PFN_BEST_BATCHING */ + pscan_results = (dhd_pno_scan_results_t *)MALLOC(dhd->osh, SCAN_RESULTS_SIZE); + if (pscan_results == NULL) { + err = BCME_NOMEM; + DHD_ERROR(("failed to allocate dhd_pno_scan_results_t\n")); + goto exit; + } + pscan_results->bestnetheader = NULL; + pscan_results->cnt_header = 0; + /* add the element into list unless total node cnt is less than MAX_NODE_ CNT */ + if (_params->params_batch.get_batch.top_node_cnt < MAX_NODE_CNT) { + list_add(&pscan_results->list, &_params->params_batch.get_batch.scan_results_list); + _params->params_batch.get_batch.top_node_cnt++; + } else { + int _removed_scan_cnt; + /* remove oldest one and add new one */ + DHD_PNO(("%s : Remove oldest node and add new one\n", __FUNCTION__)); + _removed_scan_cnt = _dhd_pno_clear_all_batch_results(dhd, + &_params->params_batch.get_batch.scan_results_list, TRUE); + _params->params_batch.get_batch.tot_scan_cnt -= _removed_scan_cnt; + list_add(&pscan_results->list, &_params->params_batch.get_batch.scan_results_list); + + } + plbestnet = (wl_pfn_lscanresults_t *)MALLOC(dhd->osh, PNO_BESTNET_LEN); + NULL_CHECK(plbestnet, "failed to allocate buffer for bestnet", err); + DHD_PNO(("%s enter\n", __FUNCTION__)); + memset(plbestnet, 0, PNO_BESTNET_LEN); + while (plbestnet->status != PFN_COMPLETE) { + memset(plbestnet, 0, PNO_BESTNET_LEN); + err = dhd_iovar(dhd, 0, "pfnlbest", (char *)plbestnet, PNO_BESTNET_LEN, 0); + if (err < 0) { + if (err == BCME_EPERM) { + DHD_ERROR(("we cannot get the batching data " + "during scanning in firmware, try again\n,")); + msleep(500); + continue; + } else { + DHD_ERROR(("%s : failed to execute pfnlbest (err :%d)\n", + __FUNCTION__, err)); + goto exit; + } + } + DHD_PNO(("ver %d, status : %d, count %d\n", plbestnet->version, + plbestnet->status, plbestnet->count)); + if (plbestnet->version != PFN_SCANRESULT_VERSION) { + err = BCME_VERSION; + DHD_ERROR(("bestnet version(%d) is mismatch with Driver version(%d)\n", + plbestnet->version, PFN_SCANRESULT_VERSION)); + goto exit; + } + plnetinfo = plbestnet->netinfo; + for (i = 0; i < plbestnet->count; i++) { + pbestnet_entry = (dhd_pno_bestnet_entry_t *) + MALLOC(dhd->osh, BESTNET_ENTRY_SIZE); + if (pbestnet_entry == NULL) { + err = BCME_NOMEM; + DHD_ERROR(("failed to allocate dhd_pno_bestnet_entry\n")); + goto exit; + } + memset(pbestnet_entry, 0, BESTNET_ENTRY_SIZE); + pbestnet_entry->recorded_time = jiffies; /* record the current time */ + /* create header for the first entry */ + allocate_header = (i == 0)? TRUE : FALSE; + /* check whether the new generation is started or not */ + if (timestamp && (TIME_DIFF(timestamp, plnetinfo->timestamp) + > TIME_MIN_DIFF)) + allocate_header = TRUE; + timestamp = plnetinfo->timestamp; + if (allocate_header) { + pbestnetheader = (dhd_pno_best_header_t *) + MALLOC(dhd->osh, BEST_HEADER_SIZE); + if (pbestnetheader == NULL) { + err = BCME_NOMEM; + if (pbestnet_entry) + MFREE(dhd->osh, pbestnet_entry, + BESTNET_ENTRY_SIZE); + DHD_ERROR(("failed to allocate dhd_pno_bestnet_entry\n")); + goto exit; + } + /* increase total cnt of bestnet header */ + pscan_results->cnt_header++; + /* need to record the reason to call dhd_pno_get_for_bach */ + if (reason) + pbestnetheader->reason = (ENABLE << reason); + memset(pbestnetheader, 0, BEST_HEADER_SIZE); + /* initialize the head of linked list */ + INIT_LIST_HEAD(&(pbestnetheader->entry_list)); + /* link the pbestnet heaer into existed list */ + if (pscan_results->bestnetheader == NULL) + /* In case of header */ + pscan_results->bestnetheader = pbestnetheader; + else { + dhd_pno_best_header_t *head = pscan_results->bestnetheader; + pscan_results->bestnetheader = pbestnetheader; + pbestnetheader->next = head; + } + } + /* fills the best network info */ + pbestnet_entry->channel = plnetinfo->pfnsubnet.channel; + pbestnet_entry->RSSI = plnetinfo->RSSI; + if (plnetinfo->flags & PFN_PARTIAL_SCAN_MASK) { + /* if RSSI is positive value, we assume that + * this scan is aborted by other scan + */ + DHD_PNO(("This scan is aborted\n")); + pbestnetheader->reason = (ENABLE << PNO_STATUS_ABORT); + } + pbestnet_entry->rtt0 = plnetinfo->rtt0; + pbestnet_entry->rtt1 = plnetinfo->rtt1; + pbestnet_entry->timestamp = plnetinfo->timestamp; + pbestnet_entry->SSID_len = plnetinfo->pfnsubnet.SSID_len; + memcpy(pbestnet_entry->SSID, plnetinfo->pfnsubnet.SSID, + pbestnet_entry->SSID_len); + memcpy(&pbestnet_entry->BSSID, &plnetinfo->pfnsubnet.BSSID, ETHER_ADDR_LEN); + /* add the element into list */ + list_add_tail(&pbestnet_entry->list, &pbestnetheader->entry_list); + /* increase best entry count */ + pbestnetheader->tot_cnt++; + pbestnetheader->tot_size += BESTNET_ENTRY_SIZE; + DHD_PNO(("Header %d\n", pscan_results->cnt_header - 1)); + DHD_PNO(("\tSSID : ")); + for (j = 0; j < plnetinfo->pfnsubnet.SSID_len; j++) + DHD_PNO(("%c", plnetinfo->pfnsubnet.SSID[j])); + DHD_PNO(("\n")); + DHD_PNO(("\tBSSID: %02x:%02x:%02x:%02x:%02x:%02x\n", + plnetinfo->pfnsubnet.BSSID.octet[0], + plnetinfo->pfnsubnet.BSSID.octet[1], + plnetinfo->pfnsubnet.BSSID.octet[2], + plnetinfo->pfnsubnet.BSSID.octet[3], + plnetinfo->pfnsubnet.BSSID.octet[4], + plnetinfo->pfnsubnet.BSSID.octet[5])); + DHD_PNO(("\tchannel: %d, RSSI: %d, timestamp: %d ms\n", + plnetinfo->pfnsubnet.channel, + plnetinfo->RSSI, plnetinfo->timestamp)); + DHD_PNO(("\tRTT0 : %d, RTT1: %d\n", plnetinfo->rtt0, plnetinfo->rtt1)); + plnetinfo++; + } + } + if (pscan_results->cnt_header == 0) { + /* In case that we didn't get any data from the firmware + * Remove the current scan_result list from get_bach.scan_results_list. + */ + DHD_PNO(("NO BATCH DATA from Firmware, Delete current SCAN RESULT LIST\n")); + list_del(&pscan_results->list); + MFREE(dhd->osh, pscan_results, SCAN_RESULTS_SIZE); + _params->params_batch.get_batch.top_node_cnt--; + } + /* increase total scan count using current scan count */ + _params->params_batch.get_batch.tot_scan_cnt += pscan_results->cnt_header; + + if (buf && bufsize) { + /* This is a first try to get batching results */ + if (!list_empty(&_params->params_batch.get_batch.scan_results_list)) { + /* move the scan_results_list to expired_scan_results_lists */ + list_for_each_entry_safe(siter, snext, + &_params->params_batch.get_batch.scan_results_list, list) { + list_move_tail(&siter->list, + &_params->params_batch.get_batch.expired_scan_results_list); + } + /* reset gloval values after moving to expired list */ + _params->params_batch.get_batch.top_node_cnt = 0; + _params->params_batch.get_batch.expired_tot_scan_cnt = + _params->params_batch.get_batch.tot_scan_cnt; + _params->params_batch.get_batch.tot_scan_cnt = 0; + } +convert_format: + err = _dhd_pno_convert_format(dhd, &_params->params_batch, buf, bufsize); + if (err < 0) { + DHD_ERROR(("failed to convert the data into upper layer format\n")); + goto exit; + } + } +exit: + if (plbestnet) + MFREE(dhd->osh, plbestnet, PNO_BESTNET_LEN); + if (_params) { + _params->params_batch.get_batch.buf = NULL; + _params->params_batch.get_batch.bufsize = 0; + _params->params_batch.get_batch.bytes_written = err; + } + mutex_unlock(&_pno_state->pno_mutex); + if (waitqueue_active(&_pno_state->get_batch_done.wait)) + complete(&_pno_state->get_batch_done); + return err; +} +static void +_dhd_pno_get_batch_handler(struct work_struct *work) +{ + dhd_pno_status_info_t *_pno_state; + dhd_pub_t *dhd; + struct dhd_pno_batch_params *params_batch; + DHD_PNO(("%s enter\n", __FUNCTION__)); + _pno_state = container_of(work, struct dhd_pno_status_info, work); + dhd = _pno_state->dhd; + if (dhd == NULL) { + DHD_ERROR(("%s : dhd is NULL\n", __FUNCTION__)); + return; + } + params_batch = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS].params_batch; + _dhd_pno_get_for_batch(dhd, params_batch->get_batch.buf, + params_batch->get_batch.bufsize, params_batch->get_batch.reason); + +} + +int +dhd_pno_get_for_batch(dhd_pub_t *dhd, char *buf, int bufsize, int reason) +{ + int err = BCME_OK; + char *pbuf = buf; + dhd_pno_status_info_t *_pno_state; + struct dhd_pno_batch_params *params_batch; + NULL_CHECK(dhd, "dhd is NULL", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + if (!dhd_support_sta_mode(dhd)) { + err = BCME_BADOPTION; + goto exit; + } + DHD_PNO(("%s enter\n", __FUNCTION__)); + _pno_state = PNO_GET_PNOSTATE(dhd); + + if (!WLS_SUPPORTED(_pno_state)) { + DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__)); + err = BCME_UNSUPPORTED; + goto exit; + } + params_batch = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS].params_batch; + if (!(_pno_state->pno_mode & DHD_PNO_BATCH_MODE)) { + DHD_ERROR(("%s: Batching SCAN mode is not enabled\n", __FUNCTION__)); + memset(pbuf, 0, bufsize); + pbuf += sprintf(pbuf, "scancount=%d\n", 0); + sprintf(pbuf, "%s", RESULTS_END_MARKER); + err = strlen(buf); + goto exit; + } + params_batch->get_batch.buf = buf; + params_batch->get_batch.bufsize = bufsize; + params_batch->get_batch.reason = reason; + params_batch->get_batch.bytes_written = 0; + schedule_work(&_pno_state->work); + wait_for_completion(&_pno_state->get_batch_done); + err = params_batch->get_batch.bytes_written; +exit: + return err; +} + +int +dhd_pno_stop_for_batch(dhd_pub_t *dhd) +{ + int err = BCME_OK; + int mode = 0; + int i = 0; + dhd_pno_status_info_t *_pno_state; + dhd_pno_params_t *_params; + wl_pfn_bssid_t *p_pfn_bssid; + wlc_ssid_t *p_ssid_list = NULL; + NULL_CHECK(dhd, "dhd is NULL", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + _pno_state = PNO_GET_PNOSTATE(dhd); + DHD_PNO(("%s enter\n", __FUNCTION__)); + if (!dhd_support_sta_mode(dhd)) { + err = BCME_BADOPTION; + goto exit; + } + if (!WLS_SUPPORTED(_pno_state)) { + DHD_ERROR(("%s : wifi location service is not supported\n", + __FUNCTION__)); + err = BCME_UNSUPPORTED; + goto exit; + } + if (!(_pno_state->pno_mode & DHD_PNO_BATCH_MODE)) { + DHD_ERROR(("%s : PNO BATCH MODE is not enabled\n", __FUNCTION__)); + goto exit; + } + _pno_state->pno_mode &= ~DHD_PNO_BATCH_MODE; + if (_pno_state->pno_mode & (DHD_PNO_LEGACY_MODE | DHD_PNO_HOTLIST_MODE)) { + mode = _pno_state->pno_mode; + dhd_pno_clean(dhd); + _pno_state->pno_mode = mode; + /* restart Legacy PNO if the Legacy PNO is on */ + if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { + struct dhd_pno_legacy_params *_params_legacy; + struct dhd_pno_ssid *iter, *next; + _params_legacy = + &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS].params_legacy); + p_ssid_list = kzalloc(sizeof(wlc_ssid_t) * + _params_legacy->nssid, GFP_KERNEL); + if (p_ssid_list == NULL) { + DHD_ERROR(("%s : failed to allocate wlc_ssid_t array (count: %d)", + __FUNCTION__, _params_legacy->nssid)); + err = BCME_ERROR; + _pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE; + goto exit; + } + i = 0; + /* convert dhd_pno_ssid to dhd_pno_ssid */ + list_for_each_entry_safe(iter, next, &_params_legacy->ssid_list, list) { + p_ssid_list[i].SSID_len = iter->SSID_len; + memcpy(p_ssid_list[i].SSID, iter->SSID, p_ssid_list[i].SSID_len); + i++; + } + err = dhd_pno_set_for_ssid(dhd, p_ssid_list, _params_legacy->nssid, + _params_legacy->scan_fr, _params_legacy->pno_repeat, + _params_legacy->pno_freq_expo_max, _params_legacy->chan_list, + _params_legacy->nchan); + if (err < 0) { + _pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE; + DHD_ERROR(("%s : failed to restart legacy PNO scan(err: %d)\n", + __FUNCTION__, err)); + goto exit; + } + } else if (_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE) { + struct dhd_pno_bssid *iter, *next; + _params = &(_pno_state->pno_params_arr[INDEX_OF_HOTLIST_PARAMS]); + p_pfn_bssid = kzalloc(sizeof(wl_pfn_bssid_t) * + _params->params_hotlist.nbssid, GFP_KERNEL); + if (p_pfn_bssid == NULL) { + DHD_ERROR(("%s : failed to allocate wl_pfn_bssid_t array" + " (count: %d)", + __FUNCTION__, _params->params_hotlist.nbssid)); + err = BCME_ERROR; + _pno_state->pno_mode &= ~DHD_PNO_HOTLIST_MODE; + goto exit; + } + i = 0; + /* convert dhd_pno_bssid to wl_pfn_bssid */ + list_for_each_entry_safe(iter, next, + &_params->params_hotlist.bssid_list, list) { + memcpy(&p_pfn_bssid[i].macaddr, &iter->macaddr, ETHER_ADDR_LEN); + p_pfn_bssid[i].flags = iter->flags; + i++; + } + err = dhd_pno_set_for_hotlist(dhd, p_pfn_bssid, &_params->params_hotlist); + if (err < 0) { + _pno_state->pno_mode &= ~DHD_PNO_HOTLIST_MODE; + DHD_ERROR(("%s : failed to restart hotlist scan(err: %d)\n", + __FUNCTION__, err)); + goto exit; + } + } + } else { + err = dhd_pno_clean(dhd); + if (err < 0) { + DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n", + __FUNCTION__, err)); + goto exit; + } + } +exit: + _params = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]; + _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_BATCH_MODE); + if (p_ssid_list) + kfree(p_ssid_list); + return err; +} + +int +dhd_pno_set_for_hotlist(dhd_pub_t *dhd, wl_pfn_bssid_t *p_pfn_bssid, + struct dhd_pno_hotlist_params *hotlist_params) +{ + int err = BCME_OK; + int i; + uint16 _chan_list[WL_NUMCHANNELS]; + int rem_nchan = 0; + int tot_nchan = 0; + int mode = 0; + dhd_pno_params_t *_params; + dhd_pno_params_t *_params2; + struct dhd_pno_bssid *_pno_bssid; + dhd_pno_status_info_t *_pno_state; + NULL_CHECK(dhd, "dhd is NULL", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + NULL_CHECK(hotlist_params, "hotlist_params is NULL", err); + NULL_CHECK(p_pfn_bssid, "p_pfn_bssid is NULL", err); + _pno_state = PNO_GET_PNOSTATE(dhd); + DHD_PNO(("%s enter\n", __FUNCTION__)); + + if (!dhd_support_sta_mode(dhd)) { + err = BCME_BADOPTION; + goto exit; + } + if (!WLS_SUPPORTED(_pno_state)) { + DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__)); + err = BCME_UNSUPPORTED; + goto exit; + } + _params = &_pno_state->pno_params_arr[INDEX_OF_HOTLIST_PARAMS]; + if (!(_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE)) { + _pno_state->pno_mode |= DHD_PNO_HOTLIST_MODE; + err = _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_HOTLIST_MODE); + if (err < 0) { + DHD_ERROR(("%s : failed to call _dhd_pno_reinitialize_prof\n", + __FUNCTION__)); + goto exit; + } + } + _params->params_batch.nchan = hotlist_params->nchan; + _params->params_batch.scan_fr = hotlist_params->scan_fr; + if (hotlist_params->nchan) + memcpy(_params->params_hotlist.chan_list, hotlist_params->chan_list, + sizeof(_params->params_hotlist.chan_list)); + memset(_chan_list, 0, sizeof(_chan_list)); + + rem_nchan = ARRAYSIZE(hotlist_params->chan_list) - hotlist_params->nchan; + if (hotlist_params->band == WLC_BAND_2G || hotlist_params->band == WLC_BAND_5G) { + /* get a valid channel list based on band B or A */ + err = _dhd_pno_get_channels(dhd, + &_params->params_hotlist.chan_list[hotlist_params->nchan], + &rem_nchan, hotlist_params->band, FALSE); + if (err < 0) { + DHD_ERROR(("%s: failed to get valid channel list(band : %d)\n", + __FUNCTION__, hotlist_params->band)); + goto exit; + } + /* now we need to update nchan because rem_chan has valid channel count */ + _params->params_hotlist.nchan += rem_nchan; + /* need to sort channel list */ + sort(_params->params_hotlist.chan_list, _params->params_hotlist.nchan, + sizeof(_params->params_hotlist.chan_list[0]), _dhd_pno_cmpfunc, NULL); + } +#ifdef PNO_DEBUG +{ + int i; + DHD_PNO(("Channel list : ")); + for (i = 0; i < _params->params_batch.nchan; i++) { + DHD_PNO(("%d ", _params->params_batch.chan_list[i])); + } + DHD_PNO(("\n")); +} +#endif + if (_params->params_hotlist.nchan) { + /* copy the channel list into local array */ + memcpy(_chan_list, _params->params_hotlist.chan_list, + sizeof(_chan_list)); + tot_nchan = _params->params_hotlist.nchan; + } + if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { + DHD_PNO(("PNO SSID is on progress in firmware\n")); + /* store current pno_mode before disabling pno */ + mode = _pno_state->pno_mode; + err = _dhd_pno_enable(dhd, PNO_OFF); + if (err < 0) { + DHD_ERROR(("%s : failed to disable PNO\n", __FUNCTION__)); + goto exit; + } + /* restore the previous mode */ + _pno_state->pno_mode = mode; + /* Use the superset for channelist between two mode */ + _params2 = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]); + if (_params2->params_legacy.nchan > 0 && + _params->params_hotlist.nchan > 0) { + err = _dhd_pno_chan_merge(_chan_list, &tot_nchan, + &_params2->params_legacy.chan_list[0], + _params2->params_legacy.nchan, + &_params->params_hotlist.chan_list[0], + _params->params_hotlist.nchan); + if (err < 0) { + DHD_ERROR(("%s : failed to merge channel list" + "between legacy and hotlist\n", + __FUNCTION__)); + goto exit; + } + } + + } + + INIT_LIST_HEAD(&(_params->params_hotlist.bssid_list)); + + err = _dhd_pno_add_bssid(dhd, p_pfn_bssid, hotlist_params->nbssid); + if (err < 0) { + DHD_ERROR(("%s : failed to call _dhd_pno_add_bssid(err :%d)\n", + __FUNCTION__, err)); + goto exit; + } + if ((err = _dhd_pno_set(dhd, _params, DHD_PNO_HOTLIST_MODE)) < 0) { + DHD_ERROR(("%s : failed to set call pno_set (err %d) in firmware\n", + __FUNCTION__, err)); + goto exit; + } + if (tot_nchan > 0) { + if ((err = _dhd_pno_cfg(dhd, _chan_list, tot_nchan)) < 0) { + DHD_ERROR(("%s : failed to set call pno_cfg (err %d) in firmware\n", + __FUNCTION__, err)); + goto exit; + } + } + for (i = 0; i < hotlist_params->nbssid; i++) { + _pno_bssid = kzalloc(sizeof(struct dhd_pno_bssid), GFP_KERNEL); + NULL_CHECK(_pno_bssid, "_pfn_bssid is NULL", err); + memcpy(&_pno_bssid->macaddr, &p_pfn_bssid[i].macaddr, ETHER_ADDR_LEN); + _pno_bssid->flags = p_pfn_bssid[i].flags; + list_add_tail(&_pno_bssid->list, &_params->params_hotlist.bssid_list); + } + _params->params_hotlist.nbssid = hotlist_params->nbssid; + if (_pno_state->pno_status == DHD_PNO_DISABLED) { + if ((err = _dhd_pno_enable(dhd, PNO_ON)) < 0) + DHD_ERROR(("%s : failed to enable PNO\n", __FUNCTION__)); + } +exit: + /* clear mode in case of error */ + if (err < 0) + _pno_state->pno_mode &= ~DHD_PNO_HOTLIST_MODE; + return err; +} + +int +dhd_pno_stop_for_hotlist(dhd_pub_t *dhd) +{ + int err = BCME_OK; + uint32 mode = 0; + dhd_pno_status_info_t *_pno_state; + dhd_pno_params_t *_params; + wlc_ssid_t *p_ssid_list; + NULL_CHECK(dhd, "dhd is NULL", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + _pno_state = PNO_GET_PNOSTATE(dhd); + + if (!WLS_SUPPORTED(_pno_state)) { + DHD_ERROR(("%s : wifi location service is not supported\n", + __FUNCTION__)); + err = BCME_UNSUPPORTED; + goto exit; + } + + if (!(_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE)) { + DHD_ERROR(("%s : Hotlist MODE is not enabled\n", + __FUNCTION__)); + goto exit; + } + _pno_state->pno_mode &= ~DHD_PNO_BATCH_MODE; + + if (_pno_state->pno_mode & (DHD_PNO_LEGACY_MODE | DHD_PNO_BATCH_MODE)) { + /* retrieve the batching data from firmware into host */ + dhd_pno_get_for_batch(dhd, NULL, 0, PNO_STATUS_DISABLE); + /* save current pno_mode before calling dhd_pno_clean */ + mode = _pno_state->pno_mode; + err = dhd_pno_clean(dhd); + if (err < 0) { + DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n", + __FUNCTION__, err)); + goto exit; + } + /* restore previos pno mode */ + _pno_state->pno_mode = mode; + if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { + /* restart Legacy PNO Scan */ + struct dhd_pno_legacy_params *_params_legacy; + struct dhd_pno_ssid *iter, *next; + _params_legacy = + &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS].params_legacy); + p_ssid_list = + kzalloc(sizeof(wlc_ssid_t) * _params_legacy->nssid, GFP_KERNEL); + if (p_ssid_list == NULL) { + DHD_ERROR(("%s : failed to allocate wlc_ssid_t array (count: %d)", + __FUNCTION__, _params_legacy->nssid)); + err = BCME_ERROR; + _pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE; + goto exit; + } + /* convert dhd_pno_ssid to dhd_pno_ssid */ + list_for_each_entry_safe(iter, next, &_params_legacy->ssid_list, list) { + p_ssid_list->SSID_len = iter->SSID_len; + memcpy(p_ssid_list->SSID, iter->SSID, p_ssid_list->SSID_len); + p_ssid_list++; + } + err = dhd_pno_set_for_ssid(dhd, p_ssid_list, _params_legacy->nssid, + _params_legacy->scan_fr, _params_legacy->pno_repeat, + _params_legacy->pno_freq_expo_max, _params_legacy->chan_list, + _params_legacy->nchan); + if (err < 0) { + _pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE; + DHD_ERROR(("%s : failed to restart legacy PNO scan(err: %d)\n", + __FUNCTION__, err)); + goto exit; + } + } else if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) { + /* restart Batching Scan */ + _params = &(_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]); + /* restart BATCH SCAN */ + err = dhd_pno_set_for_batch(dhd, &_params->params_batch); + if (err < 0) { + _pno_state->pno_mode &= ~DHD_PNO_BATCH_MODE; + DHD_ERROR(("%s : failed to restart batch scan(err: %d)\n", + __FUNCTION__, err)); + goto exit; + } + } + } else { + err = dhd_pno_clean(dhd); + if (err < 0) { + DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n", + __FUNCTION__, err)); + goto exit; + } + } +exit: + return err; +} + +int +dhd_pno_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data) +{ + int err = BCME_OK; + uint status, event_type, flags, datalen; + dhd_pno_status_info_t *_pno_state; + NULL_CHECK(dhd, "dhd is NULL", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + _pno_state = PNO_GET_PNOSTATE(dhd); + if (!WLS_SUPPORTED(_pno_state)) { + DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__)); + err = BCME_UNSUPPORTED; + goto exit; + } + event_type = ntoh32(event->event_type); + flags = ntoh16(event->flags); + status = ntoh32(event->status); + datalen = ntoh32(event->datalen); + DHD_PNO(("%s enter : event_type :%d\n", __FUNCTION__, event_type)); + switch (event_type) { + case WLC_E_PFN_BSSID_NET_FOUND: + case WLC_E_PFN_BSSID_NET_LOST: + /* TODO : need to implement event logic using generic netlink */ + break; + case WLC_E_PFN_BEST_BATCHING: + { + struct dhd_pno_batch_params *params_batch; + params_batch = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS].params_batch; + if (!waitqueue_active(&_pno_state->get_batch_done.wait)) { + DHD_PNO(("%s : WLC_E_PFN_BEST_BATCHING\n", __FUNCTION__)); + params_batch->get_batch.buf = NULL; + params_batch->get_batch.bufsize = 0; + params_batch->get_batch.reason = PNO_STATUS_EVENT; + schedule_work(&_pno_state->work); + } else + DHD_PNO(("%s : WLC_E_PFN_BEST_BATCHING" + "will skip this event\n", __FUNCTION__)); + break; + } + default: + DHD_ERROR(("unknown event : %d\n", event_type)); + } +exit: + return err; +} + +int dhd_pno_init(dhd_pub_t *dhd) +{ + int err = BCME_OK; + dhd_pno_status_info_t *_pno_state; + NULL_CHECK(dhd, "dhd is NULL", err); + DHD_PNO(("%s enter\n", __FUNCTION__)); + UNUSED_PARAMETER(_dhd_pno_suspend); + if (dhd->pno_state) + goto exit; + dhd->pno_state = MALLOC(dhd->osh, sizeof(dhd_pno_status_info_t)); + NULL_CHECK(dhd->pno_state, "failed to create dhd_pno_state", err); + memset(dhd->pno_state, 0, sizeof(dhd_pno_status_info_t)); + /* need to check whether current firmware support batching and hotlist scan */ + _pno_state = PNO_GET_PNOSTATE(dhd); + _pno_state->wls_supported = TRUE; + _pno_state->dhd = dhd; + mutex_init(&_pno_state->pno_mutex); + INIT_WORK(&_pno_state->work, _dhd_pno_get_batch_handler); + init_completion(&_pno_state->get_batch_done); + err = dhd_iovar(dhd, 0, "pfnlbest", NULL, 0, 0); + if (err == BCME_UNSUPPORTED) { + _pno_state->wls_supported = FALSE; + DHD_INFO(("Current firmware doesn't support" + " Android Location Service\n")); + } +exit: + return err; +} +int dhd_pno_deinit(dhd_pub_t *dhd) +{ + int err = BCME_OK; + dhd_pno_status_info_t *_pno_state; + dhd_pno_params_t *_params; + NULL_CHECK(dhd, "dhd is NULL", err); + + DHD_PNO(("%s enter\n", __FUNCTION__)); + _pno_state = PNO_GET_PNOSTATE(dhd); + NULL_CHECK(_pno_state, "pno_state is NULL", err); + if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) { + _params = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]; + /* clear resource if the BATCH MODE is on */ + _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_BATCH_MODE); + } + cancel_work_sync(&_pno_state->work); + MFREE(dhd->osh, _pno_state, sizeof(dhd_pno_status_info_t)); + dhd->pno_state = NULL; + return err; +} diff --git a/drivers/net/wireless/bcmdhd/dhd_pno.h b/drivers/net/wireless/bcmdhd/dhd_pno.h new file mode 100755 index 000000000000..769cdb99f1e8 --- /dev/null +++ b/drivers/net/wireless/bcmdhd/dhd_pno.h @@ -0,0 +1,250 @@ +/* + * Header file of Broadcom Dongle Host Driver (DHD) + * Prefered Network Offload code and Wi-Fi Location Service(WLS) code. + * Copyright (C) 1999-2013, 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_pno.h 423669 2013-09-12 23:01:55Z $ + */ + +#ifndef __DHD_PNO_H__ +#define __DHD_PNO_H__ + +#define PNO_TLV_PREFIX 'S' +#define PNO_TLV_VERSION '1' +#define PNO_TLV_SUBTYPE_LEGACY_PNO '2' +#define PNO_TLV_RESERVED '0' + +#define PNO_BATCHING_SET "SET" +#define PNO_BATCHING_GET "GET" +#define PNO_BATCHING_STOP "STOP" + +#define PNO_PARAMS_DELIMETER " " +#define PNO_PARAM_CHANNEL_DELIMETER "," +#define PNO_PARAM_VALUE_DELLIMETER '=' +#define PNO_PARAM_SCANFREQ "SCANFREQ" +#define PNO_PARAM_BESTN "BESTN" +#define PNO_PARAM_MSCAN "MSCAN" +#define PNO_PARAM_CHANNEL "CHANNEL" +#define PNO_PARAM_RTT "RTT" + +#define PNO_TLV_TYPE_SSID_IE 'S' +#define PNO_TLV_TYPE_TIME 'T' +#define PNO_TLV_FREQ_REPEAT 'R' +#define PNO_TLV_FREQ_EXPO_MAX 'M' + +#define MAXNUM_SSID_PER_ADD 16 +#define MAXNUM_PNO_PARAMS 2 +#define PNO_TLV_COMMON_LENGTH 1 +#define DEFAULT_BATCH_MSCAN 16 + +#define RESULTS_END_MARKER "----\n" +#define SCAN_END_MARKER "####\n" +#define AP_END_MARKER "====\n" + +enum scan_status { + /* SCAN ABORT by other scan */ + PNO_STATUS_ABORT, + /* RTT is presence or not */ + PNO_STATUS_RTT_PRESENCE, + /* Disable PNO by Driver */ + PNO_STATUS_DISABLE, + /* NORMAL BATCHING GET */ + PNO_STATUS_NORMAL, + /* WLC_E_PFN_BEST_BATCHING */ + PNO_STATUS_EVENT, + PNO_STATUS_MAX +}; +#define PNO_STATUS_ABORT_MASK 0x0001 +#define PNO_STATUS_RTT_MASK 0x0002 +#define PNO_STATUS_DISABLE_MASK 0x0004 +#define PNO_STATUS_OOM_MASK 0x0010 + +enum index_mode { + INDEX_OF_LEGACY_PARAMS, + INDEX_OF_BATCH_PARAMS, + INDEX_OF_HOTLIST_PARAMS, + INDEX_MODE_MAX +}; +enum dhd_pno_status { + DHD_PNO_DISABLED, + DHD_PNO_ENABLED, + DHD_PNO_SUSPEND +}; +typedef struct cmd_tlv { + char prefix; + char version; + char subtype; + char reserved; +} cmd_tlv_t; +typedef enum dhd_pno_mode { + /* Wi-Fi Legacy PNO Mode */ + DHD_PNO_NONE_MODE = 0, + DHD_PNO_LEGACY_MODE = (1 << (0)), + /* Wi-Fi Android BATCH SCAN Mode */ + DHD_PNO_BATCH_MODE = (1 << (1)), + /* Wi-Fi Android Hotlist SCAN Mode */ + DHD_PNO_HOTLIST_MODE = (1 << (2)) +} dhd_pno_mode_t; +struct dhd_pno_ssid { + uint32 SSID_len; + uchar SSID[DOT11_MAX_SSID_LEN]; + struct list_head list; +}; +struct dhd_pno_bssid { + struct ether_addr macaddr; + /* Bit4: suppress_lost, Bit3: suppress_found */ + uint16 flags; + struct list_head list; +}; +typedef struct dhd_pno_bestnet_entry { + struct ether_addr BSSID; + uint8 SSID_len; + uint8 SSID[DOT11_MAX_SSID_LEN]; + int8 RSSI; + uint8 channel; + uint32 timestamp; + uint16 rtt0; /* distance_cm based on RTT */ + uint16 rtt1; /* distance_cm based on sample standard deviation */ + unsigned long recorded_time; + struct list_head list; +} dhd_pno_bestnet_entry_t; +#define BESTNET_ENTRY_SIZE (sizeof(dhd_pno_bestnet_entry_t)) + +typedef struct dhd_pno_bestnet_header { + struct dhd_pno_bestnet_header *next; + uint8 reason; + uint32 tot_cnt; + uint32 tot_size; + struct list_head entry_list; +} dhd_pno_best_header_t; +#define BEST_HEADER_SIZE (sizeof(dhd_pno_best_header_t)) + +typedef struct dhd_pno_scan_results { + dhd_pno_best_header_t *bestnetheader; + uint8 cnt_header; + struct list_head list; +} dhd_pno_scan_results_t; +#define SCAN_RESULTS_SIZE (sizeof(dhd_pno_scan_results_t)) + +struct dhd_pno_get_batch_info { + /* info related to get batch */ + char *buf; + bool batch_started; + uint32 tot_scan_cnt; + uint32 expired_tot_scan_cnt; + uint32 top_node_cnt; + uint32 bufsize; + uint32 bytes_written; + int reason; + struct list_head scan_results_list; + struct list_head expired_scan_results_list; +}; +struct dhd_pno_legacy_params { + uint16 scan_fr; + uint16 chan_list[WL_NUMCHANNELS]; + uint16 nchan; + int pno_repeat; + int pno_freq_expo_max; + int nssid; + struct list_head ssid_list; +}; +struct dhd_pno_batch_params { + int32 scan_fr; + uint8 bestn; + uint8 mscan; + uint8 band; + uint16 chan_list[WL_NUMCHANNELS]; + uint16 nchan; + uint16 rtt; + struct dhd_pno_get_batch_info get_batch; +}; +struct dhd_pno_hotlist_params { + uint8 band; + int32 scan_fr; + uint16 chan_list[WL_NUMCHANNELS]; + uint16 nchan; + uint16 nbssid; + struct list_head bssid_list; +}; +typedef union dhd_pno_params { + struct dhd_pno_legacy_params params_legacy; + struct dhd_pno_batch_params params_batch; + struct dhd_pno_hotlist_params params_hotlist; +} dhd_pno_params_t; +typedef struct dhd_pno_status_info { + dhd_pub_t *dhd; + struct work_struct work; + struct mutex pno_mutex; + struct completion get_batch_done; + bool wls_supported; /* wifi location service supported or not */ + enum dhd_pno_status pno_status; + enum dhd_pno_mode pno_mode; + dhd_pno_params_t pno_params_arr[INDEX_MODE_MAX]; + struct list_head head_list; +} dhd_pno_status_info_t; + +/* wrapper functions */ +extern int +dhd_dev_pno_enable(struct net_device *dev, int enable); + +extern int +dhd_dev_pno_stop_for_ssid(struct net_device *dev); + +extern int +dhd_dev_pno_set_for_ssid(struct net_device *dev, wlc_ssid_t* ssids_local, int nssid, + uint16 scan_fr, int pno_repeat, int pno_freq_expo_max, uint16 *channel_list, int nchan); + +extern int +dhd_dev_pno_set_for_batch(struct net_device *dev, + struct dhd_pno_batch_params *batch_params); + +extern int +dhd_dev_pno_get_for_batch(struct net_device *dev, char *buf, int bufsize); + +extern int +dhd_dev_pno_stop_for_batch(struct net_device *dev); + +extern int +dhd_dev_pno_set_for_hotlist(struct net_device *dev, wl_pfn_bssid_t *p_pfn_bssid, + struct dhd_pno_hotlist_params *hotlist_params); + +/* dhd pno fuctions */ +extern int dhd_pno_stop_for_ssid(dhd_pub_t *dhd); +extern int dhd_pno_enable(dhd_pub_t *dhd, int enable); +extern int dhd_pno_set_for_ssid(dhd_pub_t *dhd, wlc_ssid_t* ssid_list, int nssid, + uint16 scan_fr, int pno_repeat, int pno_freq_expo_max, uint16 *channel_list, int nchan); + +extern int dhd_pno_set_for_batch(dhd_pub_t *dhd, struct dhd_pno_batch_params *batch_params); + +extern int dhd_pno_get_for_batch(dhd_pub_t *dhd, char *buf, int bufsize, int reason); + + +extern int dhd_pno_stop_for_batch(dhd_pub_t *dhd); + +extern int dhd_pno_set_for_hotlist(dhd_pub_t *dhd, wl_pfn_bssid_t *p_pfn_bssid, + struct dhd_pno_hotlist_params *hotlist_params); + +extern int dhd_pno_stop_for_hotlist(dhd_pub_t *dhd); + +extern int dhd_pno_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data); +extern int dhd_pno_init(dhd_pub_t *dhd); +extern int dhd_pno_deinit(dhd_pub_t *dhd); +#endif /* __DHD_PNO_H__ */ diff --git a/drivers/net/wireless/bcmdhd/dhd_proto.h b/drivers/net/wireless/bcmdhd/dhd_proto.h index 09d546809db4..9fb20528eb34 100644..100755 --- a/drivers/net/wireless/bcmdhd/dhd_proto.h +++ b/drivers/net/wireless/bcmdhd/dhd_proto.h @@ -4,7 +4,7 @@ * Provides type definitions and function prototypes used to link the * DHD OS, bus, and protocol modules. * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -24,7 +24,7 @@ * 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_proto.h 343390 2012-07-06 22:34:19Z $ + * $Id: dhd_proto.h 390836 2013-03-13 23:43:53Z $ */ #ifndef _dhd_proto_h_ @@ -54,10 +54,6 @@ extern int dhd_prot_init(dhd_pub_t *dhdp); /* Stop protocol: sync w/dongle state. */ extern void dhd_prot_stop(dhd_pub_t *dhdp); -#ifdef PROP_TXSTATUS -extern int dhd_wlfc_init(dhd_pub_t *dhd); -extern void dhd_wlfc_deinit(dhd_pub_t *dhd); -#endif /* PROP_TXSTATUS */ /* Add any protocol-specific data header. * Caller must reserve prot_hdrlen prepend space. @@ -87,12 +83,6 @@ extern int dhd_ioctl(dhd_pub_t * dhd_pub, dhd_ioctl_t *ioc, void * buf, uint buf extern int dhd_preinit_ioctls(dhd_pub_t *dhd); -#ifdef PROP_TXSTATUS -extern int dhd_wlfc_enque_sendq(void* state, int prec, void* p); -extern int dhd_wlfc_commit_packets(void* state, f_commitpkt_t fcommit, void* commit_ctx); -extern void dhd_wlfc_cleanup(dhd_pub_t *dhd); -#endif /* PROP_TXSTATUS */ - extern int dhd_process_pkt_reorder_info(dhd_pub_t *dhd, uchar *reorder_info_buf, uint reorder_info_len, void **pkt, uint32 *free_buf_count); @@ -104,8 +94,6 @@ extern int dhd_process_pkt_reorder_info(dhd_pub_t *dhd, uchar *reorder_info_buf, #define DHD_PROTOCOL "bdc" #elif defined(CDC) #define DHD_PROTOCOL "cdc" -#elif defined(RNDIS) -#define DHD_PROTOCOL "rndis" #else #define DHD_PROTOCOL "unknown" #endif /* proto */ diff --git a/drivers/net/wireless/bcmdhd/dhd_qmon.c b/drivers/net/wireless/bcmdhd/dhd_qmon.c new file mode 100755 index 000000000000..596f29f9288d --- /dev/null +++ b/drivers/net/wireless/bcmdhd/dhd_qmon.c @@ -0,0 +1,155 @@ +/* + * Queue monitoring. + * + * The feature allows monitoring the DHD queue utilization to get the percentage of a time period + * where the number of pending packets is above a configurable theshold. + * Right now, this is used by a server application, interfacing a Miracast Video Encoder, and + * doing IOVAR "qtime_percent" at regular interval. Based on IOVAR "qtime_percent" results, + * the server indicates to the Video Encoder if its bitrate can be increased or must be decreased. + * Currently, this works only with P2P interfaces and with PROP_TXSTATUS. There is no need to handle + * concurrent access to the fieds because the existing concurrent accesses are protected + * by the PROP_TXSTATUS's lock. + * + * Copyright (C) 2013, Broadcom Corporation + * All Rights Reserved. + * + * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; + * the contents of this file may not be disclosed to third parties, copied + * or duplicated in any form, in whole or in part, without the prior + * written permission of Broadcom Corporation. + * + * $Id: dhd_qmon.c 309265 2012-01-19 02:50:46Z $ + * + */ +#include <osl.h> +#include <bcmutils.h> +#include <bcmendian.h> +#include <dngl_stats.h> +#include <wlioctl.h> +#include <dhd.h> +#include <dhd_qmon.h> +#ifndef PROP_TXSTATUS +#error "PROP_TXSTATUS must be build to build dhd_qmon.c" +#endif +#include <wlfc_proto.h> +#include <dhd_wlfc.h> + +#if defined(BCMDRIVER) +#define QMON_SYSUPTIME() ((uint64)(jiffies_to_usecs(jiffies))) +#else + #error "target not yet supported" +#endif + +static dhd_qmon_t * +dhd_qmon_p2p_entry(dhd_pub_t *dhdp) +{ + wlfc_mac_descriptor_t* interfaces = NULL; + wlfc_mac_descriptor_t* nodes = NULL; + uint8 i; + + if (dhdp->wlfc_state == NULL) + return NULL; + + interfaces = ((athost_wl_status_info_t*)dhdp->wlfc_state)->destination_entries.interfaces; + nodes = ((athost_wl_status_info_t*)dhdp->wlfc_state)->destination_entries.nodes; + + ASSERT(interfaces != NULL); + ASSERT(nodes != NULL); + + for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { + if (nodes[i].occupied && + ((nodes[i].iftype == WLC_E_IF_ROLE_P2P_CLIENT) || + (nodes[i].iftype == WLC_E_IF_ROLE_P2P_GO))) + return &nodes[i].qmon; + } + + for (i = 0; i < WLFC_MAX_IFNUM; i++) { + if (interfaces[i].occupied && + ((interfaces[i].iftype == WLC_E_IF_ROLE_P2P_CLIENT) || + (interfaces[i].iftype == WLC_E_IF_ROLE_P2P_GO))) + return &nodes[i].qmon; + } + + return NULL; +} + +void +dhd_qmon_reset(dhd_qmon_t* qmon) +{ + qmon->transitq_count = 0; + qmon->queued_time_cumul = 0; + qmon->queued_time_cumul_last = 0; + qmon->queued_time_last = 0; + qmon->queued_time_last_io = 0; +} + +void +dhd_qmon_tx(dhd_qmon_t* qmon) +{ + if ((++qmon->transitq_count > qmon->queued_time_thres) && + (qmon->queued_time_last == 0)) { + /* Set timestamp when transit packet above a threshold */ + qmon->queued_time_last = QMON_SYSUPTIME(); + } +} + +void +dhd_qmon_txcomplete(dhd_qmon_t* qmon) +{ + uint64 now = QMON_SYSUPTIME(); + + qmon->transitq_count--; + if ((qmon->transitq_count <= qmon->queued_time_thres) && + (qmon->queued_time_last != 0)) { + /* Set timestamp when transit packet above a threshold */ + qmon->queued_time_cumul += now - qmon->queued_time_last; + qmon->queued_time_last = 0; + } +} + +int +dhd_qmon_thres(dhd_pub_t *dhdp, int set, int setval) +{ + int val = 0; + dhd_qmon_t* qmon = dhd_qmon_p2p_entry(dhdp); + + if (qmon == NULL) + return 0; + + if (set) + qmon->queued_time_thres = setval; + else + val = qmon->queued_time_thres; + + return val; +} + + +int +dhd_qmon_getpercent(dhd_pub_t *dhdp) +{ + int percent = 0; + uint64 time_cumul_adjust = 0; + uint64 now = QMON_SYSUPTIME(); + dhd_qmon_t* qmon = dhd_qmon_p2p_entry(dhdp); + uint64 queued_time_cumul = 0; + uint64 queued_time_last = 0; + + if (qmon == NULL) + return 0; + + queued_time_cumul = qmon->queued_time_cumul; + queued_time_last = qmon->queued_time_last; + + if (queued_time_last) + time_cumul_adjust = now - queued_time_last; + + percent = (uint32)((time_cumul_adjust + queued_time_cumul + - qmon->queued_time_cumul_last) * 100) / + (uint32)(now - qmon->queued_time_last_io); + + qmon->queued_time_cumul_last = queued_time_cumul + time_cumul_adjust; + qmon->queued_time_last_io = now; + + return percent; +} diff --git a/drivers/net/wireless/bcmdhd/dhd_qmon.h b/drivers/net/wireless/bcmdhd/dhd_qmon.h new file mode 100755 index 000000000000..d072d0fcf1bc --- /dev/null +++ b/drivers/net/wireless/bcmdhd/dhd_qmon.h @@ -0,0 +1,45 @@ +/* + * Queue monitoring. + * + * The feature allows monitoring the DHD queue utilization to get the percentage of a time period + * where the number of pending packets is above a configurable theshold. + * Right now, this is used by a server application, interfacing a Miracast Video Encoder, and + * doing IOVAR "qtime_percent" at regular interval. Based on IOVAR "qtime_percent" results, + * the server indicates to the Video Encoder if its bitrate can be increased or must be decreased. + * Currently, this works only with P2P interfaces and with PROP_TXSTATUS. There is no need to handle + * concurrent access to the fieds because the existing concurrent accesses are protected + * by the PROP_TXSTATUS's lock. + * + * Copyright (C) 2013, Broadcom Corporation + * All Rights Reserved. + * + * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; + * the contents of this file may not be disclosed to third parties, copied + * or duplicated in any form, in whole or in part, without the prior + * written permission of Broadcom Corporation. + * + * $Id: dhd_qmon.h 309265 2012-01-19 02:50:46Z $ + * + */ +#ifndef _dhd_qmon_h_ +#define _dhd_qmon_h_ + + +typedef struct dhd_qmon_s { + uint32 transitq_count; + uint32 queued_time_thres; + uint64 queued_time_cumul; + uint64 queued_time_cumul_last; + uint64 queued_time_last; + uint64 queued_time_last_io; +} dhd_qmon_t; + + +extern void dhd_qmon_reset(dhd_qmon_t* entry); +extern void dhd_qmon_tx(dhd_qmon_t* entry); +extern void dhd_qmon_txcomplete(dhd_qmon_t* entry); +extern int dhd_qmon_getpercent(dhd_pub_t *dhdp); +extern int dhd_qmon_thres(dhd_pub_t *dhdp, int set, int setval); + + +#endif /* _dhd_qmon_h_ */ diff --git a/drivers/net/wireless/bcmdhd/dhd_sdio.c b/drivers/net/wireless/bcmdhd/dhd_sdio.c index e349cb9a05a0..61b10746122c 100644..100755 --- a/drivers/net/wireless/bcmdhd/dhd_sdio.c +++ b/drivers/net/wireless/bcmdhd/dhd_sdio.c @@ -1,7 +1,7 @@ /* * DHD Bus Module for SDIO * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -21,7 +21,7 @@ * 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_sdio.c 387064 2013-02-22 23:20:39Z $ + * $Id: dhd_sdio.c 426658 2013-09-30 12:14:01Z $ */ #include <typedefs.h> @@ -66,6 +66,11 @@ #include <dhdioctl.h> #include <sdiovar.h> +bool dhd_mp_halting(dhd_pub_t *dhdp); +extern void bcmsdh_waitfor_iodrain(void *sdh); +extern void bcmsdh_reject_ioreqs(void *sdh, bool reject); +extern bool bcmsdh_fatal_error(void *sdh); + #ifndef DHDSDIO_MEM_DUMP_FNAME #define DHDSDIO_MEM_DUMP_FNAME "mem_dump" #endif @@ -76,10 +81,13 @@ #define PRIOMASK 7 #define TXRETRIES 2 /* # of retries for tx frames */ - +#ifndef DHD_RXBOUND #define DHD_RXBOUND 50 /* Default for max rx frames in one scheduling */ +#endif +#ifndef DHD_TXBOUND #define DHD_TXBOUND 20 /* Default for max tx frames in one scheduling */ +#endif #define DHD_TXMINMAX 1 /* Max tx frames if rx still pending */ @@ -153,10 +161,12 @@ extern void bcmsdh_set_irq(int flag); #ifdef PROP_TXSTATUS extern void dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success); extern void dhd_wlfc_trigger_pktcommit(dhd_pub_t *dhd); -#endif -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) -DEFINE_MUTEX(_dhd_sdio_mutex_lock_); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */ +#ifdef DHDTCPACK_SUPPRESS +extern int dhd_os_wlfc_block(dhd_pub_t *pub); +extern int dhd_os_wlfc_unblock(dhd_pub_t *pub); +#endif /* DHDTCPACK_SUPPRESS */ +#endif /* PROP_TXSTATUS */ + #ifdef DHD_DEBUG /* Device console log buffer state */ @@ -181,14 +191,17 @@ typedef struct dhd_console { #define MIN_RSRC_SR 0x3 #define CORE_CAPEXT_ADDR (SI_ENUM_BASE + 0x64c) #define CORE_CAPEXT_SR_SUPPORTED_MASK (1 << 1) -#define RCTL_MACPHY_DISABLE_MASK (1 << 26) -#define RCTL_LOGIC_DISABLE_MASK (1 << 27) +#define RCTL_MACPHY_DISABLE_MASK (1 << 26) +#define RCTL_LOGIC_DISABLE_MASK (1 << 27) #define OOB_WAKEUP_ENAB(bus) ((bus)->_oobwakeup) #define GPIO_DEV_SRSTATE 16 /* Host gpio17 mapped to device gpio0 SR state */ #define GPIO_DEV_SRSTATE_TIMEOUT 320000 /* 320ms */ #define GPIO_DEV_WAKEUP 17 /* Host gpio17 mapped to device gpio1 wakeup */ #define CC_CHIPCTRL2_GPIO1_WAKEUP (1 << 0) +#define CC_CHIPCTRL3_SR_ENG_ENABLE (1 << 2) +#define OVERFLOW_BLKSZ512_WM 48 +#define OVERFLOW_BLKSZ512_MES 80 #define CC_PMUCC3 (0x3) /* Private data for SDIO bus interaction */ @@ -389,11 +402,15 @@ uint dhd_rxbound; uint dhd_txminmax = DHD_TXMINMAX; /* override the RAM size if possible */ -#define DONGLE_MIN_MEMSIZE (128 *1024) -int dhd_dongle_memsize; +#define DONGLE_MIN_RAMSIZE (128 *1024) +int dhd_dongle_ramsize; uint dhd_doflow = TRUE; uint dhd_dpcpoll = FALSE; + +module_param(dhd_doflow, uint, 0644); +module_param(dhd_dpcpoll, uint, 0644); + static bool dhd_alignctl; static bool sd1idle; @@ -445,7 +462,6 @@ static const uint max_roundup = 512; /* Try doing readahead */ static bool dhd_readahead; - /* To check if there's window offered */ #define DATAOK(bus) \ (((uint8)(bus->tx_max - bus->tx_seq) > 1) && \ @@ -556,7 +572,7 @@ static bool dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh); static void dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation, bool reset_flag); -static void dhd_dongle_setmemsize(struct dhd_bus *bus, int mem_size); +static void dhd_dongle_setramsize(struct dhd_bus *bus, int mem_size); static int dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes, void *pkt, bcmsdh_cmplt_fn_t complete, void *handle); @@ -564,7 +580,7 @@ static int dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes, void *pkt, bcmsdh_cmplt_fn_t complete, void *handle); #ifdef BCMSDIOH_TXGLOM -static void dhd_bcmsdh_glom_post(dhd_bus_t *bus, uint8 *frame, uint len); +static void dhd_bcmsdh_glom_post(dhd_bus_t *bus, uint8 *frame, void *pkt, uint len); static void dhd_bcmsdh_glom_clear(dhd_bus_t *bus); #endif @@ -586,15 +602,48 @@ extern uint32 dhd_get_htsf(void *dhd, int ifidx); #endif /* WLMEDIA_HTSF */ static void -dhd_dongle_setmemsize(struct dhd_bus *bus, int mem_size) +dhd_overflow_war(struct dhd_bus *bus) +{ + int err; + uint8 devctl, wm, mes; + + /* See .ppt in PR for these recommended values */ + if (bus->blocksize == 512) { + wm = OVERFLOW_BLKSZ512_WM; + mes = OVERFLOW_BLKSZ512_MES; + } else { + mes = bus->blocksize/4; + wm = bus->blocksize/4; + } + + + /* Update watermark */ + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, wm, &err); + + devctl = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); + devctl |= SBSDIO_DEVCTL_F2WM_ENAB; + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err); + + /* Update MES */ + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL, + (mes | SBSDIO_MESBUSYCTRL_ENAB), &err); + + DHD_INFO(("Apply overflow WAR: 0x%02x 0x%02x 0x%02x\n", + bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err), + bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, &err), + bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL, &err))); +} + +static void +dhd_dongle_setramsize(struct dhd_bus *bus, int mem_size) { - int32 min_size = DONGLE_MIN_MEMSIZE; - /* Restrict the memsize to user specified limit */ + int32 min_size = DONGLE_MIN_RAMSIZE; + /* Restrict the ramsize to user specified limit */ DHD_ERROR(("user: Restrict the dongle ram size to %d, min accepted %d\n", - dhd_dongle_memsize, min_size)); - if ((dhd_dongle_memsize > min_size) && - (dhd_dongle_memsize < (int32)bus->orig_ramsize)) - bus->ramsize = dhd_dongle_memsize; + dhd_dongle_ramsize, min_size)); + if ((dhd_dongle_ramsize > min_size) && + (dhd_dongle_ramsize < (int32)bus->orig_ramsize)) + bus->ramsize = dhd_dongle_ramsize; } static int @@ -643,7 +692,7 @@ static bool dhdsdio_sr_cap(dhd_bus_t *bus) { bool cap = FALSE; - uint32 min = 0, core_capext, addr, data; + uint32 core_capext, addr, data; if (bus->sih->chip == BCM4324_CHIP_ID) { addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr); data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data); @@ -651,7 +700,9 @@ dhdsdio_sr_cap(dhd_bus_t *bus) core_capext = bcmsdh_reg_read(bus->sdh, data, 4); } else if (bus->sih->chip == BCM4330_CHIP_ID) { core_capext = FALSE; - } else if (bus->sih->chip == BCM4335_CHIP_ID) { + } else if ((bus->sih->chip == BCM4335_CHIP_ID) || + (bus->sih->chip == BCM4339_CHIP_ID) || + (bus->sih->chip == BCM4350_CHIP_ID)) { core_capext = TRUE; } else { core_capext = bcmsdh_reg_read(bus->sdh, CORE_CAPEXT_ADDR, 4); @@ -662,16 +713,20 @@ dhdsdio_sr_cap(dhd_bus_t *bus) if (bus->sih->chip == BCM4324_CHIP_ID) { /* FIX: Should change to query SR control register instead */ - min = bcmsdh_reg_read(bus->sdh, MIN_RSRC_ADDR, 4); - if (min == MIN_RSRC_SR) - cap = TRUE; - } else if (bus->sih->chip == BCM4335_CHIP_ID) { + cap = TRUE; + } else if ((bus->sih->chip == BCM4335_CHIP_ID) || + (bus->sih->chip == BCM4339_CHIP_ID)) { uint32 enabval = 0; addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr); data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data); bcmsdh_reg_write(bus->sdh, addr, 4, CC_PMUCC3); enabval = bcmsdh_reg_read(bus->sdh, data, 4); + if ((bus->sih->chip == BCM4350_CHIP_ID) || + 0) + enabval &= CC_CHIPCTRL3_SR_ENG_ENABLE; + + if (enabval) cap = TRUE; } else { @@ -687,7 +742,6 @@ dhdsdio_sr_cap(dhd_bus_t *bus) static int dhdsdio_srwar_init(dhd_bus_t *bus) { - bcmsdh_gpio_init(bus->sdh); #ifdef USE_OOB_GPIO1 @@ -756,7 +810,8 @@ dhdsdio_clk_kso_init(dhd_bus_t *bus) } #define KSO_DBG(x) -#define MAX_KSO_ATTEMPTS 64 +#define KSO_WAIT_US 50 +#define MAX_KSO_ATTEMPTS (PMU_MAX_TRANSITION_DLY/KSO_WAIT_US) static int dhdsdio_clk_kso_enab(dhd_bus_t *bus, bool on) { @@ -774,10 +829,9 @@ dhdsdio_clk_kso_enab(dhd_bus_t *bus, bool on) cmp_val = SBSDIO_FUNC1_SLEEPCSR_KSO_MASK | SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK; bmask = cmp_val; - msleep(3); - + OSL_SLEEP(3); } else { - /* Put device to sleep, turn off KSO */ + /* Put device to sleep, turn off KSO */ cmp_val = 0; bmask = SBSDIO_FUNC1_SLEEPCSR_KSO_MASK; } @@ -788,17 +842,15 @@ dhdsdio_clk_kso_enab(dhd_bus_t *bus, bool on) break; KSO_DBG(("%s> KSO wr/rd retry:%d, ERR:%x \n", __FUNCTION__, try_cnt, err)); - OSL_DELAY(50); + OSL_DELAY(KSO_WAIT_US); bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, wr_val, &err); - } while (try_cnt++ < MAX_KSO_ATTEMPTS); - if (try_cnt > 1) { + if (try_cnt > 2) KSO_DBG(("%s> op:%s, try_cnt:%d, rd_val:%x, ERR:%x \n", __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"), try_cnt, rd_val, err)); - } if (try_cnt > MAX_KSO_ATTEMPTS) { DHD_ERROR(("%s> op:%s, ERROR: try_cnt:%d, rd_val:%x, ERR:%x \n", @@ -830,16 +882,7 @@ dhdsdio_clk_kso_iovar(dhd_bus_t *bus, bool on) dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); } - /* Double-write to be safe in case transition of AOS */ dhdsdio_clk_kso_enab(bus, TRUE); - dhdsdio_clk_kso_enab(bus, TRUE); - OSL_DELAY(4000); - - /* Wait for device ready during transition to wake-up */ - SPINWAIT(((dhdsdio_sleepcsr_get(bus)) != - (SBSDIO_FUNC1_SLEEPCSR_KSO_MASK | - SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK)), - (10000)); DHD_ERROR(("%s: sleepcsr: 0x%x\n", __FUNCTION__, dhdsdio_sleepcsr_get(bus))); @@ -916,13 +959,11 @@ dhdsdio_clk_devsleep_iovar(dhd_bus_t *bus, bool on) DHD_TRACE(("%s: clk before sleep: 0x%x\n", __FUNCTION__, bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err))); -#ifdef USE_CMD14 - err = bcmsdh_sleep(bus->sdh, TRUE); -#else err = dhdsdio_clk_kso_enab(bus, FALSE); if (OOB_WAKEUP_ENAB(bus)) + { err = bcmsdh_gpioout(bus->sdh, GPIO_DEV_WAKEUP, FALSE); /* GPIO_1 is off */ -#endif + } } else { /* Exit Sleep */ /* Make sure we have SD bus access */ @@ -932,61 +973,35 @@ dhdsdio_clk_devsleep_iovar(dhd_bus_t *bus, bool on) } if ((bus->sih->chip == BCM4334_CHIP_ID) && (bus->sih->chiprev == 2)) { - SPINWAIT((bcmsdh_gpioin(bus->sdh, GPIO_DEV_SRSTATE) != TRUE), + SPINWAIT_SLEEP(sdioh_spinwait_sleep, + (bcmsdh_gpioin(bus->sdh, GPIO_DEV_SRSTATE) != TRUE), GPIO_DEV_SRSTATE_TIMEOUT); if (bcmsdh_gpioin(bus->sdh, GPIO_DEV_SRSTATE) == FALSE) { DHD_ERROR(("ERROR: GPIO_DEV_SRSTATE still low!\n")); } } -#ifdef USE_CMD14 - err = bcmsdh_sleep(bus->sdh, FALSE); - if (SLPAUTO_ENAB(bus) && (err != 0)) { - OSL_DELAY(10000); - DHD_TRACE(("%s: Resync device sleep\n", __FUNCTION__)); - - /* Toggle sleep to resync with host and device */ - err = bcmsdh_sleep(bus->sdh, TRUE); - OSL_DELAY(10000); - err = bcmsdh_sleep(bus->sdh, FALSE); - - if (err) { - OSL_DELAY(10000); - DHD_ERROR(("%s: CMD14 exit failed again!\n", __FUNCTION__)); - - /* Toggle sleep to resync with host and device */ - err = bcmsdh_sleep(bus->sdh, TRUE); - OSL_DELAY(10000); - err = bcmsdh_sleep(bus->sdh, FALSE); - if (err) { - DHD_ERROR(("%s: CMD14 exit failed twice!\n", __FUNCTION__)); - DHD_ERROR(("%s: FATAL: Device non-response!\n", - __FUNCTION__)); - err = 0; - } - } - } -#else if (OOB_WAKEUP_ENAB(bus)) + { err = bcmsdh_gpioout(bus->sdh, GPIO_DEV_WAKEUP, TRUE); /* GPIO_1 is on */ - + } do { err = dhdsdio_clk_kso_enab(bus, TRUE); if (err) - OSL_DELAY(10000); + OSL_SLEEP(10); } while ((err != 0) && (++retry < 3)); if (err != 0) { DHD_ERROR(("ERROR: kso set failed retry: %d\n", retry)); err = 0; /* continue anyway */ } -#endif /* !USE_CMD14 */ if (err == 0) { uint8 csr; /* Wait for device ready during transition to wake-up */ - SPINWAIT((((csr = dhdsdio_sleepcsr_get(bus)) & + SPINWAIT_SLEEP(sdioh_spinwait_sleep, + (((csr = dhdsdio_sleepcsr_get(bus)) & SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK) != (SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK)), (20000)); @@ -998,7 +1013,8 @@ dhdsdio_clk_devsleep_iovar(dhd_bus_t *bus, bool on) err = BCME_NODEVICE; } - SPINWAIT((((csr = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, + SPINWAIT_SLEEP(sdioh_spinwait_sleep, + (((csr = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err)) & SBSDIO_HT_AVAIL) != (SBSDIO_HT_AVAIL)), (10000)); @@ -1029,9 +1045,6 @@ dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok) DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -#if defined(OOB_INTR_ONLY) - pendok = FALSE; -#endif clkctl = 0; sdh = bus->sdh; @@ -1067,12 +1080,6 @@ dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok) ht_avail_error = 0; } - if (pendok && - ((bus->sih->buscoretype == PCMCIA_CORE_ID) && (bus->sih->buscorerev == 9))) { - uint32 dummy, retries; - R_SDREG(dummy, &bus->regs->clockctlstatus, retries); - BCM_REFERENCE(dummy); - } /* Check current status */ clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); @@ -1081,6 +1088,7 @@ dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok) return BCME_ERROR; } +#if !defined(OOB_INTR_ONLY) /* Go to pending and await interrupt if appropriate */ if (!SBSDIO_CLKAV(clkctl, bus->alp_only) && pendok) { /* Allow only clock-available interrupt */ @@ -1096,11 +1104,15 @@ dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok) DHD_INFO(("CLKCTL: set PENDING\n")); bus->clkstate = CLK_PENDING; return BCME_OK; - } else if (bus->clkstate == CLK_PENDING) { - /* Cancel CA-only interrupt filter */ - devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); - devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err); + } else +#endif /* !defined (OOB_INTR_ONLY) */ + { + if (bus->clkstate == CLK_PENDING) { + /* Cancel CA-only interrupt filter */ + devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); + devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; + bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err); + } } /* Otherwise, wait here (polling) for HT Avail */ @@ -1144,6 +1156,7 @@ dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok) #endif /* DHD_USE_IDLECOUNT */ } else { clkreq = 0; + if (bus->clkstate == CLK_PENDING) { /* Cancel CA-only interrupt filter */ devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); @@ -1457,6 +1470,241 @@ dhd_enable_oob_intr(struct dhd_bus *bus, bool enable) } #endif +#ifdef DHDTCPACK_SUPPRESS +extern bool dhd_use_tcpack_suppress; + +/* Please be sure this function is called under dhd_os_tcpacklock() */ +void dhd_onoff_tcpack_sup(void *pub, bool on) +{ + dhd_pub_t *dhdp = (dhd_pub_t *)pub; + + if (dhd_use_tcpack_suppress != on) { + + DHD_ERROR(("dhd_onoff_tcpack_sup: %d -> %d\n", dhd_use_tcpack_suppress, on)); + dhd_use_tcpack_suppress = on; + dhdp->tcp_ack_info_cnt = 0; + bzero(dhdp->tcp_ack_info_tbl, sizeof(struct tcp_ack_info)*MAXTCPSTREAMS); + + } else + DHD_ERROR(("dhd_onoff_tcpack_sup: alread %d\n", on)); + + return; +} + +inline void dhd_tcpack_check_xmit(dhd_pub_t *dhdp, void *pkt) +{ + uint8 i; + tcp_ack_info_t *tcp_ack_info = NULL; + int tbl_cnt; + + dhd_os_tcpacklock(dhdp); + tbl_cnt = dhdp->tcp_ack_info_cnt; + for (i = 0; i < tbl_cnt; i++) { + tcp_ack_info = &dhdp->tcp_ack_info_tbl[i]; + if (tcp_ack_info->p_tcpackinqueue == pkt) { + /* This pkt is being transmitted so remove the tcp_ack_info of it. + * compact the array unless the last element, + * then the pkt's array is removed. + */ + if (i < tbl_cnt-1) { + memmove(&dhdp->tcp_ack_info_tbl[i], + &dhdp->tcp_ack_info_tbl[i+1], + sizeof(struct tcp_ack_info)*(tbl_cnt - (i+1))); + } + bzero(&dhdp->tcp_ack_info_tbl[tbl_cnt-1], sizeof(struct tcp_ack_info)); + if (--dhdp->tcp_ack_info_cnt < 0) { + DHD_ERROR(("dhdsdio_sendfromq:(ERROR) tcp_ack_info_cnt %d" + " Stop using tcpack_suppress\n", dhdp->tcp_ack_info_cnt)); + dhd_onoff_tcpack_sup(dhdp, FALSE); + } + break; + } + } + dhd_os_tcpackunlock(dhdp); +} + +bool +dhd_tcpack_suppress(dhd_pub_t *dhdp, void *pkt) +{ + uint8 *eh_header; + uint16 eh_type; + uint8 *ip_header; + uint8 *tcp_header; + uint32 ip_hdr_len; + uint32 cur_framelen; + uint8 bdc_hdr_len = BDC_HEADER_LEN; + uint8 wlfc_hdr_len = 0; + uint8 *data = PKTDATA(dhdp->osh, pkt); + cur_framelen = PKTLEN(dhdp->osh, pkt); + +#ifdef PROP_TXSTATUS + /* In this case, BDC header is not pushed in dhd_sendpkt() */ + if (dhdp->wlfc_state) { + bdc_hdr_len = 0; + wlfc_hdr_len = 8; + } +#endif + if (cur_framelen < bdc_hdr_len + ETHER_HDR_LEN) { + DHD_TRACE(("dhd_tcpack_suppress: Too short packet length %d\n", cur_framelen)); + return FALSE; + } + + /* Get rid of BDC header */ + eh_header = data + bdc_hdr_len; + cur_framelen -= bdc_hdr_len; + eh_type = eh_header[12] << 8 | eh_header[13]; + + if (eh_type != ETHER_TYPE_IP) { + DHD_TRACE(("dhd_tcpack_suppress: Not a IP packet 0x%x\n", eh_type)); + return FALSE; + } + + DHD_TRACE(("dhd_tcpack_suppress: IP pkt! 0x%x\n", eh_type)); + + ip_header = eh_header + ETHER_HDR_LEN; + cur_framelen -= ETHER_HDR_LEN; + ip_hdr_len = 4 * (ip_header[0] & 0x0f); + + if ((ip_header[0] & 0xf0) != 0x40) { + DHD_TRACE(("dhd_tcpack_suppress: Not IPv4!\n")); + return FALSE; + } + + if (cur_framelen < ip_hdr_len) { + DHD_ERROR(("dhd_tcpack_suppress: IP packet length %d wrong!\n", cur_framelen)); + return FALSE; + } + + /* not tcp */ + if (ip_header[9] != 0x06) { + DHD_TRACE(("dhd_tcpack_suppress: Not a TCP packet 0x%x\n", ip_header[9])); + return FALSE; + } + + DHD_TRACE(("dhd_tcpack_suppress: TCP pkt!\n")); + + tcp_header = ip_header + ip_hdr_len; + + /* is it an ack ? */ + if (tcp_header[13] == 0x10) { +#if defined(DHD_DEBUG) + uint32 tcp_seq_num = tcp_header[4] << 24 | tcp_header[5] << 16 | + tcp_header[6] << 8 | tcp_header[7]; +#endif + uint32 tcp_ack_num = tcp_header[8] << 24 | tcp_header[9] << 16 | + tcp_header[10] << 8 | tcp_header[11]; + uint16 ip_tcp_ttllen = (ip_header[3] & 0xff) + (ip_header[2] << 8); + uint32 tcp_hdr_len = 4*((tcp_header[12] & 0xf0) >> 4); + DHD_TRACE(("dhd_tcpack_suppress: TCP ACK seq %ud ack %ud\n", + tcp_seq_num, tcp_ack_num)); + + + /* zero length ? */ + if (ip_tcp_ttllen == ip_hdr_len + tcp_hdr_len) { + int i; + tcp_ack_info_t *tcp_ack_info = NULL; + DHD_TRACE(("dhd_tcpack_suppress: TCP ACK zero length\n")); + /* Look for tcp_ack_info that has the same + * ip src/dst addrs and tcp src/dst ports + */ + dhd_os_tcpacklock(dhdp); + for (i = 0; i < dhdp->tcp_ack_info_cnt; i++) { + if (dhdp->tcp_ack_info_tbl[i].p_tcpackinqueue && + !memcmp(&ip_header[12], dhdp->tcp_ack_info_tbl[i].ipaddrs, 8) && + !memcmp(tcp_header, dhdp->tcp_ack_info_tbl[i].tcpports, 4)) { + tcp_ack_info = &dhdp->tcp_ack_info_tbl[i]; + break; + } + } + + if (i == dhdp->tcp_ack_info_cnt && i < MAXTCPSTREAMS) + tcp_ack_info = &dhdp->tcp_ack_info_tbl[dhdp->tcp_ack_info_cnt++]; + + if (!tcp_ack_info) { + DHD_TRACE(("dhd_tcpack_suppress: No empty tcp ack info" + "%d %d %d %d, %d %d %d %d\n", + tcp_header[0], tcp_header[1], tcp_header[2], tcp_header[3], + dhdp->tcp_ack_info_tbl[i].tcpports[0], + dhdp->tcp_ack_info_tbl[i].tcpports[1], + dhdp->tcp_ack_info_tbl[i].tcpports[2], + dhdp->tcp_ack_info_tbl[i].tcpports[3])); + dhd_os_tcpackunlock(dhdp); + return FALSE; + } + + if (tcp_ack_info->p_tcpackinqueue) { + if (tcp_ack_num > tcp_ack_info->tcpack_number) { + void *prevpkt = tcp_ack_info->p_tcpackinqueue; + uint8 pushed_len = SDPCM_HDRLEN + + (BDC_HEADER_LEN - bdc_hdr_len) + wlfc_hdr_len; +#ifdef PROP_TXSTATUS + /* In case the prev pkt is delayenqueued + * but not delayedequeued yet, it may not have + * any additional header yet. + */ + dhd_os_wlfc_block(dhdp); + if (dhdp->wlfc_state && (PKTLEN(dhdp->osh, prevpkt) == + tcp_ack_info->ip_tcp_ttllen + ETHER_HDR_LEN)) + pushed_len = 0; +#endif + if ((ip_tcp_ttllen == tcp_ack_info->ip_tcp_ttllen) && + (PKTLEN(dhdp->osh, pkt) == + PKTLEN(dhdp->osh, prevpkt) - pushed_len)) { + bcopy(PKTDATA(dhdp->osh, pkt), + PKTDATA(dhdp->osh, prevpkt) + pushed_len, + PKTLEN(dhdp->osh, pkt)); + PKTFREE(dhdp->osh, pkt, FALSE); + DHD_TRACE(("dhd_tcpack_suppress: pkt 0x%p" + " TCP ACK replace %ud -> %ud\n", prevpkt, + tcp_ack_info->tcpack_number, tcp_ack_num)); + tcp_ack_info->tcpack_number = tcp_ack_num; +#ifdef PROP_TXSTATUS + dhd_os_wlfc_unblock(dhdp); +#endif + dhd_os_tcpackunlock(dhdp); + return TRUE; + } else + DHD_TRACE(("dhd_tcpack_suppress: len mismatch" + " %d(%d) %d(%d)\n", + PKTLEN(dhdp->osh, pkt), ip_tcp_ttllen, + PKTLEN(dhdp->osh, prevpkt), + tcp_ack_info->ip_tcp_ttllen)); +#ifdef PROP_TXSTATUS + dhd_os_wlfc_unblock(dhdp); +#endif + + } else { +#ifdef TCPACK_TEST + void *prevpkt = tcp_ack_info->p_tcpackinqueue; +#endif + DHD_TRACE(("dhd_tcpack_suppress: TCP ACK number reverse" + " prev %ud (0x%p) new %ud (0x%p)\n", + tcp_ack_info->tcpack_number, + tcp_ack_info->p_tcpackinqueue, + tcp_ack_num, pkt)); +#ifdef TCPACK_TEST + if (PKTLEN(dhdp->osh, pkt) == PKTLEN(dhdp->osh, prevpkt)) { + PKTFREE(dhdp->osh, pkt, FALSE); + dhd_os_tcpackunlock(dhdp); + return TRUE; + } +#endif + } + } else { + tcp_ack_info->p_tcpackinqueue = pkt; + tcp_ack_info->tcpack_number = tcp_ack_num; + tcp_ack_info->ip_tcp_ttllen = ip_tcp_ttllen; + bcopy(&ip_header[12], tcp_ack_info->ipaddrs, 8); + bcopy(tcp_header, tcp_ack_info->tcpports, 4); + } + dhd_os_tcpackunlock(dhdp); + } else + DHD_TRACE(("dhd_tcpack_suppress: TCP ACK with DATA len %d\n", + ip_tcp_ttllen - ip_hdr_len - tcp_hdr_len)); + } + return FALSE; +} +#endif /* DHDTCPACK_SUPPRESS */ /* Writes a HW/SW header into the packet and sends it. */ /* Assumes: (a) header space already there, (b) caller holds lock */ static int @@ -1465,9 +1713,10 @@ dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt, bool queue_on int ret; osl_t *osh; uint8 *frame; - uint16 len, pad1 = 0; + uint16 len, pad1 = 0, act_len = 0; uint32 swheader; uint retries = 0; + uint32 real_pad = 0; bcmsdh_info_t *sdh; void *new; int i; @@ -1480,12 +1729,17 @@ dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt, bool queue_on htsfts_t *htsf_ts; #endif - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); sdh = bus->sdh; osh = bus->dhd->osh; +#ifdef DHDTCPACK_SUPPRESS + if (dhd_use_tcpack_suppress) { + dhd_tcpack_check_xmit(bus->dhd, pkt); + } +#endif /* DHDTCPACK_SUPPRESS */ + if (bus->dhd->dongle_reset) { ret = BCME_NOTREADY; goto done; @@ -1505,7 +1759,7 @@ dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt, bool queue_on #endif /* WLMEDIA_HTSF */ /* Add alignment padding, allocate new packet if needed */ - if (!((uintptr)frame & 1) && (pad1 = ((uintptr)frame % DHD_SDALIGN))) { + if ((pad1 = ((uintptr)frame % DHD_SDALIGN))) { if (PKTHEADROOM(osh, pkt) < pad1) { DHD_INFO(("%s: insufficient headroom %d for %d pad1\n", __FUNCTION__, (int)PKTHEADROOM(osh, pkt), pad1)); @@ -1545,7 +1799,8 @@ dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt, bool queue_on #ifdef BCMSDIOH_TXGLOM if (bus->glom_enable) { - uint32 hwheader1 = 0, hwheader2 = 0, act_len = len; + uint32 hwheader1 = 0, hwheader2 = 0; + act_len = len; /* Software tag: channel, sequence number, data offset */ swheader = ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) | @@ -1555,8 +1810,9 @@ dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt, bool queue_on htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN + sizeof(swheader)); if (queue_only) { - if (forcealign && (len & (ALIGNMENT - 1))) - len = ROUNDUP(len, ALIGNMENT); + uint8 alignment = ALIGNMENT; + if (forcealign && (len & (alignment - 1))) + len = ROUNDUP(len, alignment); /* Hardware extention tag */ /* 2byte frame length, 1byte-, 1byte frame flag, * 2byte-hdrlength, 2byte padlenght @@ -1565,8 +1821,25 @@ dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt, bool queue_on hwheader2 = (len - act_len) << 16; htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN); htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4); + real_pad = len - act_len; + if (PKTTAILROOM(osh, pkt) < real_pad) { + DHD_INFO(("%s 1: insufficient tailroom %d for %d real_pad\n", + __FUNCTION__, (int)PKTTAILROOM(osh, pkt), real_pad)); + if (PKTPADTAILROOM(osh, pkt, real_pad)) { + DHD_ERROR(("CHK1: padding error size %d\n", real_pad)); + ret = BCME_NOMEM; + goto done; + } +#ifndef BCMLXSDMMC + else + PKTSETLEN(osh, pkt, act_len); +#endif + } +#ifdef BCMLXSDMMC + PKTSETLEN(osh, pkt, len); +#endif /* BCMLXSDMMC */ /* Post the frame pointer to sdio glom array */ - dhd_bcmsdh_glom_post(bus, frame, len); + dhd_bcmsdh_glom_post(bus, frame, pkt, len); /* Save the pkt pointer in bus glom array */ bus->glom_pkt_arr[bus->glom_cnt] = pkt; bus->glom_total_len += len; @@ -1598,9 +1871,36 @@ dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt, bool queue_on hwheader2 = (len - act_len) << 16; htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN); htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4); + real_pad = len - act_len; + if (PKTTAILROOM(osh, pkt) < real_pad) { + DHD_INFO(("%s 2: insufficient tailroom %d" + " for %d real_pad\n", + __FUNCTION__, (int)PKTTAILROOM(osh, pkt), real_pad)); + if (PKTPADTAILROOM(osh, pkt, real_pad)) { + DHD_ERROR(("CHK2: padding error size %d." + " %d more pkts are discarded together.\n", + real_pad, bus->glom_cnt)); + /* Save the pkt pointer in bus glom array + * Otherwise, this last pkt will not be + * cleaned under "goto done" + */ + bus->glom_pkt_arr[bus->glom_cnt] = pkt; + bus->glom_cnt++; + bus->glom_total_len += len; + ret = BCME_NOMEM; + goto done; + } +#ifndef BCMLXSDMMC + else + PKTSETLEN(osh, pkt, act_len); +#endif + } +#ifdef BCMLXSDMMC + PKTSETLEN(osh, pkt, len); +#endif /* BCMLXSDMMC */ /* Post the frame pointer to sdio glom array */ - dhd_bcmsdh_glom_post(bus, frame, len); + dhd_bcmsdh_glom_post(bus, frame, pkt, len); /* Save the pkt pointer in bus glom array */ bus->glom_pkt_arr[bus->glom_cnt] = pkt; bus->glom_cnt++; @@ -1614,6 +1914,7 @@ dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt, bool queue_on } else #endif /* BCMSDIOH_TXGLOM */ { + act_len = len; /* Software tag: channel, sequence number, data offset */ swheader = ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) | bus->tx_seq | (((pad1 + SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK); @@ -1656,8 +1957,24 @@ dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt, bool queue_on DHD_ERROR(("%s: sending unrounded %d-byte packet\n", __FUNCTION__, len)); #endif } + real_pad = len - act_len; + if (PKTTAILROOM(osh, pkt) < real_pad) { + DHD_INFO(("%s 3: insufficient tailroom %d for %d real_pad\n", + __FUNCTION__, (int)PKTTAILROOM(osh, pkt), real_pad)); + if (PKTPADTAILROOM(osh, pkt, real_pad)) { + DHD_ERROR(("CHK3: padding error size %d\n", real_pad)); + ret = BCME_NOMEM; + goto done; + } +#ifndef BCMLXSDMMC + else + PKTSETLEN(osh, pkt, act_len); +#endif + } +#ifdef BCMLXSDMMC + PKTSETLEN(osh, pkt, len); +#endif /* BCMLXSDMMC */ } - do { ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, frame, len, pkt, NULL, NULL); @@ -1703,7 +2020,7 @@ dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt, bool queue_on done: #ifdef BCMSDIOH_TXGLOM - if (bus->glom_enable) { + if (bus->glom_enable && !queue_only) { dhd_bcmsdh_glom_clear(bus); pkt_cnt = bus->glom_cnt; } else @@ -1716,15 +2033,28 @@ done: #ifdef BCMSDIOH_TXGLOM uint32 doff; if (bus->glom_enable) { - pkt = bus->glom_pkt_arr[bus->glom_cnt - pkt_cnt]; +#ifdef BCMLXSDMMC + uint32 pad2 = 0; +#endif /* BCMLXSDMMC */ + if (!queue_only) + pkt = bus->glom_pkt_arr[bus->glom_cnt - pkt_cnt]; + frame = (uint8*)PKTDATA(osh, pkt); doff = ltoh32_ua(frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN); doff = (doff & SDPCM_DOFFSET_MASK) >> SDPCM_DOFFSET_SHIFT; +#ifdef BCMLXSDMMC + pad2 = ltoh32_ua(frame + SDPCM_FRAMETAG_LEN + 4) >> 16; + PKTSETLEN(osh, pkt, PKTLEN(osh, pkt) - pad2); +#endif /* BCMLXSDMMC */ PKTPULL(osh, pkt, doff); } else -#endif +#endif /* BCMSDIOH_TXGLOM */ { - PKTPULL(osh, pkt, SDPCM_HDRLEN + pad1); +#ifdef BCMLXSDMMC + if (act_len > 0) + PKTSETLEN(osh, pkt, act_len); +#endif /* BCMLXSDMMC */ + PKTPULL(osh, pkt, SDPCM_HDRLEN + pad1); } #ifdef PROP_TXSTATUS if (bus->dhd->wlfc_state) { @@ -1751,7 +2081,7 @@ done: #ifdef BCMSDIOH_TXGLOM /* Reset the glom array */ - if (bus->glom_enable) { + if (bus->glom_enable && !queue_only) { bus->glom_cnt = 0; bus->glom_total_len = 0; } @@ -1765,13 +2095,11 @@ dhd_bus_txdata(struct dhd_bus *bus, void *pkt) int ret = BCME_ERROR; osl_t *osh; uint datalen, prec; -#ifdef DHD_TX_DUMP +#if defined(DHD_TX_DUMP) || defined(DHD_8021X_DUMP) uint8 *dump_data; uint16 protocol; -#ifdef DHD_TX_FULL_DUMP - int i; -#endif /* DHD_TX_FULL_DUMP */ -#endif /* DHD_TX_DUMP */ +#endif /* DHD_TX_DUMP || DHD_8021X_DUMP */ + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); osh = bus->dhd->osh; @@ -1791,26 +2119,30 @@ dhd_bus_txdata(struct dhd_bus *bus, void *pkt) } #endif /* SDTEST */ -#ifdef DHD_TX_DUMP +#if defined(DHD_TX_DUMP) || defined(DHD_8021X_DUMP) dump_data = PKTDATA(osh, pkt); dump_data += 4; /* skip 4 bytes header */ protocol = (dump_data[12] << 8) | dump_data[13]; -#ifdef DHD_TX_FULL_DUMP - DHD_ERROR(("TX DUMP\n")); - for (i = 0; i < (datalen - 4); i++) { - DHD_ERROR(("%02X ", dump_data[i])); - if ((i & 15) == 15) - printk("\n"); - } - DHD_ERROR(("\n")); - -#endif /* DHD_TX_FULL_DUMP */ if (protocol == ETHER_TYPE_802_1X) { - DHD_ERROR(("ETHER_TYPE_802_1X: ver %d, type %d, replay %d\n", + DHD_ERROR(("ETHER_TYPE_802_1X [TX]: ver %d, type %d, replay %d\n", dump_data[14], dump_data[15], dump_data[30])); } -#endif /* DHD_TX_DUMP */ +#endif /* DHD_TX_DUMP || DHD_8021X_DUMP */ + +#if defined(DHD_TX_DUMP) && defined(DHD_TX_FULL_DUMP) + { + int i; + DHD_ERROR(("TX DUMP\n")); + + for (i = 0; i < (datalen - 4); i++) { + DHD_ERROR(("%02X ", dump_data[i])); + if ((i & 15) == 15) + printk("\n"); + } + DHD_ERROR(("\n")); + } +#endif /* DHD_TX_DUMP && DHD_TX_FULL_DUMP */ /* Add space for the header */ PKTPUSH(osh, pkt, SDPCM_HDRLEN); @@ -1862,7 +2194,6 @@ dhd_bus_txdata(struct dhd_bus *bus, void *pkt) } else ret = BCME_OK; - dhd_os_sdunlock_txq(bus->dhd); if ((pktq_len(&bus->txq) >= FCHI) && dhd_doflow) dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON); @@ -1871,6 +2202,8 @@ dhd_bus_txdata(struct dhd_bus *bus, void *pkt) if (pktq_plen(&bus->txq, prec) > qcount[prec]) qcount[prec] = pktq_plen(&bus->txq, prec); #endif + dhd_os_sdunlock_txq(bus->dhd); + /* Schedule DPC if needed to send queued packet(s) */ if (dhd_deferred_tx && !bus->dpc_sched) { bus->dpc_sched = TRUE; @@ -1924,6 +2257,7 @@ dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes) uint cnt = 0; uint datalen; uint8 tx_prec_map; + uint16 txpktqlen = 0; #ifdef BCMSDIOH_TXGLOM uint i; uint8 glom_cnt; @@ -1945,28 +2279,36 @@ dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes) for (cnt = 0; (cnt < maxframes) && DATAOK(bus); cnt++) { #ifdef BCMSDIOH_TXGLOM if (bus->glom_enable) { + void *pkttable[SDPCM_MAXGLOM_SIZE]; + dhd_os_sdlock_txq(bus->dhd); glom_cnt = MIN(DATABUFCNT(bus), bus->glomsize); glom_cnt = MIN(glom_cnt, pktq_mlen(&bus->txq, tx_prec_map)); glom_cnt = MIN(glom_cnt, maxframes-cnt); /* Limiting the size to 2pkts in case of copy */ if (bus->glom_mode == SDPCM_TXGLOM_CPY) - glom_cnt = MIN(glom_cnt, 5); + glom_cnt = MIN(glom_cnt, 10); + + for (i = 0; i < glom_cnt; i++) + pkttable[i] = pktq_mdeq(&bus->txq, tx_prec_map, &prec_out); + + txpktqlen = pktq_len(&bus->txq); + dhd_os_sdunlock_txq(bus->dhd); if (glom_cnt == 0) break; datalen = 0; for (i = 0; i < glom_cnt; i++) { - dhd_os_sdlock_txq(bus->dhd); - if ((pkt = pktq_mdeq(&bus->txq, tx_prec_map, &prec_out)) == NULL) { + uint datalen_tmp = 0; + + if ((pkt = pkttable[i]) == NULL) { /* This case should not happen */ DHD_ERROR(("No pkts in the queue for glomming\n")); - dhd_os_sdunlock_txq(bus->dhd); break; } - dhd_os_sdunlock_txq(bus->dhd); - datalen += (PKTLEN(bus->dhd->osh, pkt) - SDPCM_HDRLEN); + datalen_tmp = (PKTLEN(bus->dhd->osh, pkt) - SDPCM_HDRLEN); + #ifndef SDTEST ret = dhdsdio_txpkt(bus, pkt, @@ -1980,6 +2322,8 @@ dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes) TRUE, (i == (glom_cnt-1))? FALSE: TRUE); #endif + if (ret == BCME_OK) + datalen += datalen_tmp; } cnt += i-1; } else @@ -1987,9 +2331,11 @@ dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes) { dhd_os_sdlock_txq(bus->dhd); if ((pkt = pktq_mdeq(&bus->txq, tx_prec_map, &prec_out)) == NULL) { + txpktqlen = pktq_len(&bus->txq); dhd_os_sdunlock_txq(bus->dhd); break; } + txpktqlen = pktq_len(&bus->txq); dhd_os_sdunlock_txq(bus->dhd); datalen = PKTLEN(bus->dhd->osh, pkt) - SDPCM_HDRLEN; @@ -2024,12 +2370,68 @@ dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes) /* Deflow-control stack if needed */ if (dhd_doflow && dhd->up && (dhd->busstate == DHD_BUS_DATA) && - dhd->txoff && (pktq_len(&bus->txq) < FCLOW)) + dhd->txoff && (txpktqlen < FCLOW)) dhd_txflowcontrol(dhd, ALL_INTERFACES, OFF); return cnt; } +static void +dhdsdio_sendpendctl(dhd_bus_t *bus) +{ + bcmsdh_info_t *sdh = bus->sdh; + int ret, i; + uint8* frame_seq = bus->ctrl_frame_buf + SDPCM_FRAMETAG_LEN; + +#ifdef BCMSDIOH_TXGLOM + if (bus->glom_enable) + frame_seq += SDPCM_HWEXT_LEN; +#endif + + if (*frame_seq != bus->tx_seq) { + DHD_INFO(("%s IOCTL frame seq lag detected!" + " frm_seq:%d != bus->tx_seq:%d, corrected\n", + __FUNCTION__, *frame_seq, bus->tx_seq)); + *frame_seq = bus->tx_seq; + } + + ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, + (uint8 *)bus->ctrl_frame_buf, (uint32)bus->ctrl_frame_len, + NULL, NULL, NULL); + ASSERT(ret != BCME_PENDING); + if (ret == BCME_NODEVICE) { + DHD_ERROR(("%s: Device asleep already\n", __FUNCTION__)); + } else if (ret < 0) { + /* On failure, abort the command and terminate the frame */ + DHD_INFO(("%s: sdio error %d, abort command and terminate frame.\n", + __FUNCTION__, ret)); + bus->tx_sderrs++; + + bcmsdh_abort(sdh, SDIO_FUNC_2); + + bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, + SFC_WF_TERM, NULL); + bus->f1regdata++; + + for (i = 0; i < 3; i++) { + uint8 hi, lo; + hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, + SBSDIO_FUNC1_WFRAMEBCHI, NULL); + lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, + SBSDIO_FUNC1_WFRAMEBCLO, NULL); + bus->f1regdata += 2; + if ((hi == 0) && (lo == 0)) + break; + } + } + if (ret == 0) { + bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; + } + + bus->ctrl_frame_stat = FALSE; + dhd_wait_event_wakeup(bus->dhd); +} + int dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen) { @@ -2142,9 +2544,6 @@ dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen) if (!bus->dhd->hang_was_sent) { DHD_ERROR(("%s: ctrl_frame_stat == TRUE txcnt_timeout=%d\n", __FUNCTION__, bus->dhd->txcnt_timeout)); - DHD_ERROR(("%s : tx_max : %d, tx_seq : %d, clkstate : %d \n", - __FUNCTION__, bus->tx_max, bus->tx_seq, bus->clkstate)); - } ret = -1; bus->ctrl_frame_stat = FALSE; @@ -2153,6 +2552,7 @@ dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen) } bus->dhd->txcnt_timeout = 0; + bus->ctrl_frame_stat = TRUE; if (ret == -1) { #ifdef DHD_DEBUG @@ -2198,6 +2598,7 @@ dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen) } } while ((ret < 0) && retries++ < TXRETRIES); } + bus->ctrl_frame_stat = FALSE; done: if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) { @@ -2212,7 +2613,7 @@ done: else bus->dhd->tx_ctlpkts++; - if (bus->dhd->txcnt_timeout >= MAX_CNTL_TIMEOUT) + if (bus->dhd->txcnt_timeout >= MAX_CNTL_TX_TIMEOUT) return -ETIMEDOUT; return ret ? -EIO : 0; @@ -2241,7 +2642,7 @@ dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen) if (rxlen) { DHD_CTL(("%s: resumed on rxctl frame, got %d expected %d\n", - __FUNCTION__, rxlen, msglen)); + __FUNCTION__, rxlen, msglen)); } else if (timeleft == 0) { #ifdef DHD_DEBUG uint32 status, retry = 0; @@ -2270,8 +2671,10 @@ dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen) #endif /* DHD_DEBUG */ } if (timeleft == 0) { - bus->dhd->rxcnt_timeout++; - DHD_ERROR(("%s: rxcnt_timeout=%d\n", __FUNCTION__, bus->dhd->rxcnt_timeout)); + if (rxlen == 0) + bus->dhd->rxcnt_timeout++; + DHD_ERROR(("%s: rxcnt_timeout=%d, rxlen=%d\n", __FUNCTION__, + bus->dhd->rxcnt_timeout, rxlen)); } else bus->dhd->rxcnt_timeout = 0; @@ -2281,7 +2684,7 @@ dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen) else bus->dhd->rx_ctlerrs++; - if (bus->dhd->rxcnt_timeout >= MAX_CNTL_TIMEOUT) + if (bus->dhd->rxcnt_timeout >= MAX_CNTL_RX_TIMEOUT) return -ETIMEDOUT; if (bus->dhd->dongle_trap_occured) @@ -2298,7 +2701,8 @@ enum { IOV_SBREG, IOV_SDCIS, IOV_MEMBYTES, - IOV_MEMSIZE, + IOV_RAMSIZE, + IOV_RAMSTART, #ifdef DHD_DEBUG IOV_CHECKDIED, IOV_SERIALCONS, @@ -2350,7 +2754,8 @@ const bcm_iovar_t dhdsdio_iovars[] = { {"idleclock", IOV_IDLECLOCK, 0, IOVT_INT32, 0 }, {"sd1idle", IOV_SD1IDLE, 0, IOVT_BOOL, 0 }, {"membytes", IOV_MEMBYTES, 0, IOVT_BUFFER, 2 * sizeof(int) }, - {"memsize", IOV_MEMSIZE, 0, IOVT_UINT32, 0 }, + {"ramsize", IOV_RAMSIZE, 0, IOVT_UINT32, 0 }, + {"ramstart", IOV_RAMSTART, 0, IOVT_UINT32, 0 }, {"dwnldstate", IOV_SET_DOWNLOAD_STATE, 0, IOVT_BOOL, 0 }, {"socram_state", IOV_SOCRAM_STATE, 0, IOVT_BOOL, 0 }, {"vars", IOV_VARS, 0, IOVT_BUFFER, 0 }, @@ -2417,25 +2822,25 @@ dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) bcm_bprintf(strbuf, "Bus SDIO structure:\n"); bcm_bprintf(strbuf, "hostintmask 0x%08x intstatus 0x%08x sdpcm_ver %d\n", bus->hostintmask, bus->intstatus, bus->sdpcm_ver); - bcm_bprintf(strbuf, "fcstate %d qlen %d tx_seq %d, max %d, rxskip %d rxlen %d rx_seq %d\n", + bcm_bprintf(strbuf, "fcstate %d qlen %u tx_seq %d, max %d, rxskip %d rxlen %u rx_seq %d\n", bus->fcstate, pktq_len(&bus->txq), bus->tx_seq, bus->tx_max, bus->rxskip, bus->rxlen, bus->rx_seq); - bcm_bprintf(strbuf, "intr %d intrcount %d lastintrs %d spurious %d\n", + bcm_bprintf(strbuf, "intr %d intrcount %u lastintrs %u spurious %u\n", bus->intr, bus->intrcount, bus->lastintrs, bus->spurious); - bcm_bprintf(strbuf, "pollrate %d pollcnt %d regfails %d\n", + bcm_bprintf(strbuf, "pollrate %u pollcnt %u regfails %u\n", bus->pollrate, bus->pollcnt, bus->regfails); bcm_bprintf(strbuf, "\nAdditional counters:\n"); - bcm_bprintf(strbuf, "tx_sderrs %d fcqueued %d rxrtx %d rx_toolong %d rxc_errors %d\n", + bcm_bprintf(strbuf, "tx_sderrs %u fcqueued %u rxrtx %u rx_toolong %u rxc_errors %u\n", bus->tx_sderrs, bus->fcqueued, bus->rxrtx, bus->rx_toolong, bus->rxc_errors); - bcm_bprintf(strbuf, "rx_hdrfail %d badhdr %d badseq %d\n", + bcm_bprintf(strbuf, "rx_hdrfail %u badhdr %u badseq %u\n", bus->rx_hdrfail, bus->rx_badhdr, bus->rx_badseq); - bcm_bprintf(strbuf, "fc_rcvd %d, fc_xoff %d, fc_xon %d\n", + bcm_bprintf(strbuf, "fc_rcvd %u, fc_xoff %u, fc_xon %u\n", bus->fc_rcvd, bus->fc_xoff, bus->fc_xon); - bcm_bprintf(strbuf, "rxglomfail %d, rxglomframes %d, rxglompkts %d\n", + bcm_bprintf(strbuf, "rxglomfail %u, rxglomframes %u, rxglompkts %u\n", bus->rxglomfail, bus->rxglomframes, bus->rxglompkts); - bcm_bprintf(strbuf, "f2rx (hdrs/data) %d (%d/%d), f2tx %d f1regs %d\n", + bcm_bprintf(strbuf, "f2rx (hdrs/data) %u (%u/%u), f2tx %u f1regs %u\n", (bus->f2rxhdrs + bus->f2rxdata), bus->f2rxhdrs, bus->f2rxdata, bus->f2txdata, bus->f1regdata); { @@ -2475,17 +2880,17 @@ dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) #ifdef SDTEST if (bus->pktgen_count) { bcm_bprintf(strbuf, "pktgen config and count:\n"); - bcm_bprintf(strbuf, "freq %d count %d print %d total %d min %d len %d\n", + bcm_bprintf(strbuf, "freq %u count %u print %u total %u min %u len %u\n", bus->pktgen_freq, bus->pktgen_count, bus->pktgen_print, bus->pktgen_total, bus->pktgen_minlen, bus->pktgen_maxlen); - bcm_bprintf(strbuf, "send attempts %d rcvd %d fail %d\n", + bcm_bprintf(strbuf, "send attempts %u rcvd %u fail %u\n", bus->pktgen_sent, bus->pktgen_rcvd, bus->pktgen_fail); } #endif /* SDTEST */ #ifdef DHD_DEBUG bcm_bprintf(strbuf, "dpc_sched %d host interrupt%spending\n", bus->dpc_sched, (bcmsdh_intr_pending(bus->sdh) ? " " : " not ")); - bcm_bprintf(strbuf, "blocksize %d roundup %d\n", bus->blocksize, bus->roundup); + bcm_bprintf(strbuf, "blocksize %u roundup %u\n", bus->blocksize, bus->roundup); #endif /* DHD_DEBUG */ bcm_bprintf(strbuf, "clkstate %d activity %d idletime %d idlecount %d sleeping %d\n", bus->clkstate, bus->activity, bus->idletime, bus->idlecount, bus->sleeping); @@ -2794,6 +3199,9 @@ dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size) DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + if (DHD_NOCHECKDIED_ON()) + return 0; + if (data == NULL) { /* * Called after a rx ctrl timeout. "data" is NULL. @@ -3019,8 +3427,11 @@ dhd_serialconsole(dhd_bus_t *bus, bool set, bool enable, int *bcmerror) } if (bus->sih->chip == BCM4330_CHIP_ID) { uart_enab = CC_PLL_CHIPCTRL_SERIAL_ENAB; - } else if (bus->sih->chip == BCM4334_CHIP_ID || - bus->sih->chip == BCM43341_CHIP_ID) { + } + else if (bus->sih->chip == BCM4334_CHIP_ID || + bus->sih->chip == BCM43340_CHIP_ID || + bus->sih->chip == BCM43341_CHIP_ID || + 0) { if (enable) { /* Moved to PMU chipcontrol 1 from 4330 */ int_val &= ~gpio_sel; @@ -3067,7 +3478,7 @@ dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const ch int32 int_val = 0; bool bool_val = 0; - DHD_ERROR(("%s: Enter, action %d name %s params %p plen %d arg %p len %d val_size %d\n", + DHD_TRACE(("%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) @@ -3216,6 +3627,16 @@ dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const ch DHD_INFO(("%s: Request to %s %d bytes at address 0x%08x\n", __FUNCTION__, (set ? "write" : "read"), size, address)); + /* check if CR4 */ + if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { + /* + * If address is start of RAM (i.e. a downloaded image), + * store the reset instruction to be written in 0 + */ + if (address == bus->dongle_ram_base) { + bus->resetinstr = *(((uint32*)params) + 2); + } + } else { /* If we know about SOCRAM, check for a fit */ if ((bus->orig_ramsize) && ((address > bus->orig_ramsize) || (address + size > bus->orig_ramsize))) @@ -3257,6 +3678,7 @@ dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const ch break; } } + } /* Generate the actual data pointer */ data = set ? (uint8*)params + 2 * sizeof(int): (uint8*)arg; @@ -3267,11 +3689,16 @@ dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const ch break; } - case IOV_GVAL(IOV_MEMSIZE): + case IOV_GVAL(IOV_RAMSIZE): int_val = (int32)bus->ramsize; bcopy(&int_val, arg, val_size); break; + case IOV_GVAL(IOV_RAMSTART): + int_val = (int32)bus->dongle_ram_base; + bcopy(&int_val, arg, val_size); + break; + case IOV_GVAL(IOV_SDIOD_DRIVE): int_val = (int32)dhd_sdiod_drive_strength; bcopy(&int_val, arg, val_size); @@ -3509,7 +3936,7 @@ dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const ch case IOV_SVAL(IOV_MESBUSYCTRL): mesbusyctrl = (uint)int_val; mesbusyctrl = (mesbusyctrl > SBSDIO_MESBUSYCTRL_MASK) - ? SBSDIO_MESBUSYCTRL_MASK : mesbusyctrl; + ? SBSDIO_MESBUSYCTRL_MASK : mesbusyctrl; DHD_ERROR(("Setting mesbusyctrl as 0x%x.\n", mesbusyctrl)); bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL, ((uint8)mesbusyctrl | 0x80), NULL); @@ -3626,7 +4053,6 @@ dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const ch } break; #endif /* BCMSDIOH_TXGLOM */ - case IOV_SVAL(IOV_HANGREPORT): bus->dhd->hang_report = bool_val; DHD_ERROR(("%s: Set hang_report as %d\n", __FUNCTION__, bus->dhd->hang_report)); @@ -3636,8 +4062,6 @@ dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const ch int_val = (int32)bus->dhd->hang_report; bcopy(&int_val, arg, val_size); break; - - default: bcmerror = BCME_UNSUPPORTED; break; @@ -3758,6 +4182,8 @@ dhdsdio_download_state(dhd_bus_t *bus, bool enter) int bcmerror = 0; int foundcr4 = 0; + if (!bus->sih) + return BCME_ERROR; /* To enter download state, disable ARM and reset SOCRAM. * To exit download state, simply reset ARM (default is RAM boot). */ @@ -3769,45 +4195,47 @@ dhdsdio_download_state(dhd_bus_t *bus, bool enter) if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { foundcr4 = 1; } else { - DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__)); - bcmerror = BCME_ERROR; - goto fail; - } + DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__)); + bcmerror = BCME_ERROR; + goto fail; + } } if (!foundcr4) { - si_core_disable(bus->sih, 0); - if (bcmsdh_regfail(bus->sdh)) { - bcmerror = BCME_SDIO_ERROR; - goto fail; - } - - if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) { - DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__)); - bcmerror = BCME_ERROR; - goto fail; - } - - si_core_reset(bus->sih, 0, 0); - if (bcmsdh_regfail(bus->sdh)) { - DHD_ERROR(("%s: Failure trying reset SOCRAM core?\n", __FUNCTION__)); - bcmerror = BCME_SDIO_ERROR; - goto fail; - } + si_core_disable(bus->sih, 0); + if (bcmsdh_regfail(bus->sdh)) { + bcmerror = BCME_SDIO_ERROR; + goto fail; + } - /* Disable remap for download */ - if (REMAP_ENAB(bus) && si_socdevram_remap_isenb(bus->sih)) - dhdsdio_devram_remap(bus, FALSE); + if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) { + DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__)); + bcmerror = BCME_ERROR; + goto fail; + } - /* Clear the top bit of memory */ - if (bus->ramsize) { - uint32 zeros = 0; - if (dhdsdio_membytes(bus, TRUE, bus->ramsize - 4, (uint8*)&zeros, 4) < 0) { + si_core_reset(bus->sih, 0, 0); + if (bcmsdh_regfail(bus->sdh)) { + DHD_ERROR(("%s: Failure trying reset SOCRAM core?\n", + __FUNCTION__)); bcmerror = BCME_SDIO_ERROR; goto fail; } - } - } else { + + /* Disable remap for download */ + if (REMAP_ENAB(bus) && si_socdevram_remap_isenb(bus->sih)) + dhdsdio_devram_remap(bus, FALSE); + + /* Clear the top bit of memory */ + if (bus->ramsize) { + uint32 zeros = 0; + if (dhdsdio_membytes(bus, TRUE, bus->ramsize - 4, + (uint8*)&zeros, 4) < 0) { + bcmerror = BCME_SDIO_ERROR; + goto fail; + } + } + } else { /* For CR4, * Halt ARM * Remove ARM reset @@ -3821,44 +4249,44 @@ dhdsdio_download_state(dhd_bus_t *bus, bool enter) } } else { if (!si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { - if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) { - DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__)); - bcmerror = BCME_ERROR; - goto fail; - } + if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) { + DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__)); + bcmerror = BCME_ERROR; + goto fail; + } - if (!si_iscoreup(bus->sih)) { - DHD_ERROR(("%s: SOCRAM core is down after reset?\n", __FUNCTION__)); - bcmerror = BCME_ERROR; - goto fail; - } + if (!si_iscoreup(bus->sih)) { + DHD_ERROR(("%s: SOCRAM core is down after reset?\n", __FUNCTION__)); + bcmerror = BCME_ERROR; + goto fail; + } - if ((bcmerror = dhdsdio_write_vars(bus))) { - DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__)); - goto fail; - } + if ((bcmerror = dhdsdio_write_vars(bus))) { + DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__)); + goto fail; + } - /* Enable remap before ARM reset but after vars. - * No backplane access in remap mode - */ - if (REMAP_ENAB(bus) && !si_socdevram_remap_isenb(bus->sih)) - dhdsdio_devram_remap(bus, TRUE); + /* Enable remap before ARM reset but after vars. + * No backplane access in remap mode + */ + if (REMAP_ENAB(bus) && !si_socdevram_remap_isenb(bus->sih)) + dhdsdio_devram_remap(bus, TRUE); - if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) && - !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) { - DHD_ERROR(("%s: Can't change back to SDIO core?\n", __FUNCTION__)); - bcmerror = BCME_ERROR; - goto fail; - } - W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries); + if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) && + !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) { + DHD_ERROR(("%s: Can't change back to SDIO core?\n", __FUNCTION__)); + bcmerror = BCME_ERROR; + goto fail; + } + W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries); - if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) && - !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) { - DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__)); - bcmerror = BCME_ERROR; - goto fail; - } + if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) && + !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) { + DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__)); + bcmerror = BCME_ERROR; + goto fail; + } } else { /* cr4 has no socram, but tcm's */ /* write vars */ @@ -3975,6 +4403,10 @@ dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name, } else { DHD_INFO(("%s: noted %s update, value now %d\n", __FUNCTION__, "sd_blocksize", bus->blocksize)); + + if ((bus->sih->chip == BCM4335_CHIP_ID) || + (bus->sih->chip == BCM4339_CHIP_ID)) + dhd_overflow_war(bus); } } bus->roundup = MIN(max_roundup, bus->blocksize); @@ -4019,7 +4451,7 @@ dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex) { osl_t *osh; uint32 local_hostintmask; - uint8 saveclk, dat; + uint8 saveclk; uint retries; int err; if (!bus->dhd) @@ -4042,13 +4474,6 @@ dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex) BUS_WAKE(bus); - if (KSO_ENAB(bus)) { - /* Mask the interrupt */ - dat = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_INTEN, NULL); - dat &= ~(INTR_CTL_FUNC1_EN | INTR_CTL_FUNC2_EN); - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_INTEN, dat, NULL); - } - /* Change our idea of bus state */ bus->dhd->busstate = DHD_BUS_DOWN; @@ -4122,6 +4547,8 @@ dhd_txglom_enable(dhd_pub_t *dhdp, bool enable) uint32 rxglom; int32 ret; + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + if (enable) { rxglom = 1; memset(buf, 0, sizeof(buf)); @@ -4219,8 +4646,11 @@ dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex) mesbusyctrl = watermark = bus->blocksize / 4; } #endif /* SDIO_CRC_ERROR_FIX */ - - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, (uint8)watermark, &err); + if (!((bus->sih->chip == BCM4335_CHIP_ID) || + (bus->sih->chip == BCM4339_CHIP_ID))) { + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, + (uint8)watermark, &err); + } #ifdef SDIO_CRC_ERROR_FIX bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL, (uint8)mesbusyctrl|0x80, &err); @@ -4251,8 +4681,14 @@ dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex) bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL); } - if (dhdsdio_sr_cap(bus)) + if (dhdsdio_sr_cap(bus)) { dhdsdio_sr_init(bus); + /* Masking the chip active interrupt permanantly */ + bus->hostintmask &= ~I_CHIPACTIVE; + W_SDREG(bus->hostintmask, &bus->regs->hostintmask, retries); + DHD_INFO(("%s: disable I_CHIPACTIVE in hostintmask[0x%08x]\n", + __FUNCTION__, bus->hostintmask)); + } else bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err); @@ -4291,12 +4727,21 @@ dhdsdio_rxfail(dhd_bus_t *bus, bool abort, bool rtx) } bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, SFC_RF_TERM, &err); + if (err) { + DHD_ERROR(("%s: SBSDIO_FUNC1_FRAMECTRL cmd err\n", __FUNCTION__)); + goto fail; + } bus->f1regdata++; /* Wait until the packet has been flushed (device/FIFO stable) */ for (lastrbc = retries = 0xffff; retries > 0; retries--) { hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCHI, NULL); - lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCLO, NULL); + lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCLO, &err); + if (err) { + DHD_ERROR(("%s: SBSDIO_FUNC1_RFAMEBCLO cmd err\n", __FUNCTION__)); + goto fail; + } + bus->f1regdata += 2; if ((hi == 0) && (lo == 0)) @@ -4327,6 +4772,7 @@ dhdsdio_rxfail(dhd_bus_t *bus, bool abort, bool rtx) /* Clear partial in any case */ bus->nextlen = 0; +fail: /* If we can't reach the device, signal failure */ if (err || bcmsdh_regfail(sdh)) bus->dhd->busstate = DHD_BUS_DOWN; @@ -4431,6 +4877,9 @@ done: /* Awake any waiters */ dhd_os_ioctl_resp_wake(bus->dhd); } +int +dhd_process_pkt_reorder_info(dhd_pub_t *dhd, uchar *reorder_info_buf, uint reorder_info_len, + void **pkt, uint32 *pkt_count); static uint8 dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq) @@ -4801,14 +5250,11 @@ dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq) temp = PKTNEXT(osh, temp); } pfirst = temp; - if (list_tail[ifidx] == NULL) { + if (list_tail[ifidx] == NULL) list_head[ifidx] = ppfirst; - list_tail[ifidx] = pfirst; - } - else { + else PKTSETNEXT(osh, list_tail[ifidx], ppfirst); - list_tail[ifidx] = pfirst; - } + list_tail[ifidx] = pfirst; } num += (uint8)free_buf_count; @@ -4922,7 +5368,9 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) #ifdef DHDTHREAD /* tx more to improve rx performance */ - if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate && + if (TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL)) { + dhdsdio_sendpendctl(bus); + } else if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate && pktq_mlen(&bus->txq, ~bus->flowcontrol) && DATAOK(bus)) { dhdsdio_sendfromq(bus, dhd_txbound); } @@ -5448,7 +5896,6 @@ deliver: else pkt_count = 1; - /* Unlock during rx call */ dhd_os_sdunlock(bus->dhd); dhd_rx_frame(bus->dhd, ifidx, pkt, pkt_count, chan); @@ -5589,20 +6036,21 @@ dhdsdio_dpc(dhd_bus_t *bus) uint framecnt = 0; /* Temporary counter of tx/rx frames */ bool rxdone = TRUE; /* Flag for no more read data */ bool resched = FALSE; /* Flag indicating resched wanted */ - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + dhd_os_sdlock(bus->dhd); + if (bus->dhd->busstate == DHD_BUS_DOWN) { DHD_ERROR(("%s: Bus down, ret\n", __FUNCTION__)); bus->intstatus = 0; + dhd_os_sdunlock(bus->dhd); + return 0; } /* Start with leftover status bits */ intstatus = bus->intstatus; - dhd_os_sdlock(bus->dhd); - if (!SLPAUTO_ENAB(bus) && !KSO_ENAB(bus)) { DHD_ERROR(("%s: Device asleep\n", __FUNCTION__)); goto exit; @@ -5776,57 +6224,14 @@ clkwait: resched = TRUE; } #endif /* defined(OOB_INTR_ONLY) && !defined(HW_OOB) */ + #ifdef PROP_TXSTATUS dhd_wlfc_trigger_pktcommit(bus->dhd); #endif - if (TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL)) { - int ret, i; - - uint8* frame_seq = bus->ctrl_frame_buf + SDPCM_FRAMETAG_LEN; - - if (*frame_seq != bus->tx_seq) { - DHD_INFO(("%s IOCTL frame seq lag detected!" - " frm_seq:%d != bus->tx_seq:%d, corrected\n", - __FUNCTION__, *frame_seq, bus->tx_seq)); - *frame_seq = bus->tx_seq; - } - - ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, - (uint8 *)bus->ctrl_frame_buf, (uint32)bus->ctrl_frame_len, - NULL, NULL, NULL); - ASSERT(ret != BCME_PENDING); - if (ret == BCME_NODEVICE) { - DHD_ERROR(("%s: Device asleep already\n", __FUNCTION__)); - } else if (ret < 0) { - /* On failure, abort the command and terminate the frame */ - DHD_INFO(("%s: sdio error %d, abort command and terminate frame.\n", - __FUNCTION__, ret)); - bus->tx_sderrs++; - bcmsdh_abort(sdh, SDIO_FUNC_2); + if (TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL)) + dhdsdio_sendpendctl(bus); - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, - SFC_WF_TERM, NULL); - bus->f1regdata++; - - for (i = 0; i < 3; i++) { - uint8 hi, lo; - hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, - SBSDIO_FUNC1_WFRAMEBCHI, NULL); - lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, - SBSDIO_FUNC1_WFRAMEBCLO, NULL); - bus->f1regdata += 2; - if ((hi == 0) && (lo == 0)) - break; - } - } - if (ret == 0) { - bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; - } - - bus->ctrl_frame_stat = FALSE; - dhd_wait_event_wakeup(bus->dhd); - } /* Send queued frames (limit 1 if rx may still be pending) */ else if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate && pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit && DATAOK(bus)) { @@ -5869,11 +6274,13 @@ clkwait: } exit: - /* attemp to update tx credit before exiting dpc */ + if (!resched && dhd_dpcpoll) { - if (dhdsdio_readframes(bus, dhd_rxbound, &rxdone) != 0) + if (dhdsdio_readframes(bus, dhd_rxbound, &rxdone) != 0) { resched = TRUE; + } } + dhd_os_sdunlock(bus->dhd); return resched; } @@ -5938,7 +6345,7 @@ dhdsdio_isr(void *arg) #if defined(SDIO_ISR_THREAD) DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__)); DHD_OS_WAKE_LOCK(bus->dhd); - while (dhdsdio_dpc(bus)); + dhdsdio_dpc(bus); DHD_OS_WAKE_UNLOCK(bus->dhd); #else @@ -5965,7 +6372,7 @@ dhdsdio_pktgen_init(dhd_bus_t *bus) /* Default to per-watchdog burst with 10s print time */ bus->pktgen_freq = 1; - bus->pktgen_print = dhd_watchdog_ms ? (10000/dhd_watchdog_ms):0; + bus->pktgen_print = dhd_watchdog_ms ? (10000 / dhd_watchdog_ms) : 0; bus->pktgen_count = (dhd_pktgen * dhd_watchdog_ms + 999) / 1000; /* Default to echo mode */ @@ -6352,7 +6759,6 @@ dhd_bus_watchdog(dhd_pub_t *dhdp) if ((bus->idletime > 0) && (bus->idlecount >= bus->idletime)) { DHD_TIMER(("%s: DHD Idle state!!\n", __FUNCTION__)); - if (SLPAUTO_ENAB(bus)) { if (dhdsdio_bussleep(bus, TRUE) != BCME_BUSY) dhd_os_wd_timer(bus->dhd, 0); @@ -6364,7 +6770,7 @@ dhd_bus_watchdog(dhd_pub_t *dhdp) } #else if ((bus->idletime > 0) && (bus->clkstate == CLK_AVAIL)) { - if (++bus->idlecount > bus->idletime) { + if (++bus->idlecount >= bus->idletime) { bus->idlecount = 0; if (bus->activity) { bus->activity = FALSE; @@ -6497,16 +6903,28 @@ dhdsdio_chipmatch(uint16 chipid) return TRUE; if (chipid == BCM4314_CHIP_ID) return TRUE; - if (chipid == BCM4334_CHIP_ID) + if (chipid == BCM43242_CHIP_ID) + return TRUE; + if (chipid == BCM43340_CHIP_ID) return TRUE; if (chipid == BCM43341_CHIP_ID) return TRUE; + if (chipid == BCM43143_CHIP_ID) + return TRUE; + if (chipid == BCM43342_CHIP_ID) + return TRUE; + if (chipid == BCM4334_CHIP_ID) + return TRUE; if (chipid == BCM43239_CHIP_ID) return TRUE; if (chipid == BCM4324_CHIP_ID) return TRUE; if (chipid == BCM4335_CHIP_ID) return TRUE; + if (chipid == BCM4339_CHIP_ID) + return TRUE; + if (chipid == BCM4350_CHIP_ID) + return TRUE; return FALSE; } @@ -6520,16 +6938,6 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot, struct ether_addr ea_addr; #endif /* GET_CUSTOM_MAC_ENABLE */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - - if (mutex_is_locked(&_dhd_sdio_mutex_lock_) == 0) { - DHD_ERROR(("%s : no mutex held. set lock\n", __FUNCTION__)); - } - else { - DHD_ERROR(("%s : mutex is locked!. wait for unlocking\n", __FUNCTION__)); - } - mutex_lock(&_dhd_sdio_mutex_lock_); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */ /* Init global variables at run-time, not as part of the declaration. * This is required to support init/de-init of the driver. Initialization @@ -6544,7 +6952,7 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot, dhd_readahead = TRUE; retrydata = FALSE; dhd_doflow = FALSE; - dhd_dongle_memsize = 0; + dhd_dongle_ramsize = 0; dhd_txminmax = DHD_TXMINMAX; forcealign = TRUE; @@ -6583,12 +6991,6 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot, case 0x4329: DHD_INFO(("%s: found 4329 Dongle\n", __FUNCTION__)); break; - case 0x4324: - DHD_INFO(("%s: found 43241(4324) Dongle\n", __func__)); - break; - case 0xa94d: - DHD_INFO(("%s: found 43341 Dongle\n", __func__)); - break; case BCM4315_D11DUAL_ID: /* 4315 802.11a/g id */ case BCM4315_D11G_ID: /* 4315 802.11g id */ case BCM4315_D11A_ID: /* 4315 802.11a id */ @@ -6697,10 +7099,6 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot, } -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - mutex_unlock(&_dhd_sdio_mutex_lock_); - DHD_ERROR(("%s : the lock is released.\n", __FUNCTION__)); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ return bus; @@ -6708,10 +7106,6 @@ fail: dhdsdio_release(bus, osh); forcereturn: -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - mutex_unlock(&_dhd_sdio_mutex_lock_); - DHD_ERROR(("%s : the lock is released.\n", __FUNCTION__)); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ return NULL; } @@ -6731,12 +7125,6 @@ dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva, DHD_ERROR(("%s: FAILED to return to SI_ENUM_BASE\n", __FUNCTION__)); } -#ifdef DHD_DEBUG - DHD_ERROR(("F1 signature read @0x18000000=0x%4x\n", - bcmsdh_reg_read(bus->sdh, SI_ENUM_BASE, 4))); - -#endif /* DHD_DEBUG */ - /* Force PLL off until si_attach() programs PLL control regs */ @@ -6805,6 +7193,14 @@ dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva, goto fail; } + +#ifdef DHD_DEBUG + DHD_ERROR(("F1 signature OK, socitype:0x%x chip:0x%4x rev:0x%x pkg:0x%x\n", + bus->sih->socitype, bus->sih->chip, bus->sih->chiprev, + bus->sih->chippkg)); +#endif /* DHD_DEBUG */ + + bcmsdh_chipinfo(sdh, bus->sih->chip, bus->sih->chiprev); if (!dhdsdio_chipmatch((uint16)bus->sih->chip)) { @@ -6836,10 +7232,10 @@ dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva, } if (!si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { - if (!(bus->orig_ramsize = si_socram_size(bus->sih))) { - DHD_ERROR(("%s: failed to find SOCRAM memory!\n", __FUNCTION__)); - goto fail; - } + if (!(bus->orig_ramsize = si_socram_size(bus->sih))) { + DHD_ERROR(("%s: failed to find SOCRAM memory!\n", __FUNCTION__)); + goto fail; + } } else { /* cr4 has a different way to find the RAM size from TCM's */ if (!(bus->orig_ramsize = si_tcm_size(bus->sih))) { @@ -6847,14 +7243,29 @@ dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva, goto fail; } /* also populate base address */ - bus->dongle_ram_base = CR4_RAM_BASE; + switch ((uint16)bus->sih->chip) { + case BCM4335_CHIP_ID: + case BCM4339_CHIP_ID: + bus->dongle_ram_base = CR4_4335_RAM_BASE; + break; + case BCM4350_CHIP_ID: + bus->dongle_ram_base = CR4_4350_RAM_BASE; + break; + case BCM4360_CHIP_ID: + bus->dongle_ram_base = CR4_4360_RAM_BASE; + break; + default: + bus->dongle_ram_base = 0; + DHD_ERROR(("%s: WARNING: Using default ram base at 0x%x\n", + __FUNCTION__, bus->dongle_ram_base)); + } } bus->ramsize = bus->orig_ramsize; - if (dhd_dongle_memsize) - dhd_dongle_setmemsize(bus, dhd_dongle_memsize); + if (dhd_dongle_ramsize) + dhd_dongle_setramsize(bus, dhd_dongle_ramsize); - DHD_ERROR(("DHD: dongle ram size is set to %d(orig %d)\n", - bus->ramsize, bus->orig_ramsize)); + DHD_ERROR(("DHD: dongle ram size is set to %d(orig %d) at 0x%x\n", + bus->ramsize, bus->orig_ramsize, bus->dongle_ram_base)); bus->srmemsize = si_socram_srmem_size(bus->sih); } @@ -6895,7 +7306,7 @@ dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva, #ifdef BCMSDIOH_TXGLOM /* Setting default Glom mode */ - bus->glom_mode = SDPCM_TXGLOM_CPY; + bus->glom_mode = bcmsdh_set_mode(bus->sdh, SDPCM_DEFGLOM_MODE); /* Setting default Glom size */ bus->glomsize = SDPCM_DEFGLOM_SIZE; #endif @@ -7001,6 +7412,10 @@ dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh) } else { DHD_INFO(("%s: Initial value for %s is %d\n", __FUNCTION__, "sd_blocksize", bus->blocksize)); + + if ((bus->sih->chip == BCM4335_CHIP_ID) || + (bus->sih->chip == BCM4339_CHIP_ID)) + dhd_overflow_war(bus); } bus->roundup = MIN(max_roundup, bus->blocksize); @@ -7156,28 +7571,16 @@ dhdsdio_disconnect(void *ptr) { dhd_bus_t *bus = (dhd_bus_t *)ptr; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - if (mutex_is_locked(&_dhd_sdio_mutex_lock_) == 0) { - DHD_ERROR(("%s : no mutex held. set lock\n", __FUNCTION__)); - } - else { - DHD_ERROR(("%s : mutex is locked!. wait for unlocking\n", __FUNCTION__)); - } - mutex_lock(&_dhd_sdio_mutex_lock_); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */ - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); if (bus) { ASSERT(bus->dhd); dhdsdio_release(bus, bus->dhd->osh); } -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - mutex_unlock(&_dhd_sdio_mutex_lock_); - DHD_ERROR(("%s : the lock is released.\n", __FUNCTION__)); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */ + DHD_TRACE(("%s: Disconnected\n", __FUNCTION__)); } @@ -7234,6 +7637,17 @@ dhdsdio_download_code_array(struct dhd_bus *bus) /* Download image */ while ((offset + MEMBLOCK) < sizeof(dlarray)) { + /* check if CR4 */ + if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { + /* if address is 0, store the reset instruction to be written in 0 */ + + if (offset == 0) { + bus->resetinstr = *(((uint32*)dlarray)); + /* Add start of RAM address to the address given by user */ + offset += bus->dongle_ram_base; + } + } + bcmerror = dhdsdio_membytes(bus, TRUE, offset, (uint8 *) (dlarray + offset), MEMBLOCK); if (bcmerror) { @@ -7331,6 +7745,17 @@ dhdsdio_download_code_file(struct dhd_bus *bus, char *pfw_path) bcmerror = BCME_ERROR; goto err; } + /* check if CR4 */ + if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { + /* if address is 0, store the reset instruction to be written in 0 */ + + if (offset == 0) { + bus->resetinstr = *(((uint32*)memptr)); + /* Add start of RAM address to the address given by user */ + offset += bus->dongle_ram_base; + } + } + bcmerror = dhdsdio_membytes(bus, TRUE, offset, memptr, len); if (bcmerror) { DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n", @@ -7446,7 +7871,6 @@ static int _dhdsdio_download_firmware(struct dhd_bus *bus) { int bcmerror = -1; - char *p; bool embed = FALSE; /* download embedded firmware */ bool dlok = FALSE; /* download firmware succeeded */ @@ -7460,6 +7884,58 @@ _dhdsdio_download_firmware(struct dhd_bus *bus) #endif } +#ifdef NV_BCM943341_WBFGN_MULTI_MODULE_SUPPORT + if (dhd_bus_chip_id(bus->dhd) == BCM43341_CHIP_ID) { + int boardrev = dhdsdio_boardrev_bcm943341wbfgn(bus); + char *ptr = strstr(bus->nv_path, "nvram"); + DHD_ERROR(("nvram path: %s\n", ptr)); + if (ptr) { + switch (boardrev) { + case BCM943341_WBFGN_2: + strcpy(ptr, "nvram.txt"); + break; + case BCM943341_WBFGN_3: + strcpy(ptr, "nvram_43341_rev3.txt"); + break; + case BCM943341_WBFGN_4: + strcpy(ptr, "nvram_43341_rev4.txt"); + break; + default: + DHD_ERROR(("%s:Unknown bcm943341_wbfgn board\n", + __func__)); + break; + } + } else { + DHD_ERROR(("%s: Invalid nv_path for bcm943341\n", + __func__)); + goto err; + } + + if (strstr(bus->fw_path, "fw_bcmdhd_apsta")) { /* HOTSPOT mode */ + char *ptr_fw = strstr(bus->fw_path, "fw_bcmdhd_apsta"); + if (boardrev == BCM943341_WBFGN_2 + || boardrev == BCM943341_WBFGN_3) { + strcpy(ptr_fw, "fw_bcmdhd_apsta_a0.bin"); + } + } else if (strstr(bus->fw_path, "fw_bcmdhd")) { /* STATION mode */ + char *ptr_fw = strstr(bus->fw_path, "fw_bcmdhd"); + if (boardrev == BCM943341_WBFGN_2 + || boardrev == BCM943341_WBFGN_3) { + strcpy(ptr_fw, "fw_bcmdhd_a0.bin"); + } + } else { + DHD_ERROR(("%s: Invalid fw_path for bcm943341: %s\n", + __func__, bus->fw_path)); + goto err; + } + + DHD_ERROR(("%s: Modified nv_path for bcm943341_wbfgn_x: %s\n", + __func__, bus->nv_path)); + DHD_ERROR(("%s: Modified fw_path for bcm943341_wbfgn_x: %s\n", + __func__, bus->fw_path)); + } +#endif /* NV_BCM943341_WBFGN_MULTI_MODULE_SUPPORT */ + /* Keep arm in reset */ if (dhdsdio_download_state(bus, TRUE)) { DHD_ERROR(("%s: error placing ARM core in reset\n", __FUNCTION__)); @@ -7481,6 +7957,7 @@ _dhdsdio_download_firmware(struct dhd_bus *bus) dlok = TRUE; } } + #ifdef BCMEMBEDIMAGE if (embed) { if (dhdsdio_download_code_array(bus)) { @@ -7551,9 +8028,9 @@ dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf #ifdef BCMSDIOH_TXGLOM static void -dhd_bcmsdh_glom_post(dhd_bus_t *bus, uint8 *frame, uint len) +dhd_bcmsdh_glom_post(dhd_bus_t *bus, uint8 *frame, void *pkt, uint len) { - bcmsdh_glom_post(bus->sdh, frame, len); + bcmsdh_glom_post(bus->sdh, frame, pkt, len); } static void @@ -7604,12 +8081,6 @@ dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag) /* Force flow control as protection when stop come before ifconfig_down */ dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON); #endif /* !defined(IGNORE_ETH0_DOWN) */ - -#if !defined(OOB_INTR_ONLY) - /* to avoid supurious client interrupt during stop process */ - bcmsdh_stop(bus->sdh); -#endif /* !defined(OOB_INTR_ONLY) */ - /* Expect app to have torn down any connection before calling */ /* Stop the bus, disable F2 */ dhd_bus_stop(bus, FALSE); @@ -7658,6 +8129,7 @@ dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag) bcmerror = dhd_bus_init((dhd_pub_t *) bus->dhd, FALSE); if (bcmerror == BCME_OK) { #if defined(OOB_INTR_ONLY) + /* make sure oob intr get registered */ if (!bcmsdh_is_oob_intr_registered()) { sdioh_start(NULL, 1); bcmsdh_register_oob_intr(dhdp); @@ -7676,12 +8148,7 @@ dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag) dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF); #endif dhd_os_wd_timer(dhdp, dhd_watchdog_ms); -#ifdef BCMSDIOH_TXGLOM - if ((dhdp->busstate == DHD_BUS_DATA) && - bcmsdh_glom_enabled()) { - dhd_txglom_enable(dhdp, TRUE); - } -#endif /* BCMSDIOH_TXGLOM */ + DHD_TRACE(("%s: WLAN ON DONE\n", __FUNCTION__)); } else { dhd_bus_stop(bus, FALSE); @@ -7733,7 +8200,6 @@ uint dhd_bus_chippkg_id(dhd_pub_t *dhdp) return bus->sih->chippkg; } - int dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint size) { @@ -7743,26 +8209,67 @@ dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint si return dhdsdio_membytes(bus, set, address, data, size); } -#ifdef SYSFS_IDLETIME -int32 dhd_get_bus_idletime(dhd_pub_t *dhdp) +int +dhd_enableOOB(dhd_pub_t *dhd, bool sleep) { - dhd_bus_t *bus = dhdp->bus; + dhd_bus_t *bus = dhd->bus; + sdpcmd_regs_t *regs = bus->regs; + uint retries = 0; + + if (sleep) { + dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); + /* Tell device to start using OOB wakeup */ + W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries); + if (retries > retry_limit) { + DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n")); + return BCME_BUSY; + } + /* Turn off our contribution to the HT clock request */ + dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); + } else { + /* Make sure the controller has the bus up */ + dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); + + /* Send misc interrupt to indicate OOB not needed */ + W_SDREG(0, ®s->tosbmailboxdata, retries); + if (retries <= retry_limit) + W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries); - return bus->idletime; + if (retries > retry_limit) + DHD_ERROR(("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n")); + + /* Make sure we have SD bus access */ + dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); + } + return BCME_OK; } -int32 dhd_set_bus_idletime(dhd_pub_t *dhdp, int32 idletime) +void +dhd_bus_pktq_flush(dhd_pub_t *dhdp) { dhd_bus_t *bus = dhdp->bus; + /* Clear the data packet queues */ + pktq_flush(dhdp->osh, &bus->txq, TRUE, NULL, 0); +} - bus->idletime = idletime; +int +dhd_sr_config(dhd_pub_t *dhd, bool on) +{ + dhd_bus_t *bus = dhd->bus; - if (dhdp->busstate != DHD_BUS_DOWN && idletime == 0) { - dhd_os_sdlock(dhdp); - BUS_WAKE(bus); - dhd_os_sdunlock(dhdp); - } + if (!bus->_srenab) + return -1; - return 0; + return dhdsdio_clk_devsleep_iovar(bus, on); +} + +uint16 +dhd_get_chipid(dhd_pub_t *dhd) +{ + dhd_bus_t *bus = dhd->bus; + + if (bus && bus->sih) + return (uint16)bus->sih->chip; + else + return 0; } -#endif /* SYSFS_IDLETIME */ diff --git a/drivers/net/wireless/bcmdhd/dhd_wlfc.c b/drivers/net/wireless/bcmdhd/dhd_wlfc.c new file mode 100755 index 000000000000..4fe4aa736b71 --- /dev/null +++ b/drivers/net/wireless/bcmdhd/dhd_wlfc.c @@ -0,0 +1,2452 @@ +/* + * DHD PROP_TXSTATUS Module. + * + * Copyright (C) 1999-2013, 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_wlfc.c 412994 2013-07-17 12:38:03Z $ + * + */ + +#include <typedefs.h> +#include <osl.h> + +#include <bcmutils.h> +#include <bcmendian.h> + +#include <dngl_stats.h> +#include <dhd.h> + +#include <dhd_bus.h> +#include <dhd_dbg.h> + +#ifdef PROP_TXSTATUS +#include <wlfc_proto.h> +#include <dhd_wlfc.h> +#endif + + + + +#define BUS_RETRIES 1 /* # of retries before aborting a bus tx operation */ + +#ifdef PROP_TXSTATUS +typedef struct dhd_wlfc_commit_info { + uint8 needs_hdr; + uint8 ac_fifo_credit_spent; + ewlfc_packet_state_t pkt_type; + wlfc_mac_descriptor_t* mac_entry; + void* p; +} dhd_wlfc_commit_info_t; +#endif /* PROP_TXSTATUS */ + + +#ifdef PROP_TXSTATUS + +#ifdef QMONITOR +#define DHD_WLFC_QMON_COMPLETE(entry) dhd_qmon_txcomplete(&entry->qmon) +#else +#define DHD_WLFC_QMON_COMPLETE(entry) +#endif /* QMONITOR */ + +void +dhd_wlfc_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) +{ + int i; + uint8* ea; + athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) + dhdp->wlfc_state; + wlfc_hanger_t* h; + wlfc_mac_descriptor_t* mac_table; + wlfc_mac_descriptor_t* interfaces; + char* iftypes[] = {"STA", "AP", "WDS", "p2pGO", "p2pCL"}; + + if (wlfc == NULL) { + bcm_bprintf(strbuf, "wlfc not initialized yet\n"); + return; + } + h = (wlfc_hanger_t*)wlfc->hanger; + if (h == NULL) { + bcm_bprintf(strbuf, "wlfc-hanger not initialized yet\n"); + } + + mac_table = wlfc->destination_entries.nodes; + interfaces = wlfc->destination_entries.interfaces; + bcm_bprintf(strbuf, "---- wlfc stats ----\n"); + if (h) { + bcm_bprintf(strbuf, "wlfc hanger (pushed,popped,f_push," + "f_pop,f_slot, pending) = (%d,%d,%d,%d,%d,%d)\n", + h->pushed, + h->popped, + h->failed_to_push, + h->failed_to_pop, + h->failed_slotfind, + (h->pushed - h->popped)); + } + + bcm_bprintf(strbuf, "wlfc fail(tlv,credit_rqst,mac_update,psmode_update), " + "(dq_full,rollback_fail) = (%d,%d,%d,%d), (%d,%d)\n", + wlfc->stats.tlv_parse_failed, + wlfc->stats.credit_request_failed, + wlfc->stats.mac_update_failed, + wlfc->stats.psmode_update_failed, + wlfc->stats.delayq_full_error, + wlfc->stats.rollback_failed); + + bcm_bprintf(strbuf, "PKTS (credit,sent) " + "(AC0[%d,%d],AC1[%d,%d],AC2[%d,%d],AC3[%d,%d],BC_MC[%d,%d])\n", + wlfc->FIFO_credit[0], wlfc->stats.send_pkts[0], + wlfc->FIFO_credit[1], wlfc->stats.send_pkts[1], + wlfc->FIFO_credit[2], wlfc->stats.send_pkts[2], + wlfc->FIFO_credit[3], wlfc->stats.send_pkts[3], + wlfc->FIFO_credit[4], wlfc->stats.send_pkts[4]); + + bcm_bprintf(strbuf, "\n"); + for (i = 0; i < WLFC_MAX_IFNUM; i++) { + if (interfaces[i].occupied) { + char* iftype_desc; + + if (interfaces[i].iftype > WLC_E_IF_ROLE_P2P_CLIENT) + iftype_desc = "<Unknown"; + else + iftype_desc = iftypes[interfaces[i].iftype]; + + ea = interfaces[i].ea; + bcm_bprintf(strbuf, "INTERFACE[%d].ea = " + "[%02x:%02x:%02x:%02x:%02x:%02x], if:%d, type: %s" + "netif_flow_control:%s\n", i, + ea[0], ea[1], ea[2], ea[3], ea[4], ea[5], + interfaces[i].interface_id, + iftype_desc, ((wlfc->hostif_flow_state[i] == OFF) + ? " OFF":" ON")); + + bcm_bprintf(strbuf, "INTERFACE[%d].DELAYQ(len,state,credit)" + "= (%d,%s,%d)\n", + i, + interfaces[i].psq.len, + ((interfaces[i].state == + WLFC_STATE_OPEN) ? " OPEN":"CLOSE"), + interfaces[i].requested_credit); + + bcm_bprintf(strbuf, "INTERFACE[%d].DELAYQ" + "(sup,ac0),(sup,ac1),(sup,ac2),(sup,ac3) = " + "(%d,%d),(%d,%d),(%d,%d),(%d,%d)\n", + i, + interfaces[i].psq.q[0].len, + interfaces[i].psq.q[1].len, + interfaces[i].psq.q[2].len, + interfaces[i].psq.q[3].len, + interfaces[i].psq.q[4].len, + interfaces[i].psq.q[5].len, + interfaces[i].psq.q[6].len, + interfaces[i].psq.q[7].len); + } + } + + bcm_bprintf(strbuf, "\n"); + for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { + if (mac_table[i].occupied) { + ea = mac_table[i].ea; + bcm_bprintf(strbuf, "MAC_table[%d].ea = " + "[%02x:%02x:%02x:%02x:%02x:%02x], if:%d \n", i, + ea[0], ea[1], ea[2], ea[3], ea[4], ea[5], + mac_table[i].interface_id); + + bcm_bprintf(strbuf, "MAC_table[%d].DELAYQ(len,state,credit)" + "= (%d,%s,%d)\n", + i, + mac_table[i].psq.len, + ((mac_table[i].state == + WLFC_STATE_OPEN) ? " OPEN":"CLOSE"), + mac_table[i].requested_credit); +#ifdef PROP_TXSTATUS_DEBUG + bcm_bprintf(strbuf, "MAC_table[%d]: (opened, closed) = (%d, %d)\n", + i, mac_table[i].opened_ct, mac_table[i].closed_ct); +#endif + bcm_bprintf(strbuf, "MAC_table[%d].DELAYQ" + "(sup,ac0),(sup,ac1),(sup,ac2),(sup,ac3) = " + "(%d,%d),(%d,%d),(%d,%d),(%d,%d)\n", + i, + mac_table[i].psq.q[0].len, + mac_table[i].psq.q[1].len, + mac_table[i].psq.q[2].len, + mac_table[i].psq.q[3].len, + mac_table[i].psq.q[4].len, + mac_table[i].psq.q[5].len, + mac_table[i].psq.q[6].len, + mac_table[i].psq.q[7].len); + } + } + +#ifdef PROP_TXSTATUS_DEBUG + { + int avg; + int moving_avg = 0; + int moving_samples; + + if (wlfc->stats.latency_sample_count) { + moving_samples = sizeof(wlfc->stats.deltas)/sizeof(uint32); + + for (i = 0; i < moving_samples; i++) + moving_avg += wlfc->stats.deltas[i]; + moving_avg /= moving_samples; + + avg = (100 * wlfc->stats.total_status_latency) / + wlfc->stats.latency_sample_count; + bcm_bprintf(strbuf, "txstatus latency (average, last, moving[%d]) = " + "(%d.%d, %03d, %03d)\n", + moving_samples, avg/100, (avg - (avg/100)*100), + wlfc->stats.latency_most_recent, + moving_avg); + } + } + + bcm_bprintf(strbuf, "wlfc- fifo[0-5] credit stats: sent = (%d,%d,%d,%d,%d,%d), " + "back = (%d,%d,%d,%d,%d,%d)\n", + wlfc->stats.fifo_credits_sent[0], + wlfc->stats.fifo_credits_sent[1], + wlfc->stats.fifo_credits_sent[2], + wlfc->stats.fifo_credits_sent[3], + wlfc->stats.fifo_credits_sent[4], + wlfc->stats.fifo_credits_sent[5], + + wlfc->stats.fifo_credits_back[0], + wlfc->stats.fifo_credits_back[1], + wlfc->stats.fifo_credits_back[2], + wlfc->stats.fifo_credits_back[3], + wlfc->stats.fifo_credits_back[4], + wlfc->stats.fifo_credits_back[5]); + { + uint32 fifo_cr_sent = 0; + uint32 fifo_cr_acked = 0; + uint32 request_cr_sent = 0; + uint32 request_cr_ack = 0; + uint32 bc_mc_cr_ack = 0; + + for (i = 0; i < sizeof(wlfc->stats.fifo_credits_sent)/sizeof(uint32); i++) { + fifo_cr_sent += wlfc->stats.fifo_credits_sent[i]; + } + + for (i = 0; i < sizeof(wlfc->stats.fifo_credits_back)/sizeof(uint32); i++) { + fifo_cr_acked += wlfc->stats.fifo_credits_back[i]; + } + + for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { + if (wlfc->destination_entries.nodes[i].occupied) { + request_cr_sent += + wlfc->destination_entries.nodes[i].dstncredit_sent_packets; + } + } + for (i = 0; i < WLFC_MAX_IFNUM; i++) { + if (wlfc->destination_entries.interfaces[i].occupied) { + request_cr_sent += + wlfc->destination_entries.interfaces[i].dstncredit_sent_packets; + } + } + for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { + if (wlfc->destination_entries.nodes[i].occupied) { + request_cr_ack += + wlfc->destination_entries.nodes[i].dstncredit_acks; + } + } + for (i = 0; i < WLFC_MAX_IFNUM; i++) { + if (wlfc->destination_entries.interfaces[i].occupied) { + request_cr_ack += + wlfc->destination_entries.interfaces[i].dstncredit_acks; + } + } + bcm_bprintf(strbuf, "wlfc- (sent, status) => pq(%d,%d), vq(%d,%d)," + "other:%d, bc_mc:%d, signal-only, (sent,freed): (%d,%d)", + fifo_cr_sent, fifo_cr_acked, + request_cr_sent, request_cr_ack, + wlfc->destination_entries.other.dstncredit_acks, + bc_mc_cr_ack, + wlfc->stats.signal_only_pkts_sent, wlfc->stats.signal_only_pkts_freed); + } +#endif /* PROP_TXSTATUS_DEBUG */ + bcm_bprintf(strbuf, "\n"); + bcm_bprintf(strbuf, "wlfc- pkt((in,2bus,txstats,hdrpull),(dropped,hdr_only,wlc_tossed)" + "(freed,free_err,rollback)) = " + "((%d,%d,%d,%d),(%d,%d,%d),(%d,%d,%d))\n", + wlfc->stats.pktin, + wlfc->stats.pkt2bus, + wlfc->stats.txstatus_in, + wlfc->stats.dhd_hdrpulls, + + wlfc->stats.pktdropped, + wlfc->stats.wlfc_header_only_pkt, + wlfc->stats.wlc_tossed_pkts, + + wlfc->stats.pkt_freed, + wlfc->stats.pkt_free_err, wlfc->stats.rollback); + + bcm_bprintf(strbuf, "wlfc- suppress((d11,wlc,err),enq(d11,wl,hq,mac?),retx(d11,wlc,hq)) = " + "((%d,%d,%d),(%d,%d,%d,%d),(%d,%d,%d))\n", + + wlfc->stats.d11_suppress, + wlfc->stats.wl_suppress, + wlfc->stats.bad_suppress, + + wlfc->stats.psq_d11sup_enq, + wlfc->stats.psq_wlsup_enq, + wlfc->stats.psq_hostq_enq, + wlfc->stats.mac_handle_notfound, + + wlfc->stats.psq_d11sup_retx, + wlfc->stats.psq_wlsup_retx, + wlfc->stats.psq_hostq_retx); + bcm_bprintf(strbuf, "wlfc- generic error: %d", wlfc->stats.generic_error); + + return; +} + +/* Create a place to store all packet pointers submitted to the firmware until + a status comes back, suppress or otherwise. + + hang-er: noun, a contrivance on which things are hung, as a hook. +*/ +static void* +dhd_wlfc_hanger_create(osl_t *osh, int max_items) +{ + int i; + wlfc_hanger_t* hanger; + + /* allow only up to a specific size for now */ + ASSERT(max_items == WLFC_HANGER_MAXITEMS); + + if ((hanger = (wlfc_hanger_t*)MALLOC(osh, WLFC_HANGER_SIZE(max_items))) == NULL) + return NULL; + + memset(hanger, 0, WLFC_HANGER_SIZE(max_items)); + hanger->max_items = max_items; + + for (i = 0; i < hanger->max_items; i++) { + hanger->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; + } + return hanger; +} + +static int +dhd_wlfc_hanger_delete(osl_t *osh, void* hanger) +{ + wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; + + if (h) { + MFREE(osh, h, WLFC_HANGER_SIZE(h->max_items)); + return BCME_OK; + } + return BCME_BADARG; +} + +static uint16 +dhd_wlfc_hanger_get_free_slot(void* hanger) +{ + uint32 i; + wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; + + if (h) { + i = h->slot_pos + 1; + if (i == h->max_items) { + i = 0; + } + while (i != h->slot_pos) { + if (h->items[i].state == WLFC_HANGER_ITEM_STATE_FREE) { + h->slot_pos = i; + return (uint16)i; + } + i++; + if (i == h->max_items) + i = 0; + } + h->failed_slotfind++; + } + return WLFC_HANGER_MAXITEMS; +} + +static int +dhd_wlfc_hanger_get_genbit(void* hanger, void* pkt, uint32 slot_id, int* gen) +{ + int rc = BCME_OK; + wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; + + *gen = 0xff; + + /* this packet was not pushed at the time it went to the firmware */ + if (slot_id == WLFC_HANGER_MAXITEMS) + return BCME_NOTFOUND; + + if (h) { + if ((h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_INUSE) || + (h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED)) { + *gen = h->items[slot_id].gen; + } + else { + rc = BCME_NOTFOUND; + } + } + else + rc = BCME_BADARG; + return rc; +} + +static int +dhd_wlfc_hanger_pushpkt(void* hanger, void* pkt, uint32 slot_id) +{ + int rc = BCME_OK; + wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; + + if (h && (slot_id < WLFC_HANGER_MAXITEMS)) { + if (h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_FREE) { + h->items[slot_id].state = WLFC_HANGER_ITEM_STATE_INUSE; + h->items[slot_id].pkt = pkt; + h->items[slot_id].identifier = slot_id; + h->pushed++; + } + else { + h->failed_to_push++; + rc = BCME_NOTFOUND; + } + } + else + rc = BCME_BADARG; + return rc; +} + +static int +dhd_wlfc_hanger_poppkt(void* hanger, uint32 slot_id, void** pktout, int remove_from_hanger) +{ + int rc = BCME_OK; + wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; + + /* this packet was not pushed at the time it went to the firmware */ + if (slot_id == WLFC_HANGER_MAXITEMS) + return BCME_NOTFOUND; + + if (h) { + if (h->items[slot_id].state != WLFC_HANGER_ITEM_STATE_FREE) { + *pktout = h->items[slot_id].pkt; + if (remove_from_hanger) { + h->items[slot_id].state = + WLFC_HANGER_ITEM_STATE_FREE; + h->items[slot_id].pkt = NULL; + h->items[slot_id].identifier = 0; + h->items[slot_id].gen = 0xff; + h->popped++; + } + } + else { + h->failed_to_pop++; + rc = BCME_NOTFOUND; + } + } + else + rc = BCME_BADARG; + return rc; +} + +static int +dhd_wlfc_hanger_mark_suppressed(void* hanger, uint32 slot_id, uint8 gen) +{ + int rc = BCME_OK; + wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; + + /* this packet was not pushed at the time it went to the firmware */ + if (slot_id == WLFC_HANGER_MAXITEMS) + return BCME_NOTFOUND; + if (h) { + h->items[slot_id].gen = gen; + if (h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_INUSE) { + h->items[slot_id].state = WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED; + } + else + rc = BCME_BADARG; + } + else + rc = BCME_BADARG; + + return rc; +} + +static int +_dhd_wlfc_pushheader(athost_wl_status_info_t* ctx, void* p, bool tim_signal, + uint8 tim_bmp, uint8 mac_handle, uint32 htodtag) +{ + uint32 wl_pktinfo = 0; + uint8* wlh; + uint8 dataOffset; + uint8 fillers; + uint8 tim_signal_len = 0; + + struct bdc_header *h; + + if (tim_signal) { + tim_signal_len = 1 + 1 + WLFC_CTL_VALUE_LEN_PENDING_TRAFFIC_BMP; + } + + /* +2 is for Type[1] and Len[1] in TLV, plus TIM signal */ + dataOffset = WLFC_CTL_VALUE_LEN_PKTTAG + 2 + tim_signal_len; + fillers = ROUNDUP(dataOffset, 4) - dataOffset; + dataOffset += fillers; + + PKTPUSH(ctx->osh, p, dataOffset); + wlh = (uint8*) PKTDATA(ctx->osh, p); + + wl_pktinfo = htol32(htodtag); + + wlh[0] = WLFC_CTL_TYPE_PKTTAG; + wlh[1] = WLFC_CTL_VALUE_LEN_PKTTAG; + memcpy(&wlh[2], &wl_pktinfo, sizeof(uint32)); + + if (tim_signal_len) { + wlh[dataOffset - fillers - tim_signal_len ] = + WLFC_CTL_TYPE_PENDING_TRAFFIC_BMP; + wlh[dataOffset - fillers - tim_signal_len + 1] = + WLFC_CTL_VALUE_LEN_PENDING_TRAFFIC_BMP; + wlh[dataOffset - fillers - tim_signal_len + 2] = mac_handle; + wlh[dataOffset - fillers - tim_signal_len + 3] = tim_bmp; + } + if (fillers) + memset(&wlh[dataOffset - fillers], WLFC_CTL_TYPE_FILLER, fillers); + + PKTPUSH(ctx->osh, p, BDC_HEADER_LEN); + h = (struct bdc_header *)PKTDATA(ctx->osh, p); + h->flags = (BDC_PROTO_VER << BDC_FLAG_VER_SHIFT); + if (PKTSUMNEEDED(p)) + h->flags |= BDC_FLAG_SUM_NEEDED; + + + h->priority = (PKTPRIO(p) & BDC_PRIORITY_MASK); + h->flags2 = 0; + h->dataOffset = dataOffset >> 2; + BDC_SET_IF_IDX(h, DHD_PKTTAG_IF(PKTTAG(p))); + return BCME_OK; +} + +static int +_dhd_wlfc_pullheader(athost_wl_status_info_t* ctx, void* pktbuf) +{ + struct bdc_header *h; + + if (PKTLEN(ctx->osh, pktbuf) < BDC_HEADER_LEN) { + WLFC_DBGMESG(("%s: rx data too short (%d < %d)\n", __FUNCTION__, + PKTLEN(ctx->osh, pktbuf), BDC_HEADER_LEN)); + return BCME_ERROR; + } + h = (struct bdc_header *)PKTDATA(ctx->osh, pktbuf); + + /* pull BDC header */ + PKTPULL(ctx->osh, pktbuf, BDC_HEADER_LEN); + + if (PKTLEN(ctx->osh, pktbuf) < (h->dataOffset << 2)) { + WLFC_DBGMESG(("%s: rx data too short (%d < %d)\n", __FUNCTION__, + PKTLEN(ctx->osh, pktbuf), (h->dataOffset << 2))); + return BCME_ERROR; + } + + /* pull wl-header */ + PKTPULL(ctx->osh, pktbuf, (h->dataOffset << 2)); + return BCME_OK; +} + +static wlfc_mac_descriptor_t* +_dhd_wlfc_find_table_entry(athost_wl_status_info_t* ctx, void* p) +{ + int i; + wlfc_mac_descriptor_t* table = ctx->destination_entries.nodes; + uint8 ifid = DHD_PKTTAG_IF(PKTTAG(p)); + uint8* dstn = DHD_PKTTAG_DSTN(PKTTAG(p)); + wlfc_mac_descriptor_t* entry = NULL; + int iftype = ctx->destination_entries.interfaces[ifid].iftype; + + /* Multicast destination and P2P clients get the interface entry. + * STA gets the interface entry if there is no exact match. For + * example, TDLS destinations have their own entry. + */ + if ((iftype == WLC_E_IF_ROLE_STA || ETHER_ISMULTI(dstn) || + iftype == WLC_E_IF_ROLE_P2P_CLIENT) && + (ctx->destination_entries.interfaces[ifid].occupied)) { + entry = &ctx->destination_entries.interfaces[ifid]; + } + + if (entry != NULL && ETHER_ISMULTI(dstn)) + return entry; + + for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { + if (table[i].occupied) { + if (table[i].interface_id == ifid) { + if (!memcmp(table[i].ea, dstn, ETHER_ADDR_LEN)) { + entry = &table[i]; + break; + } + } + } + } + + return entry != NULL ? entry : &ctx->destination_entries.other; +} + +static int +_dhd_wlfc_rollback_packet_toq(athost_wl_status_info_t* ctx, + void* p, ewlfc_packet_state_t pkt_type, uint32 hslot) +{ + /* + put the packet back to the head of queue + + - suppressed packet goes back to suppress sub-queue + - pull out the header, if new or delayed packet + + Note: hslot is used only when header removal is done. + */ + wlfc_mac_descriptor_t* entry; + void* pktout; + int rc = BCME_OK; + int prec; + + entry = _dhd_wlfc_find_table_entry(ctx, p); + prec = DHD_PKTTAG_FIFO(PKTTAG(p)); + if (entry != NULL) { + if (pkt_type == eWLFC_PKTTYPE_SUPPRESSED) { + /* wl-header is saved for suppressed packets */ + if (WLFC_PKTQ_PENQ_HEAD(&entry->psq, ((prec << 1) + 1), p) == NULL) { + WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + rc = BCME_ERROR; + } + } + else { + /* remove header first */ + rc = _dhd_wlfc_pullheader(ctx, p); + if (rc != BCME_OK) { + WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + /* free the hanger slot */ + dhd_wlfc_hanger_poppkt(ctx->hanger, hslot, &pktout, 1); + PKTFREE(ctx->osh, p, TRUE); + ctx->stats.rollback_failed++; + return BCME_ERROR; + } + + if (pkt_type == eWLFC_PKTTYPE_DELAYED) { + /* delay-q packets are going to delay-q */ + if (WLFC_PKTQ_PENQ_HEAD(&entry->psq, (prec << 1), p) == NULL) { + WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + rc = BCME_ERROR; + } + } + + /* free the hanger slot */ + dhd_wlfc_hanger_poppkt(ctx->hanger, hslot, &pktout, 1); + + /* decrement sequence count */ + WLFC_DECR_SEQCOUNT(entry, prec); + } + /* + if this packet did not count against FIFO credit, it must have + taken a requested_credit from the firmware (for pspoll etc.) + */ + if (!DHD_PKTTAG_CREDITCHECK(PKTTAG(p))) { + entry->requested_credit++; + } + } + else { + WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + rc = BCME_ERROR; + } + if (rc != BCME_OK) + ctx->stats.rollback_failed++; + else + ctx->stats.rollback++; + + return rc; +} + +static void +_dhd_wlfc_flow_control_check(athost_wl_status_info_t* ctx, struct pktq* pq, uint8 if_id) +{ + dhd_pub_t *dhdp; + + ASSERT(ctx); + + dhdp = (dhd_pub_t *)ctx->dhdp; + + if (dhdp && dhdp->skip_fc && dhdp->skip_fc()) + return; + + if ((pq->len <= WLFC_FLOWCONTROL_LOWATER) && (ctx->hostif_flow_state[if_id] == ON)) { + /* start traffic */ + ctx->hostif_flow_state[if_id] = OFF; + /* + WLFC_DBGMESG(("qlen:%02d, if:%02d, ->OFF, start traffic %s()\n", + pq->len, if_id, __FUNCTION__)); + */ + WLFC_DBGMESG(("F")); + + dhd_txflowcontrol(ctx->dhdp, if_id, OFF); + + ctx->toggle_host_if = 0; + } + if ((pq->len >= WLFC_FLOWCONTROL_HIWATER) && (ctx->hostif_flow_state[if_id] == OFF)) { + /* stop traffic */ + ctx->hostif_flow_state[if_id] = ON; + /* + WLFC_DBGMESG(("qlen:%02d, if:%02d, ->ON, stop traffic %s()\n", + pq->len, if_id, __FUNCTION__)); + */ + WLFC_DBGMESG(("N")); + + dhd_txflowcontrol(ctx->dhdp, if_id, ON); + + ctx->host_ifidx = if_id; + ctx->toggle_host_if = 1; + } + + return; +} + +static int +_dhd_wlfc_send_signalonly_packet(athost_wl_status_info_t* ctx, wlfc_mac_descriptor_t* entry, + uint8 ta_bmp) +{ + int rc = BCME_OK; + void* p = NULL; + int dummylen = ((dhd_pub_t *)ctx->dhdp)->hdrlen+ 12; + + /* allocate a dummy packet */ + p = PKTGET(ctx->osh, dummylen, TRUE); + if (p) { + PKTPULL(ctx->osh, p, dummylen); + DHD_PKTTAG_SET_H2DTAG(PKTTAG(p), 0); + _dhd_wlfc_pushheader(ctx, p, TRUE, ta_bmp, entry->mac_handle, 0); + DHD_PKTTAG_SETSIGNALONLY(PKTTAG(p), 1); +#ifdef PROP_TXSTATUS_DEBUG + ctx->stats.signal_only_pkts_sent++; +#endif + rc = dhd_bus_txdata(((dhd_pub_t *)ctx->dhdp)->bus, p); + if (rc != BCME_OK) { + PKTFREE(ctx->osh, p, TRUE); + } + } + else { + DHD_ERROR(("%s: couldn't allocate new %d-byte packet\n", + __FUNCTION__, dummylen)); + rc = BCME_NOMEM; + } + return rc; +} + +/* Return TRUE if traffic availability changed */ +static bool +_dhd_wlfc_traffic_pending_check(athost_wl_status_info_t* ctx, wlfc_mac_descriptor_t* entry, + int prec) +{ + bool rc = FALSE; + + if (entry->state == WLFC_STATE_CLOSE) { + if ((pktq_plen(&entry->psq, (prec << 1)) == 0) && + (pktq_plen(&entry->psq, ((prec << 1) + 1)) == 0)) { + + if (entry->traffic_pending_bmp & NBITVAL(prec)) { + rc = TRUE; + entry->traffic_pending_bmp = + entry->traffic_pending_bmp & ~ NBITVAL(prec); + } + } + else { + if (!(entry->traffic_pending_bmp & NBITVAL(prec))) { + rc = TRUE; + entry->traffic_pending_bmp = + entry->traffic_pending_bmp | NBITVAL(prec); + } + } + } + if (rc) { + /* request a TIM update to firmware at the next piggyback opportunity */ + if (entry->traffic_lastreported_bmp != entry->traffic_pending_bmp) { + entry->send_tim_signal = 1; + _dhd_wlfc_send_signalonly_packet(ctx, entry, entry->traffic_pending_bmp); + entry->traffic_lastreported_bmp = entry->traffic_pending_bmp; + entry->send_tim_signal = 0; + } + else { + rc = FALSE; + } + } + return rc; +} + +static int +_dhd_wlfc_enque_suppressed(athost_wl_status_info_t* ctx, int prec, void* p) +{ + wlfc_mac_descriptor_t* entry; + + entry = _dhd_wlfc_find_table_entry(ctx, p); + if (entry == NULL) { + WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_NOTFOUND; + } + /* + - suppressed packets go to sub_queue[2*prec + 1] AND + - delayed packets go to sub_queue[2*prec + 0] to ensure + order of delivery. + */ + if (WLFC_PKTQ_PENQ(&entry->psq, ((prec << 1) + 1), p) == NULL) { + ctx->stats.delayq_full_error++; + /* WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); */ + WLFC_DBGMESG(("s")); + return BCME_ERROR; + } + /* A packet has been pushed, update traffic availability bitmap, if applicable */ + _dhd_wlfc_traffic_pending_check(ctx, entry, prec); + _dhd_wlfc_flow_control_check(ctx, &entry->psq, DHD_PKTTAG_IF(PKTTAG(p))); + return BCME_OK; +} + +static int +_dhd_wlfc_pretx_pktprocess(athost_wl_status_info_t* ctx, + wlfc_mac_descriptor_t* entry, void* p, int header_needed, uint32* slot) +{ + int rc = BCME_OK; + int hslot = WLFC_HANGER_MAXITEMS; + bool send_tim_update = FALSE; + uint32 htod = 0; + uint8 free_ctr; + + *slot = hslot; + + if (entry == NULL) { + entry = _dhd_wlfc_find_table_entry(ctx, p); + } + + if (entry == NULL) { + WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_ERROR; + } + if (entry->send_tim_signal) { + send_tim_update = TRUE; + entry->send_tim_signal = 0; + entry->traffic_lastreported_bmp = entry->traffic_pending_bmp; + } + if (header_needed) { + hslot = dhd_wlfc_hanger_get_free_slot(ctx->hanger); + free_ctr = WLFC_SEQCOUNT(entry, DHD_PKTTAG_FIFO(PKTTAG(p))); + DHD_PKTTAG_SET_H2DTAG(PKTTAG(p), htod); + WLFC_PKTFLAG_SET_GENERATION(htod, entry->generation); + entry->transit_count++; + } + else { + hslot = WLFC_PKTID_HSLOT_GET(DHD_PKTTAG_H2DTAG(PKTTAG(p))); + free_ctr = WLFC_PKTID_FREERUNCTR_GET(DHD_PKTTAG_H2DTAG(PKTTAG(p))); + } + WLFC_PKTID_HSLOT_SET(htod, hslot); + WLFC_PKTID_FREERUNCTR_SET(htod, free_ctr); + DHD_PKTTAG_SETPKTDIR(PKTTAG(p), 1); + WL_TXSTATUS_SET_FLAGS(htod, WLFC_PKTFLAG_PKTFROMHOST); + WL_TXSTATUS_SET_FIFO(htod, DHD_PKTTAG_FIFO(PKTTAG(p))); + + + if (!DHD_PKTTAG_CREDITCHECK(PKTTAG(p))) { + /* + Indicate that this packet is being sent in response to an + explicit request from the firmware side. + */ + WLFC_PKTFLAG_SET_PKTREQUESTED(htod); + } + else { + WLFC_PKTFLAG_CLR_PKTREQUESTED(htod); + } + if (header_needed) { + rc = _dhd_wlfc_pushheader(ctx, p, send_tim_update, + entry->traffic_lastreported_bmp, entry->mac_handle, htod); + if (rc == BCME_OK) { + DHD_PKTTAG_SET_H2DTAG(PKTTAG(p), htod); + /* + a new header was created for this packet. + push to hanger slot and scrub q. Since bus + send succeeded, increment seq number as well. + */ + rc = dhd_wlfc_hanger_pushpkt(ctx->hanger, p, hslot); + if (rc == BCME_OK) { + /* increment free running sequence count */ + WLFC_INCR_SEQCOUNT(entry, DHD_PKTTAG_FIFO(PKTTAG(p))); +#ifdef PROP_TXSTATUS_DEBUG + ((wlfc_hanger_t*)(ctx->hanger))->items[hslot].push_time = + OSL_SYSUPTIME(); +#endif + } + else { + WLFC_DBGMESG(("%s() hanger_pushpkt() failed, rc: %d\n", + __FUNCTION__, rc)); + } + } + } + else { + int gen; + + /* remove old header */ + rc = _dhd_wlfc_pullheader(ctx, p); + if (rc == BCME_OK) { + hslot = WLFC_PKTID_HSLOT_GET(DHD_PKTTAG_H2DTAG(PKTTAG(p))); + dhd_wlfc_hanger_get_genbit(ctx->hanger, p, hslot, &gen); + + WLFC_PKTFLAG_SET_GENERATION(htod, gen); + free_ctr = WLFC_PKTID_FREERUNCTR_GET(DHD_PKTTAG_H2DTAG(PKTTAG(p))); + /* push new header */ + _dhd_wlfc_pushheader(ctx, p, send_tim_update, + entry->traffic_lastreported_bmp, entry->mac_handle, htod); + } + } + *slot = hslot; + return rc; +} + +static int +_dhd_wlfc_is_destination_closed(athost_wl_status_info_t* ctx, + wlfc_mac_descriptor_t* entry, int prec) +{ + if (ctx->destination_entries.interfaces[entry->interface_id].iftype == + WLC_E_IF_ROLE_P2P_GO) { + /* - destination interface is of type p2p GO. + For a p2pGO interface, if the destination is OPEN but the interface is + CLOSEd, do not send traffic. But if the dstn is CLOSEd while there is + destination-specific-credit left send packets. This is because the + firmware storing the destination-specific-requested packet in queue. + */ + if ((entry->state == WLFC_STATE_CLOSE) && (entry->requested_credit == 0) && + (entry->requested_packet == 0)) + return 1; + } + /* AP, p2p_go -> unicast desc entry, STA/p2p_cl -> interface desc. entry */ + if (((entry->state == WLFC_STATE_CLOSE) && (entry->requested_credit == 0) && + (entry->requested_packet == 0)) || + (!(entry->ac_bitmap & (1 << prec)))) + return 1; + + return 0; +} + +static void* +_dhd_wlfc_deque_delayedq(athost_wl_status_info_t* ctx, + int prec, uint8* ac_credit_spent, uint8* needs_hdr, wlfc_mac_descriptor_t** entry_out) +{ + wlfc_mac_descriptor_t* entry; + wlfc_mac_descriptor_t* table; + uint8 token_pos; + int total_entries; + void* p = NULL; + int pout; + int i; + + *entry_out = NULL; + token_pos = ctx->token_pos[prec]; + /* most cases a packet will count against FIFO credit */ + *ac_credit_spent = 1; + *needs_hdr = 1; + + /* search all entries, include nodes as well as interfaces */ + table = (wlfc_mac_descriptor_t*)&ctx->destination_entries; + total_entries = sizeof(ctx->destination_entries)/sizeof(wlfc_mac_descriptor_t); + + for (i = 0; i < total_entries; i++) { + entry = &table[(token_pos + i) % total_entries]; + if (entry->occupied && !entry->deleting) { + if (!_dhd_wlfc_is_destination_closed(ctx, entry, prec)) { + p = pktq_mdeq(&entry->psq, + /* higher precedence will be picked up first, + * i.e. suppressed packets before delayed ones + */ + NBITVAL((prec << 1) + 1), &pout); + *needs_hdr = 0; + + if (p == NULL) { + if (entry->suppressed == TRUE) { + if ((entry->suppr_transit_count <= + entry->suppress_count)) { + entry->suppressed = FALSE; + } else { + return NULL; + } + } + /* De-Q from delay Q */ + p = pktq_mdeq(&entry->psq, + NBITVAL((prec << 1)), + &pout); + *needs_hdr = 1; + } + + if (p != NULL) { + /* did the packet come from suppress sub-queue? */ + if (entry->requested_credit > 0) { + entry->requested_credit--; +#ifdef PROP_TXSTATUS_DEBUG + entry->dstncredit_sent_packets++; +#endif + /* + if the packet was pulled out while destination is in + closed state but had a non-zero packets requested, + then this should not count against the FIFO credit. + That is due to the fact that the firmware will + most likely hold onto this packet until a suitable + time later to push it to the appropriate AC FIFO. + */ + if (entry->state == WLFC_STATE_CLOSE) + *ac_credit_spent = 0; + } + else if (entry->requested_packet > 0) { + entry->requested_packet--; + DHD_PKTTAG_SETONETIMEPKTRQST(PKTTAG(p)); + if (entry->state == WLFC_STATE_CLOSE) + *ac_credit_spent = 0; + } + /* move token to ensure fair round-robin */ + ctx->token_pos[prec] = + (token_pos + i + 1) % total_entries; + *entry_out = entry; + _dhd_wlfc_flow_control_check(ctx, &entry->psq, + DHD_PKTTAG_IF(PKTTAG(p))); + /* + A packet has been picked up, update traffic + availability bitmap, if applicable + */ + _dhd_wlfc_traffic_pending_check(ctx, entry, prec); + return p; + } + } + } + } + return NULL; +} + +void * +_dhd_wlfc_pktq_peek_tail(struct pktq *pq, int *prec_out) +{ + int prec; + + ASSERT(pq); + + if (pq->len == 0) + return NULL; + + for (prec = 0; prec < pq->hi_prec; prec++) + /* only pick packets from dealyed-q */ + if (((prec & 1) == 0) && pq->q[prec].head) + break; + + if (prec_out) + *prec_out = prec; + + return (pq->q[prec].tail); +} + +bool +_dhd_wlfc_prec_enq_with_drop(dhd_pub_t *dhdp, struct pktq *pq, void *pkt, int prec) +{ + void *p = NULL; + int eprec = -1; /* precedence to evict from */ + + ASSERT(dhdp && pq && pkt); + ASSERT(prec >= 0 && prec < pq->num_prec); + + /* Fast case, precedence queue is not full and we are also not + * exceeding total queue length + */ + if (!pktq_pfull(pq, prec) && !pktq_full(pq)) { + pktq_penq(pq, prec, pkt); + return TRUE; + } + + /* Determine precedence from which to evict packet, if any */ + if (pktq_pfull(pq, prec)) + eprec = prec; + else if (pktq_full(pq)) { + p = _dhd_wlfc_pktq_peek_tail(pq, &eprec); + if (!p) { + WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return FALSE; + } + if ((eprec > prec) || (eprec < 0)) { + if (!pktq_pempty(pq, prec)) { + eprec = prec; + } else { + return FALSE; + } + } + } + + /* Evict if needed */ + if (eprec >= 0) { + /* Detect queueing to unconfigured precedence */ + ASSERT(!pktq_pempty(pq, eprec)); + /* Evict all fragmented frames */ + dhd_prec_drop_pkts(dhdp->osh, pq, eprec); + } + + /* Enqueue */ + p = pktq_penq(pq, prec, pkt); + if (!p) { + WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return FALSE; + } + + return TRUE; +} + +static int +_dhd_wlfc_enque_delayq(athost_wl_status_info_t* ctx, void* pktbuf, int prec) +{ + wlfc_mac_descriptor_t* entry; + + if (pktbuf != NULL) { + entry = _dhd_wlfc_find_table_entry(ctx, pktbuf); + + if (entry == NULL) { + WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_ERROR; + } + + /* + - suppressed packets go to sub_queue[2*prec + 1] AND + - delayed packets go to sub_queue[2*prec + 0] to ensure + order of delivery. + */ + if (_dhd_wlfc_prec_enq_with_drop(ctx->dhdp, &entry->psq, pktbuf, (prec << 1)) + == FALSE) { + WLFC_DBGMESG(("D")); + /* dhd_txcomplete(ctx->dhdp, pktbuf, FALSE); */ + PKTFREE(ctx->osh, pktbuf, TRUE); + ctx->stats.delayq_full_error++; + return BCME_ERROR; + } + +#ifdef QMONITOR + dhd_qmon_tx(&entry->qmon); +#endif + /* + A packet has been pushed, update traffic availability bitmap, + if applicable + */ + _dhd_wlfc_traffic_pending_check(ctx, entry, prec); + + } + return BCME_OK; +} + +bool ifpkt_fn(void* p, int ifid) +{ + return (ifid == DHD_PKTTAG_IF(PKTTAG(p))); +} + +static int +_dhd_wlfc_mac_entry_update(athost_wl_status_info_t* ctx, wlfc_mac_descriptor_t* entry, + ewlfc_mac_entry_action_t action, uint8 ifid, uint8 iftype, uint8* ea) +{ + int rc = BCME_OK; + +#ifdef QMONITOR + dhd_qmon_reset(&entry->qmon); +#endif + + if (action == eWLFC_MAC_ENTRY_ACTION_ADD) { + entry->occupied = 1; + entry->state = WLFC_STATE_OPEN; + entry->requested_credit = 0; + entry->interface_id = ifid; + entry->iftype = iftype; + entry->ac_bitmap = 0xff; /* update this when handling APSD */ + /* for an interface entry we may not care about the MAC address */ + if (ea != NULL) + memcpy(&entry->ea[0], ea, ETHER_ADDR_LEN); + pktq_init(&entry->psq, WLFC_PSQ_PREC_COUNT, WLFC_PSQ_LEN); + } + else if (action == eWLFC_MAC_ENTRY_ACTION_UPDATE) { + entry->occupied = 1; + entry->state = WLFC_STATE_OPEN; + entry->requested_credit = 0; + entry->interface_id = ifid; + entry->iftype = iftype; + entry->ac_bitmap = 0xff; /* update this when handling APSD */ + /* for an interface entry we may not care about the MAC address */ + if (ea != NULL) + memcpy(&entry->ea[0], ea, ETHER_ADDR_LEN); + } + else if (action == eWLFC_MAC_ENTRY_ACTION_DEL) { + /* When the entry is deleted, the packets that are queued in the entry must be + cleanup. The cleanup action should be before the occupied is set as 0. The + flag deleting is set to avoid de-queue action when these queues are being + cleanup + */ + entry->deleting = 1; + dhd_wlfc_cleanup(ctx->dhdp, ifpkt_fn, ifid); + _dhd_wlfc_flow_control_check(ctx, &entry->psq, ifid); + entry->deleting = 0; + + entry->occupied = 0; + entry->suppressed = 0; + entry->state = WLFC_STATE_CLOSE; + entry->requested_credit = 0; + entry->transit_count = 0; + entry->suppr_transit_count = 0; + entry->suppress_count = 0; + memset(&entry->ea[0], 0, ETHER_ADDR_LEN); + + /* enable after packets are queued-deqeued properly. + pktq_flush(dhd->osh, &entry->psq, FALSE, NULL, 0); + */ + } + return rc; +} + +int +_dhd_wlfc_borrow_credit(athost_wl_status_info_t* ctx, uint8 available_credit_map, int borrower_ac) +{ + int lender_ac; + int rc = BCME_ERROR; + + if (ctx == NULL || available_credit_map == 0) { + WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + /* Borrow from lowest priority available AC (including BC/MC credits) */ + for (lender_ac = 0; lender_ac <= AC_COUNT; lender_ac++) { + if ((available_credit_map && (1 << lender_ac)) && + (ctx->FIFO_credit[lender_ac] > 0)) { + ctx->credits_borrowed[borrower_ac][lender_ac]++; + ctx->FIFO_credit[lender_ac]--; + rc = BCME_OK; + break; + } + } + + return rc; +} + +int +dhd_wlfc_interface_entry_update(void* state, + ewlfc_mac_entry_action_t action, uint8 ifid, uint8 iftype, uint8* ea) +{ + athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state; + wlfc_mac_descriptor_t* entry; + int ret; + + if (ifid >= WLFC_MAX_IFNUM) + return BCME_BADARG; + + entry = &ctx->destination_entries.interfaces[ifid]; + ret = _dhd_wlfc_mac_entry_update(ctx, entry, action, ifid, iftype, ea); + return ret; +} + +int +dhd_wlfc_FIFOcreditmap_update(void* state, uint8* credits) +{ + athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state; + + /* update the AC FIFO credit map */ + ctx->FIFO_credit[0] = credits[0]; + ctx->FIFO_credit[1] = credits[1]; + ctx->FIFO_credit[2] = credits[2]; + ctx->FIFO_credit[3] = credits[3]; + /* credit for bc/mc packets */ + ctx->FIFO_credit[4] = credits[4]; + /* credit for ATIM FIFO is not used yet. */ + ctx->FIFO_credit[5] = 0; + return BCME_OK; +} + +int +_dhd_wlfc_handle_packet_commit(athost_wl_status_info_t* ctx, int ac, + dhd_wlfc_commit_info_t *commit_info, f_commitpkt_t fcommit, void* commit_ctx) +{ + uint32 hslot; + int rc; + + /* + if ac_fifo_credit_spent = 0 + + This packet will not count against the FIFO credit. + To ensure the txstatus corresponding to this packet + does not provide an implied credit (default behavior) + mark the packet accordingly. + + if ac_fifo_credit_spent = 1 + + This is a normal packet and it counts against the FIFO + credit count. + */ + DHD_PKTTAG_SETCREDITCHECK(PKTTAG(commit_info->p), commit_info->ac_fifo_credit_spent); + rc = _dhd_wlfc_pretx_pktprocess(ctx, commit_info->mac_entry, commit_info->p, + commit_info->needs_hdr, &hslot); + + if (rc == BCME_OK) + rc = fcommit(commit_ctx, commit_info->p); + else + ctx->stats.generic_error++; + + if (rc == BCME_OK) { + ctx->stats.pkt2bus++; + if (commit_info->ac_fifo_credit_spent) { + ctx->stats.send_pkts[ac]++; + WLFC_HOST_FIFO_CREDIT_INC_SENTCTRS(ctx, ac); + } + } else if (rc == BCME_NORESOURCE) + rc = BCME_ERROR; + else { + /* + bus commit has failed, rollback. + - remove wl-header for a delayed packet + - save wl-header header for suppressed packets + */ + rc = _dhd_wlfc_rollback_packet_toq(ctx, commit_info->p, + (commit_info->pkt_type), hslot); + + rc = BCME_ERROR; + } + + return rc; +} + +int +dhd_wlfc_commit_packets(void* state, f_commitpkt_t fcommit, void* commit_ctx, void *pktbuf) +{ + int ac; + int credit; + int rc; + dhd_wlfc_commit_info_t commit_info; + athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state; + int credit_count = 0; + int bus_retry_count = 0; + uint8 ac_available = 0; /* Bitmask for 4 ACs + BC/MC */ + + if ((state == NULL) || + (fcommit == NULL)) { + WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + memset(&commit_info, 0, sizeof(commit_info)); + + /* + Commit packets for regular AC traffic. Higher priority first. + First, use up FIFO credits available to each AC. Based on distribution + and credits left, borrow from other ACs as applicable + + -NOTE: + If the bus between the host and firmware is overwhelmed by the + traffic from host, it is possible that higher priority traffic + starves the lower priority queue. If that occurs often, we may + have to employ weighted round-robin or ucode scheme to avoid + low priority packet starvation. + */ + + if (pktbuf) { + ac = DHD_PKTTAG_FIFO(PKTTAG(pktbuf)); + if (ETHER_ISMULTI(DHD_PKTTAG_DSTN(PKTTAG(pktbuf)))) { + ASSERT(ac == AC_COUNT); + commit_info.needs_hdr = 1; + commit_info.mac_entry = NULL; + commit_info.pkt_type = eWLFC_PKTTYPE_NEW; + commit_info.p = pktbuf; + if (ctx->FIFO_credit[ac]) { + rc = _dhd_wlfc_handle_packet_commit(ctx, ac, &commit_info, + fcommit, commit_ctx); + + /* Bus commits may fail (e.g. flow control); abort after retries */ + if (rc == BCME_OK) { + if (commit_info.ac_fifo_credit_spent) { + (void) _dhd_wlfc_borrow_credit(ctx, + ac_available, ac); + credit_count--; + } + } else { + bus_retry_count++; + if (bus_retry_count >= BUS_RETRIES) { + DHD_ERROR((" %s: bus error %d\n", + __FUNCTION__, rc)); + return rc; + } + } + } + } + else { + /* en-queue the packets to respective queue. */ + rc = _dhd_wlfc_enque_delayq(ctx, pktbuf, ac); + } + } + + for (ac = AC_COUNT; ac >= 0; ac--) { + + bool bQueueIdle = TRUE; + + /* packets from delayQ with less priority are fresh and they'd need header and + * have no MAC entry + */ + commit_info.needs_hdr = 1; + commit_info.mac_entry = NULL; + commit_info.pkt_type = eWLFC_PKTTYPE_NEW; + + for (credit = 0; credit < ctx->FIFO_credit[ac];) { + commit_info.p = _dhd_wlfc_deque_delayedq(ctx, ac, + &(commit_info.ac_fifo_credit_spent), + &(commit_info.needs_hdr), + &(commit_info.mac_entry)); + + if (commit_info.p == NULL) + break; + + bQueueIdle = FALSE; + + commit_info.pkt_type = (commit_info.needs_hdr) ? eWLFC_PKTTYPE_DELAYED : + eWLFC_PKTTYPE_SUPPRESSED; + + rc = _dhd_wlfc_handle_packet_commit(ctx, ac, &commit_info, + fcommit, commit_ctx); + + /* Bus commits may fail (e.g. flow control); abort after retries */ + if (rc == BCME_OK) { + if (commit_info.ac_fifo_credit_spent) { + credit++; + } + } + else { + bus_retry_count++; + if (bus_retry_count >= BUS_RETRIES) { + DHD_ERROR(("%s: bus error %d\n", __FUNCTION__, rc)); + ctx->FIFO_credit[ac] -= credit; + return rc; + } + } + } + + ctx->FIFO_credit[ac] -= credit; + + + /* If no pkts can be dequed, the credit can be borrowed */ + if (bQueueIdle) { + ac_available |= (1 << ac); + credit_count += ctx->FIFO_credit[ac]; + } + } + + /* We borrow only for AC_BE and only if no other traffic seen for DEFER_PERIOD + + Note that (ac_available & WLFC_AC_BE_TRAFFIC_ONLY) is done to: + a) ignore BC/MC for deferring borrow + b) ignore AC_BE being available along with other ACs + (this should happen only for pure BC/MC traffic) + + i.e. AC_VI, AC_VO, AC_BK all MUST be available (i.e. no traffic) and + we do not care if AC_BE and BC/MC are available or not + */ + if ((ac_available & WLFC_AC_BE_TRAFFIC_ONLY) == WLFC_AC_BE_TRAFFIC_ONLY) { + + if (ctx->allow_credit_borrow) { + ac = 1; /* Set ac to AC_BE and borrow credits */ + } + else { + int delta; + int curr_t = OSL_SYSUPTIME(); + + if (curr_t > ctx->borrow_defer_timestamp) + delta = curr_t - ctx->borrow_defer_timestamp; + else + delta = 0xffffffff + curr_t - ctx->borrow_defer_timestamp; + + if (delta >= WLFC_BORROW_DEFER_PERIOD_MS) { + /* Reset borrow but defer to next iteration (defensive borrowing) */ + ctx->allow_credit_borrow = TRUE; + ctx->borrow_defer_timestamp = 0; + } + return BCME_OK; + } + } + else { + /* If we have multiple AC traffic, turn off borrowing, mark time and bail out */ + ctx->allow_credit_borrow = FALSE; + ctx->borrow_defer_timestamp = OSL_SYSUPTIME(); + return BCME_OK; + } + + /* At this point, borrow all credits only for "ac" (which should be set above to AC_BE) + Generically use "ac" only in case we extend to all ACs in future + */ + for (; (credit_count > 0);) { + + commit_info.p = _dhd_wlfc_deque_delayedq(ctx, ac, + &(commit_info.ac_fifo_credit_spent), + &(commit_info.needs_hdr), + &(commit_info.mac_entry)); + if (commit_info.p == NULL) + break; + + commit_info.pkt_type = (commit_info.needs_hdr) ? eWLFC_PKTTYPE_DELAYED : + eWLFC_PKTTYPE_SUPPRESSED; + + rc = _dhd_wlfc_handle_packet_commit(ctx, ac, &commit_info, + fcommit, commit_ctx); + + /* Bus commits may fail (e.g. flow control); abort after retries */ + if (rc == BCME_OK) { + if (commit_info.ac_fifo_credit_spent) { + (void) _dhd_wlfc_borrow_credit(ctx, ac_available, ac); + credit_count--; + } + } + else { + bus_retry_count++; + if (bus_retry_count >= BUS_RETRIES) { + DHD_ERROR(("%s: bus error %d\n", __FUNCTION__, rc)); + return rc; + } + } + } + return BCME_OK; +} + +static uint8 +dhd_wlfc_find_mac_desc_id_from_mac(dhd_pub_t *dhdp, uint8* ea) +{ + wlfc_mac_descriptor_t* table = + ((athost_wl_status_info_t*)dhdp->wlfc_state)->destination_entries.nodes; + uint8 table_index; + + if (ea != NULL) { + for (table_index = 0; table_index < WLFC_MAC_DESC_TABLE_SIZE; table_index++) { + if ((memcmp(ea, &table[table_index].ea[0], ETHER_ADDR_LEN) == 0) && + table[table_index].occupied) + return table_index; + } + } + return WLFC_MAC_DESC_ID_INVALID; +} + +void +dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success) +{ + athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) + dhd->wlfc_state; + void* p; + int fifo_id; + + if (DHD_PKTTAG_SIGNALONLY(PKTTAG(txp))) { +#ifdef PROP_TXSTATUS_DEBUG + wlfc->stats.signal_only_pkts_freed++; +#endif + /* is this a signal-only packet? */ + if (success) + PKTFREE(wlfc->osh, txp, TRUE); + return; + } + if (!success) { + WLFC_DBGMESG(("At: %s():%d, bus_complete() failure for %p, htod_tag:0x%08x\n", + __FUNCTION__, __LINE__, txp, DHD_PKTTAG_H2DTAG(PKTTAG(txp)))); + dhd_wlfc_hanger_poppkt(wlfc->hanger, WLFC_PKTID_HSLOT_GET(DHD_PKTTAG_H2DTAG + (PKTTAG(txp))), &p, 1); + + /* indicate failure and free the packet */ + dhd_txcomplete(dhd, txp, FALSE); + + /* return the credit, if necessary */ + if (DHD_PKTTAG_CREDITCHECK(PKTTAG(txp))) { + int lender, credit_returned = 0; /* Note that borrower is fifo_id */ + + fifo_id = DHD_PKTTAG_FIFO(PKTTAG(txp)); + + /* Return credits to highest priority lender first */ + for (lender = AC_COUNT; lender >= 0; lender--) { + if (wlfc->credits_borrowed[fifo_id][lender] > 0) { + wlfc->FIFO_credit[lender]++; + wlfc->credits_borrowed[fifo_id][lender]--; + credit_returned = 1; + break; + } + } + + if (!credit_returned) { + wlfc->FIFO_credit[fifo_id]++; + } + } + + PKTFREE(wlfc->osh, txp, TRUE); + } + return; +} + +static int +dhd_wlfc_compressed_txstatus_update(dhd_pub_t *dhd, uint8* pkt_info, uint8 len) +{ + uint8 status_flag; + uint32 status; + int ret; + int remove_from_hanger = 1; + void* pktbuf; + uint8 fifo_id; + uint8 count = 0; + uint32 status_g; + uint32 hslot, hcnt; + wlfc_mac_descriptor_t* entry = NULL; + athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) + dhd->wlfc_state; + + memcpy(&status, pkt_info, sizeof(uint32)); + status_flag = WL_TXSTATUS_GET_FLAGS(status); + status_g = status & 0xff000000; + hslot = (status & 0x00ffff00) >> 8; + hcnt = status & 0xff; + len = pkt_info[4]; + + wlfc->stats.txstatus_in++; + + if (status_flag == WLFC_CTL_PKTFLAG_DISCARD) { + wlfc->stats.pkt_freed++; + } + + else if (status_flag == WLFC_CTL_PKTFLAG_D11SUPPRESS) { + wlfc->stats.d11_suppress++; + remove_from_hanger = 0; + } + + else if (status_flag == WLFC_CTL_PKTFLAG_WLSUPPRESS) { + wlfc->stats.wl_suppress++; + remove_from_hanger = 0; + } + + else if (status_flag == WLFC_CTL_PKTFLAG_TOSSED_BYWLC) { + wlfc->stats.wlc_tossed_pkts++; + } + while (count < len) { + status = (status_g << 24) | (hslot << 8) | (hcnt); + count++; + hslot++; + hcnt++; + + ret = dhd_wlfc_hanger_poppkt(wlfc->hanger, + WLFC_PKTID_HSLOT_GET(status), &pktbuf, remove_from_hanger); + if (ret != BCME_OK) { + /* do something */ + continue; + } + + entry = _dhd_wlfc_find_table_entry(wlfc, pktbuf); + + if (!remove_from_hanger) { + /* this packet was suppressed */ + if (!entry->suppressed || entry->generation != WLFC_PKTID_GEN(status)) { + entry->suppressed = TRUE; + entry->suppress_count = pktq_mlen(&entry->psq, + NBITVAL((WL_TXSTATUS_GET_FIFO(status) << 1) + 1)); + entry->suppr_transit_count = entry->transit_count; + } + entry->generation = WLFC_PKTID_GEN(status); + } + +#ifdef PROP_TXSTATUS_DEBUG + { + uint32 new_t = OSL_SYSUPTIME(); + uint32 old_t; + uint32 delta; + old_t = ((wlfc_hanger_t*)(wlfc->hanger))->items[ + WLFC_PKTID_HSLOT_GET(status)].push_time; + + + wlfc->stats.latency_sample_count++; + if (new_t > old_t) + delta = new_t - old_t; + else + delta = 0xffffffff + new_t - old_t; + wlfc->stats.total_status_latency += delta; + wlfc->stats.latency_most_recent = delta; + + wlfc->stats.deltas[wlfc->stats.idx_delta++] = delta; + if (wlfc->stats.idx_delta == sizeof(wlfc->stats.deltas)/sizeof(uint32)) + wlfc->stats.idx_delta = 0; + } +#endif /* PROP_TXSTATUS_DEBUG */ + + fifo_id = DHD_PKTTAG_FIFO(PKTTAG(pktbuf)); + + /* pick up the implicit credit from this packet */ + if (DHD_PKTTAG_CREDITCHECK(PKTTAG(pktbuf))) { + if (wlfc->proptxstatus_mode == WLFC_FCMODE_IMPLIED_CREDIT) { + + int lender, credit_returned = 0; /* Note that borrower is fifo_id */ + + /* Return credits to highest priority lender first */ + for (lender = AC_COUNT; lender >= 0; lender--) { + if (wlfc->credits_borrowed[fifo_id][lender] > 0) { + wlfc->FIFO_credit[lender]++; + wlfc->credits_borrowed[fifo_id][lender]--; + credit_returned = 1; + break; + } + } + + if (!credit_returned) { + wlfc->FIFO_credit[fifo_id]++; + } + } + } + else { + /* + if this packet did not count against FIFO credit, it must have + taken a requested_credit from the destination entry (for pspoll etc.) + */ + if (!entry) { + + entry = _dhd_wlfc_find_table_entry(wlfc, pktbuf); + } + if (!DHD_PKTTAG_ONETIMEPKTRQST(PKTTAG(pktbuf))) + entry->requested_credit++; +#ifdef PROP_TXSTATUS_DEBUG + entry->dstncredit_acks++; +#endif + } + if ((status_flag == WLFC_CTL_PKTFLAG_D11SUPPRESS) || + (status_flag == WLFC_CTL_PKTFLAG_WLSUPPRESS)) { + + ret = _dhd_wlfc_enque_suppressed(wlfc, fifo_id, pktbuf); + if (ret != BCME_OK) { + /* delay q is full, drop this packet */ + dhd_wlfc_hanger_poppkt(wlfc->hanger, WLFC_PKTID_HSLOT_GET(status), + &pktbuf, 1); + + /* indicate failure and free the packet */ + dhd_txcomplete(dhd, pktbuf, FALSE); + entry->transit_count--; + DHD_WLFC_QMON_COMPLETE(entry); + /* packet is transmitted Successfully by dongle + * after first suppress. + */ + if (entry->suppressed) { + entry->suppr_transit_count--; + } + PKTFREE(wlfc->osh, pktbuf, TRUE); + } else { + /* Mark suppressed to avoid a double free during wlfc cleanup */ + + dhd_wlfc_hanger_mark_suppressed(wlfc->hanger, + WLFC_PKTID_HSLOT_GET(status), WLFC_PKTID_GEN(status)); + entry->suppress_count++; + } + } + else { + dhd_txcomplete(dhd, pktbuf, TRUE); + entry->transit_count--; + DHD_WLFC_QMON_COMPLETE(entry); + + /* This packet is transmitted Successfully by dongle + * even after first suppress. + */ + if (entry->suppressed) { + entry->suppr_transit_count--; + } + /* free the packet */ + PKTFREE(wlfc->osh, pktbuf, TRUE); + } + } + return BCME_OK; +} + +/* Handle discard or suppress indication */ +static int +dhd_wlfc_txstatus_update(dhd_pub_t *dhd, uint8* pkt_info) +{ + uint8 status_flag; + uint32 status; + int ret; + int remove_from_hanger = 1; + void* pktbuf; + uint8 fifo_id; + wlfc_mac_descriptor_t* entry = NULL; + athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) + dhd->wlfc_state; + + memcpy(&status, pkt_info, sizeof(uint32)); + status_flag = WL_TXSTATUS_GET_FLAGS(status); + wlfc->stats.txstatus_in++; + + if (status_flag == WLFC_CTL_PKTFLAG_DISCARD) { + wlfc->stats.pkt_freed++; + } + + else if (status_flag == WLFC_CTL_PKTFLAG_D11SUPPRESS) { + wlfc->stats.d11_suppress++; + remove_from_hanger = 0; + } + + else if (status_flag == WLFC_CTL_PKTFLAG_WLSUPPRESS) { + wlfc->stats.wl_suppress++; + remove_from_hanger = 0; + } + + else if (status_flag == WLFC_CTL_PKTFLAG_TOSSED_BYWLC) { + wlfc->stats.wlc_tossed_pkts++; + } + + ret = dhd_wlfc_hanger_poppkt(wlfc->hanger, + WLFC_PKTID_HSLOT_GET(status), &pktbuf, remove_from_hanger); + if (ret != BCME_OK) { + /* do something */ + return ret; + } + + entry = _dhd_wlfc_find_table_entry(wlfc, pktbuf); + + if (!remove_from_hanger) { + /* this packet was suppressed */ + if (!entry->suppressed || entry->generation != WLFC_PKTID_GEN(status)) { + entry->suppressed = TRUE; + entry->suppress_count = pktq_mlen(&entry->psq, + NBITVAL((WL_TXSTATUS_GET_FIFO(status) << 1) + 1)); + entry->suppr_transit_count = entry->transit_count; + } + entry->generation = WLFC_PKTID_GEN(status); + } + +#ifdef PROP_TXSTATUS_DEBUG + { + uint32 new_t = OSL_SYSUPTIME(); + uint32 old_t; + uint32 delta; + old_t = ((wlfc_hanger_t*)(wlfc->hanger))->items[ + WLFC_PKTID_HSLOT_GET(status)].push_time; + + + wlfc->stats.latency_sample_count++; + if (new_t > old_t) + delta = new_t - old_t; + else + delta = 0xffffffff + new_t - old_t; + wlfc->stats.total_status_latency += delta; + wlfc->stats.latency_most_recent = delta; + + wlfc->stats.deltas[wlfc->stats.idx_delta++] = delta; + if (wlfc->stats.idx_delta == sizeof(wlfc->stats.deltas)/sizeof(uint32)) + wlfc->stats.idx_delta = 0; + } +#endif /* PROP_TXSTATUS_DEBUG */ + + fifo_id = DHD_PKTTAG_FIFO(PKTTAG(pktbuf)); + + /* pick up the implicit credit from this packet */ + if (DHD_PKTTAG_CREDITCHECK(PKTTAG(pktbuf))) { + if (wlfc->proptxstatus_mode == WLFC_FCMODE_IMPLIED_CREDIT) { + + int lender, credit_returned = 0; /* Note that borrower is fifo_id */ + + /* Return credits to highest priority lender first */ + for (lender = AC_COUNT; lender >= 0; lender--) { + if (wlfc->credits_borrowed[fifo_id][lender] > 0) { + wlfc->FIFO_credit[lender]++; + wlfc->credits_borrowed[fifo_id][lender]--; + credit_returned = 1; + break; + } + } + + if (!credit_returned) { + wlfc->FIFO_credit[fifo_id]++; + } + } + } + else { + /* + if this packet did not count against FIFO credit, it must have + taken a requested_credit from the destination entry (for pspoll etc.) + */ + if (!entry) { + + entry = _dhd_wlfc_find_table_entry(wlfc, pktbuf); + } + if (!DHD_PKTTAG_ONETIMEPKTRQST(PKTTAG(pktbuf))) + entry->requested_credit++; +#ifdef PROP_TXSTATUS_DEBUG + entry->dstncredit_acks++; +#endif + } + if ((status_flag == WLFC_CTL_PKTFLAG_D11SUPPRESS) || + (status_flag == WLFC_CTL_PKTFLAG_WLSUPPRESS)) { + + ret = _dhd_wlfc_enque_suppressed(wlfc, fifo_id, pktbuf); + if (ret != BCME_OK) { + /* delay q is full, drop this packet */ + dhd_wlfc_hanger_poppkt(wlfc->hanger, WLFC_PKTID_HSLOT_GET(status), + &pktbuf, 1); + + /* indicate failure and free the packet */ + dhd_txcomplete(dhd, pktbuf, FALSE); + entry->transit_count--; + DHD_WLFC_QMON_COMPLETE(entry); + /* This packet is transmitted Successfully by + * dongle even after first suppress. + */ + if (entry->suppressed) { + entry->suppr_transit_count--; + } + PKTFREE(wlfc->osh, pktbuf, TRUE); + } else { + /* Mark suppressed to avoid a double free during wlfc cleanup */ + + dhd_wlfc_hanger_mark_suppressed(wlfc->hanger, + WLFC_PKTID_HSLOT_GET(status), WLFC_PKTID_GEN(status)); + entry->suppress_count++; + } + } + else { + dhd_txcomplete(dhd, pktbuf, TRUE); + entry->transit_count--; + DHD_WLFC_QMON_COMPLETE(entry); + + /* This packet is transmitted Successfully by dongle even after first suppress. */ + if (entry->suppressed) { + entry->suppr_transit_count--; + } + /* free the packet */ + PKTFREE(wlfc->osh, pktbuf, TRUE); + } + return BCME_OK; +} + +static int +dhd_wlfc_fifocreditback_indicate(dhd_pub_t *dhd, uint8* credits) +{ + int i; + athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) + dhd->wlfc_state; + for (i = 0; i < WLFC_CTL_VALUE_LEN_FIFO_CREDITBACK; i++) { +#ifdef PROP_TXSTATUS_DEBUG + wlfc->stats.fifo_credits_back[i] += credits[i]; +#endif + /* update FIFO credits */ + if (wlfc->proptxstatus_mode == WLFC_FCMODE_EXPLICIT_CREDIT) + { + int lender; /* Note that borrower is i */ + + /* Return credits to highest priority lender first */ + for (lender = AC_COUNT; (lender >= 0) && (credits[i] > 0); lender--) { + if (wlfc->credits_borrowed[i][lender] > 0) { + if (credits[i] >= wlfc->credits_borrowed[i][lender]) { + credits[i] -= wlfc->credits_borrowed[i][lender]; + wlfc->FIFO_credit[lender] += + wlfc->credits_borrowed[i][lender]; + wlfc->credits_borrowed[i][lender] = 0; + } + else { + wlfc->credits_borrowed[i][lender] -= credits[i]; + wlfc->FIFO_credit[lender] += credits[i]; + credits[i] = 0; + } + } + } + + /* If we have more credits left over, these must belong to the AC */ + if (credits[i] > 0) { + wlfc->FIFO_credit[i] += credits[i]; + } + } + } + + return BCME_OK; +} + +static int +dhd_wlfc_dbg_senum_check(dhd_pub_t *dhd, uint8 *value) +{ + uint32 timestamp; + + (void)dhd; + + bcopy(&value[2], ×tamp, sizeof(uint32)); + DHD_INFO(("RXPKT: SEQ: %d, timestamp %d\n", value[1], timestamp)); + return BCME_OK; +} + + +static int +dhd_wlfc_rssi_indicate(dhd_pub_t *dhd, uint8* rssi) +{ + (void)dhd; + (void)rssi; + return BCME_OK; +} + +static int +dhd_wlfc_mac_table_update(dhd_pub_t *dhd, uint8* value, uint8 type) +{ + int rc; + athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) + dhd->wlfc_state; + wlfc_mac_descriptor_t* table; + uint8 existing_index; + uint8 table_index; + uint8 ifid; + uint8* ea; + + WLFC_DBGMESG(("%s(), mac [%02x:%02x:%02x:%02x:%02x:%02x],%s,idx:%d,id:0x%02x\n", + __FUNCTION__, value[2], value[3], value[4], value[5], value[6], value[7], + ((type == WLFC_CTL_TYPE_MACDESC_ADD) ? "ADD":"DEL"), + WLFC_MAC_DESC_GET_LOOKUP_INDEX(value[0]), value[0])); + + table = wlfc->destination_entries.nodes; + table_index = WLFC_MAC_DESC_GET_LOOKUP_INDEX(value[0]); + ifid = value[1]; + ea = &value[2]; + + if (type == WLFC_CTL_TYPE_MACDESC_ADD) { + existing_index = dhd_wlfc_find_mac_desc_id_from_mac(dhd, &value[2]); + if (existing_index == WLFC_MAC_DESC_ID_INVALID) { + /* this MAC entry does not exist, create one */ + if (!table[table_index].occupied) { + table[table_index].mac_handle = value[0]; + rc = _dhd_wlfc_mac_entry_update(wlfc, &table[table_index], + eWLFC_MAC_ENTRY_ACTION_ADD, ifid, + wlfc->destination_entries.interfaces[ifid].iftype, + ea); + } + else { + /* the space should have been empty, but it's not */ + wlfc->stats.mac_update_failed++; + } + } + else { + /* + there is an existing entry, move it to new index + if necessary. + */ + if (existing_index != table_index) { + /* if we already have an entry, free the old one */ + table[existing_index].occupied = 0; + table[existing_index].state = WLFC_STATE_CLOSE; + table[existing_index].requested_credit = 0; + table[existing_index].interface_id = 0; + /* enable after packets are queued-deqeued properly. + pktq_flush(dhd->osh, &table[existing_index].psq, FALSE, NULL, 0); + */ + } + } + } + if (type == WLFC_CTL_TYPE_MACDESC_DEL) { + if (table[table_index].occupied) { + rc = _dhd_wlfc_mac_entry_update(wlfc, &table[table_index], + eWLFC_MAC_ENTRY_ACTION_DEL, ifid, + wlfc->destination_entries.interfaces[ifid].iftype, + ea); + } + else { + /* the space should have been occupied, but it's not */ + wlfc->stats.mac_update_failed++; + } + } + BCM_REFERENCE(rc); + return BCME_OK; +} + +static int +dhd_wlfc_psmode_update(dhd_pub_t *dhd, uint8* value, uint8 type) +{ + /* Handle PS on/off indication */ + athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) + dhd->wlfc_state; + wlfc_mac_descriptor_t* table; + wlfc_mac_descriptor_t* desc; + uint8 mac_handle = value[0]; + int i; + + table = wlfc->destination_entries.nodes; + desc = &table[WLFC_MAC_DESC_GET_LOOKUP_INDEX(mac_handle)]; + if (desc->occupied) { + /* a fresh PS mode should wipe old ps credits? */ + desc->requested_credit = 0; + if (type == WLFC_CTL_TYPE_MAC_OPEN) { + desc->state = WLFC_STATE_OPEN; + DHD_WLFC_CTRINC_MAC_OPEN(desc); + } + else { + desc->state = WLFC_STATE_CLOSE; + DHD_WLFC_CTRINC_MAC_CLOSE(desc); + /* + Indicate to firmware if there is any traffic pending. + */ + for (i = AC_BE; i < AC_COUNT; i++) { + _dhd_wlfc_traffic_pending_check(wlfc, desc, i); + } + } + } + else { + wlfc->stats.psmode_update_failed++; + } + return BCME_OK; +} + +static int +dhd_wlfc_interface_update(dhd_pub_t *dhd, uint8* value, uint8 type) +{ + /* Handle PS on/off indication */ + athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) + dhd->wlfc_state; + wlfc_mac_descriptor_t* table; + uint8 if_id = value[0]; + + if (if_id < WLFC_MAX_IFNUM) { + table = wlfc->destination_entries.interfaces; + if (table[if_id].occupied) { + if (type == WLFC_CTL_TYPE_INTERFACE_OPEN) { + table[if_id].state = WLFC_STATE_OPEN; + /* WLFC_DBGMESG(("INTERFACE[%d] OPEN\n", if_id)); */ + } + else { + table[if_id].state = WLFC_STATE_CLOSE; + /* WLFC_DBGMESG(("INTERFACE[%d] CLOSE\n", if_id)); */ + } + return BCME_OK; + } + } + wlfc->stats.interface_update_failed++; + + return BCME_OK; +} + +static int +dhd_wlfc_credit_request(dhd_pub_t *dhd, uint8* value) +{ + athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) + dhd->wlfc_state; + wlfc_mac_descriptor_t* table; + wlfc_mac_descriptor_t* desc; + uint8 mac_handle; + uint8 credit; + + table = wlfc->destination_entries.nodes; + mac_handle = value[1]; + credit = value[0]; + + desc = &table[WLFC_MAC_DESC_GET_LOOKUP_INDEX(mac_handle)]; + if (desc->occupied) { + desc->requested_credit = credit; + + desc->ac_bitmap = value[2]; + } + else { + wlfc->stats.credit_request_failed++; + } + return BCME_OK; +} + +static int +dhd_wlfc_packet_request(dhd_pub_t *dhd, uint8* value) +{ + athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) + dhd->wlfc_state; + wlfc_mac_descriptor_t* table; + wlfc_mac_descriptor_t* desc; + uint8 mac_handle; + uint8 packet_count; + + table = wlfc->destination_entries.nodes; + mac_handle = value[1]; + packet_count = value[0]; + + desc = &table[WLFC_MAC_DESC_GET_LOOKUP_INDEX(mac_handle)]; + if (desc->occupied) { + desc->requested_packet = packet_count; + + desc->ac_bitmap = value[2]; + } + else { + wlfc->stats.packet_request_failed++; + } + return BCME_OK; +} + +static void +dhd_wlfc_reorderinfo_indicate(uint8 *val, uint8 len, uchar *info_buf, uint *info_len) +{ + if (info_len) { + if (info_buf) { + bcopy(val, info_buf, len); + *info_len = len; + } + else + *info_len = 0; + } +} + +int +dhd_wlfc_parse_header_info(dhd_pub_t *dhd, void* pktbuf, int tlv_hdr_len, uchar *reorder_info_buf, + uint *reorder_info_len) +{ + uint8 type, len; + uint8* value; + uint8* tmpbuf; + uint16 remainder = tlv_hdr_len; + uint16 processed = 0; + athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) + dhd->wlfc_state; + tmpbuf = (uint8*)PKTDATA(dhd->osh, pktbuf); + if (remainder) { + while ((processed < (WLFC_MAX_PENDING_DATALEN * 2)) && (remainder > 0)) { + type = tmpbuf[processed]; + if (type == WLFC_CTL_TYPE_FILLER) { + remainder -= 1; + processed += 1; + continue; + } + + len = tmpbuf[processed + 1]; + value = &tmpbuf[processed + 2]; + + if (remainder < (2 + len)) + break; + + remainder -= 2 + len; + processed += 2 + len; + if (type == WLFC_CTL_TYPE_TXSTATUS) + dhd_wlfc_txstatus_update(dhd, value); + if (type == WLFC_CTL_TYPE_COMP_TXSTATUS) + dhd_wlfc_compressed_txstatus_update(dhd, value, len); + + else if (type == WLFC_CTL_TYPE_HOST_REORDER_RXPKTS) + dhd_wlfc_reorderinfo_indicate(value, len, reorder_info_buf, + reorder_info_len); + else if (type == WLFC_CTL_TYPE_FIFO_CREDITBACK) + dhd_wlfc_fifocreditback_indicate(dhd, value); + + else if (type == WLFC_CTL_TYPE_RSSI) + dhd_wlfc_rssi_indicate(dhd, value); + + else if (type == WLFC_CTL_TYPE_MAC_REQUEST_CREDIT) + dhd_wlfc_credit_request(dhd, value); + + else if (type == WLFC_CTL_TYPE_MAC_REQUEST_PACKET) + dhd_wlfc_packet_request(dhd, value); + + else if ((type == WLFC_CTL_TYPE_MAC_OPEN) || + (type == WLFC_CTL_TYPE_MAC_CLOSE)) + dhd_wlfc_psmode_update(dhd, value, type); + + else if ((type == WLFC_CTL_TYPE_MACDESC_ADD) || + (type == WLFC_CTL_TYPE_MACDESC_DEL)) + dhd_wlfc_mac_table_update(dhd, value, type); + + else if (type == WLFC_CTL_TYPE_TRANS_ID) + dhd_wlfc_dbg_senum_check(dhd, value); + + else if ((type == WLFC_CTL_TYPE_INTERFACE_OPEN) || + (type == WLFC_CTL_TYPE_INTERFACE_CLOSE)) { + dhd_wlfc_interface_update(dhd, value, type); + } + } + if (remainder != 0) { + /* trouble..., something is not right */ + wlfc->stats.tlv_parse_failed++; + } + } + return BCME_OK; +} + +int +dhd_wlfc_init(dhd_pub_t *dhd) +{ + char iovbuf[12]; /* Room for "tlv" + '\0' + parameter */ + /* enable all signals & indicate host proptxstatus logic is active */ + uint32 tlv = dhd->wlfc_enabled? + WLFC_FLAGS_RSSI_SIGNALS | + WLFC_FLAGS_XONXOFF_SIGNALS | + WLFC_FLAGS_CREDIT_STATUS_SIGNALS | + WLFC_FLAGS_HOST_PROPTXSTATUS_ACTIVE | + WLFC_FLAGS_HOST_RXRERODER_ACTIVE : 0; + /* WLFC_FLAGS_HOST_PROPTXSTATUS_ACTIVE | WLFC_FLAGS_HOST_RXRERODER_ACTIVE : 0; */ + + + /* + try to enable/disable signaling by sending "tlv" iovar. if that fails, + fallback to no flow control? Print a message for now. + */ + + /* enable proptxtstatus signaling by default */ + bcm_mkiovar("tlv", (char *)&tlv, 4, iovbuf, sizeof(iovbuf)); + if (dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0) < 0) { + DHD_ERROR(("dhd_wlfc_init(): failed to enable/disable bdcv2 tlv signaling\n")); + } + else { + /* + Leaving the message for now, it should be removed after a while; once + the tlv situation is stable. + */ + DHD_ERROR(("dhd_wlfc_init(): successfully %s bdcv2 tlv signaling, %d\n", + dhd->wlfc_enabled?"enabled":"disabled", tlv)); + } + return BCME_OK; +} + +int +dhd_wlfc_enable(dhd_pub_t *dhd) +{ + int i; + athost_wl_status_info_t* wlfc; + + if (!dhd->wlfc_enabled || dhd->wlfc_state) + return BCME_OK; + + /* allocate space to track txstatus propagated from firmware */ + dhd->wlfc_state = MALLOC(dhd->osh, sizeof(athost_wl_status_info_t)); + if (dhd->wlfc_state == NULL) + return BCME_NOMEM; + + /* initialize state space */ + wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; + memset(wlfc, 0, sizeof(athost_wl_status_info_t)); + + /* remember osh & dhdp */ + wlfc->osh = dhd->osh; + wlfc->dhdp = dhd; + + wlfc->hanger = + dhd_wlfc_hanger_create(dhd->osh, WLFC_HANGER_MAXITEMS); + if (wlfc->hanger == NULL) { + MFREE(dhd->osh, dhd->wlfc_state, sizeof(athost_wl_status_info_t)); + dhd->wlfc_state = NULL; + DHD_ERROR(("Failed to malloc dhd->wlfc_state\n")); + return BCME_NOMEM; + } + + /* initialize all interfaces to accept traffic */ + for (i = 0; i < WLFC_MAX_IFNUM; i++) { + wlfc->hostif_flow_state[i] = OFF; + } + + wlfc->destination_entries.other.state = WLFC_STATE_OPEN; + /* bc/mc FIFO is always open [credit aside], i.e. b[5] */ + wlfc->destination_entries.other.ac_bitmap = 0x1f; + wlfc->destination_entries.other.interface_id = 0; + + wlfc->proptxstatus_mode = WLFC_FCMODE_EXPLICIT_CREDIT; + + wlfc->allow_credit_borrow = TRUE; + wlfc->borrow_defer_timestamp = 0; + + return BCME_OK; +} + +/* release all packet resources */ +void +dhd_wlfc_cleanup(dhd_pub_t *dhd, ifpkt_cb_t fn, int arg) +{ + int i; + int total_entries; + athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) + dhd->wlfc_state; + wlfc_mac_descriptor_t* table; + wlfc_hanger_t* h; + int prec; + void *pkt = NULL; + struct pktq *txq = NULL; + if (dhd->wlfc_state == NULL) + return; + /* flush bus->txq */ + txq = dhd_bus_txq(dhd->bus); + /* any in the hanger? */ + h = (wlfc_hanger_t*)wlfc->hanger; + total_entries = sizeof(wlfc->destination_entries)/sizeof(wlfc_mac_descriptor_t); + /* search all entries, include nodes as well as interfaces */ + table = (wlfc_mac_descriptor_t*)&wlfc->destination_entries; + + for (i = 0; i < total_entries; i++) { + if (table[i].occupied && (fn == NULL || (arg == table[i].interface_id))) { + if (table[i].psq.len) { + WLFC_DBGMESG(("%s(): DELAYQ[%d].len = %d\n", + __FUNCTION__, i, table[i].psq.len)); + /* release packets held in DELAYQ */ + pktq_flush(wlfc->osh, &table[i].psq, TRUE, fn, arg); + } + if (fn == NULL) + table[i].occupied = 0; + } + } + for (prec = 0; prec < txq->num_prec; prec++) { + pkt = pktq_pdeq_with_fn(txq, prec, fn, arg); + while (pkt) { + for (i = 0; i < h->max_items; i++) { + if (pkt == h->items[i].pkt) { + if (h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE) { + PKTFREE(wlfc->osh, h->items[i].pkt, TRUE); + h->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; + } else if (h->items[i].state == + WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED) { + /* These are already freed from the psq */ + h->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; + } + break; + } + } + pkt = pktq_pdeq(txq, prec); + } + } + /* flush remained pkt in hanger queue, not in bus->txq */ + for (i = 0; i < h->max_items; i++) { + if (h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE) { + if (fn == NULL || (*fn)(h->items[i].pkt, arg)) { + PKTFREE(wlfc->osh, h->items[i].pkt, TRUE); + h->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; + } + } else if (h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED) { + if (fn == NULL || (*fn)(h->items[i].pkt, arg)) { + /* These are freed from the psq so no need to free again */ + h->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; + } + } + } + return; +} + +void +dhd_wlfc_deinit(dhd_pub_t *dhd) +{ + /* cleanup all psq related resources */ + athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) + dhd->wlfc_state; + + dhd_os_wlfc_block(dhd); + if (dhd->wlfc_state == NULL) { + dhd_os_wlfc_unblock(dhd); + return; + } + +#ifdef PROP_TXSTATUS_DEBUG + { + int i; + wlfc_hanger_t* h = (wlfc_hanger_t*)wlfc->hanger; + for (i = 0; i < h->max_items; i++) { + if (h->items[i].state != WLFC_HANGER_ITEM_STATE_FREE) { + WLFC_DBGMESG(("%s() pkt[%d] = 0x%p, FIFO_credit_used:%d\n", + __FUNCTION__, i, h->items[i].pkt, + DHD_PKTTAG_CREDITCHECK(PKTTAG(h->items[i].pkt)))); + } + } + } +#endif + /* delete hanger */ + dhd_wlfc_hanger_delete(dhd->osh, wlfc->hanger); + + /* free top structure */ + MFREE(dhd->osh, dhd->wlfc_state, sizeof(athost_wl_status_info_t)); + dhd->wlfc_state = NULL; + dhd_os_wlfc_unblock(dhd); + + return; +} +#endif /* PROP_TXSTATUS */ diff --git a/drivers/net/wireless/bcmdhd/dhd_wlfc.h b/drivers/net/wireless/bcmdhd/dhd_wlfc.h index d844ef0bfe97..cf05d9f161f6 100644..100755 --- a/drivers/net/wireless/bcmdhd/dhd_wlfc.h +++ b/drivers/net/wireless/bcmdhd/dhd_wlfc.h @@ -1,5 +1,5 @@ /* -* Copyright (C) 1999-2012, Broadcom Corporation +* Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -18,18 +18,24 @@ * 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_wlfc.h 361006 2012-10-05 07:45:51Z $ +* $Id: dhd_wlfc.h 398418 2013-04-24 15:18:27Z $ * */ #ifndef __wlfc_host_driver_definitions_h__ #define __wlfc_host_driver_definitions_h__ +#ifdef QMONITOR +#include <dhd_qmon.h> +#endif + + /* 16 bits will provide an absolute max of 65536 slots */ #define WLFC_HANGER_MAXITEMS 1024 -#define WLFC_HANGER_ITEM_STATE_FREE 1 -#define WLFC_HANGER_ITEM_STATE_INUSE 2 +#define WLFC_HANGER_ITEM_STATE_FREE 1 +#define WLFC_HANGER_ITEM_STATE_INUSE 2 #define WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED 3 + #define WLFC_PKTID_HSLOT_MASK 0xffff /* allow 16 bits only */ #define WLFC_PKTID_HSLOT_SHIFT 8 @@ -84,8 +90,8 @@ typedef struct wlfc_hanger { uint32 failed_to_push; uint32 failed_to_pop; uint32 failed_slotfind; - wlfc_hanger_item_t items[1]; uint32 slot_pos; + wlfc_hanger_item_t items[1]; } wlfc_hanger_t; #define WLFC_HANGER_SIZE(n) ((sizeof(wlfc_hanger_t) - \ @@ -98,13 +104,9 @@ typedef struct wlfc_hanger { #define WLFC_PSQ_LEN 2048 -#define WLFC_SENDQ_LEN 256 - - #define WLFC_FLOWCONTROL_HIWATER (2048 - 256) #define WLFC_FLOWCONTROL_LOWATER 256 - typedef struct wlfc_mac_descriptor { uint8 occupied; uint8 interface_id; @@ -128,19 +130,21 @@ typedef struct wlfc_mac_descriptor { /* 1= send on next opportunity */ uint8 send_tim_signal; uint8 mac_handle; + /* Number of packets in transit for this entry. */ uint transit_count; + /* Numbe of suppression to wait before evict from delayQ */ uint suppr_transit_count; + /* Used when a new suppress is detected to track the number of + * packets getting suppressed + */ uint suppress_count; - uint8 suppressed; + /* flag. TRUE when in suppress state */ + uint8 suppressed; + uint8 deleting; -#ifdef QUEUE_BW - uint32 transitallq_count; - uint32 queued_time_thres; - uint64 queued_time_cumul; - uint64 queued_time_cumul_last; - uint64 queued_time_last; - uint64 queued_time_last_io; -#endif /* QUEUE_BW */ +#ifdef QMONITOR + dhd_qmon_t qmon; +#endif /* QMONITOR */ #ifdef PROP_TXSTATUS_DEBUG uint32 dstncredit_sent_packets; @@ -163,7 +167,6 @@ typedef struct athost_wl_stat_counters { uint32 tlv_parse_failed; uint32 rollback; uint32 rollback_failed; - uint32 sendq_full_error; uint32 delayq_full_error; uint32 credit_request_failed; uint32 packet_request_failed; @@ -188,7 +191,7 @@ typedef struct athost_wl_stat_counters { uint32 dhd_hdrpulls; uint32 generic_error; /* an extra one for bc/mc traffic */ - uint32 sendq_pkts[AC_COUNT + 1]; + uint32 send_pkts[AC_COUNT + 1]; #ifdef PROP_TXSTATUS_DEBUG /* all pkt2bus -> txstatus latency accumulated */ uint32 latency_sample_count; @@ -247,8 +250,6 @@ typedef struct athost_wl_status_info { /* Credit borrow counts for each FIFO from each of the other FIFOs */ int credits_borrowed[AC_COUNT + 2][AC_COUNT + 2]; - struct pktq SENDQ; - /* packet hanger and MAC->handle lookup table */ void* hanger; struct { @@ -293,4 +294,13 @@ int dhd_wlfc_event(struct dhd_info *dhd); int dhd_os_wlfc_block(dhd_pub_t *pub); int dhd_os_wlfc_unblock(dhd_pub_t *pub); +void dhd_wlfc_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf); +int dhd_wlfc_init(dhd_pub_t *dhd); +void dhd_wlfc_deinit(dhd_pub_t *dhd); +int dhd_wlfc_parse_header_info(dhd_pub_t *dhd, void* pktbuf, int tlv_hdr_len, + uchar *reorder_info_buf, uint *reorder_info_len); +int dhd_wlfc_commit_packets(void* state, f_commitpkt_t fcommit, + void* commit_ctx, void *pktbuf); +void dhd_wlfc_cleanup(dhd_pub_t *dhd, ifpkt_cb_t fn, int arg); +bool ifpkt_fn(void* p, int ifid); #endif /* __wlfc_host_driver_definitions_h__ */ diff --git a/drivers/net/wireless/bcmdhd/dngl_stats.h b/drivers/net/wireless/bcmdhd/dngl_stats.h index 5e5a2e2e5314..0bc3b53f29e8 100644..100755 --- a/drivers/net/wireless/bcmdhd/dngl_stats.h +++ b/drivers/net/wireless/bcmdhd/dngl_stats.h @@ -2,7 +2,7 @@ * Common stats definitions for clients of dongle * ports * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd/dngl_wlhdr.h b/drivers/net/wireless/bcmdhd/dngl_wlhdr.h index 0e37df6e19ef..d5eda8cb3ea5 100644..100755 --- a/drivers/net/wireless/bcmdhd/dngl_wlhdr.h +++ b/drivers/net/wireless/bcmdhd/dngl_wlhdr.h @@ -1,7 +1,7 @@ /* * Dongle WL Header definitions * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd/hndpmu.c b/drivers/net/wireless/bcmdhd/hndpmu.c index e639015b1498..e94fe802bdb9 100644..100755 --- a/drivers/net/wireless/bcmdhd/hndpmu.c +++ b/drivers/net/wireless/bcmdhd/hndpmu.c @@ -2,7 +2,7 @@ * Misc utility routines for accessing PMU corerev specific features * of the SiliconBackplane-based Broadcom chips. * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -22,7 +22,16 @@ * 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: hndpmu.c 354194 2012-08-30 08:39:03Z $ + * $Id: hndpmu.c 414368 2013-07-24 15:00:23Z $ + */ + +/* + * Note: this file contains PLL/FLL related functions. A chip can contain multiple PLLs/FLLs. + * However, in the context of this file the baseband ('BB') PLL/FLL is referred to. + * + * Throughout this code, the prefixes 'pmu0_', 'pmu1_' and 'pmu2_' are used. + * They refer to different revisions of the PMU (which is at revision 18 @ Apr 25, 2012) + * pmu2_ marks the transition from PLL to ADFLL (Digital Frequency Locked Loop) */ #include <bcm_cfg.h> @@ -116,16 +125,54 @@ static const sdiod_drive_str_t sdiod_drive_strength_tab6_1v8[] = { {1, 0x1}, {0, 0x0} }; + +/* + * SDIO Drive Strength to sel value table for 43143 PMU Rev 17, see Confluence 43143 Toplevel + * architecture page, section 'PMU Chip Control 1 Register definition', click link to picture + * BCM43143_sel_sdio_signals.jpg. Valid after PMU Chip Control 0 Register, bit31 (override) has + * been written '1'. + */ +#if !defined(BCM_SDIO_VDDIO) || BCM_SDIO_VDDIO == 33 + +static const sdiod_drive_str_t sdiod_drive_strength_tab7_3v3[] = { + /* note: for 14, 10, 6 and 2mA hw timing is not met according to rtl team */ + {16, 0x7}, + {12, 0x5}, + {8, 0x3}, + {4, 0x1} }; /* note: 43143 does not support tristate */ + +#else + +static const sdiod_drive_str_t sdiod_drive_strength_tab7_1v8[] = { + /* note: for 7, 5, 3 and 1mA hw timing is not met according to rtl team */ + {8, 0x7}, + {6, 0x5}, + {4, 0x3}, + {2, 0x1} }; /* note: 43143 does not support tristate */ + +#endif /* BCM_SDIO_VDDIO */ + #define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu)) +/** + * Balance between stable SDIO operation and power consumption is achieved using this function. + * Note that each drive strength table is for a specific VDDIO of the SDIO pads, ideally this + * function should read the VDDIO itself to select the correct table. For now it has been solved + * with the 'BCM_SDIO_VDDIO' preprocessor constant. + * + * 'drivestrength': desired pad drive strength in mA. Drive strength of 0 requests tri-state (if + * hardware supports this), if no hw support drive strength is not programmed. + */ void si_sdiod_drive_strength_init(si_t *sih, osl_t *osh, uint32 drivestrength) { chipcregs_t *cc; uint origidx, intr_val = 0; sdiod_drive_str_t *str_tab = NULL; - uint32 str_mask = 0; + uint32 str_mask = 0; /* only alter desired bits in PMU chipcontrol 1 register */ uint32 str_shift = 0; + uint32 str_ovr_pmuctl = PMU_CHIPCTL0; /* PMU chipcontrol register containing override bit */ + uint32 str_ovr_pmuval = 0; /* position of bit within this register */ if (!(sih->cccaps & CC_CAP_PMU)) { return; @@ -173,10 +220,22 @@ si_sdiod_drive_strength_init(si_t *sih, osl_t *osh, uint32 drivestrength) str_mask = 0x00001800; str_shift = 11; break; + case SDIOD_DRVSTR_KEY(BCM43143_CHIP_ID, 17): +#if !defined(BCM_SDIO_VDDIO) || BCM_SDIO_VDDIO == 33 + if (drivestrength >= ARRAYLAST(sdiod_drive_strength_tab7_3v3)->strength) { + str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab7_3v3; + } +#else + if (drivestrength >= ARRAYLAST(sdiod_drive_strength_tab7_1v8)->strength) { + str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab7_1v8; + } +#endif /* BCM_SDIO_VDDIO */ + str_mask = 0x00000007; + str_ovr_pmuval = PMU43143_CC0_SDIO_DRSTR_OVR; + break; default: PMU_MSG(("No SDIO Drive strength init done for chip %s rev %d pmurev %d\n", bcm_chipname(sih->chip, chn, 8), sih->chiprev, sih->pmurev)); - break; } @@ -193,16 +252,19 @@ si_sdiod_drive_strength_init(si_t *sih, osl_t *osh, uint32 drivestrength) if (i > 0 && drivestrength > str_tab[i].strength) i--; - W_REG(osh, &cc->chipcontrol_addr, 1); + W_REG(osh, &cc->chipcontrol_addr, PMU_CHIPCTL1); cc_data_temp = R_REG(osh, &cc->chipcontrol_data); cc_data_temp &= ~str_mask; cc_data_temp |= str_tab[i].sel << str_shift; W_REG(osh, &cc->chipcontrol_data, cc_data_temp); - + if (str_ovr_pmuval) { /* enables the selected drive strength */ + W_REG(osh, &cc->chipcontrol_addr, str_ovr_pmuctl); + OR_REG(osh, &cc->chipcontrol_data, str_ovr_pmuval); + } PMU_MSG(("SDIO: %dmA drive strength requested; set to %dmA\n", drivestrength, str_tab[i].strength)); } /* Return to original core */ si_restore_core(sih, origidx, intr_val); -} +} /* si_sdiod_drive_strength_init */ diff --git a/drivers/net/wireless/bcmdhd/include/Makefile b/drivers/net/wireless/bcmdhd/include/Makefile index 42b3b689b561..2ae584c97a99 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/Makefile +++ b/drivers/net/wireless/bcmdhd/include/Makefile @@ -10,10 +10,10 @@ # # Copyright 2005, Broadcom, Inc. # -# $Id: Makefile 241686 2011-02-19 00:22:45Z $ +# $Id: Makefile 347587 2012-07-27 09:13:31Z prakashd $ # -SRCBASE := .. +export SRCBASE:=.. TARGETS := epivers.h @@ -23,11 +23,11 @@ endif all release: epivers compvers -# Generate epivers.h for native branch version +# Generate epivers.h for native branch url epivers: bash epivers.sh -# Generate epivers.h for native branch version +# Generate component versions based on component url compvers: @if [ -s "compvers.sh" ]; then \ echo "Generating component versions, if any"; \ @@ -51,3 +51,4 @@ clean: clean_all: clean clean_compvers .PHONY: all release clean epivers compvers clean_compvers + diff --git a/drivers/net/wireless/bcmdhd/include/aidmp.h b/drivers/net/wireless/bcmdhd/include/aidmp.h index d55707997f82..ba5ef2172ce9 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/aidmp.h +++ b/drivers/net/wireless/bcmdhd/include/aidmp.h @@ -1,7 +1,7 @@ /* * Broadcom AMBA Interconnect definitions. * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -21,7 +21,7 @@ * 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: aidmp.h 241182 2011-02-17 21:50:03Z $ + * $Id: aidmp.h 385510 2013-02-15 21:02:07Z $ */ #ifndef _AIDMP_H @@ -372,4 +372,15 @@ typedef volatile struct _aidmp { #define OOB_SEL_OUTEN_B_5 15 #define OOB_SEL_OUTEN_B_6 23 +/* AI_OOBSEL for A/B/C/D, 0-7 */ +#define AI_OOBSEL_MASK 0x1F +#define AI_OOBSEL_0_SHIFT 0 +#define AI_OOBSEL_1_SHIFT 8 +#define AI_OOBSEL_2_SHIFT 16 +#define AI_OOBSEL_3_SHIFT 24 +#define AI_OOBSEL_4_SHIFT 0 +#define AI_OOBSEL_5_SHIFT 8 +#define AI_OOBSEL_6_SHIFT 16 +#define AI_OOBSEL_7_SHIFT 24 + #endif /* _AIDMP_H */ diff --git a/drivers/net/wireless/bcmdhd/include/bcm_cfg.h b/drivers/net/wireless/bcmdhd/include/bcm_cfg.h index ecff4f4d3640..bb7d20f25653 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/bcm_cfg.h +++ b/drivers/net/wireless/bcmdhd/include/bcm_cfg.h @@ -1,7 +1,7 @@ /* * BCM common config options * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: bcm_cfg.h 294399 2011-11-07 03:31:22Z $ + * $Id: bcm_cfg.h 351867 2012-08-21 18:46:16Z $ */ #ifndef _bcm_cfg_h_ diff --git a/drivers/net/wireless/bcmdhd/include/bcm_mpool_pub.h b/drivers/net/wireless/bcmdhd/include/bcm_mpool_pub.h index 8fe3de7afb72..51a5de712542 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/bcm_mpool_pub.h +++ b/drivers/net/wireless/bcmdhd/include/bcm_mpool_pub.h @@ -35,7 +35,7 @@ * and instrumentation on top of the heap, without modifying the heap * allocation implementation. * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd/include/bcmcdc.h b/drivers/net/wireless/bcmdhd/include/bcmcdc.h index a1d12713ea4e..2aa6d62ecd7b 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/bcmcdc.h +++ b/drivers/net/wireless/bcmdhd/include/bcmcdc.h @@ -4,7 +4,7 @@ * * Definitions subject to change without notice. * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd/include/bcmdefs.h b/drivers/net/wireless/bcmdhd/include/bcmdefs.h index 00906e357473..d02efddd5128 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/bcmdefs.h +++ b/drivers/net/wireless/bcmdhd/include/bcmdefs.h @@ -1,7 +1,7 @@ /* * Misc system wide definitions * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -21,7 +21,7 @@ * 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: bcmdefs.h 316830 2012-02-23 20:29:22Z $ + * $Id: bcmdefs.h 424298 2013-09-17 06:38:13Z $ */ #ifndef _bcmdefs_h_ @@ -65,9 +65,17 @@ #define BCMNMIATTACHFN(_fn) _fn #define BCMNMIATTACHDATA(_data) _data #define CONST const + +#undef BCM47XX_CA9 + #ifndef BCMFASTPATH +#if defined(BCM47XX_CA9) +#define BCMFASTPATH __attribute__ ((__section__ (".text.fastpath"))) +#define BCMFASTPATH_HOST __attribute__ ((__section__ (".text.fastpath_host"))) +#else #define BCMFASTPATH #define BCMFASTPATH_HOST +#endif #endif /* BCMFASTPATH */ @@ -193,9 +201,13 @@ typedef struct { #if defined(BCM_RPC_NOCOPY) || defined(BCM_RCP_TXNOCOPY) /* add 40 bytes to allow for extra RPC header and info */ -#define BCMEXTRAHDROOM 220 +#define BCMEXTRAHDROOM 260 #else /* BCM_RPC_NOCOPY || BCM_RPC_TXNOCOPY */ -#define BCMEXTRAHDROOM 172 +#if defined(BCM47XX_CA9) +#define BCMEXTRAHDROOM 224 +#else +#define BCMEXTRAHDROOM 204 +#endif /* linux && BCM47XX_CA9 */ #endif /* BCM_RPC_NOCOPY || BCM_RPC_TXNOCOPY */ /* Packet alignment for most efficient SDIO (can change based on platform) */ diff --git a/drivers/net/wireless/bcmdhd/include/bcmdevs.h b/drivers/net/wireless/bcmdhd/include/bcmdevs.h index c3dd89fc68c4..507733d7a3a7 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/bcmdevs.h +++ b/drivers/net/wireless/bcmdhd/include/bcmdevs.h @@ -1,7 +1,7 @@ /* * Broadcom device-specific manifest constants. * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -21,7 +21,7 @@ * 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: bcmdevs.h 329854 2012-04-27 01:42:28Z $ + * $Id: bcmdevs.h 414368 2013-07-24 15:00:23Z $ */ #ifndef _BCMDEVS_H @@ -63,6 +63,12 @@ #define BCM_DNGL_BL_PID_43239 0xbd1b #define BCM_DNGL_BL_PID_4324 0xbd1c #define BCM_DNGL_BL_PID_4360 0xbd1d +#define BCM_DNGL_BL_PID_43143 0xbd1e +#define BCM_DNGL_BL_PID_43242 0xbd1f +#define BCM_DNGL_BL_PID_43342 0xbd21 +#define BCM_DNGL_BL_PID_4335 0xbd20 +#define BCM_DNGL_BL_PID_4350 0xbd23 +#define BCM_DNGL_BL_PID_43341 0xbd22 #define BCM_DNGL_BDC_PID 0x0bdc #define BCM_DNGL_JTAG_PID 0x4a44 @@ -131,6 +137,8 @@ #define BCM4330_D11N5G_ID 0x4362 /* 4330 802.11n 5G device */ #define BCM4336_D11N_ID 0x4343 /* 4336 802.11n 2.4GHz device */ #define BCM6362_D11N_ID 0x435f /* 6362 802.11n dualband device */ +#define BCM6362_D11N2G_ID 0x433f /* 6362 802.11n 2.4Ghz band id */ +#define BCM6362_D11N5G_ID 0x434f /* 6362 802.11n 5Ghz band id */ #define BCM4331_D11N_ID 0x4331 /* 4331 802.11n dualband id */ #define BCM4331_D11N2G_ID 0x4332 /* 4331 802.11n 2.4Ghz band id */ #define BCM4331_D11N5G_ID 0x4333 /* 4331 802.11n 5Ghz band id */ @@ -146,28 +154,42 @@ #define BCM43131_D11N2G_ID 0x43aa /* 43131 802.11n 2.4GHz device */ #define BCM4314_D11N2G_ID 0x4364 /* 4314 802.11n 2.4G device */ #define BCM43142_D11N2G_ID 0x4365 /* 43142 802.11n 2.4G device */ +#define BCM43143_D11N2G_ID 0x4366 /* 43143 802.11n 2.4G device */ #define BCM4334_D11N_ID 0x4380 /* 4334 802.11n dualband device */ #define BCM4334_D11N2G_ID 0x4381 /* 4334 802.11n 2.4G device */ #define BCM4334_D11N5G_ID 0x4382 /* 4334 802.11n 5G device */ +#define BCM43342_D11N_ID 0x4383 /* 43342 802.11n dualband device */ +#define BCM43342_D11N2G_ID 0x4384 /* 43342 802.11n 2.4G device */ +#define BCM43342_D11N5G_ID 0x4385 /* 43342 802.11n 5G device */ #define BCM43341_D11N_ID 0x4386 /* 43341 802.11n dualband device */ #define BCM43341_D11N2G_ID 0x4387 /* 43341 802.11n 2.4G device */ #define BCM43341_D11N5G_ID 0x4388 /* 43341 802.11n 5G device */ #define BCM4360_D11AC_ID 0x43a0 #define BCM4360_D11AC2G_ID 0x43a1 #define BCM4360_D11AC5G_ID 0x43a2 +#define BCM4335_D11AC_ID 0x43ae +#define BCM4335_D11AC2G_ID 0x43af +#define BCM4335_D11AC5G_ID 0x43b0 +#define BCM4352_D11AC_ID 0x43b1 /* 4352 802.11ac dualband device */ +#define BCM4352_D11AC2G_ID 0x43b2 /* 4352 802.11ac 2.4G device */ +#define BCM4352_D11AC5G_ID 0x43b3 /* 4352 802.11ac 5G device */ /* PCI Subsystem ID */ #define BCM943228HMB_SSID_VEN1 0x0607 #define BCM94313HMGBL_SSID_VEN1 0x0608 #define BCM94313HMG_SSID_VEN1 0x0609 +#define BCM943142HM_SSID_VEN1 0x0611 +#define BCM43143_D11N2G_ID 0x4366 /* 43143 802.11n 2.4G device */ + +#define BCM43242_D11N_ID 0x4367 /* 43242 802.11n dualband device */ +#define BCM43242_D11N2G_ID 0x4368 /* 43242 802.11n 2.4G device */ +#define BCM43242_D11N5G_ID 0x4369 /* 43242 802.11n 5G device */ + +#define BCM4350_D11AC_ID 0x43a3 +#define BCM4350_D11AC2G_ID 0x43a4 +#define BCM4350_D11AC5G_ID 0x43a5 -#define BCM4335_D11AC_ID 0x43ae -#define BCM4335_D11AC2G_ID 0x43af -#define BCM4335_D11AC5G_ID 0x43b0 -#define BCM4352_D11AC_ID 0x43b1 /* 4352 802.11ac dualband device */ -#define BCM4352_D11AC2G_ID 0x43b2 /* 4352 802.11ac 2.4G device */ -#define BCM4352_D11AC5G_ID 0x43b3 /* 4352 802.11ac 5G device */ #define BCMGPRS_UART_ID 0x4333 /* Uart id used by 4306/gprs card */ #define BCMGPRS2_UART_ID 0x4344 /* Uart id used by 4306/gprs card */ @@ -205,6 +227,8 @@ #define BCM47XX_GIGETH_ID 0x471f /* 47xx GbE (5700) */ #define BCM4712_MIPS_ID 0x4720 /* 4712 base devid */ #define BCM4716_DEVICE_ID 0x4722 /* 4716 base devid */ +#define BCM47XX_USB30H_ID 0x472a /* 47xx usb 3.0 host */ +#define BCM47XX_USB30D_ID 0x472b /* 47xx usb 3.0 device */ #define BCM47XX_SMBUS_EMU_ID 0x47fe /* 47xx emulated SMBus device */ #define BCM47XX_XOR_EMU_ID 0x47ff /* 47xx emulated XOR engine */ #define EPI41210_DEVICE_ID 0xa0fa /* bcm4210 */ @@ -260,21 +284,28 @@ #define BCM6362_CHIP_ID 0x6362 /* 6362 chipcommon chipid */ #define BCM4314_CHIP_ID 0x4314 /* 4314 chipcommon chipid */ #define BCM43142_CHIP_ID 43142 /* 43142 chipcommon chipid */ +#define BCM43143_CHIP_ID 43143 /* 43143 chipcommon chipid */ #define BCM4324_CHIP_ID 0x4324 /* 4324 chipcommon chipid */ #define BCM43242_CHIP_ID 43242 /* 43242 chipcommon chipid */ +#define BCM43243_CHIP_ID 43243 /* 43243 chipcommon chipid */ #define BCM4334_CHIP_ID 0x4334 /* 4334 chipcommon chipid */ +#define BCM4335_CHIP_ID 0x4335 /* 4335 chipcommon chipid */ +#define BCM4339_CHIP_ID 0x4339 /* 4339 chipcommon chipid */ #define BCM4360_CHIP_ID 0x4360 /* 4360 chipcommon chipid */ #define BCM4352_CHIP_ID 0x4352 /* 4352 chipcommon chipid */ #define BCM43526_CHIP_ID 0xAA06 +#define BCM43340_CHIP_ID 43340 /* 43340 chipcommon chipid */ #define BCM43341_CHIP_ID 43341 /* 43341 chipcommon chipid */ #define BCM43342_CHIP_ID 43342 /* 43342 chipcommon chipid */ - -#define BCM4335_CHIP_ID 0x4335 +#define BCM4350_CHIP_ID 0x4350 /* 4350 chipcommon chipid */ #define BCM4342_CHIP_ID 4342 /* 4342 chipcommon chipid (OTP, RBBU) */ #define BCM4402_CHIP_ID 0x4402 /* 4402 chipid */ #define BCM4704_CHIP_ID 0x4704 /* 4704 chipcommon chipid */ #define BCM4706_CHIP_ID 0x5300 /* 4706 chipcommon chipid */ +#define BCM4707_CHIP_ID 53010 /* 4707 chipcommon chipid */ +#define BCM53018_CHIP_ID 53018 /* 53018 chipcommon chipid */ +#define BCM4707_CHIP(chipid) (((chipid) == BCM4707_CHIP_ID) || ((chipid) == BCM53018_CHIP_ID)) #define BCM4710_CHIP_ID 0x4710 /* 4710 chipid */ #define BCM4712_CHIP_ID 0x4712 /* 4712 chipcommon chipid */ #define BCM4716_CHIP_ID 0x4716 /* 4716 chipcommon chipid */ @@ -336,27 +367,38 @@ #define BCM4314SDIO_FPBGA_PKG_ID (8 | 4) /* 4314 FpBGA SDIO package id */ #define BCM4314DEV_PKG_ID (8 | 6) /* 4314 Developement package id */ +#define BCM4707_PKG_ID 1 /* 4707 package id */ +#define BCM4708_PKG_ID 2 /* 4708 package id */ +#define BCM4709_PKG_ID 0 /* 4709 package id */ + #define PCIXX21_FLASHMEDIA0_ID 0x8033 /* TI PCI xx21 Standard Host Controller */ #define PCIXX21_SDIOH0_ID 0x8034 /* TI PCI xx21 Standard Host Controller */ +#define BCM4335_WLCSP_PKG_ID (0x0) /* WLCSP Module/Mobile SDIO/HSIC. */ +#define BCM4335_FCBGA_PKG_ID (0x1) /* FCBGA PC/Embeded/Media PCIE/SDIO */ +#define BCM4335_WLBGA_PKG_ID (0x2) /* WLBGA COB/Mobile SDIO/HSIC. */ +#define BCM4335_FCBGAD_PKG_ID (0x3) /* FCBGA Debug Debug/Dev All if's. */ +#define BCM4335_PKG_MASK (0x3) + /* boardflags */ #define BFL_BTC2WIRE 0x00000001 /* old 2wire Bluetooth coexistence, OBSOLETE */ #define BFL_BTCOEX 0x00000001 /* Board supports BTCOEX */ #define BFL_PACTRL 0x00000002 /* Board has gpio 9 controlling the PA */ #define BFL_AIRLINEMODE 0x00000004 /* Board implements gpio 13 radio disable indication, UNUSED */ #define BFL_ADCDIV 0x00000008 /* Board has the rssi ADC divider */ -#define BFL_RFPLL 0x00000008 /* ACPHY: Changing RFPLL BW to be 150 MHz */ +#define BFL_DIS_256QAM 0x00000008 #define BFL_ENETROBO 0x00000010 /* Board has robo switch or core */ #define BFL_NOPLLDOWN 0x00000020 /* Not ok to power down the chip pll and oscillator */ #define BFL_CCKHIPWR 0x00000040 /* Can do high-power CCK transmission */ #define BFL_ENETADM 0x00000080 /* Board has ADMtek switch */ #define BFL_ENETVLAN 0x00000100 /* Board has VLAN capability */ -#define BFL_UNUSED 0x00000200 +#define BFL_LTECOEX 0x00000200 /* Board has LTE coex capability */ #define BFL_NOPCI 0x00000400 /* Board leaves PCI floating */ #define BFL_FEM 0x00000800 /* Board supports the Front End Module */ #define BFL_EXTLNA 0x00001000 /* Board has an external LNA in 2.4GHz band */ #define BFL_HGPA 0x00002000 /* Board has a high gain PA */ -#define BFL_BTC2WIRE_ALTGPIO 0x00004000 /* Board's BTC 2wire is in the alternate gpios */ +#define BFL_BTC2WIRE_ALTGPIO 0x00004000 +/* Board's BTC 2wire is in the alternate gpios OBSLETE */ #define BFL_ALTIQ 0x00008000 /* Alternate I/Q settings */ #define BFL_NOPA 0x00010000 /* Board has no PA */ #define BFL_RSSIINV 0x00020000 /* Board's RSSI uses positive slope(not TSSI) */ @@ -365,6 +407,7 @@ #define BFL_PHASESHIFT 0x00100000 /* Board can support phase shifter */ #define BFL_BUCKBOOST 0x00200000 /* Power topology uses BUCKBOOST */ #define BFL_FEM_BT 0x00400000 /* Board has FEM and switch to share antenna w/ BT */ +#define BFL_RXCHAIN_OFF_BT 0x00400000 /* one rxchain is to be shut off when BT is active */ #define BFL_NOCBUCK 0x00800000 /* Power topology doesn't use CBUCK */ #define BFL_CCKFAVOREVM 0x01000000 /* Favor CCK EVM over spectral mask */ #define BFL_PALDO 0x02000000 /* Power topology uses PALDO */ @@ -373,6 +416,7 @@ #define BFL_UCPWRCTL_MININDX 0x08000000 /* Enforce min power index to avoid FEM damage */ #define BFL_EXTLNA_5GHz 0x10000000 /* Board has an external LNA in 5GHz band */ #define BFL_TRSW_1by2 0x20000000 /* Board has 2 TRSW's in 1by2 designs */ +#define BFL_GAINBOOSTA01 0x20000000 /* 5g Gainboost for core0 and core1 */ #define BFL_LO_TRSW_R_5GHz 0x40000000 /* In 5G do not throw TRSW to T for clipLO gain */ #define BFL_ELNA_GAINDEF 0x80000000 /* Backoff InitGain based on elna_2g/5g field * when this flag is set @@ -409,7 +453,8 @@ #define BFL2_ANAPACTRL_2G 0x00100000 /* 2G ext PAs are controlled by analog PA ctrl lines */ #define BFL2_ANAPACTRL_5G 0x00200000 /* 5G ext PAs are controlled by analog PA ctrl lines */ #define BFL2_ELNACTRL_TRSW_2G 0x00400000 /* AZW4329: 2G gmode_elna_gain controls TR Switch */ -#define BFL2_BT_SHARE_ANT0 0x00800000 /* share core0 antenna with BT */ +#define BFL2_BT_SHARE_ANT0 0x00800000 /* WLAN/BT share antenna 0 */ +#define BFL2_BT_SHARE_BM_BIT0 0x00800000 /* bit 0 of WLAN/BT shared core bitmap */ #define BFL2_TEMPSENSE_HIGHER 0x01000000 /* The tempsense threshold can sustain higher value * than programmed. The exact delta is decided by * driver per chip/boardtype. This can be used @@ -421,7 +466,46 @@ /* ucode control of eLNA during Tx */ #define BFL2_4313_RADIOREG 0x10000000 /* board rework */ -#define BFL2_SDR_EN 0x20000000 /* SDR enabled or disabled */ +#define BFL2_DYNAMIC_VMID 0x10000000 /* boardflag to enable dynamic Vmid idle TSSI CAL */ +#define BFL2_SDR_EN 0x20000000 /* SDR enabled or disabled */ +#define BFL2_LNA1BYPFORTR2G 0x40000000 /* acphy, enable lna1 bypass for clip gain, 2g */ +#define BFL2_LNA1BYPFORTR5G 0x80000000 /* acphy, enable lna1 bypass for clip gain, 5g */ + +/* SROM 11 - 11ac boardflag definitions */ +#define BFL_SROM11_BTCOEX 0x00000001 /* Board supports BTCOEX */ +#define BFL_SROM11_WLAN_BT_SH_XTL 0x00000002 /* bluetooth and wlan share same crystal */ +#define BFL_SROM11_EXTLNA 0x00001000 /* Board has an external LNA in 2.4GHz band */ +#define BFL_SROM11_EXTLNA_5GHz 0x10000000 /* Board has an external LNA in 5GHz band */ +#define BFL_SROM11_GAINBOOSTA01 0x20000000 /* 5g Gainboost for core0 and core1 */ +#define BFL2_SROM11_APLL_WAR 0x00000002 /* Flag to implement alternative A-band PLL settings */ +#define BFL2_SROM11_ANAPACTRL_2G 0x00100000 /* 2G ext PAs are ctrl-ed by analog PA ctrl lines */ +#define BFL2_SROM11_ANAPACTRL_5G 0x00200000 /* 5G ext PAs are ctrl-ed by analog PA ctrl lines */ + +/* boardflags3 */ +#define BFL3_FEMCTRL_SUB 0x00000007 /* acphy, subrevs of femctrl on top of srom_femctrl */ +#define BFL3_RCAL_WAR 0x00000008 /* acphy, rcal war active on this board (4335a0) */ +#define BFL3_TXGAINTBLID 0x00000070 /* acphy, txgain table id */ +#define BFL3_TXGAINTBLID_SHIFT 0x4 /* acphy, txgain table id shift bit */ +#define BFL3_TSSI_DIV_WAR 0x00000080 /* acphy, Seperate paparam for 20/40/80 */ +#define BFL3_TSSI_DIV_WAR_SHIFT 0x7 /* acphy, Seperate paparam for 20/40/80 shift bit */ +#define BFL3_FEMTBL_FROM_NVRAM 0x00000100 /* acphy, femctrl table is read from nvram */ +#define BFL3_FEMTBL_FROM_NVRAM_SHIFT 0x8 /* acphy, femctrl table is read from nvram */ +#define BFL3_AGC_CFG_2G 0x00000200 /* acphy, gain control configuration for 2G */ +#define BFL3_AGC_CFG_5G 0x00000400 /* acphy, gain control configuration for 5G */ +#define BFL3_PPR_BIT_EXT 0x00000800 /* acphy, bit position for 1bit extension for ppr */ +#define BFL3_PPR_BIT_EXT_SHIFT 11 /* acphy, bit shift for 1bit extension for ppr */ +#define BFL3_BBPLL_SPR_MODE_DIS 0x00001000 /* acphy, disables bbpll spur modes */ +#define BFL3_RCAL_OTP_VAL_EN 0x00002000 /* acphy, to read rcal_trim value from otp */ +#define BFL3_2GTXGAINTBL_BLANK 0x00004000 /* acphy, blank the first X ticks of 2g gaintbl */ +#define BFL3_2GTXGAINTBL_BLANK_SHIFT 14 /* acphy, blank the first X ticks of 2g gaintbl */ +#define BFL3_5GTXGAINTBL_BLANK 0x00008000 /* acphy, blank the first X ticks of 5g gaintbl */ +#define BFL3_5GTXGAINTBL_BLANK_SHIFT 15 /* acphy, blank the first X ticks of 5g gaintbl */ +#define BFL3_BT_SHARE_BM_BIT1 0x40000000 /* bit 1 of WLAN/BT shared core bitmap */ +#define BFL3_PHASETRACK_MAX_ALPHABETA 0x00010000 /* acphy, to max out alpha,beta to 511 */ +#define BFL3_PHASETRACK_MAX_ALPHABETA_SHIFT 16 /* acphy, to max out alpha,beta to 511 */ +#define BFL3_BT_SHARE_BM_BIT1 0x40000000 /* bit 1 of WLAN/BT shared core bitmap */ +#define BFL3_EN_NONBRCM_TXBF 0x10000000 /* acphy, enable non-brcm TXBF */ +#define BFL3_EN_P2PLINK_TXBF 0x20000000 /* acphy, enable TXBF in p2p links */ /* board specific GPIO assignment, gpio 0-3 are also customer-configurable led */ #define BOARD_GPIO_BTC3W_IN 0x850 /* bit 4 is RF_ACTIVE, bit 6 is STATUS, bit 11 is PRI */ @@ -464,6 +548,9 @@ /* 43341 Boards */ #define BCM943341WLABGS_SSID 0x062d +/* 43342 Boards */ +#define BCM943342FCAGBI_SSID 0x0641 + /* # of GPIO pins */ #define GPIO_NUMPINS 32 @@ -478,8 +565,18 @@ #define RDL_RAM_BASE_4328 0x80000000 #define RDL_RAM_SIZE_4322 0x60000 #define RDL_RAM_BASE_4322 0x60000000 - -/* generic defs for nvram "muxenab" bits */ +#define RDL_RAM_SIZE_4360 0xA0000 +#define RDL_RAM_BASE_4360 0x60000000 +#define RDL_RAM_SIZE_43242 0x90000 +#define RDL_RAM_BASE_43242 0x60000000 +#define RDL_RAM_SIZE_43143 0x70000 +#define RDL_RAM_BASE_43143 0x60000000 +#define RDL_RAM_SIZE_4350 0xC0000 +#define RDL_RAM_BASE_4350 0x180800 + +/* generic defs for nvram "muxenab" bits +* Note: these differ for 4335a0. refer bcmchipc.h for specific mux options. +*/ #define MUXENAB_UART 0x00000001 #define MUXENAB_GPIO 0x00000002 #define MUXENAB_ERCX 0x00000004 /* External Radio BT coex */ diff --git a/drivers/net/wireless/bcmdhd/include/bcmendian.h b/drivers/net/wireless/bcmdhd/include/bcmendian.h index 0cf9145478e0..1545f4ef16c3 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/bcmendian.h +++ b/drivers/net/wireless/bcmdhd/include/bcmendian.h @@ -1,7 +1,7 @@ /* * Byte order utilities * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd/include/bcmpcispi.h b/drivers/net/wireless/bcmdhd/include/bcmpcispi.h deleted file mode 100644 index 44b263cec6a1..000000000000 --- a/drivers/net/wireless/bcmdhd/include/bcmpcispi.h +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Broadcom PCI-SPI Host Controller Register Definitions - * - * Copyright (C) 1999-2012, 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: bcmpcispi.h 241182 2011-02-17 21:50:03Z $ - */ -#ifndef _BCM_PCI_SPI_H -#define _BCM_PCI_SPI_H - -/* cpp contortions to concatenate w/arg prescan */ -#ifndef PAD -#define _PADLINE(line) pad ## line -#define _XSTR(line) _PADLINE(line) -#define PAD _XSTR(__LINE__) -#endif /* PAD */ - - -typedef volatile struct { - uint32 spih_ctrl; /* 0x00 SPI Control Register */ - uint32 spih_stat; /* 0x04 SPI Status Register */ - uint32 spih_data; /* 0x08 SPI Data Register, 32-bits wide */ - uint32 spih_ext; /* 0x0C SPI Extension Register */ - uint32 PAD[4]; /* 0x10-0x1F PADDING */ - - uint32 spih_gpio_ctrl; /* 0x20 SPI GPIO Control Register */ - uint32 spih_gpio_data; /* 0x24 SPI GPIO Data Register */ - uint32 PAD[6]; /* 0x28-0x3F PADDING */ - - uint32 spih_int_edge; /* 0x40 SPI Interrupt Edge Register (0=Level, 1=Edge) */ - uint32 spih_int_pol; /* 0x44 SPI Interrupt Polarity Register (0=Active Low, */ - /* 1=Active High) */ - uint32 spih_int_mask; /* 0x48 SPI Interrupt Mask */ - uint32 spih_int_status; /* 0x4C SPI Interrupt Status */ - uint32 PAD[4]; /* 0x50-0x5F PADDING */ - - uint32 spih_hex_disp; /* 0x60 SPI 4-digit hex display value */ - uint32 spih_current_ma; /* 0x64 SPI SD card current consumption in mA */ - uint32 PAD[1]; /* 0x68 PADDING */ - uint32 spih_disp_sel; /* 0x6c SPI 4-digit hex display mode select (1=current) */ - uint32 PAD[4]; /* 0x70-0x7F PADDING */ - uint32 PAD[8]; /* 0x80-0x9F PADDING */ - uint32 PAD[8]; /* 0xA0-0xBF PADDING */ - uint32 spih_pll_ctrl; /* 0xC0 PLL Control Register */ - uint32 spih_pll_status; /* 0xC4 PLL Status Register */ - uint32 spih_xtal_freq; /* 0xC8 External Clock Frequency in units of 10000Hz */ - uint32 spih_clk_count; /* 0xCC External Clock Count Register */ - -} spih_regs_t; - -typedef volatile struct { - uint32 cfg_space[0x40]; /* 0x000-0x0FF PCI Configuration Space (Read Only) */ - uint32 P_IMG_CTRL0; /* 0x100 PCI Image0 Control Register */ - - uint32 P_BA0; /* 0x104 32 R/W PCI Image0 Base Address register */ - uint32 P_AM0; /* 0x108 32 R/W PCI Image0 Address Mask register */ - uint32 P_TA0; /* 0x10C 32 R/W PCI Image0 Translation Address register */ - uint32 P_IMG_CTRL1; /* 0x110 32 R/W PCI Image1 Control register */ - uint32 P_BA1; /* 0x114 32 R/W PCI Image1 Base Address register */ - uint32 P_AM1; /* 0x118 32 R/W PCI Image1 Address Mask register */ - uint32 P_TA1; /* 0x11C 32 R/W PCI Image1 Translation Address register */ - uint32 P_IMG_CTRL2; /* 0x120 32 R/W PCI Image2 Control register */ - uint32 P_BA2; /* 0x124 32 R/W PCI Image2 Base Address register */ - uint32 P_AM2; /* 0x128 32 R/W PCI Image2 Address Mask register */ - uint32 P_TA2; /* 0x12C 32 R/W PCI Image2 Translation Address register */ - uint32 P_IMG_CTRL3; /* 0x130 32 R/W PCI Image3 Control register */ - uint32 P_BA3; /* 0x134 32 R/W PCI Image3 Base Address register */ - uint32 P_AM3; /* 0x138 32 R/W PCI Image3 Address Mask register */ - uint32 P_TA3; /* 0x13C 32 R/W PCI Image3 Translation Address register */ - uint32 P_IMG_CTRL4; /* 0x140 32 R/W PCI Image4 Control register */ - uint32 P_BA4; /* 0x144 32 R/W PCI Image4 Base Address register */ - uint32 P_AM4; /* 0x148 32 R/W PCI Image4 Address Mask register */ - uint32 P_TA4; /* 0x14C 32 R/W PCI Image4 Translation Address register */ - uint32 P_IMG_CTRL5; /* 0x150 32 R/W PCI Image5 Control register */ - uint32 P_BA5; /* 0x154 32 R/W PCI Image5 Base Address register */ - uint32 P_AM5; /* 0x158 32 R/W PCI Image5 Address Mask register */ - uint32 P_TA5; /* 0x15C 32 R/W PCI Image5 Translation Address register */ - uint32 P_ERR_CS; /* 0x160 32 R/W PCI Error Control and Status register */ - uint32 P_ERR_ADDR; /* 0x164 32 R PCI Erroneous Address register */ - uint32 P_ERR_DATA; /* 0x168 32 R PCI Erroneous Data register */ - - uint32 PAD[5]; /* 0x16C-0x17F PADDING */ - - uint32 WB_CONF_SPC_BAR; /* 0x180 32 R WISHBONE Configuration Space Base Address */ - uint32 W_IMG_CTRL1; /* 0x184 32 R/W WISHBONE Image1 Control register */ - uint32 W_BA1; /* 0x188 32 R/W WISHBONE Image1 Base Address register */ - uint32 W_AM1; /* 0x18C 32 R/W WISHBONE Image1 Address Mask register */ - uint32 W_TA1; /* 0x190 32 R/W WISHBONE Image1 Translation Address reg */ - uint32 W_IMG_CTRL2; /* 0x194 32 R/W WISHBONE Image2 Control register */ - uint32 W_BA2; /* 0x198 32 R/W WISHBONE Image2 Base Address register */ - uint32 W_AM2; /* 0x19C 32 R/W WISHBONE Image2 Address Mask register */ - uint32 W_TA2; /* 0x1A0 32 R/W WISHBONE Image2 Translation Address reg */ - uint32 W_IMG_CTRL3; /* 0x1A4 32 R/W WISHBONE Image3 Control register */ - uint32 W_BA3; /* 0x1A8 32 R/W WISHBONE Image3 Base Address register */ - uint32 W_AM3; /* 0x1AC 32 R/W WISHBONE Image3 Address Mask register */ - uint32 W_TA3; /* 0x1B0 32 R/W WISHBONE Image3 Translation Address reg */ - uint32 W_IMG_CTRL4; /* 0x1B4 32 R/W WISHBONE Image4 Control register */ - uint32 W_BA4; /* 0x1B8 32 R/W WISHBONE Image4 Base Address register */ - uint32 W_AM4; /* 0x1BC 32 R/W WISHBONE Image4 Address Mask register */ - uint32 W_TA4; /* 0x1C0 32 R/W WISHBONE Image4 Translation Address reg */ - uint32 W_IMG_CTRL5; /* 0x1C4 32 R/W WISHBONE Image5 Control register */ - uint32 W_BA5; /* 0x1C8 32 R/W WISHBONE Image5 Base Address register */ - uint32 W_AM5; /* 0x1CC 32 R/W WISHBONE Image5 Address Mask register */ - uint32 W_TA5; /* 0x1D0 32 R/W WISHBONE Image5 Translation Address reg */ - uint32 W_ERR_CS; /* 0x1D4 32 R/W WISHBONE Error Control and Status reg */ - uint32 W_ERR_ADDR; /* 0x1D8 32 R WISHBONE Erroneous Address register */ - uint32 W_ERR_DATA; /* 0x1DC 32 R WISHBONE Erroneous Data register */ - uint32 CNF_ADDR; /* 0x1E0 32 R/W Configuration Cycle register */ - uint32 CNF_DATA; /* 0x1E4 32 R/W Configuration Cycle Generation Data reg */ - - uint32 INT_ACK; /* 0x1E8 32 R Interrupt Acknowledge register */ - uint32 ICR; /* 0x1EC 32 R/W Interrupt Control register */ - uint32 ISR; /* 0x1F0 32 R/W Interrupt Status register */ -} spih_pciregs_t; - -/* - * PCI Core interrupt enable and status bit definitions. - */ - -/* PCI Core ICR Register bit definitions */ -#define PCI_INT_PROP_EN (1 << 0) /* Interrupt Propagation Enable */ -#define PCI_WB_ERR_INT_EN (1 << 1) /* Wishbone Error Interrupt Enable */ -#define PCI_PCI_ERR_INT_EN (1 << 2) /* PCI Error Interrupt Enable */ -#define PCI_PAR_ERR_INT_EN (1 << 3) /* Parity Error Interrupt Enable */ -#define PCI_SYS_ERR_INT_EN (1 << 4) /* System Error Interrupt Enable */ -#define PCI_SOFTWARE_RESET (1U << 31) /* Software reset of the PCI Core. */ - - -/* PCI Core ISR Register bit definitions */ -#define PCI_INT_PROP_ST (1 << 0) /* Interrupt Propagation Status */ -#define PCI_WB_ERR_INT_ST (1 << 1) /* Wishbone Error Interrupt Status */ -#define PCI_PCI_ERR_INT_ST (1 << 2) /* PCI Error Interrupt Status */ -#define PCI_PAR_ERR_INT_ST (1 << 3) /* Parity Error Interrupt Status */ -#define PCI_SYS_ERR_INT_ST (1 << 4) /* System Error Interrupt Status */ - - -/* Registers on the Wishbone bus */ -#define SPIH_CTLR_INTR (1 << 0) /* SPI Host Controller Core Interrupt */ -#define SPIH_DEV_INTR (1 << 1) /* SPI Device Interrupt */ -#define SPIH_WFIFO_INTR (1 << 2) /* SPI Tx FIFO Empty Intr (FPGA Rev >= 8) */ - -/* GPIO Bit definitions */ -#define SPIH_CS (1 << 0) /* SPI Chip Select (active low) */ -#define SPIH_SLOT_POWER (1 << 1) /* SD Card Slot Power Enable */ -#define SPIH_CARD_DETECT (1 << 2) /* SD Card Detect */ - -/* SPI Status Register Bit definitions */ -#define SPIH_STATE_MASK 0x30 /* SPI Transfer State Machine state mask */ -#define SPIH_STATE_SHIFT 4 /* SPI Transfer State Machine state shift */ -#define SPIH_WFFULL (1 << 3) /* SPI Write FIFO Full */ -#define SPIH_WFEMPTY (1 << 2) /* SPI Write FIFO Empty */ -#define SPIH_RFFULL (1 << 1) /* SPI Read FIFO Full */ -#define SPIH_RFEMPTY (1 << 0) /* SPI Read FIFO Empty */ - -#define SPIH_EXT_CLK (1U << 31) /* Use External Clock as PLL Clock source. */ - -#define SPIH_PLL_NO_CLK (1 << 1) /* Set to 1 if the PLL's input clock is lost. */ -#define SPIH_PLL_LOCKED (1 << 3) /* Set to 1 when the PLL is locked. */ - -/* Spin bit loop bound check */ -#define SPI_SPIN_BOUND 0xf4240 /* 1 million */ - -#endif /* _BCM_PCI_SPI_H */ diff --git a/drivers/net/wireless/bcmdhd/include/bcmperf.h b/drivers/net/wireless/bcmdhd/include/bcmperf.h index 743830768899..fad33ffa245c 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/bcmperf.h +++ b/drivers/net/wireless/bcmdhd/include/bcmperf.h @@ -1,7 +1,7 @@ /* * Performance counters software interface. * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdbus.h b/drivers/net/wireless/bcmdhd/include/bcmsdbus.h index 2fa706db0ef8..daa4234e444e 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/bcmsdbus.h +++ b/drivers/net/wireless/bcmdhd/include/bcmsdbus.h @@ -2,7 +2,7 @@ * Definitions for API from sdio common code (bcmsdh) to individual * host controller drivers. * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -22,7 +22,7 @@ * 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: bcmsdbus.h 347614 2012-07-27 10:24:51Z $ + * $Id: bcmsdbus.h 408155 2013-06-17 21:52:27Z $ */ #ifndef _sdio_api_h_ @@ -48,13 +48,33 @@ #ifdef BCMSDIOH_TXGLOM /* Max number of glommed pkts */ +#ifdef CUSTOM_MAX_TXGLOM_SIZE +#define SDPCM_MAXGLOM_SIZE CUSTOM_MAX_TXGLOM_SIZE +#else #define SDPCM_MAXGLOM_SIZE 10 -#define SDPCM_DEFGLOM_SIZE 3 +#endif /* CUSTOM_MAX_TXGLOM_SIZE */ #define SDPCM_TXGLOM_CPY 0 /* SDIO 2.0 should use copy mode */ #define SDPCM_TXGLOM_MDESC 1 /* SDIO 3.0 should use multi-desc mode */ -#endif +#ifdef BCMSDIOH_TXGLOM_HIGHSPEED +#define SDPCM_DEFGLOM_MODE SDPCM_TXGLOM_MDESC +#ifdef CUSTOM_DEF_TXGLOM_SIZE +#define SDPCM_DEFGLOM_SIZE CUSTOM_DEF_TXGLOM_SIZE +#else +#define SDPCM_DEFGLOM_SIZE 10 +#endif /* CUSTOM_DEF_TXGLOM_SIZE */ +#else +#define SDPCM_DEFGLOM_MODE SDPCM_TXGLOM_CPY +#define SDPCM_DEFGLOM_SIZE 3 +#endif /* BCMSDIOH_TXGLOM_HIGHSPEED */ + +#if SDPCM_DEFGLOM_SIZE > SDPCM_MAXGLOM_SIZE +#warning "SDPCM_DEFGLOM_SIZE cannot be higher than SDPCM_MAXGLOM_SIZE!!" +#undef SDPCM_DEFGLOM_SIZE +#define SDPCM_DEFGLOM_SIZE SDPCM_MAXGLOM_SIZE +#endif +#endif /* BCMSDIOH_TXGLOM */ typedef int SDIOH_API_RC; @@ -96,12 +116,12 @@ extern SDIOH_API_RC sdioh_request_buffer(sdioh_info_t *si, uint pio_dma, uint fi void *pkt); #ifdef BCMSDIOH_TXGLOM -extern void sdioh_glom_post(sdioh_info_t *sd, uint8 *frame, uint len); +extern void sdioh_glom_post(sdioh_info_t *sd, uint8 *frame, void *pkt, uint len); extern void sdioh_glom_clear(sdioh_info_t *sd); extern uint sdioh_set_mode(sdioh_info_t *sd, uint mode); extern bool sdioh_glom_enabled(void); #else -#define sdioh_glom_post(a, b, c) +#define sdioh_glom_post(a, b, c, d) #define sdioh_glom_clear(a) #define sdioh_set_mode(a) (0) #define sdioh_glom_enabled() (FALSE) diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdh.h b/drivers/net/wireless/bcmdhd/include/bcmsdh.h index efb78fed70bf..6433bb8545f6 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/bcmsdh.h +++ b/drivers/net/wireless/bcmdhd/include/bcmsdh.h @@ -3,7 +3,7 @@ * export functions to client drivers * abstract OS and BUS specific details of SDIO * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -23,7 +23,7 @@ * 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: bcmsdh.h 347614 2012-07-27 10:24:51Z $ + * $Id: bcmsdh.h 414953 2013-07-26 17:36:27Z $ */ /** @@ -48,6 +48,8 @@ extern const uint bcmsdh_msglevel; typedef struct bcmsdh_info bcmsdh_info_t; typedef void (*bcmsdh_cb_fn_t)(void *); +extern struct device *pm_dev; + /* Attach and build an interface to the underlying SD host driver. * - Allocates resources (structs, arrays, mem, OS handles, etc) needed by bcmsdh. * - Returns the bcmsdh handle and virtual address base for register access. @@ -55,13 +57,7 @@ typedef void (*bcmsdh_cb_fn_t)(void *); * implementation may maintain a single "default" handle (e.g. the first or * most recent one) to enable single-instance implementations to pass NULL. */ - -#if 0 && (NDISVER >= 0x0630) && 1 -extern bcmsdh_info_t *bcmsdh_attach(osl_t *osh, void *cfghdl, - void **regsva, uint irq, shared_info_t *sh); -#else extern bcmsdh_info_t *bcmsdh_attach(osl_t *osh, void *cfghdl, void **regsva, uint irq); -#endif /* Detach - freeup resources allocated in attach */ extern int bcmsdh_detach(osl_t *osh, void *sdh); @@ -145,7 +141,7 @@ extern 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); -extern void bcmsdh_glom_post(void *sdh, uint8 *frame, uint len); +extern void bcmsdh_glom_post(void *sdh, uint8 *frame, void *pkt, uint len); extern void bcmsdh_glom_clear(void *sdh); extern uint bcmsdh_set_mode(void *sdh, uint mode); extern bool bcmsdh_glom_enabled(void); diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h b/drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h index dbd604b93d29..6912c4f2b834 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h +++ b/drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h @@ -1,7 +1,7 @@ /* * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -21,7 +21,7 @@ * 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: bcmsdh_sdmmc.h 366812 2012-11-05 13:49:32Z $ + * $Id: bcmsdh_sdmmc.h 396592 2013-04-13 16:14:38Z $ */ #ifndef __BCMSDH_SDMMC_H__ @@ -34,7 +34,6 @@ #define sd_data(x) #define sd_ctrl(x) -#define sd_trace_hw4 sd_trace #define sd_sync_dma(sd, read, nbytes) #define sd_init_dma(sd) @@ -61,10 +60,19 @@ extern void sdioh_sdmmc_osfree(sdioh_info_t *sd); /* private bus modes */ #define SDIOH_MODE_SD4 2 -#define CLIENT_INTR 0x100 /* Get rid of this! */ +#define CLIENT_INTR 0x100 /* Get rid of this! */ + +#ifdef BCMSDIOH_TXGLOM + +typedef struct glom_buf { + void *glom_pkt_head; + void *glom_pkt_tail; + uint32 count; /* Total number of pkts queued */ +} glom_buf_t; +#endif /* BCMSDIOH_TXGLOM */ struct sdioh_info { - osl_t *osh; /* osh handler */ + osl_t *osh; /* osh handler */ bool client_intr_enabled; /* interrupt connnected flag */ bool intr_handler_valid; /* client driver interrupt handler valid */ sdioh_cb_fn_t intr_handler; /* registered interrupt handler */ @@ -72,22 +80,27 @@ struct sdioh_info { uint16 intmask; /* Current active interrupts */ void *sdos_info; /* Pointer to per-OS private data */ - uint irq; /* Client irq */ - int intrcount; /* Client interrupts */ + uint irq; /* Client irq */ + int intrcount; /* Client interrupts */ bool sd_use_dma; /* DMA on CMD53 */ - bool sd_blockmode; /* sd_blockmode == FALSE => 64 Byte Cmd 53s. */ + bool sd_blockmode; /* sd_blockmode == FALSE => 64 Byte Cmd 53s. */ /* Must be on for sd_multiblock to be effective */ bool use_client_ints; /* If this is false, make sure to restore */ int sd_mode; /* SD1/SD4/SPI */ int client_block_size[SDIOD_MAX_IOFUNCS]; /* Blocksize */ uint8 num_funcs; /* Supported funcs on client */ uint32 com_cis_ptr; - uint32 func_cis_ptr[SDIOD_MAX_IOFUNCS]; + uint32 func_cis_ptr[SDIOD_MAX_IOFUNCS]; #define SDIOH_SDMMC_MAX_SG_ENTRIES 32 struct scatterlist sg_list[SDIOH_SDMMC_MAX_SG_ENTRIES]; bool use_rxchain; + +#ifdef BCMSDIOH_TXGLOM + glom_buf_t glom_info; /* pkt information used for glomming */ + uint txglom_mode; /* Txglom mode: 0 - copy, 1 - multi-descriptor */ +#endif }; /************************************************************ diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdpcm.h b/drivers/net/wireless/bcmdhd/include/bcmsdpcm.h index fb2ec3af60f1..4ebe3d709295 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/bcmsdpcm.h +++ b/drivers/net/wireless/bcmdhd/include/bcmsdpcm.h @@ -2,7 +2,7 @@ * Broadcom SDIO/PCMCIA * Software-specific definitions shared between device and host side * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -22,7 +22,7 @@ * 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: bcmsdpcm.h 362722 2012-10-12 23:55:55Z $ + * $Id: bcmsdpcm.h 364353 2012-10-23 20:31:46Z $ */ #ifndef _bcmsdpcm_h_ diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdspi.h b/drivers/net/wireless/bcmdhd/include/bcmsdspi.h index 3d444f3ba265..21792abca736 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/bcmsdspi.h +++ b/drivers/net/wireless/bcmdhd/include/bcmsdspi.h @@ -1,7 +1,7 @@ /* * SD-SPI Protocol Conversion - BCMSDH->SPI Translation Layer * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdstd.h b/drivers/net/wireless/bcmdhd/include/bcmsdstd.h index 896686cfcf2a..096285629578 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/bcmsdstd.h +++ b/drivers/net/wireless/bcmdhd/include/bcmsdstd.h @@ -1,7 +1,7 @@ /* * 'Standard' SDIO HOST CONTROLLER driver * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -21,7 +21,7 @@ * 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: bcmsdstd.h 347614 2012-07-27 10:24:51Z $ + * $Id: bcmsdstd.h 343301 2012-07-06 13:07:32Z $ */ #ifndef _BCM_SD_STD_H #define _BCM_SD_STD_H diff --git a/drivers/net/wireless/bcmdhd/include/bcmspi.h b/drivers/net/wireless/bcmdhd/include/bcmspi.h index e226cb102292..e81ea62524b9 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/bcmspi.h +++ b/drivers/net/wireless/bcmdhd/include/bcmspi.h @@ -1,7 +1,7 @@ /* * Broadcom SPI Low-Level Hardware Driver API * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd/include/bcmutils.h b/drivers/net/wireless/bcmdhd/include/bcmutils.h index ffa1c8e9e733..b26a1b9d65e9 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/bcmutils.h +++ b/drivers/net/wireless/bcmdhd/include/bcmutils.h @@ -1,7 +1,7 @@ /* * Misc useful os-independent macros and functions. * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -21,7 +21,7 @@ * 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: bcmutils.h 354837 2012-09-04 06:58:44Z $ + * $Id: bcmutils.h 427979 2013-10-07 08:35:57Z $ */ #ifndef _bcmutils_h_ @@ -140,6 +140,8 @@ typedef struct { increases with use ('inverse' of max_avail) */ uint32 queue_capacity; /* the maximum capacity of the queue */ + uint32 rtsfail; /* count of rts attempts that failed to receive cts */ + uint32 acked; /* count of packets sent (acked) successfully */ } pktq_counters_t; #endif /* PKTQ_LOG */ @@ -156,7 +158,9 @@ struct pktq { /* q array must be last since # of elements can be either PKTQ_MAX_PREC or 1 */ struct pktq_prec q[PKTQ_MAX_PREC]; #ifdef PKTQ_LOG - pktq_counters_t _prec_cnt[PKTQ_MAX_PREC]; /* Counters per queue */ + pktq_counters_t _prec_cnt[PKTQ_MAX_PREC]; /* Counters per queue */ + pktq_counters_t _prec_bytes[PKTQ_MAX_PREC]; /* Byte count per queue */ + uint32 _logtime; /* timestamp of last counter clear */ #endif }; @@ -300,6 +304,7 @@ extern void *pktq_penq(struct pktq *pq, int prec, void *p); extern void *pktq_penq_head(struct pktq *pq, int prec, void *p); extern void *pktq_pdeq(struct pktq *pq, int prec); extern void *pktq_pdeq_prev(struct pktq *pq, int prec, void *prev_p); +extern void *pktq_pdeq_with_fn(struct pktq *pq, int prec, ifpkt_cb_t fn, int arg); extern void *pktq_pdeq_tail(struct pktq *pq, int prec); /* Empty the queue at particular precedence level */ extern void pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir, @@ -346,7 +351,8 @@ extern uint pkttotlen(osl_t *osh, void *p); extern void *pktlast(osl_t *osh, void *p); extern uint pktsegcnt(osl_t *osh, void *p); extern uint pktsegcnt_war(osl_t *osh, void *p); -extern uint8 *pktoffset(osl_t *osh, void *p, uint offset); +extern uint8 *pktdataoffset(osl_t *osh, void *p, uint offset); +extern void *pktoffset(osl_t *osh, void *p, uint offset); /* Get priority from a packet and pass it back in scb (or equiv) */ #define PKTPRIO_VDSCP 0x100 /* DSCP prio found after VLAN tag */ @@ -354,6 +360,22 @@ extern uint8 *pktoffset(osl_t *osh, void *p, uint offset); #define PKTPRIO_UPD 0x400 /* DSCP used to update VLAN prio */ #define PKTPRIO_DSCP 0x800 /* DSCP prio found */ +/* DSCP type definitions (RFC4594) */ +/* AF1x: High-Throughput Data (RFC2597) */ +#define DSCP_AF11 0x0A +#define DSCP_AF12 0x0C +#define DSCP_AF13 0x0E +/* AF2x: Low-Latency Data (RFC2597) */ +#define DSCP_AF21 0x12 +#define DSCP_AF22 0x14 +#define DSCP_AF23 0x16 +/* AF3x: Multimedia Streaming (RFC2597) */ +#define DSCP_AF31 0x1A +#define DSCP_AF32 0x1C +#define DSCP_AF33 0x1E +/* EF: Telephony (RFC3246) */ +#define DSCP_EF 0x2E + extern uint pktsetprio(void *pkt, bool update_vtag); /* string */ @@ -375,7 +397,7 @@ extern int bcm_ether_atoe(const char *p, struct ether_addr *ea); /* ip address */ struct ipv4_addr; extern char *bcm_ip_ntoa(struct ipv4_addr *ia, char *buf); - +extern int bcm_atoipv4(const char *p, struct ipv4_addr *ip); /* delay */ extern void bcm_mdelay(uint ms); /* variable access */ @@ -529,7 +551,11 @@ extern int bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len); #define BCME_NODEVICE -40 /* Device not present */ #define BCME_NMODE_DISABLED -41 /* NMODE disabled */ #define BCME_NONRESIDENT -42 /* access to nonresident overlay */ -#define BCME_LAST BCME_NONRESIDENT +#define BCME_SCANREJECT -43 /* reject scan request */ +#define BCME_USAGE_ERROR -44 /* WLCMD usage error */ +#define BCME_IOCTL_ERROR -45 /* WLCMD ioctl error */ +#define BCME_SERIAL_PORT_ERR -46 /* RWL serial port error */ +#define BCME_LAST BCME_SERIAL_PORT_ERR /* These are collection of BCME Error strings */ #define BCMERRSTRINGTABLE { \ @@ -576,6 +602,10 @@ extern int bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len); "Device Not Present", \ "NMODE Disabled", \ "Nonresident overlay access", \ + "Scan Rejected", \ + "WLCMD usage error", \ + "WLCMD ioctl error", \ + "RWL serial port error", \ } #ifndef ABS @@ -590,6 +620,24 @@ extern int bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len); #define MAX(a, b) (((a) > (b)) ? (a) : (b)) #endif /* MAX */ +/* limit to [min, max] */ +#ifndef LIMIT_TO_RANGE +#define LIMIT_TO_RANGE(x, min, max) \ + ((x) < (min) ? (min) : ((x) > (max) ? (max) : (x))) +#endif /* LIMIT_TO_RANGE */ + +/* limit to max */ +#ifndef LIMIT_TO_MAX +#define LIMIT_TO_MAX(x, max) \ + (((x) > (max) ? (max) : (x))) +#endif /* LIMIT_TO_MAX */ + +/* limit to min */ +#ifndef LIMIT_TO_MIN +#define LIMIT_TO_MIN(x, min) \ + (((x) < (min) ? (min) : (x))) +#endif /* LIMIT_TO_MIN */ + #define CEIL(x, y) (((x) + ((y) - 1)) / (y)) #define ROUNDUP(x, y) ((((x) + ((y) - 1)) / (y)) * (y)) #define ISALIGNED(a, x) (((uintptr)(a) & ((x) - 1)) == 0) @@ -618,21 +666,34 @@ extern int bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len); #define ARRAYSIZE(a) (sizeof(a) / sizeof(a[0])) #endif +#ifndef ARRAYLAST /* returns pointer to last array element */ +#define ARRAYLAST(a) (&a[ARRAYSIZE(a)-1]) +#endif + /* Reference a function; used to prevent a static function from being optimized out */ extern void *_bcmutils_dummy_fn; #define REFERENCE_FUNCTION(f) (_bcmutils_dummy_fn = (void *)(f)) /* bit map related macros */ #ifndef setbit -#ifndef NBBY /* the BSD family defines NBBY */ +#ifndef NBBY /* the BSD family defines NBBY */ #define NBBY 8 /* 8 bits per byte */ #endif /* #ifndef NBBY */ +#ifdef BCMUTILS_BIT_MACROS_USE_FUNCS +extern void setbit(void *array, uint bit); +extern void clrbit(void *array, uint bit); +extern bool isset(const void *array, uint bit); +extern bool isclr(const void *array, uint bit); +#else #define setbit(a, i) (((uint8 *)a)[(i) / NBBY] |= 1 << ((i) % NBBY)) #define clrbit(a, i) (((uint8 *)a)[(i) / NBBY] &= ~(1 << ((i) % NBBY))) #define isset(a, i) (((const uint8 *)a)[(i) / NBBY] & (1 << ((i) % NBBY))) #define isclr(a, i) ((((const uint8 *)a)[(i) / NBBY] & (1 << ((i) % NBBY))) == 0) +#endif #endif /* setbit */ +#define isbitset(a, i) (((a) & (1 << (i))) != 0) + #define NBITS(type) (sizeof(type) * 8) #define NBITVAL(nbits) (1 << (nbits)) #define MAXBITVAL(nbits) ((1 << (nbits)) - 1) @@ -697,6 +758,13 @@ typedef struct bcm_bit_desc { const char* name; } bcm_bit_desc_t; +/* bcm_format_field */ +typedef struct bcm_bit_desc_ex { + uint32 mask; + const bcm_bit_desc_t *bitfield; +} bcm_bit_desc_ex_t; + + /* tag_ID/length/value_buffer tuple */ typedef struct bcm_tlv { uint8 id; @@ -743,6 +811,9 @@ extern uint32 hndcrc32(uint8 *p, uint nbytes, uint32 crc); /* format/print */ #if defined(DHD_DEBUG) || defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || \ defined(WLMSG_ASSOC) +/* print out the value a field has: fields may have 1-32 bits and may hold any value */ +extern int bcm_format_field(const bcm_bit_desc_ex_t *bd, uint32 field, char* buf, int len); +/* print out which bits in flags are set */ extern int bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char* buf, int len); #endif @@ -764,7 +835,7 @@ extern bcm_tlv_t *bcm_parse_ordered_tlvs(void *buf, int buflen, uint key); /* bcmerror */ extern const char *bcmerrorstr(int bcmerror); -extern bcm_tlv_t *bcm_parse_tlvs(void *buf, int buflen, uint key); +/* extern bcm_tlv_t *bcm_parse_tlvs(void *buf, int buflen, uint key); */ /* multi-bool data type: set of bools, mbool is true if any is set */ typedef uint32 mbool; @@ -800,6 +871,13 @@ extern uint8 bcm_mw_to_qdbm(uint16 mw); extern uint bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint len); unsigned int process_nvram_vars(char *varbuf, unsigned int len); +extern bcm_tlv_t *find_vendor_ie(void *tlvs, int tlvs_len, + const char *voui, uint8 *type, int type_len); + +/* calculate a * b + c */ +extern void bcm_uint64_multiple_add(uint32* r_high, uint32* r_low, uint32 a, uint32 b, uint32 c); +/* calculate a / b */ +extern void bcm_uint64_divide(uint32* r, uint32 a_high, uint32 a_low, uint32 b); #ifdef __cplusplus } diff --git a/drivers/net/wireless/bcmdhd/include/bcmwifi_channels.h b/drivers/net/wireless/bcmdhd/include/bcmwifi_channels.h index bc57aca2f286..a3a38281f3aa 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/bcmwifi_channels.h +++ b/drivers/net/wireless/bcmdhd/include/bcmwifi_channels.h @@ -3,7 +3,7 @@ * This header file housing the define and function prototype use by * both the wl driver, tools & Apps. * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -47,7 +47,8 @@ typedef uint16 chanspec_t; * this is that + 1 rounded up to a multiple of NBBY (8). * DO NOT MAKE it > 255: channels are uint8's all over */ -#define CHSPEC_CTLOVLP(sp1, sp2, sep) ABS(wf_chspec_ctlchan(sp1) - wf_chspec_ctlchan(sp2)) < (sep) +#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 @@ -86,6 +87,13 @@ typedef uint16 chanspec_t; #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 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 | \ WL_CHANSPEC_CTL_SB_NONE | (((channel) <= CH_MAX_2G_CHANNEL) ? \ @@ -184,6 +192,13 @@ typedef uint16 chanspec_t; ((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) @@ -298,6 +313,11 @@ typedef uint16 chanspec_t; #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)) + #endif /* D11AC_IOTYPES */ /* @@ -324,21 +344,6 @@ typedef uint16 chanspec_t; */ #define WF_CHAN_FACTOR_4_G 8000 /* 4.9 GHz band for Japan */ -/* defined rate in 500kbps */ -#define WLC_MAXRATE 108 /* in 500kbps units */ -#define WLC_RATE_1M 2 /* in 500kbps units */ -#define WLC_RATE_2M 4 /* in 500kbps units */ -#define WLC_RATE_5M5 11 /* in 500kbps units */ -#define WLC_RATE_11M 22 /* in 500kbps units */ -#define WLC_RATE_6M 12 /* in 500kbps units */ -#define WLC_RATE_9M 18 /* in 500kbps units */ -#define WLC_RATE_12M 24 /* in 500kbps units */ -#define WLC_RATE_18M 36 /* in 500kbps units */ -#define WLC_RATE_24M 48 /* in 500kbps units */ -#define WLC_RATE_36M 72 /* in 500kbps units */ -#define WLC_RATE_48M 96 /* in 500kbps units */ -#define WLC_RATE_54M 108 /* in 500kbps units */ - #define WLC_2G_25MHZ_OFFSET 5 /* 2.4GHz band channel offset */ /** @@ -487,4 +492,8 @@ extern int wf_channel2mhz(uint channel, uint start_factor); */ extern uint16 wf_channel2chspec(uint ctl_ch, uint bw); +extern uint wf_channel2freq(uint channel); +extern uint wf_freq2channel(uint freq); + + #endif /* _bcmwifi_channels_h_ */ diff --git a/drivers/net/wireless/bcmdhd/include/bcmwifi_rates.h b/drivers/net/wireless/bcmdhd/include/bcmwifi_rates.h index ddc6ab5ac973..37c14c17e663 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/bcmwifi_rates.h +++ b/drivers/net/wireless/bcmdhd/include/bcmwifi_rates.h @@ -1,7 +1,7 @@ /* * Indices for 802.11 a/b/g/n/ac 1-3 chain symmetric transmit rates * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -21,7 +21,7 @@ * 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: bcmwifi_rates.h 252708 2011-04-12 06:45:56Z $ + * $Id: bcmwifi_rates.h 5187 2012-06-29 06:17:50Z $ */ #ifndef _bcmwifi_rates_h_ @@ -48,8 +48,7 @@ typedef enum wl_tx_bw { WL_TX_BW_80, WL_TX_BW_20IN40, WL_TX_BW_20IN80, - WL_TX_BW_40IN80, - WL_TX_BW_ALL + WL_TX_BW_40IN80 } wl_tx_bw_t; @@ -61,7 +60,8 @@ typedef enum wl_tx_mode { WL_TX_MODE_NONE, WL_TX_MODE_STBC, WL_TX_MODE_CDD, - WL_TX_MODE_SDM + WL_TX_MODE_TXBF, + WL_NUM_TX_MODES } wl_tx_mode_t; @@ -83,9 +83,9 @@ typedef enum wl_tx_nss { typedef enum clm_rates { /************ - * 1 chain * - ************ - */ + * 1 chain * + ************ + */ /* 1 Stream */ WL_RATE_1X1_DSSS_1 = 0, @@ -124,9 +124,9 @@ typedef enum clm_rates { /************ - * 2 chains * - ************ - */ + * 2 chains * + ************ + */ /* 1 Stream expanded + 1 */ WL_RATE_1X2_DSSS_1 = 22, @@ -204,11 +204,10 @@ typedef enum clm_rates { WL_RATE_2X2_VHT8SS2 = 62, WL_RATE_2X2_VHT9SS2 = 63, - /************ - * 3 chains * - ************ - */ + * 3 chains * + ************ + */ /* 1 Stream expanded + 2 */ WL_RATE_1X3_DSSS_1 = 64, @@ -307,10 +306,146 @@ typedef enum clm_rates { WL_RATE_3X3_VHT8SS3 = 114, WL_RATE_3X3_VHT9SS3 = 115, - /* Number of rate codes */ - WL_NUMRATES = 116 + + /**************************** + * TX Beamforming, 2 chains * + **************************** + */ + + /* 1 Stream expanded + 1 */ + + WL_RATE_1X2_TXBF_OFDM_6 = 116, + WL_RATE_1X2_TXBF_OFDM_9 = 117, + WL_RATE_1X2_TXBF_OFDM_12 = 118, + WL_RATE_1X2_TXBF_OFDM_18 = 119, + WL_RATE_1X2_TXBF_OFDM_24 = 120, + WL_RATE_1X2_TXBF_OFDM_36 = 121, + WL_RATE_1X2_TXBF_OFDM_48 = 122, + WL_RATE_1X2_TXBF_OFDM_54 = 123, + + WL_RATE_1X2_TXBF_MCS0 = 124, + WL_RATE_1X2_TXBF_MCS1 = 125, + WL_RATE_1X2_TXBF_MCS2 = 126, + WL_RATE_1X2_TXBF_MCS3 = 127, + WL_RATE_1X2_TXBF_MCS4 = 128, + WL_RATE_1X2_TXBF_MCS5 = 129, + WL_RATE_1X2_TXBF_MCS6 = 130, + WL_RATE_1X2_TXBF_MCS7 = 131, + + WL_RATE_1X2_TXBF_VHT0SS1 = 124, + WL_RATE_1X2_TXBF_VHT1SS1 = 125, + WL_RATE_1X2_TXBF_VHT2SS1 = 126, + WL_RATE_1X2_TXBF_VHT3SS1 = 127, + WL_RATE_1X2_TXBF_VHT4SS1 = 128, + WL_RATE_1X2_TXBF_VHT5SS1 = 129, + WL_RATE_1X2_TXBF_VHT6SS1 = 130, + WL_RATE_1X2_TXBF_VHT7SS1 = 131, + WL_RATE_1X2_TXBF_VHT8SS1 = 132, + WL_RATE_1X2_TXBF_VHT9SS1 = 133, + + /* 2 Streams */ + + WL_RATE_2X2_TXBF_SDM_MCS8 = 134, + WL_RATE_2X2_TXBF_SDM_MCS9 = 135, + WL_RATE_2X2_TXBF_SDM_MCS10 = 136, + WL_RATE_2X2_TXBF_SDM_MCS11 = 137, + WL_RATE_2X2_TXBF_SDM_MCS12 = 138, + WL_RATE_2X2_TXBF_SDM_MCS13 = 139, + WL_RATE_2X2_TXBF_SDM_MCS14 = 140, + WL_RATE_2X2_TXBF_SDM_MCS15 = 141, + + WL_RATE_2X2_TXBF_VHT0SS2 = 134, + WL_RATE_2X2_TXBF_VHT1SS2 = 135, + WL_RATE_2X2_TXBF_VHT2SS2 = 136, + WL_RATE_2X2_TXBF_VHT3SS2 = 137, + WL_RATE_2X2_TXBF_VHT4SS2 = 138, + WL_RATE_2X2_TXBF_VHT5SS2 = 139, + WL_RATE_2X2_TXBF_VHT6SS2 = 140, + WL_RATE_2X2_TXBF_VHT7SS2 = 141, + + + /**************************** + * TX Beamforming, 3 chains * + **************************** + */ + + /* 1 Stream expanded + 2 */ + + WL_RATE_1X3_TXBF_OFDM_6 = 142, + WL_RATE_1X3_TXBF_OFDM_9 = 143, + WL_RATE_1X3_TXBF_OFDM_12 = 144, + WL_RATE_1X3_TXBF_OFDM_18 = 145, + WL_RATE_1X3_TXBF_OFDM_24 = 146, + WL_RATE_1X3_TXBF_OFDM_36 = 147, + WL_RATE_1X3_TXBF_OFDM_48 = 148, + WL_RATE_1X3_TXBF_OFDM_54 = 149, + + WL_RATE_1X3_TXBF_MCS0 = 150, + WL_RATE_1X3_TXBF_MCS1 = 151, + WL_RATE_1X3_TXBF_MCS2 = 152, + WL_RATE_1X3_TXBF_MCS3 = 153, + WL_RATE_1X3_TXBF_MCS4 = 154, + WL_RATE_1X3_TXBF_MCS5 = 155, + WL_RATE_1X3_TXBF_MCS6 = 156, + WL_RATE_1X3_TXBF_MCS7 = 157, + + WL_RATE_1X3_TXBF_VHT0SS1 = 150, + WL_RATE_1X3_TXBF_VHT1SS1 = 151, + WL_RATE_1X3_TXBF_VHT2SS1 = 152, + WL_RATE_1X3_TXBF_VHT3SS1 = 153, + WL_RATE_1X3_TXBF_VHT4SS1 = 154, + WL_RATE_1X3_TXBF_VHT5SS1 = 155, + WL_RATE_1X3_TXBF_VHT6SS1 = 156, + WL_RATE_1X3_TXBF_VHT7SS1 = 157, + WL_RATE_1X3_TXBF_VHT8SS1 = 158, + WL_RATE_1X3_TXBF_VHT9SS1 = 159, + + /* 2 Streams expanded + 1 */ + + WL_RATE_2X3_TXBF_SDM_MCS8 = 160, + WL_RATE_2X3_TXBF_SDM_MCS9 = 161, + WL_RATE_2X3_TXBF_SDM_MCS10 = 162, + WL_RATE_2X3_TXBF_SDM_MCS11 = 163, + WL_RATE_2X3_TXBF_SDM_MCS12 = 164, + WL_RATE_2X3_TXBF_SDM_MCS13 = 165, + WL_RATE_2X3_TXBF_SDM_MCS14 = 166, + WL_RATE_2X3_TXBF_SDM_MCS15 = 167, + + WL_RATE_2X3_TXBF_VHT0SS2 = 160, + WL_RATE_2X3_TXBF_VHT1SS2 = 161, + WL_RATE_2X3_TXBF_VHT2SS2 = 162, + WL_RATE_2X3_TXBF_VHT3SS2 = 163, + WL_RATE_2X3_TXBF_VHT4SS2 = 164, + WL_RATE_2X3_TXBF_VHT5SS2 = 165, + WL_RATE_2X3_TXBF_VHT6SS2 = 166, + WL_RATE_2X3_TXBF_VHT7SS2 = 167, + WL_RATE_2X3_TXBF_VHT8SS2 = 168, + WL_RATE_2X3_TXBF_VHT9SS2 = 169, + + /* 3 Streams */ + + WL_RATE_3X3_TXBF_SDM_MCS16 = 170, + WL_RATE_3X3_TXBF_SDM_MCS17 = 171, + WL_RATE_3X3_TXBF_SDM_MCS18 = 172, + WL_RATE_3X3_TXBF_SDM_MCS19 = 173, + WL_RATE_3X3_TXBF_SDM_MCS20 = 174, + WL_RATE_3X3_TXBF_SDM_MCS21 = 175, + WL_RATE_3X3_TXBF_SDM_MCS22 = 176, + WL_RATE_3X3_TXBF_SDM_MCS23 = 177, + + WL_RATE_3X3_TXBF_VHT0SS3 = 170, + WL_RATE_3X3_TXBF_VHT1SS3 = 171, + WL_RATE_3X3_TXBF_VHT2SS3 = 172, + WL_RATE_3X3_TXBF_VHT3SS3 = 173, + WL_RATE_3X3_TXBF_VHT4SS3 = 174, + WL_RATE_3X3_TXBF_VHT5SS3 = 175, + WL_RATE_3X3_TXBF_VHT6SS3 = 176, + WL_RATE_3X3_TXBF_VHT7SS3 = 177 } clm_rates_t; +/* Number of rate codes */ +#define WL_NUMRATES 178 + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/drivers/net/wireless/bcmdhd/include/dhdioctl.h b/drivers/net/wireless/bcmdhd/include/dhdioctl.h index aba6cdc9520b..08758e1ffe83 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/dhdioctl.h +++ b/drivers/net/wireless/bcmdhd/include/dhdioctl.h @@ -5,7 +5,7 @@ * * Definitions subject to change without notice. * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -25,7 +25,7 @@ * 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: dhdioctl.h 354894 2012-09-04 12:34:07Z $ + * $Id: dhdioctl.h 419132 2013-08-19 21:33:05Z $ */ #ifndef _dhdioctl_h_ @@ -85,16 +85,13 @@ enum { #define DHD_GLOM_VAL 0x0400 #define DHD_EVENT_VAL 0x0800 #define DHD_BTA_VAL 0x1000 -#if 0 && (NDISVER >= 0x0630) && 1 -#define DHD_SCAN_VAL 0x2000 -#else #define DHD_ISCAN_VAL 0x2000 -#endif #define DHD_ARPOE_VAL 0x4000 #define DHD_REORDER_VAL 0x8000 #define DHD_WL_VAL 0x10000 -#define DHD_WL_VAL2 0x20000 - +#define DHD_NOCHECKDIED_VAL 0x20000 /* UTF WAR */ +#define DHD_WL_VAL2 0x40000 +#define DHD_PNO_VAL 0x80000 #ifdef SDTEST /* For pktgen iovar */ diff --git a/drivers/net/wireless/bcmdhd/include/epivers.h b/drivers/net/wireless/bcmdhd/include/epivers.h index 1a796904ea11..0a0e889dbdac 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/epivers.h +++ b/drivers/net/wireless/bcmdhd/include/epivers.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -19,7 +19,7 @@ * 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: epivers.h.in,v 13.33 2010-09-08 22:08:53 $ + * $Id: epivers.h.in,v 13.33 2010-09-08 22:08:53 csm Exp $ * */ @@ -28,21 +28,29 @@ #define EPI_MAJOR_VERSION 1 -#define EPI_MINOR_VERSION 28 +#define EPI_MINOR_VERSION 88 -#define EPI_RC_NUMBER 28 +#define EPI_RC_NUMBER 55 -#define EPI_INCREMENTAL_NUMBER 4 +#define EPI_INCREMENTAL_NUMBER 0 -#define EPI_BUILD_NUMBER 1 +#define EPI_BUILD_NUMBER 0 -#define EPI_VERSION 1, 28, 28, 4 +#define EPI_VERSION 1, 88, 55, 0 -#define EPI_VERSION_NUM 0x011c1c01 +#define EPI_VERSION_NUM 0x01583700 -#define EPI_VERSION_DEV 1.28.28 +#define EPI_VERSION_DEV 1.88.55 /* Driver Version String, ASCII, 32 chars max */ -#define EPI_VERSION_STR "1.28.28.4 (r388498)" +#ifdef BCMINTERNAL +#define EPI_VERSION_STR "1.88.55 (r BCMINT)" +#else +#ifdef WLTEST +#define EPI_VERSION_STR "1.88.55 (r WLTEST)" +#else +#define EPI_VERSION_STR "1.88.55 (r)" +#endif +#endif /* BCMINTERNAL */ #endif /* _epivers_h_ */ diff --git a/drivers/net/wireless/bcmdhd/include/hndpmu.h b/drivers/net/wireless/bcmdhd/include/hndpmu.h index c41def6c7d8a..9ed9de264da9 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/hndpmu.h +++ b/drivers/net/wireless/bcmdhd/include/hndpmu.h @@ -1,7 +1,7 @@ /* * HND SiliconBackplane PMU support. * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -21,7 +21,7 @@ * 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: hndpmu.h 241182 2011-02-17 21:50:03Z $ + * $Id: hndpmu.h 385540 2013-02-15 23:14:50Z $ */ #ifndef _hndpmu_h_ diff --git a/drivers/net/wireless/bcmdhd/include/hndrte_armtrap.h b/drivers/net/wireless/bcmdhd/include/hndrte_armtrap.h index 90d979929381..875a6935f220 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/hndrte_armtrap.h +++ b/drivers/net/wireless/bcmdhd/include/hndrte_armtrap.h @@ -1,7 +1,7 @@ /* * HNDRTE arm trap handling. * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd/include/hndrte_cons.h b/drivers/net/wireless/bcmdhd/include/hndrte_cons.h index 57abbbd5b67b..4e4272087cca 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/hndrte_cons.h +++ b/drivers/net/wireless/bcmdhd/include/hndrte_cons.h @@ -1,7 +1,7 @@ /* * Console support for hndrte. * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -21,7 +21,7 @@ * 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: hndrte_cons.h 300516 2011-12-04 17:39:44Z $ + * $Id: hndrte_cons.h 383834 2013-02-07 23:21:51Z $ */ #ifndef _HNDRTE_CONS_H #define _HNDRTE_CONS_H @@ -64,4 +64,6 @@ typedef struct { char cbuf[CBUF_LEN]; } hndrte_cons_t; +hndrte_cons_t *hndrte_get_active_cons_state(void); + #endif /* _HNDRTE_CONS_H */ diff --git a/drivers/net/wireless/bcmdhd/include/hndrte_debug.h b/drivers/net/wireless/bcmdhd/include/hndrte_debug.h new file mode 100755 index 000000000000..bd2a9a24bea5 --- /dev/null +++ b/drivers/net/wireless/bcmdhd/include/hndrte_debug.h @@ -0,0 +1,114 @@ +/* + * HND Run Time Environment debug info area + * + * Copyright (C) 1999-2013, 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: hndrte_debug.h 342211 2012-07-02 02:23:04Z $ + */ + +#ifndef _HNDRTE_DEBUG_H +#define _HNDRTE_DEBUG_H + +/* Magic number at a magic location to find HNDRTE_DEBUG pointers */ +#define HNDRTE_DEBUG_PTR_PTR_ADDR 0xf8 +#define HNDRTE_DEBUG_PTR_PTR_MAGIC 0x50504244 /* DBPP */ + +#ifndef _LANGUAGE_ASSEMBLY + +/* Includes only when building dongle code */ + + +#define NUM_EVENT_LOG_SETS 4 + +/* We use explicit sizes here since this gets included from different + * systems. The sizes must be the size of the creating system + * (currently 32 bit ARM) since this is gleaned from dump. + */ + +/* Define pointers for use on other systems */ +#define _HD_EVLOG_P uint32 +#define _HD_CONS_P uint32 +#define _HD_TRAP_P uint32 + +typedef struct hndrte_debug { + uint32 magic; +#define HNDRTE_DEBUG_MAGIC 0x47424544 /* 'DEBG' */ + + uint32 version; /* Debug struct version */ +#define HNDRTE_DEBUG_VERSION 1 + + uint32 fwid; /* 4 bytes of fw info */ + char epivers[32]; + + _HD_TRAP_P trap_ptr; /* trap_t data struct */ + _HD_CONS_P console; /* Console */ + + uint32 ram_base; + uint32 ram_size; + + uint32 rom_base; + uint32 rom_size; + + _HD_EVLOG_P event_log_top; + +} hndrte_debug_t; + +/* + * timeval_t and prstatus_t are copies of the Linux structures. + * Included here because we need the definitions for the target processor + * (32 bits) and not the definition on the host this is running on + * (which could be 64 bits). + */ + +typedef struct { /* Time value with microsecond resolution */ + uint32 tv_sec; /* Seconds */ + uint32 tv_usec; /* Microseconds */ +} timeval_t; + + +/* Linux/ARM 32 prstatus for notes section */ +typedef struct prstatus { + int32 si_signo; /* Signal number */ + int32 si_code; /* Extra code */ + int32 si_errno; /* Errno */ + uint16 pr_cursig; /* Current signal. */ + uint16 unused; + uint32 pr_sigpend; /* Set of pending signals. */ + uint32 pr_sighold; /* Set of held signals. */ + uint32 pr_pid; + uint32 pr_ppid; + uint32 pr_pgrp; + uint32 pr_sid; + timeval_t pr_utime; /* User time. */ + timeval_t pr_stime; /* System time. */ + timeval_t pr_cutime; /* Cumulative user time. */ + timeval_t pr_cstime; /* Cumulative system time. */ + uint32 uregs[18]; + int32 pr_fpvalid; /* True if math copro being used. */ +} prstatus_t; + +#ifdef DUMP_INFO +extern hndrte_debug_t hndrte_debug_info __attribute__ ((weak)); +#endif + +#endif /* LANGUAGE_ASSEMBLY */ + +#endif /* _HNDRTE_DEBUG_H */ diff --git a/drivers/net/wireless/bcmdhd/include/hndsoc.h b/drivers/net/wireless/bcmdhd/include/hndsoc.h index 66640c3b0cbd..e259cc6f1c0c 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/hndsoc.h +++ b/drivers/net/wireless/bcmdhd/include/hndsoc.h @@ -1,7 +1,7 @@ /* * Broadcom HND chip & on-chip-interconnect-related definitions. * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -21,7 +21,7 @@ * 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: hndsoc.h 309193 2012-01-19 00:03:57Z $ + * $Id: hndsoc.h 365041 2012-10-26 09:10:35Z $ */ #ifndef _HNDSOC_H @@ -46,10 +46,8 @@ #define SI_WRAP_BASE 0x18100000 /* Wrapper space base */ #define SI_CORE_SIZE 0x1000 /* each core gets 4Kbytes for registers */ -#define SI_MAXCORES 16 /* Max cores (this is arbitrary, for software - * convenience and could be changed if we - * make any larger chips - */ + +#define SI_MAXCORES 32 /* NorthStar has more cores */ #define SI_FASTRAM 0x19000000 /* On-chip RAM on chips that also have DDR */ #define SI_FASTRAM_SWAPPED 0x19800000 @@ -59,6 +57,13 @@ #define SI_ARMCM3_ROM 0x1e000000 /* ARM Cortex-M3 ROM */ #define SI_FLASH1 0x1fc00000 /* MIPS Flash Region 1 */ #define SI_FLASH1_SZ 0x00400000 /* MIPS Size of Flash Region 1 */ +#define SI_FLASH_WINDOW 0x01000000 /* Flash XIP Window */ + +#define SI_NS_NANDFLASH 0x1c000000 /* NorthStar NAND flash base */ +#define SI_NS_NORFLASH 0x1e000000 /* NorthStar NOR flash base */ +#define SI_NS_ROM 0xfffd0000 /* NorthStar ROM */ +#define SI_NS_FLASH_WINDOW 0x02000000 /* Flash XIP Window */ + #define SI_ARM7S_ROM 0x20000000 /* ARM7TDMI-S ROM */ #define SI_ARMCR4_ROM 0x000f0000 /* ARM Cortex-R4 ROM */ #define SI_ARMCM3_SRAM2 0x60000000 /* ARM Cortex-M3 SRAM Region 2 */ @@ -147,7 +152,21 @@ */ #define CC_4706_CORE_ID 0x500 /* chipcommon core */ +#define NS_PCIEG2_CORE_ID 0x501 /* PCIE Gen 2 core */ +#define NS_DMA_CORE_ID 0x502 /* DMA core */ +#define NS_SDIO3_CORE_ID 0x503 /* SDIO3 core */ +#define NS_USB20_CORE_ID 0x504 /* USB2.0 core */ +#define NS_USB30_CORE_ID 0x505 /* USB3.0 core */ +#define NS_A9JTAG_CORE_ID 0x506 /* ARM Cortex A9 JTAG core */ +#define NS_DDR23_CORE_ID 0x507 /* Denali DDR2/DDR3 memory controller */ +#define NS_ROM_CORE_ID 0x508 /* ROM core */ +#define NS_NAND_CORE_ID 0x509 /* NAND flash controller core */ +#define NS_QSPI_CORE_ID 0x50a /* SPI flash controller core */ +#define NS_CCB_CORE_ID 0x50b /* ChipcommonB core */ #define SOCRAM_4706_CORE_ID 0x50e /* internal memory core */ +#define NS_SOCRAM_CORE_ID SOCRAM_4706_CORE_ID +#define ARMCA9_CORE_ID 0x510 /* ARM Cortex A9 core (ihost) */ +#define NS_IHOST_CORE_ID ARMCA9_CORE_ID /* ARM Cortex A9 core (ihost) */ #define GMAC_COMMON_4706_CORE_ID 0x5dc /* Gigabit MAC core */ #define GMAC_4706_CORE_ID 0x52d /* Gigabit MAC core */ #define AMEMC_CORE_ID 0x52e /* DDR1/2 memory controller core */ @@ -172,6 +191,7 @@ #define SOCI_SB 0 #define SOCI_AI 1 #define SOCI_UBUS 2 +#define SOCI_NAI 3 /* Common core control flags */ #define SICF_BIST_EN 0x8000 @@ -187,6 +207,14 @@ #define SISF_DMA64 0x1000 #define SISF_CORE_BITS 0x0fff +/* Norstar core status flags */ +#define SISF_NS_BOOTDEV_MASK 0x0003 /* ROM core */ +#define SISF_NS_BOOTDEV_NOR 0x0000 /* ROM core */ +#define SISF_NS_BOOTDEV_NAND 0x0001 /* ROM core */ +#define SISF_NS_BOOTDEV_ROM 0x0002 /* ROM core */ +#define SISF_NS_BOOTDEV_OFFLOAD 0x0003 /* ROM core */ +#define SISF_NS_SKUVEC_MASK 0x000c /* ROM core */ + /* A register that is common to all cores to * communicate w/PMU regarding clock control. */ @@ -232,4 +260,18 @@ #define BISZ_BSSEND_IDX 6 /* 6: bss end */ #define BISZ_SIZE 7 /* descriptor size in 32-bit integers */ +/* Boot/Kernel related defintion and functions */ +#define SOC_BOOTDEV_ROM 0x00000001 +#define SOC_BOOTDEV_PFLASH 0x00000002 +#define SOC_BOOTDEV_SFLASH 0x00000004 +#define SOC_BOOTDEV_NANDFLASH 0x00000008 + +#define SOC_KNLDEV_NORFLASH 0x00000002 +#define SOC_KNLDEV_NANDFLASH 0x00000004 + +#ifndef _LANGUAGE_ASSEMBLY +int soc_boot_dev(void *sih); +int soc_knl_dev(void *sih); +#endif /* _LANGUAGE_ASSEMBLY */ + #endif /* _HNDSOC_H */ diff --git a/drivers/net/wireless/bcmdhd/include/linux_osl.h b/drivers/net/wireless/bcmdhd/include/linux_osl.h index 111b1dd27cb2..5b23a3ac23bd 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/linux_osl.h +++ b/drivers/net/wireless/bcmdhd/include/linux_osl.h @@ -1,7 +1,7 @@ /* * Linux OS Independent Layer * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -21,7 +21,7 @@ * 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: linux_osl.h 354452 2012-08-31 04:59:17Z $ + * $Id: linux_osl.h 411126 2013-07-05 01:22:09Z $ */ #ifndef _linux_osl_h_ @@ -67,6 +67,9 @@ extern void osl_assert(const char *exp, const char *file, int line); #define OSL_DELAY(usec) osl_delay(usec) extern void osl_delay(uint usec); +#define OSL_SLEEP(ms) osl_sleep(ms) +extern void osl_sleep(uint ms); + #define OSL_PCMCIA_READ_ATTR(osh, offset, buf, size) \ osl_pcmcia_read_attr((osh), (offset), (buf), (size)) #define OSL_PCMCIA_WRITE_ATTR(osh, offset, buf, size) \ @@ -92,7 +95,6 @@ extern struct pci_dev *osl_pci_device(osl_t *osh); /* Pkttag flag should be part of public information */ typedef struct { bool pkttag; - uint pktalloced; /* Number of allocated packet buffers */ bool mmbus; /* Bus supports memory-mapped register accesses */ pktfree_cb_fn_t tx_fn; /* Callback function for PKTFREE */ void *tx_ctx; /* Context to the callback function */ @@ -139,7 +141,8 @@ extern void osl_dma_free_consistent(osl_t *osh, void *va, uint size, ulong pa); /* map/unmap shared (dma-able) memory */ #define DMA_UNMAP(osh, pa, size, direction, p, dmah) \ osl_dma_unmap((osh), (pa), (size), (direction)) -extern uint osl_dma_map(osl_t *osh, void *va, uint size, int direction); +extern uint osl_dma_map(osl_t *osh, void *va, uint size, int direction, void *p, + hnddma_seg_map_t *txp_dmah); extern void osl_dma_unmap(osl_t *osh, uint pa, uint size, int direction); /* API for DMA addressing capability */ @@ -224,6 +227,9 @@ extern int osl_error(int bcmerror); #define OSL_UNCACHED(va) ((void *)va) #define OSL_CACHED(va) ((void *)va) +/* ARM NorthStar */ +#define OSL_CACHE_FLUSH(va, len) + #define OSL_PREF_RANGE_LD(va, sz) #define OSL_PREF_RANGE_ST(va, sz) @@ -256,30 +262,77 @@ extern int osl_error(int bcmerror); #include <linuxver.h> /* use current 2.4.x calling conventions */ /* packet primitives */ +#ifdef BCMDBG_CTRACE +#define PKTGET(osh, len, send) osl_pktget((osh), (len), __LINE__, __FILE__) +#define PKTDUP(osh, skb) osl_pktdup((osh), (skb), __LINE__, __FILE__) +#else #define PKTGET(osh, len, send) osl_pktget((osh), (len)) #define PKTDUP(osh, skb) osl_pktdup((osh), (skb)) +#endif /* BCMDBG_CTRACE */ #define PKTLIST_DUMP(osh, buf) #define PKTDBG_TRACE(osh, pkt, bit) #define PKTFREE(osh, skb, send) osl_pktfree((osh), (skb), (send)) #ifdef CONFIG_DHD_USE_STATIC_BUF #define PKTGET_STATIC(osh, len, send) osl_pktget_static((osh), (len)) #define PKTFREE_STATIC(osh, skb, send) osl_pktfree_static((osh), (skb), (send)) +#else +#define PKTGET_STATIC PKTGET +#define PKTFREE_STATIC PKTFREE #endif /* CONFIG_DHD_USE_STATIC_BUF */ #define PKTDATA(osh, skb) (((struct sk_buff*)(skb))->data) #define PKTLEN(osh, skb) (((struct sk_buff*)(skb))->len) #define PKTHEADROOM(osh, skb) (PKTDATA(osh, skb)-(((struct sk_buff*)(skb))->head)) -#define PKTTAILROOM(osh, skb) ((((struct sk_buff*)(skb))->end)-(((struct sk_buff*)(skb))->tail)) +#define PKTTAILROOM(osh, skb) skb_tailroom((struct sk_buff*)(skb)) +#define PKTPADTAILROOM(osh, skb, padlen) osh_pktpadtailroom((osh), (skb), (padlen)) #define PKTNEXT(osh, skb) (((struct sk_buff*)(skb))->next) #define PKTSETNEXT(osh, skb, x) (((struct sk_buff*)(skb))->next = (struct sk_buff*)(x)) #define PKTSETLEN(osh, skb, len) __skb_trim((struct sk_buff*)(skb), (len)) #define PKTPUSH(osh, skb, bytes) skb_push((struct sk_buff*)(skb), (bytes)) #define PKTPULL(osh, skb, bytes) skb_pull((struct sk_buff*)(skb), (bytes)) #define PKTTAG(skb) ((void*)(((struct sk_buff*)(skb))->cb)) -#define PKTALLOCED(osh) ((osl_pubinfo_t *)(osh))->pktalloced #define PKTSETPOOL(osh, skb, x, y) do {} while (0) #define PKTPOOL(osh, skb) FALSE #define PKTSHRINK(osh, m) (m) +#ifdef BCMDBG_CTRACE +#define DEL_CTRACE(zosh, zskb) { \ + unsigned long zflags; \ + spin_lock_irqsave(&(zosh)->ctrace_lock, zflags); \ + list_del(&(zskb)->ctrace_list); \ + (zosh)->ctrace_num--; \ + (zskb)->ctrace_start = 0; \ + (zskb)->ctrace_count = 0; \ + spin_unlock_irqrestore(&(zosh)->ctrace_lock, zflags); \ +} + +#define UPDATE_CTRACE(zskb, zfile, zline) { \ + struct sk_buff *_zskb = (struct sk_buff *)(zskb); \ + if (_zskb->ctrace_count < CTRACE_NUM) { \ + _zskb->func[_zskb->ctrace_count] = zfile; \ + _zskb->line[_zskb->ctrace_count] = zline; \ + _zskb->ctrace_count++; \ + } \ + else { \ + _zskb->func[_zskb->ctrace_start] = zfile; \ + _zskb->line[_zskb->ctrace_start] = zline; \ + _zskb->ctrace_start++; \ + if (_zskb->ctrace_start >= CTRACE_NUM) \ + _zskb->ctrace_start = 0; \ + } \ +} + +#define ADD_CTRACE(zosh, zskb, zfile, zline) { \ + unsigned long zflags; \ + spin_lock_irqsave(&(zosh)->ctrace_lock, zflags); \ + list_add(&(zskb)->ctrace_list, &(zosh)->ctrace_list); \ + (zosh)->ctrace_num++; \ + UPDATE_CTRACE(zskb, zfile, zline); \ + spin_unlock_irqrestore(&(zosh)->ctrace_lock, zflags); \ +} + +#define PKTCALLER(zskb) UPDATE_CTRACE((struct sk_buff *)zskb, (char *)__FUNCTION__, __LINE__) +#endif /* BCMDBG_CTRACE */ + #ifdef CTFPOOL #define CTFPOOL_REFILL_THRESH 3 typedef struct ctfpool { @@ -293,66 +346,117 @@ typedef struct ctfpool { uint fast_frees; uint slow_allocs; } ctfpool_t; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) +#define FASTBUF (1 << 0) +#define PKTSETFAST(osh, skb) ((((struct sk_buff*)(skb))->pktc_flags) |= FASTBUF) +#define PKTCLRFAST(osh, skb) ((((struct sk_buff*)(skb))->pktc_flags) &= (~FASTBUF)) +#define PKTISFAST(osh, skb) ((((struct sk_buff*)(skb))->pktc_flags) & FASTBUF) +#define PKTFAST(osh, skb) (((struct sk_buff*)(skb))->pktc_flags) +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) #define FASTBUF (1 << 16) -#define CTFBUF (1 << 17) #define PKTSETFAST(osh, skb) ((((struct sk_buff*)(skb))->mac_len) |= FASTBUF) #define PKTCLRFAST(osh, skb) ((((struct sk_buff*)(skb))->mac_len) &= (~FASTBUF)) -#define PKTSETCTF(osh, skb) ((((struct sk_buff*)(skb))->mac_len) |= CTFBUF) -#define PKTCLRCTF(osh, skb) ((((struct sk_buff*)(skb))->mac_len) &= (~CTFBUF)) #define PKTISFAST(osh, skb) ((((struct sk_buff*)(skb))->mac_len) & FASTBUF) -#define PKTISCTF(osh, skb) ((((struct sk_buff*)(skb))->mac_len) & CTFBUF) #define PKTFAST(osh, skb) (((struct sk_buff*)(skb))->mac_len) #else #define FASTBUF (1 << 0) -#define CTFBUF (1 << 1) #define PKTSETFAST(osh, skb) ((((struct sk_buff*)(skb))->__unused) |= FASTBUF) #define PKTCLRFAST(osh, skb) ((((struct sk_buff*)(skb))->__unused) &= (~FASTBUF)) -#define PKTSETCTF(osh, skb) ((((struct sk_buff*)(skb))->__unused) |= CTFBUF) -#define PKTCLRCTF(osh, skb) ((((struct sk_buff*)(skb))->__unused) &= (~CTFBUF)) #define PKTISFAST(osh, skb) ((((struct sk_buff*)(skb))->__unused) & FASTBUF) -#define PKTISCTF(osh, skb) ((((struct sk_buff*)(skb))->__unused) & CTFBUF) #define PKTFAST(osh, skb) (((struct sk_buff*)(skb))->__unused) #endif /* 2.6.22 */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) +#define CTFPOOLPTR(osh, skb) (((struct sk_buff*)(skb))->ctfpool) +#define CTFPOOLHEAD(osh, skb) (((ctfpool_t *)((struct sk_buff*)(skb))->ctfpool)->head) +#else #define CTFPOOLPTR(osh, skb) (((struct sk_buff*)(skb))->sk) #define CTFPOOLHEAD(osh, skb) (((ctfpool_t *)((struct sk_buff*)(skb))->sk)->head) +#endif extern void *osl_ctfpool_add(osl_t *osh); extern void osl_ctfpool_replenish(osl_t *osh, uint thresh); extern int32 osl_ctfpool_init(osl_t *osh, uint numobj, uint size); extern void osl_ctfpool_cleanup(osl_t *osh); extern void osl_ctfpool_stats(osl_t *osh, void *b); +#else /* CTFPOOL */ +#define PKTSETFAST(osh, skb) +#define PKTCLRFAST(osh, skb) +#define PKTISFAST(osh, skb) (FALSE) #endif /* CTFPOOL */ +#define PKTSETCTF(osh, skb) +#define PKTCLRCTF(osh, skb) +#define PKTISCTF(osh, skb) (FALSE) #ifdef HNDCTF -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) +#define SKIPCT (1 << 2) +#define CHAINED (1 << 3) +#define PKTSETSKIPCT(osh, skb) (((struct sk_buff*)(skb))->pktc_flags |= SKIPCT) +#define PKTCLRSKIPCT(osh, skb) (((struct sk_buff*)(skb))->pktc_flags &= (~SKIPCT)) +#define PKTSKIPCT(osh, skb) (((struct sk_buff*)(skb))->pktc_flags & SKIPCT) +#define PKTSETCHAINED(osh, skb) (((struct sk_buff*)(skb))->pktc_flags |= CHAINED) +#define PKTCLRCHAINED(osh, skb) (((struct sk_buff*)(skb))->pktc_flags &= (~CHAINED)) +#define PKTISCHAINED(skb) (((struct sk_buff*)(skb))->pktc_flags & CHAINED) +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) #define SKIPCT (1 << 18) +#define CHAINED (1 << 19) #define PKTSETSKIPCT(osh, skb) (((struct sk_buff*)(skb))->mac_len |= SKIPCT) #define PKTCLRSKIPCT(osh, skb) (((struct sk_buff*)(skb))->mac_len &= (~SKIPCT)) #define PKTSKIPCT(osh, skb) (((struct sk_buff*)(skb))->mac_len & SKIPCT) +#define PKTSETCHAINED(osh, skb) (((struct sk_buff*)(skb))->mac_len |= CHAINED) +#define PKTCLRCHAINED(osh, skb) (((struct sk_buff*)(skb))->mac_len &= (~CHAINED)) +#define PKTISCHAINED(skb) (((struct sk_buff*)(skb))->mac_len & CHAINED) #else /* 2.6.22 */ #define SKIPCT (1 << 2) +#define CHAINED (1 << 3) #define PKTSETSKIPCT(osh, skb) (((struct sk_buff*)(skb))->__unused |= SKIPCT) #define PKTCLRSKIPCT(osh, skb) (((struct sk_buff*)(skb))->__unused &= (~SKIPCT)) #define PKTSKIPCT(osh, skb) (((struct sk_buff*)(skb))->__unused & SKIPCT) +#define PKTSETCHAINED(osh, skb) (((struct sk_buff*)(skb))->__unused |= CHAINED) +#define PKTCLRCHAINED(osh, skb) (((struct sk_buff*)(skb))->__unused &= (~CHAINED)) +#define PKTISCHAINED(skb) (((struct sk_buff*)(skb))->__unused & CHAINED) #endif /* 2.6.22 */ +typedef struct ctf_mark { + uint32 value; +} ctf_mark_t; +#define CTF_MARK(m) (m.value) #else /* HNDCTF */ #define PKTSETSKIPCT(osh, skb) #define PKTCLRSKIPCT(osh, skb) #define PKTSKIPCT(osh, skb) +#define CTF_MARK(m) 0 #endif /* HNDCTF */ extern void osl_pktfree(osl_t *osh, void *skb, bool send); extern void *osl_pktget_static(osl_t *osh, uint len); extern void osl_pktfree_static(osl_t *osh, void *skb, bool send); - +extern int osh_pktpadtailroom(osl_t *osh, void* skb, int pad); + +#ifdef BCMDBG_CTRACE +#define PKT_CTRACE_DUMP(osh, b) osl_ctrace_dump((osh), (b)) +extern void *osl_pktget(osl_t *osh, uint len, int line, char *file); +extern void *osl_pkt_frmnative(osl_t *osh, void *skb, int line, char *file); +extern int osl_pkt_is_frmnative(osl_t *osh, struct sk_buff *pkt); +extern void *osl_pktdup(osl_t *osh, void *skb, int line, char *file); +struct bcmstrbuf; +extern void osl_ctrace_dump(osl_t *osh, struct bcmstrbuf *b); +#else extern void *osl_pkt_frmnative(osl_t *osh, void *skb); extern void *osl_pktget(osl_t *osh, uint len); extern void *osl_pktdup(osl_t *osh, void *skb); +#endif /* BCMDBG_CTRACE */ extern struct sk_buff *osl_pkt_tonative(osl_t *osh, void *pkt); +#ifdef BCMDBG_CTRACE +#define PKTFRMNATIVE(osh, skb) osl_pkt_frmnative(((osl_t *)osh), \ + (struct sk_buff*)(skb), __LINE__, __FILE__) +#define PKTISFRMNATIVE(osh, skb) osl_pkt_is_frmnative((osl_t *)(osh), (struct sk_buff *)(skb)) +#else #define PKTFRMNATIVE(osh, skb) osl_pkt_frmnative(((osl_t *)osh), (struct sk_buff*)(skb)) +#endif /* BCMDBG_CTRACE */ #define PKTTONATIVE(osh, pkt) osl_pkt_tonative((osl_t *)(osh), (pkt)) #define PKTLINK(skb) (((struct sk_buff*)(skb))->prev) @@ -365,8 +469,24 @@ extern struct sk_buff *osl_pkt_tonative(osl_t *osh, void *pkt); /* PKTSETSUMNEEDED and PKTSUMGOOD are not possible because skb->ip_summed is overloaded */ #define PKTSHARED(skb) (((struct sk_buff*)(skb))->cloned) +#ifdef CONFIG_NF_CONNTRACK_MARK +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) +#define PKTMARK(p) (((struct sk_buff *)(p))->mark) +#define PKTSETMARK(p, m) ((struct sk_buff *)(p))->mark = (m) +#else /* !2.6.0 */ +#define PKTMARK(p) (((struct sk_buff *)(p))->nfmark) +#define PKTSETMARK(p, m) ((struct sk_buff *)(p))->nfmark = (m) +#endif /* 2.6.0 */ +#else /* CONFIG_NF_CONNTRACK_MARK */ +#define PKTMARK(p) 0 +#define PKTSETMARK(p, m) +#endif /* CONFIG_NF_CONNTRACK_MARK */ + +#define PKTALLOCED(osh) osl_pktalloced(osh) +extern uint osl_pktalloced(osl_t *osh); + #define DMA_MAP(osh, va, size, direction, p, dmah) \ - osl_dma_map((osh), (va), (size), (direction)) + osl_dma_map((osh), (va), (size), (direction), (p), (dmah)) #ifdef PKTC /* Use 8 bytes of skb tstamp field to store below info */ @@ -375,33 +495,52 @@ struct chain_node { unsigned int flags:3, pkts:9, bytes:20; }; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14) -#define CHAIN_NODE(skb) ((struct chain_node*)&(((struct sk_buff*)skb)->tstamp)) -#else -#define CHAIN_NODE(skb) ((struct chain_node*)&(((struct sk_buff*)skb)->stamp)) -#endif +#define CHAIN_NODE(skb) ((struct chain_node*)(((struct sk_buff*)skb)->pktc_cb)) +#define PKTCSETATTR(s, f, p, b) ({CHAIN_NODE(s)->flags = (f); CHAIN_NODE(s)->pkts = (p); \ + CHAIN_NODE(s)->bytes = (b);}) +#define PKTCCLRATTR(s) ({CHAIN_NODE(s)->flags = CHAIN_NODE(s)->pkts = \ + CHAIN_NODE(s)->bytes = 0;}) +#define PKTCGETATTR(s) (CHAIN_NODE(s)->flags << 29 | CHAIN_NODE(s)->pkts << 20 | \ + CHAIN_NODE(s)->bytes) #define PKTCCNT(skb) (CHAIN_NODE(skb)->pkts) #define PKTCLEN(skb) (CHAIN_NODE(skb)->bytes) +#define PKTCGETFLAGS(skb) (CHAIN_NODE(skb)->flags) +#define PKTCSETFLAGS(skb, f) (CHAIN_NODE(skb)->flags = (f)) +#define PKTCCLRFLAGS(skb) (CHAIN_NODE(skb)->flags = 0) #define PKTCFLAGS(skb) (CHAIN_NODE(skb)->flags) -#define PKTCSETCNT(skb, c) (CHAIN_NODE(skb)->pkts = (c) & ((1 << 9) - 1)) -#define PKTCSETLEN(skb, l) (CHAIN_NODE(skb)->bytes = (l) & ((1 << 20) - 1)) +#define PKTCSETCNT(skb, c) (CHAIN_NODE(skb)->pkts = (c)) +#define PKTCINCRCNT(skb) (CHAIN_NODE(skb)->pkts++) +#define PKTCADDCNT(skb, c) (CHAIN_NODE(skb)->pkts += (c)) +#define PKTCSETLEN(skb, l) (CHAIN_NODE(skb)->bytes = (l)) +#define PKTCADDLEN(skb, l) (CHAIN_NODE(skb)->bytes += (l)) #define PKTCSETFLAG(skb, fb) (CHAIN_NODE(skb)->flags |= (fb)) #define PKTCCLRFLAG(skb, fb) (CHAIN_NODE(skb)->flags &= ~(fb)) #define PKTCLINK(skb) (CHAIN_NODE(skb)->link) #define PKTSETCLINK(skb, x) (CHAIN_NODE(skb)->link = (struct sk_buff*)(x)) -#define PKTISCHAINED(skb) (PKTCLINK(skb) != NULL) #define FOREACH_CHAINED_PKT(skb, nskb) \ for (; (skb) != NULL; (skb) = (nskb)) \ - if ((nskb) = PKTCLINK(skb), PKTSETCLINK((skb), NULL), 1) + if ((nskb) = (PKTISCHAINED(skb) ? PKTCLINK(skb) : NULL), \ + PKTSETCLINK((skb), NULL), 1) #define PKTCFREE(osh, skb, send) \ do { \ void *nskb; \ ASSERT((skb) != NULL); \ FOREACH_CHAINED_PKT((skb), nskb) { \ + PKTCLRCHAINED((osh), (skb)); \ + PKTCCLRFLAGS((skb)); \ PKTFREE((osh), (skb), (send)); \ } \ } while (0) +#define PKTCENQTAIL(h, t, p) \ +do { \ + if ((t) == NULL) { \ + (h) = (t) = (p); \ + } else { \ + PKTSETCLINK((t), (p)); \ + (t) = (p); \ + } \ +} while (0) #endif /* PKTC */ #else /* ! BCMDRIVER */ diff --git a/drivers/net/wireless/bcmdhd/include/linuxver.h b/drivers/net/wireless/bcmdhd/include/linuxver.h index c8f08a5c5769..10be026d286a 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/linuxver.h +++ b/drivers/net/wireless/bcmdhd/include/linuxver.h @@ -2,7 +2,7 @@ * Linux-specific abstractions to gain some independence from linux kernel versions. * Pave over some 2.2 versus 2.4 versus 2.6 kernel differences. * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -22,12 +22,13 @@ * 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: linuxver.h 366812 2012-11-05 13:49:32Z $ + * $Id: linuxver.h 417757 2013-08-12 12:24:45Z $ */ #ifndef _linuxver_h_ #define _linuxver_h_ +#include <typedefs.h> #include <linux/version.h> #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) #include <linux/config.h> @@ -68,6 +69,7 @@ #include <linux/string.h> #include <linux/pci.h> #include <linux/interrupt.h> +#include <linux/kthread.h> #include <linux/netdevice.h> #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) #include <linux/semaphore.h> @@ -97,7 +99,10 @@ #endif #endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 41) */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) +#define DAEMONIZE(a) +#elif ((LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)) && \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))) #define DAEMONIZE(a) daemonize(a); \ allow_signal(SIGKILL); \ allow_signal(SIGTERM); @@ -150,7 +155,11 @@ typedef irqreturn_t(*FN_ISR) (int irq, void *dev_id, struct pt_regs *ptregs); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) #include <linux/sched.h> -#endif +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) */ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)) +#include <linux/sched/rt.h> +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) #include <net/lib80211.h> @@ -164,7 +173,6 @@ typedef irqreturn_t(*FN_ISR) (int irq, void *dev_id, struct pt_regs *ptregs); #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30) */ - #ifndef __exit #define __exit #endif @@ -488,9 +496,11 @@ pci_restore_state(struct pci_dev *dev, u32 *buffer) #define SET_NETDEV_DEV(net, pdev) do {} while (0) #endif +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0)) #ifndef HAVE_FREE_NETDEV #define free_netdev(dev) kfree(dev) #endif +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0) */ #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) /* struct packet_type redefined in 2.6.x */ @@ -509,13 +519,16 @@ pci_restore_state(struct pci_dev *dev, u32 *buffer) #endif typedef struct { - void *parent; /* some external entity that the thread supposed to work for */ + void *parent; /* some external entity that the thread supposed to work for */ + char *proc_name; struct task_struct *p_task; - pid_t thr_pid; - int prio; + long thr_pid; + int prio; /* priority */ struct semaphore sema; int terminated; struct completion completed; + spinlock_t spinlock; + int up_cnt; } tsk_ctl_t; @@ -527,38 +540,63 @@ typedef struct { #define DBG_THR(x) #endif +static inline bool binary_sema_down(tsk_ctl_t *tsk) +{ + if (down_interruptible(&tsk->sema) == 0) { + unsigned long flags = 0; + spin_lock_irqsave(&tsk->spinlock, flags); + if (tsk->up_cnt == 1) + tsk->up_cnt--; + else { + DBG_THR(("dhd_dpc_thread: Unexpected up_cnt %d\n", tsk->up_cnt)); + } + spin_unlock_irqrestore(&tsk->spinlock, flags); + return FALSE; + } else + return TRUE; +} + +static inline bool binary_sema_up(tsk_ctl_t *tsk) +{ + bool sem_up = FALSE; + unsigned long flags = 0; + + spin_lock_irqsave(&tsk->spinlock, flags); + if (tsk->up_cnt == 0) { + tsk->up_cnt++; + sem_up = TRUE; + } else if (tsk->up_cnt == 1) { + /* dhd_sched_dpc: dpc is alread up! */ + } else + DBG_THR(("dhd_sched_dpc: unexpected up cnt %d!\n", tsk->up_cnt)); + + spin_unlock_irqrestore(&tsk->spinlock, flags); + + if (sem_up) + up(&tsk->sema); + + return sem_up; +} + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) #define SMP_RD_BARRIER_DEPENDS(x) smp_read_barrier_depends(x) #else #define SMP_RD_BARRIER_DEPENDS(x) smp_rmb(x) #endif - -#define PROC_START(thread_func, owner, tsk_ctl, flags) \ -{ \ - sema_init(&((tsk_ctl)->sema), 0); \ - init_completion(&((tsk_ctl)->completed)); \ - (tsk_ctl)->parent = owner; \ - (tsk_ctl)->terminated = FALSE; \ - (tsk_ctl)->thr_pid = kernel_thread(thread_func, tsk_ctl, flags); \ - DBG_THR(("%s thr:%lx created\n", __FUNCTION__, (tsk_ctl)->thr_pid)); \ - if ((tsk_ctl)->thr_pid > 0) \ - wait_for_completion(&((tsk_ctl)->completed)); \ - DBG_THR(("%s thr:%lx started\n", __FUNCTION__, (tsk_ctl)->thr_pid)); \ -} - -#ifdef USE_KTHREAD_API -#define PROC_START2(thread_func, owner, tsk_ctl, flags, name) \ +#define PROC_START(thread_func, owner, tsk_ctl, flags, name) \ { \ sema_init(&((tsk_ctl)->sema), 0); \ init_completion(&((tsk_ctl)->completed)); \ (tsk_ctl)->parent = owner; \ + (tsk_ctl)->proc_name = name; \ (tsk_ctl)->terminated = FALSE; \ (tsk_ctl)->p_task = kthread_run(thread_func, tsk_ctl, (char*)name); \ (tsk_ctl)->thr_pid = (tsk_ctl)->p_task->pid; \ - DBG_THR(("%s thr:%d created\n", __FUNCTION__, (tsk_ctl)->thr_pid)); \ + spin_lock_init(&((tsk_ctl)->spinlock)); \ + DBG_THR(("%s(): thread:%s:%lx started\n", __FUNCTION__, \ + (tsk_ctl)->proc_name, (tsk_ctl)->thr_pid)); \ } -#endif #define PROC_STOP(tsk_ctl) \ { \ @@ -566,7 +604,8 @@ typedef struct { smp_wmb(); \ up(&((tsk_ctl)->sema)); \ wait_for_completion(&((tsk_ctl)->completed)); \ - DBG_THR(("%s thr:%lx terminated OK\n", __FUNCTION__, (tsk_ctl)->thr_pid)); \ + DBG_THR(("%s(): thread:%s:%lx terminated OK\n", __FUNCTION__, \ + (tsk_ctl)->proc_name, (tsk_ctl)->thr_pid)); \ (tsk_ctl)->thr_pid = -1; \ } @@ -659,4 +698,16 @@ not match our unaligned address for < 2.6.24 #define netdev_priv(dev) dev->priv #endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) +#define RANDOM32 prandom_u32 +#else +#define RANDOM32 random32 +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) */ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) +#define SRANDOM32(entropy) prandom_seed(entropy) +#else +#define SRANDOM32(entropy) srandom32(entropy) +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) */ + #endif /* _linuxver_h_ */ diff --git a/drivers/net/wireless/bcmdhd/include/miniopt.h b/drivers/net/wireless/bcmdhd/include/miniopt.h index c1eca68a602d..ba48da04438f 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/miniopt.h +++ b/drivers/net/wireless/bcmdhd/include/miniopt.h @@ -1,7 +1,7 @@ /* * Command line options parser. * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd/include/msgtrace.h b/drivers/net/wireless/bcmdhd/include/msgtrace.h index 7c5fd8106f3f..aa5261a1e696 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/msgtrace.h +++ b/drivers/net/wireless/bcmdhd/include/msgtrace.h @@ -1,7 +1,7 @@ /* * Trace messages sent over HBUS * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -21,7 +21,7 @@ * 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: msgtrace.h 281527 2011-09-02 17:12:53Z $ + * $Id: msgtrace.h 369735 2012-11-19 22:50:22Z $ */ #ifndef _MSGTRACE_H @@ -40,11 +40,14 @@ /* Message trace header */ typedef BWL_PRE_PACKED_STRUCT struct msgtrace_hdr { uint8 version; - uint8 spare; + uint8 trace_type; +#define MSGTRACE_HDR_TYPE_MSG 0 +#define MSGTRACE_HDR_TYPE_LOG 1 uint16 len; /* Len of the trace */ uint32 seqnum; /* Sequence number of message. Useful if the messsage has been lost * because of DMA error or a bus reset (ex: SDIO Func2) */ + /* Msgtrace type only */ uint32 discarded_bytes; /* Number of discarded bytes because of trace overflow */ uint32 discarded_printf; /* Number of discarded printf because of trace overflow */ } BWL_POST_PACKED_STRUCT msgtrace_hdr_t; @@ -63,7 +66,7 @@ typedef void (*msgtrace_func_send_t)(void *hdl1, void *hdl2, uint8 *hdr, uint16 hdrlen, uint8 *buf, uint16 buflen); extern void msgtrace_start(void); extern void msgtrace_stop(void); -extern void msgtrace_sent(void); +extern int msgtrace_sent(void); extern void msgtrace_put(char *buf, int count); extern void msgtrace_init(void *hdl1, void *hdl2, msgtrace_func_send_t func_send); extern bool msgtrace_event_enabled(void); diff --git a/drivers/net/wireless/bcmdhd/include/osl.h b/drivers/net/wireless/bcmdhd/include/osl.h index 0a11d230f05b..115e662370ae 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/osl.h +++ b/drivers/net/wireless/bcmdhd/include/osl.h @@ -1,7 +1,7 @@ /* * OS Abstraction Layer * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -21,7 +21,7 @@ * 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: osl.h 320905 2012-03-13 15:33:25Z $ + * $Id: osl.h 370064 2012-11-20 21:00:25Z $ */ #ifndef _osl_h_ @@ -71,20 +71,33 @@ typedef void (*osl_wreg_fn_t)(void *ctx, volatile void *reg, unsigned int val, #endif /* OSL_SYSUPTIME */ #if !defined(PKTC) -#define PKTCCNT(skb) (0) -#define PKTCLEN(skb) (0) +#define PKTCGETATTR(s) (0) +#define PKTCSETATTR(skb, f, p, b) +#define PKTCCLRATTR(skb) +#define PKTCCNT(skb) (1) +#define PKTCLEN(skb) PKTLEN(NULL, skb) +#define PKTCGETFLAGS(skb) (0) +#define PKTCSETFLAGS(skb, f) +#define PKTCCLRFLAGS(skb) #define PKTCFLAGS(skb) (0) #define PKTCSETCNT(skb, c) +#define PKTCINCRCNT(skb) +#define PKTCADDCNT(skb, c) #define PKTCSETLEN(skb, l) +#define PKTCADDLEN(skb, l) #define PKTCSETFLAG(skb, fb) #define PKTCCLRFLAG(skb, fb) -#define PKTCLINK(skb) PKTLINK(skb) -#define PKTSETCLINK(skb, x) PKTSETLINK((skb), (x)) -#define PKTISCHAINED(skb) FALSE +#define PKTCLINK(skb) NULL +#define PKTSETCLINK(skb, x) #define FOREACH_CHAINED_PKT(skb, nskb) \ for ((nskb) = NULL; (skb) != NULL; (skb) = (nskb)) #define PKTCFREE PKTFREE -#endif +#endif /* !linux || !PKTC */ +#ifndef HNDCTF +#define PKTSETCHAINED(osh, skb) +#define PKTCLRCHAINED(osh, skb) +#define PKTISCHAINED(skb) (FALSE) +#endif #endif /* _osl_h_ */ diff --git a/drivers/net/wireless/bcmdhd/include/packed_section_end.h b/drivers/net/wireless/bcmdhd/include/packed_section_end.h index 0779b04c5e56..fcd3701364f8 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/packed_section_end.h +++ b/drivers/net/wireless/bcmdhd/include/packed_section_end.h @@ -15,7 +15,7 @@ * #include <packed_section_end.h> * * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd/include/packed_section_start.h b/drivers/net/wireless/bcmdhd/include/packed_section_start.h index ee93a4b15893..3f42d4898d96 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/packed_section_start.h +++ b/drivers/net/wireless/bcmdhd/include/packed_section_start.h @@ -15,7 +15,7 @@ * #include <packed_section_end.h> * * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd/include/pcicfg.h b/drivers/net/wireless/bcmdhd/include/pcicfg.h index 0278bb297649..e15f75d5b184 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/pcicfg.h +++ b/drivers/net/wireless/bcmdhd/include/pcicfg.h @@ -1,7 +1,7 @@ /* * pcicfg.h: PCI configuration constants and structures. * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -21,7 +21,7 @@ * 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: pcicfg.h 309193 2012-01-19 00:03:57Z $ + * $Id: pcicfg.h 346935 2012-07-25 00:24:55Z $ */ #ifndef _h_pcicfg_ @@ -58,6 +58,7 @@ #define PCI_CFG_PIN 0x3d #define PCI_CFG_MINGNT 0x3e #define PCI_CFG_MAXLAT 0x3f +#define PCI_CFG_DEVCTRL 0xd8 #define PCI_BAR0_WIN 0x80 /* backplane addres space accessed by BAR0 */ #define PCI_BAR1_WIN 0x84 /* backplane addres space accessed by BAR1 */ #define PCI_SPROM_CONTROL 0x88 /* sprom property control */ diff --git a/drivers/net/wireless/bcmdhd/include/proto/802.11.h b/drivers/net/wireless/bcmdhd/include/proto/802.11.h index 8e10053c69a3..feedc5c1cc13 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/proto/802.11.h +++ b/drivers/net/wireless/bcmdhd/include/proto/802.11.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -21,7 +21,7 @@ * * Fundamental types and constants relating to 802.11 * - * $Id: 802.11.h 346820 2012-07-24 13:53:12Z $ + * $Id: 802.11.h 386067 2013-02-19 15:24:20Z $ */ #ifndef _802_11_H_ @@ -304,6 +304,12 @@ BWL_PRE_PACKED_STRUCT struct dot11_action_sa_query { uint16 id; } BWL_POST_PACKED_STRUCT; +BWL_PRE_PACKED_STRUCT struct dot11_action_vht_oper_mode { + uint8 category; + uint8 action; + uint8 mode; +} BWL_POST_PACKED_STRUCT; + #define SM_PWRSAVE_ENABLE 1 #define SM_PWRSAVE_MODE 2 @@ -425,6 +431,36 @@ BWL_PRE_PACKED_STRUCT struct dot11y_action_ext_csa { struct dot11_csa_body b; /* body of the ie */ } BWL_POST_PACKED_STRUCT; +/* Wide Bandwidth Channel Switch IE data structure */ +BWL_PRE_PACKED_STRUCT struct dot11_wide_bw_channel_switch { + uint8 id; /* id DOT11_MNG_WIDE_BW_CHANNEL_SWITCH_ID */ + uint8 len; /* length of IE */ + uint8 channel_width; /* new channel width */ + uint8 center_frequency_segment_0; /* center frequency segment 0 */ + uint8 center_frequency_segment_1; /* center frequency segment 1 */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_wide_bw_channel_switch dot11_wide_bw_chan_switch_ie_t; + +#define DOT11_WIDE_BW_SWITCH_IE_LEN 3 /* length of IE data, not including 2 byte header */ + +/* Channel Switch Wrapper IE data structure */ +BWL_PRE_PACKED_STRUCT struct dot11_channel_switch_wrapper { + uint8 id; /* id DOT11_MNG_WIDE_BW_CHANNEL_SWITCH_ID */ + uint8 len; /* length of IE */ + dot11_wide_bw_chan_switch_ie_t wb_chan_switch_ie; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_channel_switch_wrapper dot11_chan_switch_wrapper_ie_t; + +/* VHT Transmit Power Envelope IE data structure */ +BWL_PRE_PACKED_STRUCT struct dot11_vht_transmit_power_envelope { + uint8 id; /* id DOT11_MNG_WIDE_BW_CHANNEL_SWITCH_ID */ + uint8 len; /* length of IE */ + uint8 transmit_power_info; + uint8 local_max_transmit_power_20; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_vht_transmit_power_envelope dot11_vht_transmit_power_envelope_ie_t; + + BWL_PRE_PACKED_STRUCT struct dot11_obss_coex { uint8 id; uint8 len; @@ -453,25 +489,40 @@ BWL_PRE_PACKED_STRUCT struct dot11_extcap_ie { } BWL_POST_PACKED_STRUCT; typedef struct dot11_extcap_ie dot11_extcap_ie_t; -#define DOT11_EXTCAP_LEN_MAX 7 +#define DOT11_EXTCAP_LEN_MAX 8 + #define DOT11_EXTCAP_LEN_COEX 1 #define DOT11_EXTCAP_LEN_BT 3 #define DOT11_EXTCAP_LEN_IW 4 #define DOT11_EXTCAP_LEN_SI 6 #define DOT11_EXTCAP_LEN_TDLS 5 +#define DOT11_11AC_EXTCAP_LEN_TDLS 8 + +#define DOT11_EXTCAP_LEN_FMS 2 +#define DOT11_EXTCAP_LEN_PROXY_ARP 2 +#define DOT11_EXTCAP_LEN_TFS 3 +#define DOT11_EXTCAP_LEN_WNM_SLEEP 3 +#define DOT11_EXTCAP_LEN_TIMBC 3 +#define DOT11_EXTCAP_LEN_BSSTRANS 3 +#define DOT11_EXTCAP_LEN_DMS 4 +#define DOT11_EXTCAP_LEN_WNM_NOTIFICATION 6 +#define DOT11_EXTCAP_LEN_TDLS_WBW 8 +#define DOT11_EXTCAP_LEN_OPMODE_NOTIFICATION 8 + BWL_PRE_PACKED_STRUCT struct dot11_extcap { - uint8 extcap[DOT11_EXTCAP_LEN_TDLS]; + uint8 extcap[DOT11_EXTCAP_LEN_MAX]; } BWL_POST_PACKED_STRUCT; typedef struct dot11_extcap dot11_extcap_t; /* TDLS Capabilities */ -#define TDLS_CAP_TDLS 37 /* TDLS support */ -#define TDLS_CAP_PU_BUFFER_STA 28 /* TDLS Peer U-APSD buffer STA support */ -#define TDLS_CAP_PEER_PSM 20 /* TDLS Peer PSM support */ -#define TDLS_CAP_CH_SW 30 /* TDLS Channel switch */ -#define TDLS_CAP_PROH 38 /* TDLS prohibited */ -#define TDLS_CAP_CH_SW_PROH 39 /* TDLS Channel switch prohibited */ +#define DOT11_TDLS_CAP_TDLS 37 /* TDLS support */ +#define DOT11_TDLS_CAP_PU_BUFFER_STA 28 /* TDLS Peer U-APSD buffer STA support */ +#define DOT11_TDLS_CAP_PEER_PSM 20 /* TDLS Peer PSM support */ +#define DOT11_TDLS_CAP_CH_SW 30 /* TDLS Channel switch */ +#define DOT11_TDLS_CAP_PROH 38 /* TDLS prohibited */ +#define DOT11_TDLS_CAP_CH_SW_PROH 39 /* TDLS Channel switch prohibited */ +#define DOT11_TDLS_CAP_TDLS_WIDER_BW 61 /* TDLS Wider Band-Width */ #define TDLS_CAP_MAX_BIT 39 /* TDLS max bit defined in ext cap */ @@ -484,7 +535,7 @@ typedef struct dot11_extcap dot11_extcap_t; #define DOT11_MEASURE_TYPE_NOISE 4 /* d11 measurement Noise Histogram type */ #define DOT11_MEASURE_TYPE_BEACON 5 /* d11 measurement Beacon type */ #define DOT11_MEASURE_TYPE_FRAME 6 /* d11 measurement Frame type */ -#define DOT11_MEASURE_TYPE_STATS 7 /* d11 measurement STA Statistics type */ +#define DOT11_MEASURE_TYPE_STAT 7 /* d11 measurement STA Statistics type */ #define DOT11_MEASURE_TYPE_LCI 8 /* d11 measurement LCI type */ #define DOT11_MEASURE_TYPE_TXSTREAM 9 /* d11 measurement TX Stream type */ #define DOT11_MEASURE_TYPE_PAUSE 255 /* d11 measurement pause type */ @@ -864,6 +915,7 @@ typedef struct ti_ie ti_ie_t; #define FC_SUBTYPE_ANY_NULL(s) (((s) & 4) != 0) #define FC_SUBTYPE_ANY_CF_POLL(s) (((s) & 2) != 0) #define FC_SUBTYPE_ANY_CF_ACK(s) (((s) & 1) != 0) +#define FC_SUBTYPE_ANY_PSPOLL(s) (((s) & 10) != 0) /* Type/Subtype Combos */ #define FC_KIND_MASK (FC_TYPE_MASK | FC_SUBTYPE_MASK) /* FC kind mask */ @@ -1067,7 +1119,7 @@ typedef struct ti_ie ti_ie_t; * station not supporting the ER-PBCC * Modulation option */ -#define DOT11_SC_ASSOC_DSSOFDM_REQUIRED 27 /* Association denied due to requesting +#define DOT11_SC_ASSOC_DSSSOFDM_REQUIRED 27 /* Association denied due to requesting * station not supporting the DSS-OFDM * option */ @@ -1079,6 +1131,9 @@ typedef struct ti_ie ti_ie_t; #define DOT11_SC_ASSOC_MFP_VIOLATION 31 /* Association denied due to Robust Management * frame policy violation */ +#define DOT11_SC_ASSOC_HT_REQUIRED 32 /* Association denied because the requesting + * station does not support HT features + */ #define DOT11_SC_DECLINED 37 /* request declined */ #define DOT11_SC_INVALID_PARAMS 38 /* One or more params have invalid values */ @@ -1090,9 +1145,21 @@ typedef struct ti_ie ti_ie_t; #define DOT11_SC_INVALID_MDID 54 /* Association denied due to invalid MDID */ #define DOT11_SC_INVALID_FTIE 55 /* Association denied due to invalid FTIE */ +#define DOT11_SC_ADV_PROTO_NOT_SUPPORTED 59 /* ad proto not supported */ +#define DOT11_SC_NO_OUTSTAND_REQ 60 /* no outstanding req */ +#define DOT11_SC_RSP_NOT_RX_FROM_SERVER 61 /* no response from server */ +#define DOT11_SC_TIMEOUT 62 /* timeout */ +#define DOT11_SC_QUERY_RSP_TOO_LARGE 63 /* query rsp too large */ +#define DOT11_SC_SERVER_UNREACHABLE 65 /* server unreachable */ + #define DOT11_SC_UNEXP_MSG 70 /* Unexpected message */ #define DOT11_SC_INVALID_SNONCE 71 /* Invalid SNonce */ #define DOT11_SC_INVALID_RSNIE 72 /* Invalid contents of RSNIE */ +#define DOT11_SC_ASSOC_VHT_REQUIRED 104 /* Association denied because the requesting + * station does not support VHT features. + */ + +#define DOT11_SC_TRANSMIT_FAILURE 79 /* transmission failure */ /* Info Elts, length of INFORMATION portion of Info Elts */ #define DOT11_MNG_DS_PARAM_LEN 1 /* d11 management DS parameter length */ @@ -1127,6 +1194,8 @@ typedef struct ti_ie ti_ie_t; #define DOT11_MNG_REQUEST_ID 10 /* d11 management request id */ #define DOT11_MNG_QBSS_LOAD_ID 11 /* d11 management QBSS Load id */ #define DOT11_MNG_EDCA_PARAM_ID 12 /* 11E EDCA Parameter id */ +#define DOT11_MNG_TSPEC_ID 13 /* d11 management TSPEC id */ +#define DOT11_MNG_TCLAS_ID 14 /* d11 management TCLAS id */ #define DOT11_MNG_CHALLENGE_ID 16 /* d11 management chanllenge id */ #define DOT11_MNG_PWR_CONSTRAINT_ID 32 /* 11H PowerConstraint */ #define DOT11_MNG_PWR_CAP_ID 33 /* 11H PowerCapability */ @@ -1140,31 +1209,50 @@ typedef struct ti_ie ti_ie_t; #define DOT11_MNG_IBSS_DFS_ID 41 /* 11H IBSS_DFS */ #define DOT11_MNG_ERP_ID 42 /* d11 management ERP id */ #define DOT11_MNG_TS_DELAY_ID 43 /* d11 management TS Delay id */ +#define DOT11_MNG_TCLAS_PROC_ID 44 /* d11 management TCLAS processing id */ #define DOT11_MNG_HT_CAP 45 /* d11 mgmt HT cap id */ #define DOT11_MNG_QOS_CAP_ID 46 /* 11E QoS Capability id */ #define DOT11_MNG_NONERP_ID 47 /* d11 management NON-ERP id */ #define DOT11_MNG_RSN_ID 48 /* d11 management RSN id */ #define DOT11_MNG_EXT_RATES_ID 50 /* d11 management ext. rates id */ -#define DOT11_MNG_AP_CHREP_ID 51 /* 11k AP Channel report id */ -#define DOT11_MNG_NBR_REP_ID 52 /* 11k Neighbor report id */ -#define DOT11_MNG_MDIE_ID 54 /* 11r Mobility domain id */ -#define DOT11_MNG_FTIE_ID 55 /* 11r Fast Bss Transition id */ -#define DOT11_MNG_FT_TI_ID 56 /* 11r Timeout Interval id */ +#define DOT11_MNG_AP_CHREP_ID 51 /* 11k AP Channel report id */ +#define DOT11_MNG_NEIGHBOR_REP_ID 52 /* 11k & 11v Neighbor report id */ +#define DOT11_MNG_RCPI_ID 53 /* 11k RCPI */ +#define DOT11_MNG_MDIE_ID 54 /* 11r Mobility domain id */ +#define DOT11_MNG_FTIE_ID 55 /* 11r Fast Bss Transition id */ +#define DOT11_MNG_FT_TI_ID 56 /* 11r Timeout Interval id */ +#define DOT11_MNG_RDE_ID 57 /* 11r RIC Data Element id */ #define DOT11_MNG_REGCLASS_ID 59 /* d11 management regulatory class id */ #define DOT11_MNG_EXT_CSA_ID 60 /* d11 Extended CSA */ #define DOT11_MNG_HT_ADD 61 /* d11 mgmt additional HT info */ #define DOT11_MNG_EXT_CHANNEL_OFFSET 62 /* d11 mgmt ext channel offset */ +#define DOT11_MNG_BSS_AVR_ACCESS_DELAY_ID 63 /* 11k bss average access delay */ +#define DOT11_MNG_ANTENNA_ID 64 /* 11k antenna id */ +#define DOT11_MNG_RSNI_ID 65 /* 11k RSNI id */ +#define DOT11_MNG_MEASUREMENT_PILOT_TX_ID 66 /* 11k measurement pilot tx info id */ +#define DOT11_MNG_BSS_AVAL_ADMISSION_CAP_ID 67 /* 11k bss aval admission cap id */ +#define DOT11_MNG_BSS_AC_ACCESS_DELAY_ID 68 /* 11k bss AC access delay id */ #define DOT11_MNG_WAPI_ID 68 /* d11 management WAPI id */ #define DOT11_MNG_TIME_ADVERTISE_ID 69 /* 11p time advertisement */ #define DOT11_MNG_RRM_CAP_ID 70 /* 11k radio measurement capability */ +#define DOT11_MNG_MULTIPLE_BSSID_ID 71 /* 11k multiple BSSID id */ #define DOT11_MNG_HT_BSS_COEXINFO_ID 72 /* d11 mgmt OBSS Coexistence INFO */ #define DOT11_MNG_HT_BSS_CHANNEL_REPORT_ID 73 /* d11 mgmt OBSS Intolerant Channel list */ #define DOT11_MNG_HT_OBSS_ID 74 /* d11 mgmt OBSS HT info */ -#define DOT11_MNG_CHANNEL_USAGE 97 /* 11v channel usage */ +#define DOT11_MNG_MMIE_ID 76 /* d11 mgmt MIC IE */ +#define DOT11_MNG_BSS_MAX_IDLE_PERIOD_ID 90 /* 11v bss max idle id */ +#define DOT11_MNG_TFS_REQUEST_ID 91 /* 11v tfs request id */ +#define DOT11_MNG_TFS_RESPONSE_ID 92 /* 11v tfs response id */ +#define DOT11_MNG_WNM_SLEEP_MODE_ID 93 /* 11v wnm-sleep mode id */ +#define DOT11_MNG_TIMBC_REQ_ID 94 /* 11v TIM broadcast request id */ +#define DOT11_MNG_TIMBC_RESP_ID 95 /* 11v TIM broadcast response id */ +#define DOT11_MNG_CHANNEL_USAGE 97 /* 11v channel usage */ #define DOT11_MNG_TIME_ZONE_ID 98 /* 11v time zone */ -#define DOT11_MNG_LINK_IDENTIFIER_ID 101 /* 11z TDLS Link Identifier IE */ -#define DOT11_MNG_WAKEUP_SCHEDULE_ID 102 /* 11z TDLS Wakeup Schedule IE */ -#define DOT11_MNG_CHANNEL_SWITCH_TIMING_ID 104 /* 11z TDLS Channel Switch Timing IE */ +#define DOT11_MNG_DMS_REQUEST_ID 99 /* 11v dms request id */ +#define DOT11_MNG_DMS_RESPONSE_ID 100 /* 11v dms response id */ +#define DOT11_MNG_LINK_IDENTIFIER_ID 101 /* 11z TDLS Link Identifier IE */ +#define DOT11_MNG_WAKEUP_SCHEDULE_ID 102 /* 11z TDLS Wakeup Schedule IE */ +#define DOT11_MNG_CHANNEL_SWITCH_TIMING_ID 104 /* 11z TDLS Channel Switch Timing IE */ #define DOT11_MNG_PTI_CONTROL_ID 105 /* 11z TDLS PTI Control IE */ #define DOT11_MNG_PU_BUFFER_STATUS_ID 106 /* 11z TDLS PU Buffer Status IE */ #define DOT11_MNG_INTERWORKING_ID 107 /* 11u interworking */ @@ -1173,18 +1261,60 @@ typedef struct ti_ie ti_ie_t; #define DOT11_MNG_QOS_MAP_ID 110 /* 11u QoS map set */ #define DOT11_MNG_ROAM_CONSORT_ID 111 /* 11u roaming consortium */ #define DOT11_MNG_EMERGCY_ALERT_ID 112 /* 11u emergency alert identifier */ -#define DOT11_MNG_EXT_CAP_ID 127 /* d11 mgmt ext capability */ -#define DOT11_MNG_VHT_CAP_ID 191 /* d11 mgmt VHT cap id */ -#define DOT11_MNG_VHT_OPERATION_ID 192 /* d11 mgmt VHT op id */ +#define DOT11_MNG_EXT_CAP_ID 127 /* d11 mgmt ext capability */ +#define DOT11_MNG_VHT_CAP_ID 191 /* d11 mgmt VHT cap id */ +#define DOT11_MNG_VHT_OPERATION_ID 192 /* d11 mgmt VHT op id */ +#define DOT11_MNG_WIDE_BW_CHANNEL_SWITCH_ID 194 /* Wide BW Channel Switch IE */ +#define DOT11_MNG_VHT_TRANSMIT_POWER_ENVELOPE_ID 195 /* VHT transmit Power Envelope IE */ +#define DOT11_MNG_CHANNEL_SWITCH_WRAPPER_ID 196 /* Channel Switch Wrapper IE */ +#define DOT11_MNG_AID_ID 197 /* Association ID IE */ +#define DOT11_MNG_OPER_MODE_NOTIF_ID 199 /* d11 mgmt VHT oper mode notif */ + #define DOT11_MNG_WPA_ID 221 /* d11 management WPA id */ #define DOT11_MNG_PROPR_ID 221 /* d11 management proprietary id */ /* should start using this one instead of above two */ #define DOT11_MNG_VS_ID 221 /* d11 management Vendor Specific IE */ -/* Rate element Basic flag and rate mask */ -#define DOT11_RATE_BASIC 0x80 /* flag for a Basic Rate */ -#define DOT11_RATE_MASK 0x7F /* mask for numeric part of rate */ +/* Rate Defines */ + +/* Valid rates for the Supported Rates and Extended Supported Rates IEs. + * Encoding is the rate in 500kbps units, rouding up for fractional values. + * 802.11-2012, section 6.5.5.2, DATA_RATE parameter enumerates all the values. + * The rate values cover DSSS, HR/DSSS, ERP, and OFDM phy rates. + * The defines below do not cover the rates specific to 10MHz, {3, 4.5, 27}, + * and 5MHz, {1.5, 2.25, 3, 4.5, 13.5}, which are not supported by Broadcom devices. + */ + +#define DOT11_RATE_1M 2 /* 1 Mbps in 500kbps units */ +#define DOT11_RATE_2M 4 /* 2 Mbps in 500kbps units */ +#define DOT11_RATE_5M5 11 /* 5.5 Mbps in 500kbps units */ +#define DOT11_RATE_11M 22 /* 11 Mbps in 500kbps units */ +#define DOT11_RATE_6M 12 /* 6 Mbps in 500kbps units */ +#define DOT11_RATE_9M 18 /* 9 Mbps in 500kbps units */ +#define DOT11_RATE_12M 24 /* 12 Mbps in 500kbps units */ +#define DOT11_RATE_18M 36 /* 18 Mbps in 500kbps units */ +#define DOT11_RATE_24M 48 /* 24 Mbps in 500kbps units */ +#define DOT11_RATE_36M 72 /* 36 Mbps in 500kbps units */ +#define DOT11_RATE_48M 96 /* 48 Mbps in 500kbps units */ +#define DOT11_RATE_54M 108 /* 54 Mbps in 500kbps units */ +#define DOT11_RATE_MAX 108 /* highest rate (54 Mbps) in 500kbps units */ + +/* Supported Rates and Extended Supported Rates IEs + * The supported rates octets are defined a the MSB indicatin a Basic Rate + * and bits 0-6 as the rate value + */ +#define DOT11_RATE_BASIC 0x80 /* flag for a Basic Rate */ +#define DOT11_RATE_MASK 0x7F /* mask for numeric part of rate */ + +/* BSS Membership Selector parameters + * 802.11-2012 and 802.11ac_D4.0 sec 8.4.2.3 + * These selector values are advertised in Supported Rates and Extended Supported Rates IEs + * in the supported rates list with the Basic rate bit set. + * Constants below include the basic bit. + */ +#define DOT11_BSS_MEMBERSHIP_HT 0xFF /* Basic 0x80 + 127, HT Required to join */ +#define DOT11_BSS_MEMBERSHIP_VHT 0xFE /* Basic 0x80 + 126, VHT Required to join */ /* ERP info element bit values */ #define DOT11_MNG_ERP_LEN 1 /* ERP is currently 1 byte long */ @@ -1211,22 +1341,95 @@ typedef struct ti_ie ti_ie_t; #define DOT11_CAP_PBCC 0x0040 /* d11 cap. PBCC */ #define DOT11_CAP_AGILITY 0x0080 /* d11 cap. agility */ #define DOT11_CAP_SPECTRUM 0x0100 /* d11 cap. spectrum */ +#define DOT11_CAP_QOS 0x0200 /* d11 cap. qos */ #define DOT11_CAP_SHORTSLOT 0x0400 /* d11 cap. shortslot */ -#define DOT11_CAP_RRM 0x1000 /* d11 cap. 11k radio measurement */ +#define DOT11_CAP_APSD 0x0800 /* d11 cap. apsd */ +#define DOT11_CAP_RRM 0x1000 /* d11 cap. 11k radio measurement */ #define DOT11_CAP_CCK_OFDM 0x2000 /* d11 cap. CCK/OFDM */ +#define DOT11_CAP_DELAY_BA 0x4000 /* d11 cap. delayed block ack */ +#define DOT11_CAP_IMMEDIATE_BA 0x8000 /* d11 cap. immediate block ack */ /* Extended capabilities IE bitfields */ /* 20/40 BSS Coexistence Management support bit position */ #define DOT11_EXT_CAP_OBSS_COEX_MGMT 0 /* scheduled PSMP support bit position */ -#define DOT11_EXT_CAP_SPSMP 6 +#define DOT11_EXT_CAP_SPSMP 6 +/* Flexible Multicast Service */ +#define DOT11_EXT_CAP_FMS 11 +/* proxy ARP service support bit position */ +#define DOT11_EXT_CAP_PROXY_ARP 12 +/* Traffic Filter Service */ +#define DOT11_EXT_CAP_TFS 16 +/* WNM-Sleep Mode */ +#define DOT11_EXT_CAP_WNM_SLEEP 17 +/* TIM Broadcast service */ +#define DOT11_EXT_CAP_TIMBC 18 /* BSS Transition Management support bit position */ -#define DOT11_EXT_CAP_BSS_TRANSITION_MGMT 19 +#define DOT11_EXT_CAP_BSSTRANS_MGMT 19 +/* Direct Multicast Service */ +#define DOT11_EXT_CAP_DMS 26 /* Interworking support bit position */ -#define DOT11_EXT_CAP_IW 31 +#define DOT11_EXT_CAP_IW 31 /* service Interval granularity bit position and mask */ -#define DOT11_EXT_CAP_SI 41 -#define DOT11_EXT_CAP_SI_MASK 0x0E +#define DOT11_EXT_CAP_SI 41 +#define DOT11_EXT_CAP_SI_MASK 0x0E +/* WNM notification */ +#define DOT11_EXT_CAP_WNM_NOTIF 46 +/* Operating mode notification - VHT (11ac D3.0 - 8.4.2.29) */ +#define DOT11_EXT_CAP_OPER_MODE_NOTIF 62 + +/* VHT Operating mode bit fields - (11ac D3.0 - 8.4.1.50) */ +#define DOT11_OPER_MODE_CHANNEL_WIDTH_SHIFT 0 +#define DOT11_OPER_MODE_CHANNEL_WIDTH_MASK 0x3 +#define DOT11_OPER_MODE_RXNSS_SHIFT 4 +#define DOT11_OPER_MODE_RXNSS_MASK 0x70 +#define DOT11_OPER_MODE_RXNSS_TYPE_SHIFT 7 +#define DOT11_OPER_MODE_RXNSS_TYPE_MASK 0x80 + +#define DOT11_OPER_MODE(type, nss, chanw) (\ + ((type) << DOT11_OPER_MODE_RXNSS_TYPE_SHIFT &\ + DOT11_OPER_MODE_RXNSS_TYPE_MASK) |\ + (((nss) - 1) << DOT11_OPER_MODE_RXNSS_SHIFT & DOT11_OPER_MODE_RXNSS_MASK) |\ + ((chanw) << DOT11_OPER_MODE_CHANNEL_WIDTH_SHIFT &\ + DOT11_OPER_MODE_CHANNEL_WIDTH_MASK)) + +#define DOT11_OPER_MODE_CHANNEL_WIDTH(mode) \ + (((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK)\ + >> DOT11_OPER_MODE_CHANNEL_WIDTH_SHIFT) +#define DOT11_OPER_MODE_RXNSS(mode) \ + ((((mode) & DOT11_OPER_MODE_RXNSS_MASK) \ + >> DOT11_OPER_MODE_RXNSS_SHIFT) + 1) +#define DOT11_OPER_MODE_RXNSS_TYPE(mode) \ + (((mode) & DOT11_OPER_MODE_RXNSS_TYPE_MASK)\ + >> DOT11_OPER_MODE_RXNSS_TYPE_SHIFT) + +#define DOT11_OPER_MODE_20MHZ 0 +#define DOT11_OPER_MODE_40MHZ 1 +#define DOT11_OPER_MODE_80MHZ 2 +#define DOT11_OPER_MODE_160MHZ 3 +#define DOT11_OPER_MODE_8080MHZ 3 + +#define DOT11_OPER_MODE_CHANNEL_WIDTH_20MHZ(mode) (\ + ((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK) == DOT11_OPER_MODE_20MHZ) +#define DOT11_OPER_MODE_CHANNEL_WIDTH_40MHZ(mode) (\ + ((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK) == DOT11_OPER_MODE_40MHZ) +#define DOT11_OPER_MODE_CHANNEL_WIDTH_80MHZ(mode) (\ + ((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK) == DOT11_OPER_MODE_80MHZ) +#define DOT11_OPER_MODE_CHANNEL_WIDTH_160MHZ(mode) (\ + ((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK) == DOT11_OPER_MODE_160MHZ) +#define DOT11_OPER_MODE_CHANNEL_WIDTH_8080MHZ(mode) (\ + ((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK) == DOT11_OPER_MODE_8080MHZ) + +/* Operating mode information element 802.11ac D3.0 - 8.4.2.168 */ +BWL_PRE_PACKED_STRUCT struct dot11_oper_mode_notif_ie { + uint8 mode; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_oper_mode_notif_ie dot11_oper_mode_notif_ie_t; + +#define DOT11_OPER_MODE_NOTIF_IE_LEN 1 + +/* Extended Capability Information Field */ +#define DOT11_OBSS_COEX_MNG_SUPPORT 0x01 /* 20/40 BSS Coexistence Management support */ /* * Action Frame Constants @@ -1235,7 +1438,7 @@ typedef struct ti_ie ti_ie_t; #define DOT11_ACTION_CAT_OFF 0 /* category offset */ #define DOT11_ACTION_ACT_OFF 1 /* action offset */ -/* Action Category field (sec 7.3.1.11) */ +/* Action Category field (sec 8.4.1.11) */ #define DOT11_ACTION_CAT_ERR_MASK 0x80 /* category error mask */ #define DOT11_ACTION_CAT_MASK 0x7F /* category mask */ #define DOT11_ACTION_CAT_SPECT_MNG 0 /* category spectrum management */ @@ -1248,8 +1451,10 @@ typedef struct ti_ie ti_ie_t; #define DOT11_ACTION_CAT_HT 7 /* category for HT */ #define DOT11_ACTION_CAT_SA_QUERY 8 /* security association query */ #define DOT11_ACTION_CAT_PDPA 9 /* protected dual of public action */ -#define DOT11_ACTION_CAT_BSSMGMT 10 /* category for BSS transition management */ +#define DOT11_ACTION_CAT_WNM 10 /* category for WNM */ +#define DOT11_ACTION_CAT_UWNM 11 /* category for Unprotected WNM */ #define DOT11_ACTION_NOTIFICATION 17 +#define DOT11_ACTION_CAT_VHT 21 /* VHT action */ #define DOT11_ACTION_CAT_VSP 126 /* protected vendor specific */ #define DOT11_ACTION_CAT_VS 127 /* category Vendor Specific */ @@ -1294,42 +1499,51 @@ typedef struct ti_ie ti_ie_t; #define DOT11_FT_ACTION_FT_ACK 4 /* FBT ack */ /* DLS action types */ -#define DOT11_DLS_ACTION_REQ 0 /* DLS Request */ -#define DOT11_DLS_ACTION_RESP 1 /* DLS Response */ -#define DOT11_DLS_ACTION_TD 2 /* DLS Teardown */ +#define DOT11_DLS_ACTION_REQ 0 /* DLS Request */ +#define DOT11_DLS_ACTION_RESP 1 /* DLS Response */ +#define DOT11_DLS_ACTION_TD 2 /* DLS Teardown */ /* Wireless Network Management (WNM) action types */ -#define DOT11_WNM_ACTION_EVENT_REQ 0 -#define DOT11_WNM_ACTION_EVENT_REP 1 -#define DOT11_WNM_ACTION_DIAG_REQ 2 -#define DOT11_WNM_ACTION_DIAG_REP 3 +#define DOT11_WNM_ACTION_EVENT_REQ 0 +#define DOT11_WNM_ACTION_EVENT_REP 1 +#define DOT11_WNM_ACTION_DIAG_REQ 2 +#define DOT11_WNM_ACTION_DIAG_REP 3 #define DOT11_WNM_ACTION_LOC_CFG_REQ 4 #define DOT11_WNM_ACTION_LOC_RFG_RESP 5 -#define DOT11_WNM_ACTION_BSS_TRANS_QURY 6 -#define DOT11_WNM_ACTION_BSS_TRANS_REQ 7 -#define DOT11_WNM_ACTION_BSS_TRANS_RESP 8 -#define DOT11_WNM_ACTION_FMS_REQ 9 -#define DOT11_WNM_ACTION_FMS_RESP 10 +#define DOT11_WNM_ACTION_BSSTRANS_QUERY 6 +#define DOT11_WNM_ACTION_BSSTRANS_REQ 7 +#define DOT11_WNM_ACTION_BSSTRANS_RESP 8 +#define DOT11_WNM_ACTION_FMS_REQ 9 +#define DOT11_WNM_ACTION_FMS_RESP 10 #define DOT11_WNM_ACTION_COL_INTRFRNCE_REQ 11 #define DOT11_WNM_ACTION_COL_INTRFRNCE_REP 12 -#define DOT11_WNM_ACTION_TFS_REQ 13 -#define DOT11_WNM_ACTION_TFS_RESP 14 -#define DOT11_WNM_ACTION_TFS_NOTIFY 15 +#define DOT11_WNM_ACTION_TFS_REQ 13 +#define DOT11_WNM_ACTION_TFS_RESP 14 +#define DOT11_WNM_ACTION_TFS_NOTIFY 15 #define DOT11_WNM_ACTION_WNM_SLEEP_REQ 16 #define DOT11_WNM_ACTION_WNM_SLEEP_RESP 17 -#define DOT11_WNM_ACTION_TIM_BCAST_REQ 18 -#define DOT11_WNM_ACTION_TIM_BCAST_RESP 19 +#define DOT11_WNM_ACTION_TIMBC_REQ 18 +#define DOT11_WNM_ACTION_TIMBC_RESP 19 #define DOT11_WNM_ACTION_QOS_TRFC_CAP_UPD 20 #define DOT11_WNM_ACTION_CHAN_USAGE_REQ 21 #define DOT11_WNM_ACTION_CHAN_USAGE_RESP 22 -#define DOT11_WNM_ACTION_DMS_REQ 23 -#define DOT11_WNM_ACTION_DMS_RESP 24 +#define DOT11_WNM_ACTION_DMS_REQ 23 +#define DOT11_WNM_ACTION_DMS_RESP 24 #define DOT11_WNM_ACTION_TMNG_MEASUR_REQ 25 #define DOT11_WNM_ACTION_NOTFCTN_REQ 26 -#define DOT11_WNM_ACTION_NOTFCTN_RES 27 +#define DOT11_WNM_ACTION_NOTFCTN_RESP 27 + +/* Unprotected Wireless Network Management (WNM) action types */ +#define DOT11_UWNM_ACTION_TIM 0 +#define DOT11_UWNM_ACTION_TIMING_MEASUREMENT 1 #define DOT11_MNG_COUNTRY_ID_LEN 3 +/* VHT category action types - 802.11ac D3.0 - 8.5.23.1 */ +#define DOT11_VHT_ACTION_CBF 0 /* Compressed Beamforming */ +#define DOT11_VHT_ACTION_GID_MGMT 1 /* Group ID Management */ +#define DOT11_VHT_ACTION_OPER_MODE_NOTIF 2 /* Operating mode notif'n */ + /* DLS Request frame header */ BWL_PRE_PACKED_STRUCT struct dot11_dls_req { uint8 category; /* category of action frame (2) */ @@ -1356,83 +1570,528 @@ typedef struct dot11_dls_resp dot11_dls_resp_t; #define DOT11_DLS_RESP_LEN 16 /* Fixed length */ +/* ************* 802.11v related definitions. ************* */ + /* BSS Management Transition Query frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_bss_trans_query { +BWL_PRE_PACKED_STRUCT struct dot11_bsstrans_query { + uint8 category; /* category of action frame (10) */ + uint8 action; /* WNM action: trans_query (6) */ + uint8 token; /* dialog token */ + uint8 reason; /* transition query reason */ + uint8 data[1]; /* Elements */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_bsstrans_query dot11_bsstrans_query_t; +#define DOT11_BSSTRANS_QUERY_LEN 4 /* Fixed length */ + +/* BSS Management Transition Request frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_bsstrans_req { + uint8 category; /* category of action frame (10) */ + uint8 action; /* WNM action: trans_req (7) */ + uint8 token; /* dialog token */ + uint8 reqmode; /* transition request mode */ + uint16 disassoc_tmr; /* disassociation timer */ + uint8 validity_intrvl; /* validity interval */ + uint8 data[1]; /* optional: BSS term duration, ... */ + /* ...session info URL, candidate list */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_bsstrans_req dot11_bsstrans_req_t; +#define DOT11_BSSTRANS_REQ_LEN 7 /* Fixed length */ + +/* BSS Mgmt Transition Request Mode Field - 802.11v */ +#define DOT11_BSSTRANS_REQMODE_PREF_LIST_INCL 0x01 +#define DOT11_BSSTRANS_REQMODE_ABRIDGED 0x02 +#define DOT11_BSSTRANS_REQMODE_DISASSOC_IMMINENT 0x04 +#define DOT11_BSSTRANS_REQMODE_BSS_TERM_INCL 0x08 +#define DOT11_BSSTRANS_REQMODE_ESS_DISASSOC_IMNT 0x10 + +/* BSS Management transition response frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_bsstrans_resp { + uint8 category; /* category of action frame (10) */ + uint8 action; /* WNM action: trans_resp (8) */ + uint8 token; /* dialog token */ + uint8 status; /* transition status */ + uint8 term_delay; /* validity interval */ + uint8 data[1]; /* optional: BSSID target, candidate list */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_bsstrans_resp dot11_bsstrans_resp_t; +#define DOT11_BSSTRANS_RESP_LEN 5 /* Fixed length */ + +/* BSS Mgmt Transition Response Status Field */ +#define DOT11_BSSTRANS_RESP_STATUS_ACCEPT 0 +#define DOT11_BSSTRANS_RESP_STATUS_REJECT 1 +#define DOT11_BSSTRANS_RESP_STATUS_REJ_INSUFF_BCN 2 +#define DOT11_BSSTRANS_RESP_STATUS_REJ_INSUFF_CAP 3 +#define DOT11_BSSTRANS_RESP_STATUS_REJ_TERM_UNDESIRED 4 +#define DOT11_BSSTRANS_RESP_STATUS_REJ_TERM_DELAY_REQ 5 +#define DOT11_BSSTRANS_RESP_STATUS_REJ_BSS_LIST_PROVIDED 6 +#define DOT11_BSSTRANS_RESP_STATUS_REJ_NO_SUITABLE_BSS 7 +#define DOT11_BSSTRANS_RESP_STATUS_REJ_LEAVING_ESS 8 + + +/* BSS Max Idle Period information element */ +BWL_PRE_PACKED_STRUCT struct dot11_bss_max_idle_period_ie { + uint8 id; /* 90, DOT11_MNG_BSS_MAX_IDLE_PERIOD_ID */ + uint8 len; + uint16 max_idle_period; /* in unit of 1000 TUs */ + uint8 idle_opt; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_bss_max_idle_period_ie dot11_bss_max_idle_period_ie_t; +#define DOT11_BSS_MAX_IDLE_PERIOD_IE_LEN 3 /* bss max idle period IE size */ +#define DOT11_BSS_MAX_IDLE_PERIOD_OPT_PROTECTED 1 /* BSS max idle option */ + +/* TIM Broadcast request information element */ +BWL_PRE_PACKED_STRUCT struct dot11_timbc_req_ie { + uint8 id; /* 94, DOT11_MNG_TIMBC_REQ_ID */ + uint8 len; + uint8 interval; /* in unit of beacon interval */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_timbc_req_ie dot11_timbc_req_ie_t; +#define DOT11_TIMBC_REQ_IE_LEN 1 /* Fixed length */ + +/* TIM Broadcast request frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_timbc_req { uint8 category; /* category of action frame (10) */ - uint8 action; /* WNM action: trans_query (6) */ + uint8 action; /* WNM action: DOT11_WNM_ACTION_TIMBC_REQ(18) */ + uint8 token; /* dialog token */ + uint8 data[1]; /* TIM broadcast request element */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_timbc_req dot11_timbc_req_t; +#define DOT11_TIMBC_REQ_LEN 3 /* Fixed length */ + +/* TIM Broadcast response information element */ +BWL_PRE_PACKED_STRUCT struct dot11_timbc_resp_ie { + uint8 id; /* 95, DOT11_MNG_TIM_BROADCAST_RESP_ID */ + uint8 len; + uint8 status; /* status of add request */ + uint8 interval; /* in unit of beacon interval */ + int32 offset; /* in unit of ms */ + uint16 high_rate; /* in unit of 0.5 Mb/s */ + uint16 low_rate; /* in unit of 0.5 Mb/s */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_timbc_resp_ie dot11_timbc_resp_ie_t; +#define DOT11_TIMBC_DENY_RESP_IE_LEN 1 /* Deny. Fixed length */ +#define DOT11_TIMBC_ACCEPT_RESP_IE_LEN 10 /* Accept. Fixed length */ + +#define DOT11_TIMBC_STATUS_ACCEPT 0 +#define DOT11_TIMBC_STATUS_ACCEPT_TSTAMP 1 +#define DOT11_TIMBC_STATUS_DENY 2 +#define DOT11_TIMBC_STATUS_OVERRIDDEN 3 + +/* TIM Broadcast request frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_timbc_resp { + uint8 category; /* category of action frame (10) */ + uint8 action; /* action: DOT11_WNM_ACTION_TIMBC_RESP(19) */ + uint8 token; /* dialog token */ + uint8 data[1]; /* TIM broadcast response element */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_timbc_resp dot11_timbc_resp_t; +#define DOT11_TIMBC_RESP_LEN 3 /* Fixed length */ + +/* TIM element */ +BWL_PRE_PACKED_STRUCT struct dot11_tim_ie { + uint8 id; /* 5, DOT11_MNG_TIM_ID */ + uint8 len; /* 4 - 255 */ + uint8 dtim_count; /* DTIM decrementing counter */ + uint8 dtim_period; /* DTIM period */ + uint8 bitmap_control; /* AID 0 + bitmap offset */ + uint8 pvb[1]; /* Partial Virtual Bitmap, variable length */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tim_ie dot11_tim_ie_t; +#define DOT11_TIM_IE_FIXED_LEN 3 /* Fixed length, without id and len */ +#define DOT11_TIM_IE_FIXED_TOTAL_LEN 5 /* Fixed length, with id and len */ + +/* TIM Broadcast frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_timbc { + uint8 category; /* category of action frame (11) */ + uint8 action; /* action: TIM (0) */ + uint8 check_beacon; /* need to check-beacon */ + uint8 tsf[8]; /* Time Synchronization Function */ + dot11_tim_ie_t tim_ie; /* TIM element */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_timbc dot11_timbc_t; +#define DOT11_TIMBC_HDR_LEN (sizeof(dot11_timbc_t) - sizeof(dot11_tim_ie_t)) +#define DOT11_TIMBC_FIXED_LEN (sizeof(dot11_timbc_t) - 1) /* Fixed length */ +#define DOT11_TIMBC_LEN 11 /* Fixed length */ + +/* TCLAS frame classifier type */ +BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_hdr { + uint8 type; + uint8 mask; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_fc_hdr dot11_tclas_fc_hdr_t; +#define DOT11_TCLAS_FC_HDR_LEN 2 /* Fixed length */ + +#define DOT11_TCLAS_MASK_0 0x1 +#define DOT11_TCLAS_MASK_1 0x2 +#define DOT11_TCLAS_MASK_2 0x4 +#define DOT11_TCLAS_MASK_3 0x8 +#define DOT11_TCLAS_MASK_4 0x10 +#define DOT11_TCLAS_MASK_5 0x20 +#define DOT11_TCLAS_MASK_6 0x40 +#define DOT11_TCLAS_MASK_7 0x80 + +#define DOT11_TCLAS_FC_0_ETH 0 +#define DOT11_TCLAS_FC_1_IP 1 +#define DOT11_TCLAS_FC_2_8021Q 2 +#define DOT11_TCLAS_FC_3_OFFSET 3 +#define DOT11_TCLAS_FC_4_IP_HIGHER 4 +#define DOT11_TCLAS_FC_5_8021D 5 + +/* TCLAS frame classifier type 0 parameters for Ethernet */ +BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_0_eth { + uint8 type; + uint8 mask; + uint8 sa[ETHER_ADDR_LEN]; + uint8 da[ETHER_ADDR_LEN]; + uint16 eth_type; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_fc_0_eth dot11_tclas_fc_0_eth_t; +#define DOT11_TCLAS_FC_0_ETH_LEN 16 + +/* TCLAS frame classifier type 1 parameters for IPV4 */ +BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_1_ipv4 { + uint8 type; + uint8 mask; + uint8 version; + uint32 src_ip; + uint32 dst_ip; + uint16 src_port; + uint16 dst_port; + uint8 dscp; + uint8 protocol; + uint8 reserved; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_fc_1_ipv4 dot11_tclas_fc_1_ipv4_t; +#define DOT11_TCLAS_FC_1_IPV4_LEN 18 + +/* TCLAS frame classifier type 2 parameters for 802.1Q */ +BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_2_8021q { + uint8 type; + uint8 mask; + uint16 tci; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_fc_2_8021q dot11_tclas_fc_2_8021q_t; +#define DOT11_TCLAS_FC_2_8021Q_LEN 4 + +/* TCLAS frame classifier type 3 parameters for filter offset */ +BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_3_filter { + uint8 type; + uint8 mask; + uint16 offset; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_fc_3_filter dot11_tclas_fc_3_filter_t; +#define DOT11_TCLAS_FC_3_FILTER_LEN 4 + +/* TCLAS frame classifier type 4 parameters for IPV4 is the same as TCLAS type 1 */ +typedef struct dot11_tclas_fc_1_ipv4 dot11_tclas_fc_4_ipv4_t; +#define DOT11_TCLAS_FC_4_IPV4_LEN DOT11_TCLAS_FC_1_IPV4_LEN + +/* TCLAS frame classifier type 4 parameters for IPV6 */ +BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_4_ipv6 { + uint8 type; + uint8 mask; + uint8 version; + uint8 saddr[16]; + uint8 daddr[16]; + uint16 src_port; + uint16 dst_port; + uint8 dscp; + uint8 nexthdr; + uint8 flow_lbl[3]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_fc_4_ipv6 dot11_tclas_fc_4_ipv6_t; +#define DOT11_TCLAS_FC_4_IPV6_LEN 44 + +/* TCLAS frame classifier type 5 parameters for 802.1D */ +BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_5_8021d { + uint8 type; + uint8 mask; + uint8 pcp; + uint8 cfi; + uint16 vid; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_fc_5_8021d dot11_tclas_fc_5_8021d_t; +#define DOT11_TCLAS_FC_5_8021D_LEN 6 + +/* TCLAS frame classifier type parameters */ +BWL_PRE_PACKED_STRUCT union dot11_tclas_fc { + uint8 data[1]; + dot11_tclas_fc_hdr_t hdr; + dot11_tclas_fc_0_eth_t t0_eth; + dot11_tclas_fc_1_ipv4_t t1_ipv4; + dot11_tclas_fc_2_8021q_t t2_8021q; + dot11_tclas_fc_3_filter_t t3_filter; + dot11_tclas_fc_4_ipv4_t t4_ipv4; + dot11_tclas_fc_4_ipv6_t t4_ipv6; + dot11_tclas_fc_5_8021d_t t5_8021d; +} BWL_POST_PACKED_STRUCT; +typedef union dot11_tclas_fc dot11_tclas_fc_t; + +#define DOT11_TCLAS_FC_MIN_LEN 4 +#define DOT11_TCLAS_FC_MAX_LEN 254 + +/* TCLAS information element */ +BWL_PRE_PACKED_STRUCT struct dot11_tclas_ie { + uint8 id; /* 14, DOT11_MNG_TCLAS_ID */ + uint8 len; + uint8 user_priority; + dot11_tclas_fc_t fc; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_ie dot11_tclas_ie_t; +#define DOT11_TCLAS_IE_LEN 3 /* Fixed length, include id and len */ + +/* TCLAS processing information element */ +BWL_PRE_PACKED_STRUCT struct dot11_tclas_proc_ie { + uint8 id; /* 44, DOT11_MNG_TCLAS_PROC_ID */ + uint8 len; + uint8 process; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tclas_proc_ie dot11_tclas_proc_ie_t; +#define DOT11_TCLAS_PROC_IE_LEN 3 /* Fixed length, include id and len */ + +#define DOT11_TCLAS_PROC_MATCHALL 0 /* All high level element need to match */ +#define DOT11_TCLAS_PROC_MATCHONE 1 /* One high level element need to match */ +#define DOT11_TCLAS_PROC_NONMATCH 2 /* Non match to any high level element */ + + +/* TSPEC element defined in 802.11 std section 8.4.2.32 - Not supported */ +#define DOT11_TSPEC_IE_LEN 57 /* Fixed length */ + +/* TFS request information element */ +BWL_PRE_PACKED_STRUCT struct dot11_tfs_req_ie { + uint8 id; /* 91, DOT11_MNG_TFS_REQUEST_ID */ + uint8 len; + uint8 tfs_id; + uint8 tfs_actcode; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tfs_req_ie dot11_tfs_req_ie_t; +#define DOT11_TFS_REQ_IE_LEN 4 /* Fixed length, include id and len */ + +#define DOT11_TFS_ACTCODE_DELETE 1 +#define DOT11_TFS_ACTCODE_MODIFY 2 + +/* TFS request subelement */ +BWL_PRE_PACKED_STRUCT struct dot11_tfs_req_se { + uint8 sub_id; + uint8 length; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tfs_req_se dot11_tfs_req_se_t; + +BWL_PRE_PACKED_STRUCT struct dot11_tfs_se { + uint8 sub_id; + uint8 len; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tfs_se dot11_tfs_se_t; +#define DOT11_TFS_REQ_SUBELEM_LEN 2 /* Fixed length, include id and len */ + +#define DOT11_TFS_SUBELEM_ID_TFS 1 +#define DOT11_TFS_SUBELEM_ID_VENDOR 221 + +/* TFS response information element */ +BWL_PRE_PACKED_STRUCT struct dot11_tfs_resp_ie { + uint8 id; /* 92, DOT11_MNG_TFS_RESPONSE_ID */ + uint8 len; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tfs_resp_ie dot11_tfs_resp_ie_t; +#define DOT11_TFS_RESP_IE_LEN 2 /* Fixed length, include id and len */ + +/* TFS status subelement */ +BWL_PRE_PACKED_STRUCT struct dot11_tfs_status_se { + uint8 id; /* 92, DOT11_MNG_TFS_RESPONSE_ID */ + uint8 len; + uint8 resp_st; + uint8 tfs_id; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tfs_status_se dot11_tfs_status_se_t; + +#define DOT11_TFS_STATUS_SE_LEN 4 /* TFS Status Subelement length */ +#define DOT11_TFS_STATUS_SE_DATA_LEN 2 /* TFS status Subelement Data length */ + +#define DOT11_TFS_STATUS_SE_ID_TFS_ST 1 +#define DOT11_TFS_STATUS_SE_ID_TFS 2 +#define DOT11_TFS_STATUS_SE_ID_VENDOR 221 + +#define DOT11_TFS_RESP_ST_ACCEPT 0 +#define DOT11_TFS_RESP_ST_DENY_FORMAT 1 +#define DOT11_TFS_RESP_ST_DENY_RESOURCE 2 +#define DOT11_TFS_RESP_ST_DENY_POLICY 4 +#define DOT11_TFS_RESP_ST_PREFERRED_AP_INCAP 14 + + +/* TFS Management Request frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_tfs_req { + uint8 category; /* category of action frame (10) */ + uint8 action; /* WNM action: tfs request (13) */ uint8 token; /* dialog token */ - uint8 reason; /* transition query reason */ uint8 data[1]; /* Elements */ } BWL_POST_PACKED_STRUCT; -typedef struct dot11_bss_trans_query dot11_bss_trans_query_t; -#define DOT11_BSS_TRANS_QUERY_LEN 4 /* Fixed length */ +typedef struct dot11_tfs_req dot11_tfs_req_t; +#define DOT11_TFS_REQ_LEN 3 /* Fixed length */ -/* BSS Management Transition Request frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_bss_trans_req { +/* TFS Management Response frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_tfs_resp { uint8 category; /* category of action frame (10) */ - uint8 action; /* WNM action: trans_req (7) */ + uint8 action; /* WNM action: tfs request (14) */ uint8 token; /* dialog token */ - uint8 reqmode; /* transition request mode */ - uint16 disassoc_tmr; /* disassociation timer */ - uint8 validity_intrvl; /* validity interval */ - uint8 data[1]; /* optional: BSS term duration, ... */ - /* ...session info URL, list */ + uint8 data[1]; /* Elements */ } BWL_POST_PACKED_STRUCT; -typedef struct dot11_bss_trans_req dot11_bss_trans_req_t; -#define DOT11_BSS_TRANS_REQ_LEN 7 /* Fixed length */ +typedef struct dot11_tfs_resp dot11_tfs_resp_t; +#define DOT11_TFS_RESP_LEN 3 /* Fixed length */ -#define DOT11_BSS_TERM_DUR_LEN 12 /* Fixed length if present */ +/* TFS Management Notify frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_tfs_notify { + uint8 category; /* category of action frame (10) */ + uint8 action; /* WNM action: tfs request (15) */ + uint8 num_tfs_id; /* number of TFS IDs */ + uint8 data[1]; /* Elements */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_tfs_notify dot11_tfs_notify_t; +#define DOT11_TFS_NOTIFY_LEN 3 /* Fixed length */ +#define DOT11_TFS_NOTIFY_ACT_DEL 1 +#define DOT11_TFS_NOTIFY_ACT_NOTIFY 2 -/* BSS Mgmt Transition Request Mode Field - 802.11v */ -#define DOT11_BSS_TRNS_REQMODE_PREF_LIST_INCL 0x01 -#define DOT11_BSS_TRNS_REQMODE_ABRIDGED 0x02 -#define DOT11_BSS_TRNS_REQMODE_DISASSOC_IMMINENT 0x04 -#define DOT11_BSS_TRNS_REQMODE_BSS_TERM_INCL 0x08 -#define DOT11_BSS_TRNS_REQMODE_ESS_DISASSOC_IMNT 0x10 +/* WNM-Sleep Management Request frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_req { + uint8 category; /* category of action frame (10) */ + uint8 action; /* WNM action: wnm-sleep request (16) */ + uint8 token; /* dialog token */ + uint8 data[1]; /* Elements */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_wnm_sleep_req dot11_wnm_sleep_req_t; +#define DOT11_WNM_SLEEP_REQ_LEN 3 /* Fixed length */ + +/* WNM-Sleep Management Response frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_resp { + uint8 category; /* category of action frame (10) */ + uint8 action; /* WNM action: wnm-sleep request (17) */ + uint8 token; /* dialog token */ + uint16 key_len; /* key data length */ + uint8 data[1]; /* Elements */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_wnm_sleep_resp dot11_wnm_sleep_resp_t; +#define DOT11_WNM_SLEEP_RESP_LEN 5 /* Fixed length */ +#define DOT11_WNM_SLEEP_SUBELEM_ID_GTK 0 +#define DOT11_WNM_SLEEP_SUBELEM_ID_IGTK 1 -/* BSS Management transition response frame header */ -BWL_PRE_PACKED_STRUCT struct dot11_bss_trans_res { +BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_subelem_gtk { + uint8 sub_id; + uint8 len; + uint16 key_info; + uint8 key_length; + uint8 rsc[8]; + uint8 key[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_wnm_sleep_subelem_gtk dot11_wnm_sleep_subelem_gtk_t; +#define DOT11_WNM_SLEEP_SUBELEM_GTK_FIXED_LEN 11 /* without sub_id, len, and key */ +#define DOT11_WNM_SLEEP_SUBELEM_GTK_MAX_LEN 43 /* without sub_id and len */ + +BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_subelem_igtk { + uint8 sub_id; + uint8 len; + uint16 key_id; + uint8 pn[6]; + uint8 key[16]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_wnm_sleep_subelem_igtk dot11_wnm_sleep_subelem_igtk_t; +#define DOT11_WNM_SLEEP_SUBELEM_IGTK_LEN 24 /* Fixed length */ + +BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_ie { + uint8 id; /* 93, DOT11_MNG_WNM_SLEEP_MODE_ID */ + uint8 len; + uint8 act_type; + uint8 resp_status; + uint16 interval; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_wnm_sleep_ie dot11_wnm_sleep_ie_t; +#define DOT11_WNM_SLEEP_IE_LEN 4 /* Fixed length */ + +#define DOT11_WNM_SLEEP_ACT_TYPE_ENTER 0 +#define DOT11_WNM_SLEEP_ACT_TYPE_EXIT 1 + +#define DOT11_WNM_SLEEP_RESP_ACCEPT 0 +#define DOT11_WNM_SLEEP_RESP_UPDATE 1 +#define DOT11_WNM_SLEEP_RESP_DENY 2 +#define DOT11_WNM_SLEEP_RESP_DENY_TEMP 3 +#define DOT11_WNM_SLEEP_RESP_DENY_KEY 4 +#define DOT11_WNM_SLEEP_RESP_DENY_INUSE 5 +#define DOT11_WNM_SLEEP_RESP_LAST 6 + +/* DMS Management Request frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_dms_req { uint8 category; /* category of action frame (10) */ - uint8 action; /* WNM action: trans_res (8) */ + uint8 action; /* WNM action: dms request (23) */ uint8 token; /* dialog token */ - uint8 status; /* transition status */ - uint8 term_delay; /* validity interval */ - uint8 data[1]; /* optional: BSS term duration, ... */ - /* ...session info URL, list */ + uint8 data[1]; /* Elements */ } BWL_POST_PACKED_STRUCT; -typedef struct dot11_bss_trans_res dot11_bss_trans_res_t; -#define DOT11_BSS_TRANS_RES_LEN 5 /* Fixed length */ +typedef struct dot11_dms_req dot11_dms_req_t; +#define DOT11_DMS_REQ_LEN 3 /* Fixed length */ -/* BSS Mgmt Transition Response Status Field */ -#define DOT11_BSS_TRNS_RES_STATUS_ACCEPT 0 -#define DOT11_BSS_TRNS_RES_STATUS_REJECT 1 -#define DOT11_BSS_TRNS_RES_STATUS_REJ_INSUFF_BCN 2 -#define DOT11_BSS_TRNS_RES_STATUS_REJ_INSUFF_CAP 3 -#define DOT11_BSS_TRNS_RES_STATUS_REJ_TERM_UNDESIRED 4 -#define DOT11_BSS_TRNS_RES_STATUS_REJ_TERM_DELAY_REQ 5 -#define DOT11_BSS_TRNS_RES_STATUS_REJ_BSS_LIST_PROVIDED 6 -#define DOT11_BSS_TRNS_RES_STATUS_REJ_NO_SUITABLE_BSS 7 -#define DOT11_BSS_TRNS_RES_STATUS_REJ_LEAVING_ESS 8 +/* DMS Management Response frame header */ +BWL_PRE_PACKED_STRUCT struct dot11_dms_resp { + uint8 category; /* category of action frame (10) */ + uint8 action; /* WNM action: dms request (24) */ + uint8 token; /* dialog token */ + uint8 data[1]; /* Elements */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_dms_resp dot11_dms_resp_t; +#define DOT11_DMS_RESP_LEN 3 /* Fixed length */ +/* DMS request information element */ +BWL_PRE_PACKED_STRUCT struct dot11_dms_req_ie { + uint8 id; /* 99, DOT11_MNG_DMS_REQUEST_ID */ + uint8 len; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_dms_req_ie dot11_dms_req_ie_t; +#define DOT11_DMS_REQ_IE_LEN 2 /* Fixed length */ -/* Neighbor Report BSSID Information Field */ -#define DOT11_NBR_RPRT_BSSID_INFO_REACHABILTY 0x0003 -#define DOT11_NBR_RPRT_BSSID_INFO_SEC 0x0004 -#define DOT11_NBR_RPRT_BSSID_INFO_KEY_SCOPE 0x0008 -#define DOT11_NBR_RPRT_BSSID_INFO_CAP 0x03f0 +/* DMS response information element */ +BWL_PRE_PACKED_STRUCT struct dot11_dms_resp_ie { + uint8 id; /* 100, DOT11_MNG_DMS_RESPONSE_ID */ + uint8 len; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_dms_resp_ie dot11_dms_resp_ie_t; +#define DOT11_DMS_RESP_IE_LEN 2 /* Fixed length */ -#define DOT11_NBR_RPRT_BSSID_INFO_CAP_SPEC_MGMT 0x0010 -#define DOT11_NBR_RPRT_BSSID_INFO_CAP_QOS 0x0020 -#define DOT11_NBR_RPRT_BSSID_INFO_CAP_APSD 0x0040 -#define DOT11_NBR_RPRT_BSSID_INFO_CAP_RDIO_MSMT 0x0080 -#define DOT11_NBR_RPRT_BSSID_INFO_CAP_DEL_BA 0x0100 -#define DOT11_NBR_RPRT_BSSID_INFO_CAP_IMM_BA 0x0200 +/* DMS request descriptor */ +BWL_PRE_PACKED_STRUCT struct dot11_dms_req_desc { + uint8 dms_id; + uint8 len; + uint8 type; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_dms_req_desc dot11_dms_req_desc_t; +#define DOT11_DMS_REQ_DESC_LEN 3 /* Fixed length */ -/* Neighbor Report Subelements */ -#define DOT11_NBR_RPRT_SUBELEM_BSS_CANDDT_PREF_ID 3 +#define DOT11_DMS_REQ_TYPE_ADD 0 +#define DOT11_DMS_REQ_TYPE_REMOVE 1 +#define DOT11_DMS_REQ_TYPE_CHANGE 2 +/* DMS response status */ +BWL_PRE_PACKED_STRUCT struct dot11_dms_resp_st { + uint8 dms_id; + uint8 len; + uint8 type; + uint16 lsc; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_dms_resp_st dot11_dms_resp_st_t; +#define DOT11_DMS_RESP_STATUS_LEN 5 /* Fixed length */ + +#define DOT11_DMS_RESP_TYPE_ACCEPT 0 +#define DOT11_DMS_RESP_TYPE_DENY 1 +#define DOT11_DMS_RESP_TYPE_TERM 2 + +#define DOT11_DMS_RESP_LSC_UNSUPPORTED 0xFFFF BWL_PRE_PACKED_STRUCT struct dot11_addba_req { uint8 category; /* category of action frame (3) */ @@ -1500,12 +2159,27 @@ BWL_PRE_PACKED_STRUCT struct dot11_ft_res { typedef struct dot11_ft_res dot11_ft_res_t; #define DOT11_FT_RES_FIXED_LEN 16 +/* RDE RIC Data Element. */ +BWL_PRE_PACKED_STRUCT struct dot11_rde_ie { + uint8 id; /* 11r, DOT11_MNG_RDE_ID */ + uint8 length; + uint8 rde_id; /* RDE identifier. */ + uint8 rd_count; /* Resource Descriptor Count. */ + uint16 status; /* Status Code. */ +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rde_ie dot11_rde_ie_t; + +/* 11r - Size of the RDE (RIC Data Element) IE, including TLV header. */ +#define DOT11_MNG_RDE_IE_LEN sizeof(dot11_rde_ie_t) + /* ************* 802.11k related definitions. ************* */ /* Radio measurements enabled capability ie */ #define DOT11_RRM_CAP_LEN 5 /* length of rrm cap bitmap */ +#define RCPI_IE_LEN 1 +#define RSNI_IE_LEN 1 BWL_PRE_PACKED_STRUCT struct dot11_rrm_cap_ie { uint8 cap[DOT11_RRM_CAP_LEN]; } BWL_POST_PACKED_STRUCT; @@ -1526,6 +2200,13 @@ typedef struct dot11_rrm_cap_ie dot11_rrm_cap_ie_t; /* Operating Class (formerly "Regulatory Class") definitions */ #define DOT11_OP_CLASS_NONE 255 +BWL_PRE_PACKED_STRUCT struct do11_ap_chrep { + uint8 id; + uint8 len; + uint8 reg; + uint8 chanlist[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct do11_ap_chrep dot11_ap_chrep_t; /* Radio Measurements action ids */ #define DOT11_RM_ACTION_RM_REQ 0 /* Radio measurement request */ @@ -1550,6 +2231,7 @@ BWL_PRE_PACKED_STRUCT struct dot11_rmreq { uint8 action; /* radio measurement action */ uint8 token; /* dialog token */ uint16 reps; /* no. of repetitions */ + uint8 data[1]; } BWL_POST_PACKED_STRUCT; typedef struct dot11_rmreq dot11_rmreq_t; #define DOT11_RMREQ_LEN 5 @@ -1613,11 +2295,11 @@ typedef struct dot11_rmrep_bcn dot11_rmrep_bcn_t; #define DOT11_RMREQ_BCN_TABLE 2 /* Sub-element IDs for Beacon Request */ -#define DOT11_RMREQ_BCN_SSID_ID 0 -#define DOT11_RMREQ_BCN_REPINFO_ID 1 -#define DOT11_RMREQ_BCN_REPDET_ID 2 -#define DOT11_RMREQ_BCN_REQUEST_ID 10 -#define DOT11_RMREQ_BCN_APCHREP_ID 51 +#define DOT11_RMREQ_BCN_SSID_ID 0 +#define DOT11_RMREQ_BCN_REPINFO_ID 1 +#define DOT11_RMREQ_BCN_REPDET_ID 2 +#define DOT11_RMREQ_BCN_REQUEST_ID 10 +#define DOT11_RMREQ_BCN_APCHREP_ID DOT11_MNG_AP_CHREP_ID /* Reporting Detail element definition */ #define DOT11_RMREQ_BCN_REPDET_FIXED 0 /* Fixed length fields only */ @@ -1627,17 +2309,242 @@ typedef struct dot11_rmrep_bcn dot11_rmrep_bcn_t; /* Sub-element IDs for Beacon Report */ #define DOT11_RMREP_BCN_FRM_BODY 1 -/* Neighbor measurement report */ -BWL_PRE_PACKED_STRUCT struct dot11_rmrep_nbr { - struct ether_addr bssid; - uint32 bssid_info; +/* Sub-element IDs for Frame Report */ +#define DOT11_RMREP_FRAME_COUNT_REPORT 1 + +/* Channel load request */ +BWL_PRE_PACKED_STRUCT struct dot11_rmreq_chanload { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; uint8 reg; uint8 channel; + uint16 interval; + uint16 duration; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmreq_chanload dot11_rmreq_chanload_t; +#define DOT11_RMREQ_CHANLOAD_LEN 11 + +/* Channel load report */ +BWL_PRE_PACKED_STRUCT struct dot11_rmrep_chanload { + uint8 reg; + uint8 channel; + uint32 starttime[2]; + uint16 duration; + uint8 channel_load; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmrep_chanload dot11_rmrep_chanload_t; +#define DOT11_RMREP_CHANLOAD_LEN 13 + +/* Noise histogram request */ +BWL_PRE_PACKED_STRUCT struct dot11_rmreq_noise { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + uint8 reg; + uint8 channel; + uint16 interval; + uint16 duration; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmreq_noise dot11_rmreq_noise_t; +#define DOT11_RMREQ_NOISE_LEN 11 + +/* Noise histogram report */ +BWL_PRE_PACKED_STRUCT struct dot11_rmrep_noise { + uint8 reg; + uint8 channel; + uint32 starttime[2]; + uint16 duration; + uint8 antid; + uint8 anpi; + uint8 ipi0_dens; + uint8 ipi1_dens; + uint8 ipi2_dens; + uint8 ipi3_dens; + uint8 ipi4_dens; + uint8 ipi5_dens; + uint8 ipi6_dens; + uint8 ipi7_dens; + uint8 ipi8_dens; + uint8 ipi9_dens; + uint8 ipi10_dens; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmrep_noise dot11_rmrep_noise_t; +#define DOT11_RMREP_NOISE_LEN 25 + +/* Frame request */ +BWL_PRE_PACKED_STRUCT struct dot11_rmreq_frame { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + uint8 reg; + uint8 channel; + uint16 interval; + uint16 duration; + uint8 req_type; + struct ether_addr ta; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmreq_frame dot11_rmreq_frame_t; +#define DOT11_RMREQ_FRAME_LEN 18 + +/* Frame report */ +BWL_PRE_PACKED_STRUCT struct dot11_rmrep_frame { + uint8 reg; + uint8 channel; + uint32 starttime[2]; + uint16 duration; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmrep_frame dot11_rmrep_frame_t; +#define DOT11_RMREP_FRAME_LEN 12 + +/* Frame report entry */ +BWL_PRE_PACKED_STRUCT struct dot11_rmrep_frmentry { + struct ether_addr ta; + struct ether_addr bssid; + uint8 phy_type; + uint8 avg_rcpi; + uint8 last_rsni; + uint8 last_rcpi; + uint8 ant_id; + uint16 frame_cnt; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmrep_frmentry dot11_rmrep_frmentry_t; +#define DOT11_RMREP_FRMENTRY_LEN 19 + +/* STA statistics request */ +BWL_PRE_PACKED_STRUCT struct dot11_rmreq_stat { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + struct ether_addr peer; + uint16 interval; + uint16 duration; + uint8 group_id; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmreq_stat dot11_rmreq_stat_t; +#define DOT11_RMREQ_STAT_LEN 16 + +/* STA statistics report */ +BWL_PRE_PACKED_STRUCT struct dot11_rmrep_stat { + uint16 duration; + uint8 group_id; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmrep_stat dot11_rmrep_stat_t; + +/* Transmit stream/category measurement request */ +BWL_PRE_PACKED_STRUCT struct dot11_rmreq_tx_stream { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + uint16 interval; + uint16 duration; + struct ether_addr peer; + uint8 traffic_id; + uint8 bin0_range; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmreq_tx_stream dot11_rmreq_tx_stream_t; + +/* Transmit stream/category measurement report */ +BWL_PRE_PACKED_STRUCT struct dot11_rmrep_tx_stream { + uint32 starttime[2]; + uint16 duration; + struct ether_addr peer; + uint8 traffic_id; + uint8 reason; + uint32 txmsdu_cnt; + uint32 msdu_discarded_cnt; + uint32 msdufailed_cnt; + uint32 msduretry_cnt; + uint32 cfpolls_lost_cnt; + uint32 avrqueue_delay; + uint32 avrtx_delay; + uint8 bin0_range; + uint32 bin0; + uint32 bin1; + uint32 bin2; + uint32 bin3; + uint32 bin4; + uint32 bin5; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmrep_tx_stream dot11_rmrep_tx_stream_t; + +/* Measurement pause request */ +BWL_PRE_PACKED_STRUCT struct dot11_rmreq_pause_time { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + uint16 pause_time; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmreq_pause_time dot11_rmreq_pause_time_t; + + +/* Neighbor Report subelements ID (11k & 11v) */ +#define DOT11_NGBR_TSF_INFO_SE_ID 1 +#define DOT11_NGBR_CCS_SE_ID 2 +#define DOT11_NGBR_BSSTRANS_PREF_SE_ID 3 +#define DOT11_NGBR_BSS_TERM_DUR_SE_ID 4 +#define DOT11_NGBR_BEARING_SE_ID 5 + +/* Neighbor Report, BSS Transition Candidate Preference subelement */ +BWL_PRE_PACKED_STRUCT struct dot11_ngbr_bsstrans_pref_se { + uint8 sub_id; + uint8 len; + uint8 preference; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ngbr_bsstrans_pref_se dot11_ngbr_bsstrans_pref_se_t; +#define DOT11_NGBR_BSSTRANS_PREF_SE_LEN 1 + +/* Neighbor Report, BSS Termination Duration subelement */ +BWL_PRE_PACKED_STRUCT struct dot11_ngbr_bss_term_dur_se { + uint8 sub_id; + uint8 len; + uint8 tsf[8]; + uint16 duration; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ngbr_bss_term_dur_se dot11_ngbr_bss_term_dur_se_t; +#define DOT11_NGBR_BSS_TERM_DUR_SE_LEN 10 + +/* Neighbor Report BSSID Information Field */ +#define DOT11_NGBR_BI_REACHABILTY_UNKN 0x0002 +#define DOT11_NGBR_BI_REACHABILTY 0x0003 +#define DOT11_NGBR_BI_SEC 0x0004 +#define DOT11_NGBR_BI_KEY_SCOPE 0x0008 +#define DOT11_NGBR_BI_CAP 0x03f0 +#define DOT11_NGBR_BI_CAP_SPEC_MGMT 0x0010 +#define DOT11_NGBR_BI_CAP_QOS 0x0020 +#define DOT11_NGBR_BI_CAP_APSD 0x0040 +#define DOT11_NGBR_BI_CAP_RDIO_MSMT 0x0080 +#define DOT11_NGBR_BI_CAP_DEL_BA 0x0100 +#define DOT11_NGBR_BI_CAP_IMM_BA 0x0200 +#define DOT11_NGBR_BI_MOBILITY 0x0400 +#define DOT11_NGBR_BI_HT 0x0800 + +/* Neighbor Report element (11k & 11v) */ +BWL_PRE_PACKED_STRUCT struct dot11_neighbor_rep_ie { + uint8 id; + uint8 len; + struct ether_addr bssid; + uint32 bssid_info; + uint8 reg; /* Operating class */ + uint8 channel; uint8 phytype; - uchar sub_elements[1]; /* Variable size data */ + uint8 data[1]; /* Variable size subelements */ } BWL_POST_PACKED_STRUCT; -typedef struct dot11_rmrep_nbr dot11_rmrep_nbr_t; -#define DOT11_RMREP_NBR_LEN 13 +typedef struct dot11_neighbor_rep_ie dot11_neighbor_rep_ie_t; +#define DOT11_NEIGHBOR_REP_IE_FIXED_LEN 13 + /* MLME Enumerations */ #define DOT11_BSSTYPE_INFRASTRUCTURE 0 /* d11 infrastructure */ @@ -1682,42 +2589,56 @@ typedef struct dot11_lmrep dot11_lmrep_t; * HT-SIG is composed of two 24 bit parts, HT-SIG1 and HT-SIG2 */ /* HT-SIG1 */ -#define HT_SIG1_MCS_MASK 0x00007F -#define HT_SIG1_CBW 0x000080 -#define HT_SIG1_HT_LENGTH 0xFFFF00 +#define HT_SIG1_MCS_MASK 0x00007F +#define HT_SIG1_CBW 0x000080 +#define HT_SIG1_HT_LENGTH 0xFFFF00 /* HT-SIG2 */ -#define HT_SIG2_SMOOTHING 0x000001 -#define HT_SIG2_NOT_SOUNDING 0x000002 -#define HT_SIG2_RESERVED 0x000004 -#define HT_SIG2_AGGREGATION 0x000008 -#define HT_SIG2_STBC_MASK 0x000030 -#define HT_SIG2_STBC_SHIFT 4 -#define HT_SIG2_FEC_CODING 0x000040 -#define HT_SIG2_SHORT_GI 0x000080 -#define HT_SIG2_ESS_MASK 0x000300 -#define HT_SIG2_ESS_SHIFT 8 -#define HT_SIG2_CRC 0x03FC00 -#define HT_SIG2_TAIL 0x1C0000 +#define HT_SIG2_SMOOTHING 0x000001 +#define HT_SIG2_NOT_SOUNDING 0x000002 +#define HT_SIG2_RESERVED 0x000004 +#define HT_SIG2_AGGREGATION 0x000008 +#define HT_SIG2_STBC_MASK 0x000030 +#define HT_SIG2_STBC_SHIFT 4 +#define HT_SIG2_FEC_CODING 0x000040 +#define HT_SIG2_SHORT_GI 0x000080 +#define HT_SIG2_ESS_MASK 0x000300 +#define HT_SIG2_ESS_SHIFT 8 +#define HT_SIG2_CRC 0x03FC00 +#define HT_SIG2_TAIL 0x1C0000 + +/* HT Timing-related parameters (802.11-2012, sec 20.3.6) */ +#define HT_T_LEG_PREAMBLE 16 +#define HT_T_L_SIG 4 +#define HT_T_SIG 8 +#define HT_T_LTF1 4 +#define HT_T_GF_LTF1 8 +#define HT_T_LTFs 4 +#define HT_T_STF 4 +#define HT_T_GF_STF 8 +#define HT_T_SYML 4 + +#define HT_N_SERVICE 16 /* bits in SERVICE field */ +#define HT_N_TAIL 6 /* tail bits per BCC encoder */ /* 802.11 A PHY constants */ -#define APHY_SLOT_TIME 9 /* APHY slot time */ -#define APHY_SIFS_TIME 16 /* APHY SIFS time */ -#define APHY_DIFS_TIME (APHY_SIFS_TIME + (2 * APHY_SLOT_TIME)) /* APHY DIFS time */ -#define APHY_PREAMBLE_TIME 16 /* APHY preamble time */ -#define APHY_SIGNAL_TIME 4 /* APHY signal time */ -#define APHY_SYMBOL_TIME 4 /* APHY symbol time */ -#define APHY_SERVICE_NBITS 16 /* APHY service nbits */ -#define APHY_TAIL_NBITS 6 /* APHY tail nbits */ -#define APHY_CWMIN 15 /* APHY cwmin */ +#define APHY_SLOT_TIME 9 /* APHY slot time */ +#define APHY_SIFS_TIME 16 /* APHY SIFS time */ +#define APHY_DIFS_TIME (APHY_SIFS_TIME + (2 * APHY_SLOT_TIME)) /* APHY DIFS time */ +#define APHY_PREAMBLE_TIME 16 /* APHY preamble time */ +#define APHY_SIGNAL_TIME 4 /* APHY signal time */ +#define APHY_SYMBOL_TIME 4 /* APHY symbol time */ +#define APHY_SERVICE_NBITS 16 /* APHY service nbits */ +#define APHY_TAIL_NBITS 6 /* APHY tail nbits */ +#define APHY_CWMIN 15 /* APHY cwmin */ /* 802.11 B PHY constants */ -#define BPHY_SLOT_TIME 20 /* BPHY slot time */ -#define BPHY_SIFS_TIME 10 /* BPHY SIFS time */ -#define BPHY_DIFS_TIME 50 /* BPHY DIFS time */ -#define BPHY_PLCP_TIME 192 /* BPHY PLCP time */ -#define BPHY_PLCP_SHORT_TIME 96 /* BPHY PLCP short time */ -#define BPHY_CWMIN 31 /* BPHY cwmin */ +#define BPHY_SLOT_TIME 20 /* BPHY slot time */ +#define BPHY_SIFS_TIME 10 /* BPHY SIFS time */ +#define BPHY_DIFS_TIME 50 /* BPHY DIFS time */ +#define BPHY_PLCP_TIME 192 /* BPHY PLCP time */ +#define BPHY_PLCP_SHORT_TIME 96 /* BPHY PLCP short time */ +#define BPHY_CWMIN 31 /* BPHY cwmin */ /* 802.11 G constants */ #define DOT11_OFDM_SIGNAL_EXTENSION 6 /* d11 OFDM signal extension */ @@ -1726,36 +2647,42 @@ typedef struct dot11_lmrep dot11_lmrep_t; #define DOT11_MAXNUMFRAGS 16 /* max # fragments per MSDU */ -/* 802.11 AC (VHT) constants */ +/* 802.11 VHT constants */ typedef int vht_group_id_t; /* for VHT-A1 */ /* SIG-A1 reserved bits */ -#define VHT_SIGA1_CONST_MASK 0x800004 +#define VHT_SIGA1_CONST_MASK 0x800004 -#define VHT_SIGA1_20MHZ_VAL 0x000000 -#define VHT_SIGA1_40MHZ_VAL 0x000001 -#define VHT_SIGA1_80MHZ_VAL 0x000002 -#define VHT_SIGA1_160MHZ_VAL 0x000003 +#define VHT_SIGA1_BW_MASK 0x000003 +#define VHT_SIGA1_20MHZ_VAL 0x000000 +#define VHT_SIGA1_40MHZ_VAL 0x000001 +#define VHT_SIGA1_80MHZ_VAL 0x000002 +#define VHT_SIGA1_160MHZ_VAL 0x000003 -#define VHT_SIGA1_STBC 0x000008 +#define VHT_SIGA1_STBC 0x000008 -#define VHT_SIGA1_GID_MAX_GID 0x3f -#define VHT_SIGA1_GID_SHIFT 4 -#define VHT_SIGA1_GID_TO_AP 0x00 -#define VHT_SIGA1_GID_NOT_TO_AP 0x3f +#define VHT_SIGA1_GID_MASK 0x0003f0 +#define VHT_SIGA1_GID_SHIFT 4 +#define VHT_SIGA1_GID_TO_AP 0x00 +#define VHT_SIGA1_GID_NOT_TO_AP 0x3f +#define VHT_SIGA1_GID_MAX_GID 0x3f -#define VHT_SIGA1_NSTS_SHIFT 10 #define VHT_SIGA1_NSTS_SHIFT_MASK_USER0 0x001C00 +#define VHT_SIGA1_NSTS_SHIFT 10 -#define VHT_SIGA1_PARTIAL_AID_SHIFT 13 +#define VHT_SIGA1_PARTIAL_AID_MASK 0x3fe000 +#define VHT_SIGA1_PARTIAL_AID_SHIFT 13 + +#define VHT_SIGA1_TXOP_PS_NOT_ALLOWED 0x400000 /* for VHT-A2 */ #define VHT_SIGA2_GI_NONE 0x000000 #define VHT_SIGA2_GI_SHORT 0x000001 #define VHT_SIGA2_GI_W_MOD10 0x000002 #define VHT_SIGA2_CODING_LDPC 0x000004 +#define VHT_SIGA2_LDPC_EXTRA_OFDM_SYM 0x000008 #define VHT_SIGA2_BEAMFORM_ENABLE 0x000100 #define VHT_SIGA2_MCS_SHIFT 4 @@ -1763,8 +2690,17 @@ typedef int vht_group_id_t; #define VHT_SIGA2_TAIL_MASK 0xfc0000 #define VHT_SIGA2_TAIL_VALUE 0x000000 -#define VHT_SIGA2_SVC_BITS 16 -#define VHT_SIGA2_TAIL_BITS 6 +/* VHT Timing-related parameters (802.11ac D4.0, sec 22.3.6) */ +#define VHT_T_LEG_PREAMBLE 16 +#define VHT_T_L_SIG 4 +#define VHT_T_SIG_A 8 +#define VHT_T_LTF 4 +#define VHT_T_STF 4 +#define VHT_T_SIG_B 4 +#define VHT_T_SYML 4 + +#define VHT_N_SERVICE 16 /* bits in SERVICE field */ +#define VHT_N_TAIL 6 /* tail bits per BCC encoder */ /* dot11Counters Table - 802.11 spec., Annex D */ @@ -1789,6 +2725,9 @@ typedef struct d11cnt { #define BRCM_PROP_OUI "\x00\x90\x4C" /* Broadcom proprietary OUI */ +/* brcm syscap_ie cap */ +#define BRCM_SYSCAP_WET_TUNNEL 0x0100 /* Device with WET_TUNNEL support */ + /* BRCM OUI: Used in the proprietary(221) IE in all broadcom devices */ #define BRCM_OUI "\x00\x10\x18" /* Broadcom OUI */ @@ -1819,6 +2758,7 @@ typedef struct brcm_ie brcm_ie_t; #define BRF1_RX_LARGE_AGG 0x10 /* device can rx large aggregates */ #define BRF1_RFAWARE_DCS 0x20 /* RFAWARE dynamic channel selection (DCS) */ #define BRF1_SOFTAP 0x40 /* Configure as Broadcom SOFTAP */ +#define BRF1_DWDS 0x80 /* DWDS capable */ /* Vendor IE structure */ BWL_PRE_PACKED_STRUCT struct vndr_ie { @@ -1832,7 +2772,36 @@ typedef struct vndr_ie vndr_ie_t; #define VNDR_IE_HDR_LEN 2 /* id + len field */ #define VNDR_IE_MIN_LEN 3 /* size of the oui field */ #define VNDR_IE_FIXED_LEN (VNDR_IE_HDR_LEN + VNDR_IE_MIN_LEN) -#define VNDR_IE_MAX_LEN 256 /* verdor IE max length */ + +#define VNDR_IE_MAX_LEN 255 /* vendor IE max length, without ID and len */ + +/* BRCM PROP DEVICE PRIMARY MAC ADDRESS IE */ +BWL_PRE_PACKED_STRUCT struct member_of_brcm_prop_ie { + uchar id; + uchar len; + uchar oui[3]; + uint8 type; /* type inidicates what follows */ + struct ether_addr ea; /* Device Primary MAC Adrress */ +} BWL_POST_PACKED_STRUCT; +typedef struct member_of_brcm_prop_ie member_of_brcm_prop_ie_t; + +#define MEMBER_OF_BRCM_PROP_IE_LEN 10 /* IE max length */ +#define MEMBER_OF_BRCM_PROP_IE_TYPE 54 + +/* BRCM Reliable Multicast IE */ +BWL_PRE_PACKED_STRUCT struct relmcast_brcm_prop_ie { + uchar id; + uchar len; + uchar oui[3]; + uint8 type; /* type inidicates what follows */ + struct ether_addr ea; /* The ack sender's MAC Adrress */ + struct ether_addr mcast_ea; /* The multicast MAC address */ + uint8 updtmo; /* time interval(second) for client to send null packet to report its rssi */ +} BWL_POST_PACKED_STRUCT; +typedef struct relmcast_brcm_prop_ie relmcast_brcm_prop_ie_t; + +#define RELMCAST_BRCM_PROP_IE_LEN (sizeof(relmcast_brcm_prop_ie_t)-2) /* IE length */ +#define RELMCAST_BRCM_PROP_IE_TYPE 55 /* ************* HT definitions. ************* */ #define MCSSET_LEN 16 /* 16-bits per 8-bit set to give 128-bits bitmap of MCS Index */ @@ -1848,6 +2817,13 @@ BWL_PRE_PACKED_STRUCT struct ht_cap_ie { } BWL_POST_PACKED_STRUCT; typedef struct ht_cap_ie ht_cap_ie_t; +BWL_PRE_PACKED_STRUCT struct dot11_ht_cap_ie { + uint8 id; + uint8 len; + ht_cap_ie_t ht_cap; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ht_cap_ie dot11_ht_cap_ie_t; + /* CAP IE: HT 1.0 spec. simply stole a 802.11 IE, we use our prop. IE until this is resolved */ /* the capability IE is primarily used to convey this nodes abilities */ BWL_PRE_PACKED_STRUCT struct ht_prop_cap_ie { @@ -1889,6 +2865,37 @@ typedef struct ht_prop_cap_ie ht_prop_cap_ie_t; #define HT_CAP_RX_STBC_TWO_STREAM 0x2 /* rx STBC support of 1-2 spatial streams */ #define HT_CAP_RX_STBC_THREE_STREAM 0x3 /* rx STBC support of 1-3 spatial streams */ + +#define HT_CAP_TXBF_CAP_IMPLICIT_TXBF_RX 0x1 +#define HT_CAP_TXBF_CAP_NDP_TX 0x8 +#define HT_CAP_TXBF_CAP_NDP_RX 0x10 +#define HT_CAP_TXBF_CAP_EXPLICIT_CSI 0x100 +#define HT_CAP_TXBF_CAP_EXPLICIT_NC_STEERING 0x200 +#define HT_CAP_TXBF_CAP_EXPLICIT_C_STEERING 0x400 +#define HT_CAP_TXBF_CAP_EXPLICIT_CSI_FB_MASK 0x1800 +#define HT_CAP_TXBF_CAP_EXPLICIT_CSI_FB_SHIFT 11 +#define HT_CAP_TXBF_CAP_EXPLICIT_NC_FB_MASK 0x6000 +#define HT_CAP_TXBF_CAP_EXPLICIT_NC_FB_SHIFT 13 +#define HT_CAP_TXBF_CAP_EXPLICIT_C_FB_MASK 0x18000 +#define HT_CAP_TXBF_CAP_EXPLICIT_C_FB_SHIFT 15 +#define HT_CAP_TXBF_CAP_CSI_BFR_ANT_SHIFT 19 +#define HT_CAP_TXBF_CAP_NC_BFR_ANT_SHIFT 21 +#define HT_CAP_TXBF_CAP_C_BFR_ANT_SHIFT 23 +#define HT_CAP_TXBF_CAP_C_BFR_ANT_MASK 0x1800000 + +#define HT_CAP_TXBF_CAP_CHAN_ESTIM_SHIFT 27 +#define HT_CAP_TXBF_CAP_CHAN_ESTIM_MASK 0x18000000 + +#define HT_CAP_TXBF_FB_TYPE_NONE 0 +#define HT_CAP_TXBF_FB_TYPE_DELAYED 1 +#define HT_CAP_TXBF_FB_TYPE_IMMEDIATE 2 +#define HT_CAP_TXBF_FB_TYPE_BOTH 3 + +#define HT_CAP_TX_BF_CAP_EXPLICIT_CSI_FB_MASK 0x400 +#define HT_CAP_TX_BF_CAP_EXPLICIT_CSI_FB_SHIFT 10 +#define HT_CAP_TX_BF_CAP_EXPLICIT_COMPRESSED_FB_MASK 0x18000 +#define HT_CAP_TX_BF_CAP_EXPLICIT_COMPRESSED_FB_SHIFT 15 + #define VHT_MAX_MPDU 11454 /* max mpdu size for now (bytes) */ #define VHT_MPDU_MSDU_DELTA 56 /* Difference in spec - vht mpdu, amsdu len */ /* Max AMSDU len - per spec */ @@ -2049,6 +3056,10 @@ typedef struct dot11_obss_ie dot11_obss_ie_t; /* ************* VHT definitions. ************* */ +/* + * VHT Capabilites IE (sec 8.4.2.160) + */ + BWL_PRE_PACKED_STRUCT struct vht_cap_ie { uint32 vht_cap_info; /* supported MCS set - 64 bit field */ @@ -2058,24 +3069,23 @@ BWL_PRE_PACKED_STRUCT struct vht_cap_ie { uint16 tx_max_rate; } BWL_POST_PACKED_STRUCT; typedef struct vht_cap_ie vht_cap_ie_t; + /* 4B cap_info + 8B supp_mcs */ #define VHT_CAP_IE_LEN 12 -/* 32bit - cap info */ -#define VHT_CAP_INFO_MAX_MPDU_LEN_MASK 0x00000003 + +/* VHT Capabilities Info field - 32bit - in VHT Cap IE */ +#define VHT_CAP_INFO_MAX_MPDU_LEN_MASK 0x00000003 #define VHT_CAP_INFO_SUPP_CHAN_WIDTH_MASK 0x0000000c #define VHT_CAP_INFO_LDPC 0x00000010 #define VHT_CAP_INFO_SGI_80MHZ 0x00000020 - #define VHT_CAP_INFO_SGI_160MHZ 0x00000040 #define VHT_CAP_INFO_TX_STBC 0x00000080 - #define VHT_CAP_INFO_RX_STBC_MASK 0x00000700 #define VHT_CAP_INFO_RX_STBC_SHIFT 8 #define VHT_CAP_INFO_SU_BEAMFMR 0x00000800 #define VHT_CAP_INFO_SU_BEAMFMEE 0x00001000 #define VHT_CAP_INFO_NUM_BMFMR_ANT_MASK 0x0000e000 #define VHT_CAP_INFO_NUM_BMFMR_ANT_SHIFT 13 - #define VHT_CAP_INFO_NUM_SOUNDING_DIM_MASK 0x00070000 #define VHT_CAP_INFO_NUM_SOUNDING_DIM_SHIFT 16 #define VHT_CAP_INFO_MU_BEAMFMR 0x00080000 @@ -2084,39 +3094,77 @@ typedef struct vht_cap_ie vht_cap_ie_t; #define VHT_CAP_INFO_HTCVHT 0x00400000 #define VHT_CAP_INFO_AMPDU_MAXLEN_EXP_MASK 0x03800000 #define VHT_CAP_INFO_AMPDU_MAXLEN_EXP_SHIFT 23 - #define VHT_CAP_INFO_LINK_ADAPT_CAP_MASK 0x0c000000 #define VHT_CAP_INFO_LINK_ADAPT_CAP_SHIFT 26 -/* 64-bit Supp MCS. */ -#define VHT_CAP_SUPP_MCS_RX_HIGHEST_RATE_MASK 0x1fff -#define VHT_CAP_SUPP_MCS_RX_HIGHEST_RATE_SHIFT 0 - -#define VHT_CAP_SUPP_MCS_TX_HIGHEST_RATE_MASK 0x1fff -#define VHT_CAP_SUPP_MCS_TX_HIGHEST_RATE_SHIFT 0 - -#define VHT_CAP_MCS_MAP_0_7 0 -#define VHT_CAP_MCS_MAP_0_8 1 -#define VHT_CAP_MCS_MAP_0_9 2 -#define VHT_CAP_MCS_MAP_NONE 3 - -#define VHT_CAP_MCS_MAP_NSS_MAX 8 +/* VHT Supported MCS Set - 64-bit - in VHT Cap IE */ +#define VHT_CAP_SUPP_MCS_RX_HIGHEST_RATE_MASK 0x1fff +#define VHT_CAP_SUPP_MCS_RX_HIGHEST_RATE_SHIFT 0 + +#define VHT_CAP_SUPP_MCS_TX_HIGHEST_RATE_MASK 0x1fff +#define VHT_CAP_SUPP_MCS_TX_HIGHEST_RATE_SHIFT 0 + +#define VHT_CAP_MCS_MAP_0_7 0 +#define VHT_CAP_MCS_MAP_0_8 1 +#define VHT_CAP_MCS_MAP_0_9 2 +#define VHT_CAP_MCS_MAP_NONE 3 +#define VHT_CAP_MCS_MAP_S 2 /* num bits for 1-stream */ +#define VHT_CAP_MCS_MAP_M 0x3 /* mask for 1-stream */ +/* assumes VHT_CAP_MCS_MAP_NONE is 3 and 2 bits are used for encoding */ +#define VHT_CAP_MCS_MAP_NONE_ALL 0xffff +/* mcsmap with MCS0-9 for Nss = 3 */ +#define VHT_CAP_MCS_MAP_0_9_NSS3 \ + ((VHT_CAP_MCS_MAP_0_9 << VHT_MCS_MAP_GET_SS_IDX(1)) | \ + (VHT_CAP_MCS_MAP_0_9 << VHT_MCS_MAP_GET_SS_IDX(2)) | \ + (VHT_CAP_MCS_MAP_0_9 << VHT_MCS_MAP_GET_SS_IDX(3))) + +#define VHT_CAP_MCS_MAP_NSS_MAX 8 + +/* get mcsmap with given mcs for given nss streams */ +#define VHT_CAP_MCS_MAP_CREATE(mcsmap, nss, mcs) \ + do { \ + int i; \ + for (i = 1; i <= nss; i++) { \ + VHT_MCS_MAP_SET_MCS_PER_SS(i, mcs, mcsmap); \ + } \ + } while (0) + +/* Map the mcs code to mcs bit map */ +#define VHT_MCS_CODE_TO_MCS_MAP(mcs_code) \ + ((mcs_code == VHT_CAP_MCS_MAP_0_7) ? 0xff : \ + (mcs_code == VHT_CAP_MCS_MAP_0_8) ? 0x1ff : \ + (mcs_code == VHT_CAP_MCS_MAP_0_9) ? 0x3ff : 0) + +/* Map the mcs bit map to mcs code */ +#define VHT_MCS_MAP_TO_MCS_CODE(mcs_map) \ + ((mcs_map == 0xff) ? VHT_CAP_MCS_MAP_0_7 : \ + (mcs_map == 0x1ff) ? VHT_CAP_MCS_MAP_0_8 : \ + (mcs_map == 0x3ff) ? VHT_CAP_MCS_MAP_0_9 : VHT_CAP_MCS_MAP_NONE) /* VHT Capabilities Supported Channel Width */ typedef enum vht_cap_chan_width { - VHT_CAP_CHAN_WIDTH_20_40 = 0x00, - VHT_CAP_CHAN_WIDTH_80 = 0x04, - VHT_CAP_CHAN_WIDTH_160 = 0x08 + VHT_CAP_CHAN_WIDTH_SUPPORT_MANDATORY = 0x00, + VHT_CAP_CHAN_WIDTH_SUPPORT_160 = 0x04, + VHT_CAP_CHAN_WIDTH_SUPPORT_160_8080 = 0x08 } vht_cap_chan_width_t; -/* VHT Capabilities Supported max MPDU LEN */ +/* VHT Capabilities Supported max MPDU LEN (sec 8.4.2.160.2) */ typedef enum vht_cap_max_mpdu_len { - VHT_CAP_MPDU_MAX_4K = 0x00, - VHT_CAP_MPDU_MAX_8K = 0x01, - VHT_CAP_MPDU_MAX_11K = 0x02 + VHT_CAP_MPDU_MAX_4K = 0x00, + VHT_CAP_MPDU_MAX_8K = 0x01, + VHT_CAP_MPDU_MAX_11K = 0x02 } vht_cap_max_mpdu_len_t; -/* VHT Operation Element */ +/* Maximum MPDU Length byte counts for the VHT Capabilities advertised limits */ +#define VHT_MPDU_LIMIT_4K 3895 +#define VHT_MPDU_LIMIT_8K 7991 +#define VHT_MPDU_LIMIT_11K 11454 + + +/* + * VHT Operation IE (sec 8.4.2.161) + */ + BWL_PRE_PACKED_STRUCT struct vht_op_ie { uint8 chan_width; uint8 chan1; @@ -2124,6 +3172,7 @@ BWL_PRE_PACKED_STRUCT struct vht_op_ie { uint16 supp_mcs; /* same def as above in vht cap */ } BWL_POST_PACKED_STRUCT; typedef struct vht_op_ie vht_op_ie_t; + /* 3B VHT Op info + 2B Basic MCS */ #define VHT_OP_IE_LEN 5 @@ -2134,12 +3183,44 @@ typedef enum vht_op_chan_width { VHT_OP_CHAN_WIDTH_80_80 = 3 } vht_op_chan_width_t; +/* AID length */ +#define AID_IE_LEN 2 +/* + * BRCM vht features IE header + * The header if the fixed part of the IE + * On the 5GHz band this is the entire IE, + * on 2.4GHz the VHT IEs as defined in the 802.11ac + * specification follows + * + * + * VHT features rates bitmap. + * Bit0: 5G MCS 0-9 BW 160MHz + * Bit1: 5G MCS 0-9 support BW 80MHz + * Bit2: 5G MCS 0-9 support BW 20MHz + * Bit3: 2.4G MCS 0-9 support BW 20MHz + * Bits:4-7 Reserved for future use + * + */ +#define VHT_FEATURES_IE_TYPE 0x4 +BWL_PRE_PACKED_STRUCT struct vht_features_ie_hdr { + uint8 oui[3]; /* Proprietary OUI, BRCM_PROP_OUI */ + uint8 type; /* type of this IE = 4 */ + uint8 rate_mask; /* VHT rate mask */ +} BWL_POST_PACKED_STRUCT; +typedef struct vht_features_ie_hdr vht_features_ie_hdr_t; + /* Def for rx & tx basic mcs maps - ea ss num has 2 bits of info */ -#define VHT_MCS_MAP_GET_SS_IDX(nss) (((nss)-1)*2) +#define VHT_MCS_MAP_GET_SS_IDX(nss) (((nss)-1) * VHT_CAP_MCS_MAP_S) #define VHT_MCS_MAP_GET_MCS_PER_SS(nss, mcsMap) \ - (((mcsMap) >> VHT_MCS_MAP_GET_SS_IDX(nss)) & 0x3) + (((mcsMap) >> VHT_MCS_MAP_GET_SS_IDX(nss)) & VHT_CAP_MCS_MAP_M) #define VHT_MCS_MAP_SET_MCS_PER_SS(nss, numMcs, mcsMap) \ - ((mcsMap) |= (((numMcs) & 0x3) << VHT_MCS_MAP_GET_SS_IDX(nss))) + do { \ + (mcsMap) &= (~(VHT_CAP_MCS_MAP_M << VHT_MCS_MAP_GET_SS_IDX(nss))); \ + (mcsMap) |= (((numMcs) & VHT_CAP_MCS_MAP_M) << VHT_MCS_MAP_GET_SS_IDX(nss)); \ + } while (0) +#define VHT_MCS_SS_SUPPORTED(nss, mcsMap) \ + (VHT_MCS_MAP_GET_MCS_PER_SS((nss), (mcsMap)) != VHT_CAP_MCS_MAP_NONE) + /* ************* WPA definitions. ************* */ #define WPA_OUI "\x00\x50\xF2" /* WPA OUI */ @@ -2167,13 +3248,17 @@ typedef enum vht_op_chan_width { #ifdef P2P_IE_OVRD #define WFA_OUI_TYPE_P2P MAC_OUI_TYPE_P2P #else +#define WFA_OUI_TYPE_TPC 8 #define WFA_OUI_TYPE_P2P 9 #endif #define WFA_OUI_TYPE_TPC 8 #ifdef WLTDLS +#define WFA_OUI_TYPE_TPQ 4 /* WFD Tunneled Probe ReQuest */ +#define WFA_OUI_TYPE_TPS 5 /* WFD Tunneled Probe ReSponse */ #define WFA_OUI_TYPE_WFD 10 #endif /* WTDLS */ +#define WFA_OUI_TYPE_HS20 0x10 /* RSN authenticated key managment suite */ #define RSN_AKM_NONE 0 /* None (IBSS) */ @@ -2207,6 +3292,7 @@ typedef enum vht_op_chan_width { #define AES_KEY_SIZE 16 /* size of AES key */ #define AES_MIC_SIZE 8 /* size of AES MIC */ #define BIP_KEY_SIZE 16 /* size of BIP key */ +#define BIP_MIC_SIZE 8 /* sizeof BIP MIC */ /* WCN */ #define WCN_OUI "\x00\x50\xf2" /* WCN OUI */ @@ -2250,7 +3336,6 @@ BWL_PRE_PACKED_STRUCT struct dot11_timeout_ie { } BWL_POST_PACKED_STRUCT; typedef struct dot11_timeout_ie dot11_timeout_ie_t; - /* GTK ie */ BWL_PRE_PACKED_STRUCT struct dot11_gtk_ie { uint8 id; @@ -2262,6 +3347,16 @@ BWL_PRE_PACKED_STRUCT struct dot11_gtk_ie { } BWL_POST_PACKED_STRUCT; typedef struct dot11_gtk_ie dot11_gtk_ie_t; +/* Management MIC ie */ +BWL_PRE_PACKED_STRUCT struct mmic_ie { + uint8 id; /* IE ID: 0xDD */ + uint8 len; /* IE length */ + uint16 key_id; /* key id */ + uint8 ipn[6]; /* ipn */ + uint8 mic[BIP_MIC_SIZE]; /* mic */ +} BWL_POST_PACKED_STRUCT; +typedef struct mmic_ie mmic_ie_t; + #define BSSID_INVALID "\x00\x00\x00\x00\x00\x00" #define BSSID_BROADCAST "\xFF\xFF\xFF\xFF\xFF\xFF" @@ -2334,6 +3429,156 @@ typedef struct pu_buffer_status_ie pu_buffer_status_ie_t; #define TDLS_PU_BUFFER_STATUS_AC_VI 4 #define TDLS_PU_BUFFER_STATUS_AC_VO 8 +/* 802.11u GAS action frames */ +#define GAS_REQUEST_ACTION_FRAME 10 +#define GAS_RESPONSE_ACTION_FRAME 11 +#define GAS_COMEBACK_REQUEST_ACTION_FRAME 12 +#define GAS_COMEBACK_RESPONSE_ACTION_FRAME 13 + +/* 802.11u interworking access network options */ +#define IW_ANT_MASK 0x0f +#define IW_INTERNET_MASK 0x10 +#define IW_ASRA_MASK 0x20 +#define IW_ESR_MASK 0x40 +#define IW_UESA_MASK 0x80 + +/* 802.11u interworking access network type */ +#define IW_ANT_PRIVATE_NETWORK 0 +#define IW_ANT_PRIVATE_NETWORK_WITH_GUEST 1 +#define IW_ANT_CHARGEABLE_PUBLIC_NETWORK 2 +#define IW_ANT_FREE_PUBLIC_NETWORK 3 +#define IW_ANT_PERSONAL_DEVICE_NETWORK 4 +#define IW_ANT_EMERGENCY_SERVICES_NETWORK 5 +#define IW_ANT_TEST_NETWORK 14 +#define IW_ANT_WILDCARD_NETWORK 15 + +/* 802.11u advertisement protocol */ +#define ADVP_ANQP_PROTOCOL_ID 0 + +/* 802.11u advertisement protocol masks */ +#define ADVP_QRL_MASK 0x7f +#define ADVP_PAME_BI_MASK 0x80 + +/* 802.11u advertisement protocol values */ +#define ADVP_QRL_REQUEST 0x00 +#define ADVP_QRL_RESPONSE 0x7f +#define ADVP_PAME_BI_DEPENDENT 0x00 +#define ADVP_PAME_BI_INDEPENDENT ADVP_PAME_BI_MASK + +/* 802.11u ANQP information ID */ +#define ANQP_ID_QUERY_LIST 256 +#define ANQP_ID_CAPABILITY_LIST 257 +#define ANQP_ID_VENUE_NAME_INFO 258 +#define ANQP_ID_EMERGENCY_CALL_NUMBER_INFO 259 +#define ANQP_ID_NETWORK_AUTHENTICATION_TYPE_INFO 260 +#define ANQP_ID_ROAMING_CONSORTIUM_LIST 261 +#define ANQP_ID_IP_ADDRESS_TYPE_AVAILABILITY_INFO 262 +#define ANQP_ID_NAI_REALM_LIST 263 +#define ANQP_ID_G3PP_CELLULAR_NETWORK_INFO 264 +#define ANQP_ID_AP_GEOSPATIAL_LOCATION 265 +#define ANQP_ID_AP_CIVIC_LOCATION 266 +#define ANQP_ID_AP_LOCATION_PUBLIC_ID_URI 267 +#define ANQP_ID_DOMAIN_NAME_LIST 268 +#define ANQP_ID_EMERGENCY_ALERT_ID_URI 269 +#define ANQP_ID_EMERGENCY_NAI 271 +#define ANQP_ID_VENDOR_SPECIFIC_LIST 56797 + +/* 802.11u ANQP OUI */ +#define ANQP_OUI_SUBTYPE 9 + +/* 802.11u venue name */ +#define VENUE_LANGUAGE_CODE_SIZE 3 +#define VENUE_NAME_SIZE 255 + +/* 802.11u venue groups */ +#define VENUE_UNSPECIFIED 0 +#define VENUE_ASSEMBLY 1 +#define VENUE_BUSINESS 2 +#define VENUE_EDUCATIONAL 3 +#define VENUE_FACTORY 4 +#define VENUE_INSTITUTIONAL 5 +#define VENUE_MERCANTILE 6 +#define VENUE_RESIDENTIAL 7 +#define VENUE_STORAGE 8 +#define VENUE_UTILITY 9 +#define VENUE_VEHICULAR 10 +#define VENUE_OUTDOOR 11 + +/* 802.11u network authentication type indicator */ +#define NATI_ACCEPTANCE_OF_TERMS_CONDITIONS 0 +#define NATI_ONLINE_ENROLLMENT_SUPPORTED 1 +#define NATI_HTTP_HTTPS_REDIRECTION 2 +#define NATI_DNS_REDIRECTION 3 + +/* 802.11u IP address type availability - IPv6 */ +#define IPA_IPV6_SHIFT 0 +#define IPA_IPV6_MASK (0x03 << IPA_IPV6_SHIFT) +#define IPA_IPV6_NOT_AVAILABLE 0x00 +#define IPA_IPV6_AVAILABLE 0x01 +#define IPA_IPV6_UNKNOWN_AVAILABILITY 0x02 + +/* 802.11u IP address type availability - IPv4 */ +#define IPA_IPV4_SHIFT 2 +#define IPA_IPV4_MASK (0x3f << IPA_IPV4_SHIFT) +#define IPA_IPV4_NOT_AVAILABLE 0x00 +#define IPA_IPV4_PUBLIC 0x01 +#define IPA_IPV4_PORT_RESTRICT 0x02 +#define IPA_IPV4_SINGLE_NAT 0x03 +#define IPA_IPV4_DOUBLE_NAT 0x04 +#define IPA_IPV4_PORT_RESTRICT_SINGLE_NAT 0x05 +#define IPA_IPV4_PORT_RESTRICT_DOUBLE_NAT 0x06 +#define IPA_IPV4_UNKNOWN_AVAILABILITY 0x07 + +/* 802.11u NAI realm encoding */ +#define REALM_ENCODING_RFC4282 0 +#define REALM_ENCODING_UTF8 1 + +/* 802.11u IANA EAP method type numbers */ +#define REALM_EAP_TLS 13 +#define REALM_EAP_SIM 18 +#define REALM_EAP_TTLS 21 +#define REALM_EAP_AKA 23 +#define REALM_EAP_PSK 47 +#define REALM_EAP_AKAP 50 + +/* 802.11u authentication ID */ +#define REALM_EXPANDED_EAP 1 +#define REALM_NON_EAP_INNER_AUTHENTICATION 2 +#define REALM_INNER_AUTHENTICATION_EAP 3 +#define REALM_EXPANDED_INNER_EAP 4 +#define REALM_CREDENTIAL 5 +#define REALM_TUNNELED_EAP_CREDENTIAL 6 +#define REALM_VENDOR_SPECIFIC_EAP 221 + +/* 802.11u non-EAP inner authentication type */ +#define REALM_PAP 1 +#define REALM_CHAP 2 +#define REALM_MSCHAP 3 +#define REALM_MSCHAPV2 4 + +/* 802.11u credential type */ +#define REALM_SIM 1 +#define REALM_USIM 2 +#define REALM_NFC 3 +#define REALM_HARDWARE_TOKEN 4 +#define REALM_SOFTOKEN 5 +#define REALM_CERTIFICATE 6 +#define REALM_USERNAME_PASSWORD 7 +#define REALM_SERVER_SIDE 8 + +/* 802.11u 3GPP PLMN */ +#define G3PP_GUD_VERSION 0 +#define G3PP_PLMN_LIST_IE 0 + +/* hotspot2.0 indication element (vendor specific) */ +BWL_PRE_PACKED_STRUCT struct hs20_ie { + uint8 oui[3]; + uint8 type; + uint8 config; +} BWL_POST_PACKED_STRUCT; +typedef struct hs20_ie hs20_ie_t; +#define HS20_IE_LEN 5 /* HS20 IE length */ + /* This marks the end of a packed structure section. */ #include <packed_section_end.h> diff --git a/drivers/net/wireless/bcmdhd/include/proto/802.11_bta.h b/drivers/net/wireless/bcmdhd/include/proto/802.11_bta.h index 3ee5a748695a..ee7f9593ca48 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/proto/802.11_bta.h +++ b/drivers/net/wireless/bcmdhd/include/proto/802.11_bta.h @@ -1,7 +1,7 @@ /* * BT-AMP (BlueTooth Alternate Mac and Phy) 802.11 PAL (Protocol Adaptation Layer) * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -21,7 +21,7 @@ * 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: 802.11_bta.h 294267 2011-11-04 23:41:52Z $ + * $Id: 802.11_bta.h 382882 2013-02-04 23:24:31Z $ */ #ifndef _802_11_BTA_H_ diff --git a/drivers/net/wireless/bcmdhd/include/proto/802.11e.h b/drivers/net/wireless/bcmdhd/include/proto/802.11e.h index f391e68c1104..391139f55391 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/proto/802.11e.h +++ b/drivers/net/wireless/bcmdhd/include/proto/802.11e.h @@ -1,7 +1,7 @@ /* * 802.11e protocol header file * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -21,7 +21,7 @@ * 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: 802.11e.h 241182 2011-02-17 21:50:03Z $ + * $Id: 802.11e.h 382883 2013-02-04 23:26:09Z $ */ #ifndef _802_11e_H_ @@ -110,7 +110,8 @@ typedef BWL_PRE_PACKED_STRUCT struct tspec { #define QBSS_LOAD_IE_LEN 5 /* QBSS Load IE length */ #define QBSS_LOAD_AAC_OFF 3 /* AAC offset in IE */ -#define CAC_ADDTS_RESP_TIMEOUT 300 /* default ADDTS response timeout in ms */ +#define CAC_ADDTS_RESP_TIMEOUT 1000 /* default ADDTS response timeout in ms */ + /* DEFVAL dot11ADDTSResponseTimeout = 1s */ /* 802.11e ADDTS status code */ #define DOT11E_STATUS_ADMISSION_ACCEPTED 0 /* TSPEC Admission accepted status */ diff --git a/drivers/net/wireless/bcmdhd/include/proto/802.1d.h b/drivers/net/wireless/bcmdhd/include/proto/802.1d.h index f11cc6c49269..07bc6b007c0d 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/proto/802.1d.h +++ b/drivers/net/wireless/bcmdhd/include/proto/802.1d.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -21,7 +21,7 @@ * * Fundamental types and constants relating to 802.1D * - * $Id: 802.1d.h 241182 2011-02-17 21:50:03Z $ + * $Id: 802.1d.h 382882 2013-02-04 23:24:31Z $ */ #ifndef _802_1_D_ diff --git a/drivers/net/wireless/bcmdhd/include/proto/802.3.h b/drivers/net/wireless/bcmdhd/include/proto/802.3.h new file mode 100755 index 000000000000..91dc342c6b16 --- /dev/null +++ b/drivers/net/wireless/bcmdhd/include/proto/802.3.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 1999-2013, 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. + * + * Fundamental constants relating to 802.3 + * + * $Id: 802.3.h 417942 2013-08-13 07:53:57Z $ + */ + +#ifndef _802_3_h_ +#define _802_3_h_ + +/* This marks the start of a packed structure section. */ +#include <packed_section_start.h> + +#define SNAP_HDR_LEN 6 /* 802.3 SNAP header length */ +#define DOT3_OUI_LEN 3 /* 802.3 oui length */ + +BWL_PRE_PACKED_STRUCT struct dot3_mac_llc_snap_header { + uint8 ether_dhost[ETHER_ADDR_LEN]; /* dest mac */ + uint8 ether_shost[ETHER_ADDR_LEN]; /* src mac */ + uint16 length; /* frame length incl header */ + uint8 dsap; /* always 0xAA */ + uint8 ssap; /* always 0xAA */ + uint8 ctl; /* always 0x03 */ + uint8 oui[DOT3_OUI_LEN]; /* RFC1042: 0x00 0x00 0x00 + * Bridge-Tunnel: 0x00 0x00 0xF8 + */ + uint16 type; /* ethertype */ +} BWL_POST_PACKED_STRUCT; + +/* This marks the end of a packed structure section. */ +#include <packed_section_end.h> + +#endif /* #ifndef _802_3_h_ */ diff --git a/drivers/net/wireless/bcmdhd/include/proto/bcmeth.h b/drivers/net/wireless/bcmdhd/include/proto/bcmeth.h index 91ae75c334e8..94ba2469c14d 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/proto/bcmeth.h +++ b/drivers/net/wireless/bcmdhd/include/proto/bcmeth.h @@ -1,7 +1,7 @@ /* * Broadcom Ethernettype protocol definitions * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -21,7 +21,7 @@ * 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: bcmeth.h 294352 2011-11-06 19:23:00Z $ + * $Id: bcmeth.h 382882 2013-02-04 23:24:31Z $ */ /* diff --git a/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h b/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h index 4baa104112b9..6474ecb228a5 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h +++ b/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h @@ -1,7 +1,7 @@ /* * Broadcom Event protocol definitions * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -23,7 +23,7 @@ * * Dependencies: proto/bcmeth.h * - * $Id: bcmevent.h 386753 2013-02-21 20:37:53Z $ + * $Id: bcmevent.h 429124 2013-10-11 09:47:05Z $ * */ @@ -38,6 +38,8 @@ #ifndef _TYPEDEFS_H_ #include <typedefs.h> #endif +/* #include <ethernet.h> -- TODO: req., excluded to overwhelming coupling (break up ethernet.h) */ +#include <proto/bcmeth.h> /* This marks the start of a packed structure section. */ #include <packed_section_start.h> @@ -144,15 +146,14 @@ typedef BWL_PRE_PACKED_STRUCT struct bcm_event { #define WLC_E_EXCEEDED_MEDIUM_TIME 48 /* WMMAC excedded medium time */ #define WLC_E_ICV_ERROR 49 /* WEP ICV error occurred */ #define WLC_E_UNICAST_DECODE_ERROR 50 /* Unsupported unicast encrypted frame */ -#define WLC_E_MULTICAST_DECODE_ERROR 51 /* Unsupported multicast encrypted frame */ +#define WLC_E_MULTICAST_DECODE_ERROR 51 /* Unsupported multicast encrypted frame */ #define WLC_E_TRACE 52 -#ifdef WLBTAMP -#define WLC_E_BTA_HCI_EVENT 53 /* BT-AMP HCI event */ -#endif #define WLC_E_IF 54 /* I/F change (for dongle host notification) */ #define WLC_E_P2P_DISC_LISTEN_COMPLETE 55 /* listen state expires */ #define WLC_E_RSSI 56 /* indicate RSSI change based on configured levels */ #define WLC_E_PFN_SCAN_COMPLETE 57 /* PFN completed scan of network list */ +/* PFN best network batching event, conflict/share with WLC_E_PFN_SCAN_COMPLETE */ +#define WLC_E_PFN_BEST_BATCHING 57 #define WLC_E_EXTLOG_MSG 58 #define WLC_E_ACTION_FRAME 59 /* Action frame Rx */ #define WLC_E_ACTION_FRAME_COMPLETE 60 /* Action frame Tx complete */ @@ -169,9 +170,7 @@ typedef BWL_PRE_PACKED_STRUCT struct bcm_event { #define WLC_E_PROBRESP_MSG 71 /* probe response received */ #define WLC_E_P2P_PROBREQ_MSG 72 /* P2P Probe request received */ #define WLC_E_DCS_REQUEST 73 - #define WLC_E_FIFO_CREDIT_MAP 74 /* credits for D11 FIFOs. [AC0,AC1,AC2,AC3,BC_MC,ATIM] */ - #define WLC_E_ACTION_FRAME_RX 75 /* Received action frame event WITH * wl_event_rx_frame_data_t header */ @@ -182,23 +181,57 @@ typedef BWL_PRE_PACKED_STRUCT struct bcm_event { #define WLC_E_CSA_COMPLETE_IND 80 /* 802.11 CHANNEL SWITCH ACTION completed */ #define WLC_E_EXCESS_PM_WAKE_EVENT 81 /* excess PM Wake Event to inform host */ #define WLC_E_PFN_SCAN_NONE 82 /* no PFN networks around */ +/* PFN BSSID network found event, conflict/share with WLC_E_PFN_SCAN_NONE */ +#define WLC_E_PFN_BSSID_NET_FOUND 82 #define WLC_E_PFN_SCAN_ALLGONE 83 /* last found PFN network gets lost */ -#define WLC_E_GTK_PLUMBED 84 +/* PFN BSSID network lost event, conflict/share with WLC_E_PFN_SCAN_ALLGONE */ +#define WLC_E_PFN_BSSID_NET_LOST 83 +#define WLC_E_GTK_PLUMBED 84 #define WLC_E_ASSOC_IND_NDIS 85 /* 802.11 ASSOC indication for NDIS only */ #define WLC_E_REASSOC_IND_NDIS 86 /* 802.11 REASSOC indication for NDIS only */ -#define WLC_E_ASSOC_REQ_IE 87 -#define WLC_E_ASSOC_RESP_IE 88 -#define WLC_E_ASSOC_RECREATED 89 /* association recreated on resume */ +#define WLC_E_ASSOC_REQ_IE 87 +#define WLC_E_ASSOC_RESP_IE 88 +#define WLC_E_ASSOC_RECREATED 89 /* association recreated on resume */ #define WLC_E_ACTION_FRAME_RX_NDIS 90 /* rx action frame event for NDIS only */ -#define WLC_E_AUTH_REQ 91 /* authentication request received */ -#define WLC_E_TDLS_PEER_EVENT 92 /* discovered peer, connected or disconnected peer */ +#define WLC_E_AUTH_REQ 91 /* authentication request received */ +#define WLC_E_TDLS_PEER_EVENT 92 /* discovered peer, connected/disconnected peer */ #define WLC_E_SPEEDY_RECREATE_FAIL 93 /* fast assoc recreation failed */ -#define WLC_E_SERVICE_FOUND 102 /* desired service found */ -#define WLC_E_GAS_FRAGMENT_RX 103 /* GAS fragment received */ -#define WLC_E_GAS_COMPLETE 104 /* GAS sessions all complete */ -#define WLC_E_P2PO_ADD_DEVICE 105 /* New device found by p2p offload */ -#define WLC_E_P2PO_DEL_DEVICE 106 /* device has been removed by p2p offload */ -#define WLC_E_LAST 107 /* highest val + 1 for range checking */ +#define WLC_E_NATIVE 94 /* port-specific event and payload (e.g. NDIS) */ +#define WLC_E_PKTDELAY_IND 95 /* event for tx pkt delay suddently jump */ +#define WLC_E_AWDL_AW 96 /* AWDL AW period starts */ +#define WLC_E_AWDL_ROLE 97 /* AWDL Master/Slave/NE master role event */ +#define WLC_E_AWDL_EVENT 98 /* Generic AWDL event */ +#ifdef WLNIC +#define WLC_E_NIC_AF_TXS 99 /* NIC AF txstatus */ +#define WLC_E_NIC_NIC_REPORT 100 /* NIC period report */ +#endif +#define WLC_E_BEACON_FRAME_RX 101 +#define WLC_E_SERVICE_FOUND 102 /* desired service found */ +#define WLC_E_GAS_FRAGMENT_RX 103 /* GAS fragment received */ +#define WLC_E_GAS_COMPLETE 104 /* GAS sessions all complete */ +#define WLC_E_P2PO_ADD_DEVICE 105 /* New device found by p2p offload */ +#define WLC_E_P2PO_DEL_DEVICE 106 /* device has been removed by p2p offload */ +#define WLC_E_WNM_STA_SLEEP 107 /* WNM event to notify STA enter sleep mode */ +#define WLC_E_NONE 108 /* event removed, free to be reused */ +#define WLC_E_PROXD 109 /* Proximity Detection event */ +#define WLC_E_IBSS_COALESCE 110 /* IBSS Coalescing */ +#define WLC_E_AIBSS_TXFAIL 110 /* TXFAIL event for AIBSS, re using event 110 */ +#define WLC_E_AWDL_AW_EXT_END 111 /* AWDL extended period ends */ +#define WLC_E_AWDL_AW_EXT_START 112 /* SWDL AW extension start */ +#define WLC_E_AWDL_AW_START 113 /* AWDL start Event to inform host */ +#define WLC_E_AWDL_RADIO_OFF 114 /* Radio Off */ +#define WLC_E_AWDL_PEER_STATE 115 /* AWDL peer state open/close */ +#define WLC_E_AWDL_SYNC_STATE_CHANGED 116 /* AWDL sync role changed */ +#define WLC_E_AWDL_CHIP_RESET 117 /* infroms the interface of a chip rest */ +#define WLC_E_AWDL_INTERLEAVED_SCAN_START 118 +#define WLC_E_AWDL_INTERLEAVED_SCAN_STOP 119 +#define WLC_E_AWDL_PEER_CACHE_CONTROL 120 +#define WLC_E_CSA_START_IND 121 +#define WLC_E_CSA_DONE_IND 122 +#define WLC_E_CSA_FAILURE_IND 123 +#define WLC_E_CCA_CHAN_QUAL 124 /* CCA based channel quality report */ +#define WLC_E_CCX_S69_RESP_RX 129 +#define WLC_E_LAST 130 /* highest val + 1 for range checking */ /* Table of event name strings for UIs and debugging dumps */ @@ -234,18 +267,18 @@ extern const int bcmevent_names_size; #define WLC_E_REASON_DEAUTH 2 /* roamed due to DEAUTH indication */ #define WLC_E_REASON_DISASSOC 3 /* roamed due to DISASSOC indication */ #define WLC_E_REASON_BCNS_LOST 4 /* roamed due to lost beacons */ -#define WLC_E_REASON_MINTXRATE 9 /* roamed because at mintxrate for too long */ -#define WLC_E_REASON_TXFAIL 10 /* We can hear AP, but AP can't hear us */ /* Roam codes used primarily by CCX */ #define WLC_E_REASON_FAST_ROAM_FAILED 5 /* roamed due to fast roam failure */ #define WLC_E_REASON_DIRECTED_ROAM 6 /* roamed due to request by AP */ #define WLC_E_REASON_TSPEC_REJECTED 7 /* roamed due to TSPEC rejection */ #define WLC_E_REASON_BETTER_AP 8 /* roamed due to finding better AP */ - +#define WLC_E_REASON_MINTXRATE 9 /* roamed because at mintxrate for too long */ +#define WLC_E_REASON_TXFAIL 10 /* We can hear AP, but AP can't hear us */ #define WLC_E_REASON_REQUESTED_ROAM 11 /* roamed due to BSS Mgmt Transition request by AP */ + /* prune reason codes */ #define WLC_E_PRUNE_ENCR_MISMATCH 1 /* encryption mismatch */ #define WLC_E_PRUNE_BCAST_BSSID 2 /* AP uses a broadcast BSSID */ @@ -286,6 +319,14 @@ extern const int bcmevent_names_size; * WLC_E_P2P_PROBREQ_MSG * WLC_E_ACTION_FRAME_RX */ +#ifdef WLAWDL +#define WLC_E_AWDL_SCAN_START 1 /* Scan start indication to host */ +#define WLC_E_AWDL_SCAN_DONE 0 /* Scan Done indication to host */ + +#define WLC_E_AWDL_RX_ACT_FRAME 1 +#define WLC_E_AWDL_RX_PRB_RESP 2 + +#endif typedef BWL_PRE_PACKED_STRUCT struct wl_event_rx_frame_data { uint16 version; uint16 channel; /* Matches chanspec_t format from bcmwifi_channels.h */ @@ -300,7 +341,7 @@ typedef BWL_PRE_PACKED_STRUCT struct wl_event_rx_frame_data { typedef struct wl_event_data_if { uint8 ifidx; /* RTE virtual device index (for dongle) */ uint8 opcode; /* see I/F opcode */ - uint8 reserved; + uint8 reserved; /* bit mask (WLC_E_IF_FLAGS_XXX ) */ uint8 bssidx; /* bsscfg index */ uint8 role; /* see I/F role */ } wl_event_data_if_t; @@ -310,19 +351,22 @@ typedef struct wl_event_data_if { #define WLC_E_IF_DEL 2 /* bsscfg delete */ #define WLC_E_IF_CHANGE 3 /* bsscfg role change */ -/* WLC_E_IF flag */ -#define WLC_E_IF_FLAGS_BSSCFG_NOIF 0x1 /* no host I/F creation needed */ - /* I/F role code in WLC_E_IF event */ #define WLC_E_IF_ROLE_STA 0 /* Infra STA */ #define WLC_E_IF_ROLE_AP 1 /* Access Point */ #define WLC_E_IF_ROLE_WDS 2 /* WDS link */ #define WLC_E_IF_ROLE_P2P_GO 3 /* P2P Group Owner */ #define WLC_E_IF_ROLE_P2P_CLIENT 4 /* P2P Client */ -#ifdef WLBTAMP -#define WLC_E_IF_ROLE_BTA_CREATOR 5 /* BT-AMP Creator */ -#define WLC_E_IF_ROLE_BTA_ACCEPTOR 6 /* BT-AMP Acceptor */ -#endif + +/* WLC_E_RSSI event data */ +typedef struct wl_event_data_rssi { + int32 rssi; + int32 snr; + int32 noise; +} wl_event_data_rssi_t; + +/* WLC_E_IF flag */ +#define WLC_E_IF_FLAGS_BSSCFG_NOIF 0x1 /* no host I/F creation needed */ /* Reason codes for LINK */ #define WLC_E_LINK_BCN_LOSS 1 /* Link down because of beacon loss */ @@ -339,6 +383,22 @@ typedef struct wl_event_data_if { #define WLC_E_TDLS_PEER_CONNECTED 1 #define WLC_E_TDLS_PEER_DISCONNECTED 2 +#ifdef WLAWDL +/* WLC_E_AWDL_EVENT subtypes */ +#define WLC_E_AWDL_SCAN_STATUS 0 +#define WLC_E_AWDL_RX_ACT_FRAME 1 +#define WLC_E_AWDL_RX_PRB_RESP 2 +#define WLC_E_AWDL_PHYCAL_STATUS 3 +#define WLC_E_AWDL_WOWL_NULLPKT 4 +#define WLC_E_AWDL_OOB_AF_STATUS 5 + +/* WLC_E_AWDL_SCAN_STATUS status values */ +#define WLC_E_AWDL_SCAN_START 1 /* Scan start indication to host */ +#define WLC_E_AWDL_SCAN_DONE 0 /* Scan Done indication to host */ +#define WLC_E_AWDL_PHYCAL_START 1 /* Phy calibration start indication to host */ +#define WLC_E_AWDL_PHYCAL_DONE 0 /* Phy calibration done indication to host */ +#endif + /* GAS event data */ typedef BWL_PRE_PACKED_STRUCT struct wl_event_gas { uint16 channel; /* channel of GAS protocol */ @@ -365,6 +425,24 @@ typedef BWL_PRE_PACKED_STRUCT struct wl_event_sd { wl_sd_tlv_t tlv[1]; /* service discovery TLV */ } BWL_POST_PACKED_STRUCT wl_event_sd_t; +/* Reason codes for WLC_E_PROXD */ +#define WLC_E_PROXD_FOUND 1 /* Found a proximity device */ +#define WLC_E_PROXD_GONE 2 /* Lost a proximity device */ + +/* WLC_E_AWDL_AW event data */ +typedef BWL_PRE_PACKED_STRUCT struct awdl_aws_event_data { + uint32 fw_time; /* firmware PMU time */ + struct ether_addr current_master; /* Current master Mac addr */ + uint16 aw_counter; /* AW seq# */ + uint8 aw_ext_count; /* AW extension count */ + uint8 aw_role; /* AW role */ + uint8 flags; /* AW event flag */ + uint16 aw_chan; +} BWL_POST_PACKED_STRUCT awdl_aws_event_data_t; + +/* For awdl_aws_event_data_t.flags */ +#define AWDL_AW_LAST_EXT 0x01 + /* This marks the end of a packed structure section. */ #include <packed_section_end.h> diff --git a/drivers/net/wireless/bcmdhd/include/proto/bcmip.h b/drivers/net/wireless/bcmdhd/include/proto/bcmip.h index 52cd71d5a8c5..2521974de883 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/proto/bcmip.h +++ b/drivers/net/wireless/bcmdhd/include/proto/bcmip.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -21,7 +21,7 @@ * * Fundamental constants relating to IP Protocol * - * $Id: bcmip.h 290206 2011-10-17 19:13:51Z $ + * $Id: bcmip.h 384540 2013-02-12 04:28:58Z $ */ #ifndef _bcmip_h_ @@ -52,15 +52,16 @@ #define IP_PROT_ICMP6 0x3a /* ICMPv6 protocol type */ /* IPV4 field offsets */ -#define IPV4_VER_HL_OFFSET 0 /* version and ihl byte offset */ -#define IPV4_TOS_OFFSET 1 /* type of service offset */ -#define IPV4_PKTLEN_OFFSET 2 /* packet length offset */ -#define IPV4_PKTFLAG_OFFSET 6 /* more-frag,dont-frag flag offset */ -#define IPV4_PROT_OFFSET 9 /* protocol type offset */ -#define IPV4_CHKSUM_OFFSET 10 /* IP header checksum offset */ -#define IPV4_SRC_IP_OFFSET 12 /* src IP addr offset */ -#define IPV4_DEST_IP_OFFSET 16 /* dest IP addr offset */ -#define IPV4_OPTIONS_OFFSET 20 /* IP options offset */ +#define IPV4_VER_HL_OFFSET 0 /* version and ihl byte offset */ +#define IPV4_TOS_OFFSET 1 /* type of service offset */ +#define IPV4_PKTLEN_OFFSET 2 /* packet length offset */ +#define IPV4_PKTFLAG_OFFSET 6 /* more-frag,dont-frag flag offset */ +#define IPV4_PROT_OFFSET 9 /* protocol type offset */ +#define IPV4_CHKSUM_OFFSET 10 /* IP header checksum offset */ +#define IPV4_SRC_IP_OFFSET 12 /* src IP addr offset */ +#define IPV4_DEST_IP_OFFSET 16 /* dest IP addr offset */ +#define IPV4_OPTIONS_OFFSET 20 /* IP options offset */ +#define IPV4_MIN_HEADER_LEN 20 /* Minimum size for an IP header (no options) */ /* IPV4 field decodes */ #define IPV4_VER_MASK 0xf0 /* IPV4 version mask */ @@ -204,6 +205,8 @@ ipv6_exthdr_len(uint8 *h, uint8 *proto) return len; } +#define IPV4_ISMULTI(a) (((a) & 0xf0000000) == 0xe0000000) + /* This marks the end of a packed structure section. */ #include <packed_section_end.h> diff --git a/drivers/net/wireless/bcmdhd/include/proto/bt_amp_hci.h b/drivers/net/wireless/bcmdhd/include/proto/bt_amp_hci.h index 8617985dd36d..d56b10b7cdc5 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/proto/bt_amp_hci.h +++ b/drivers/net/wireless/bcmdhd/include/proto/bt_amp_hci.h @@ -1,7 +1,7 @@ /* * BT-AMP (BlueTooth Alternate Mac and Phy) HCI (Host/Controller Interface) * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -21,7 +21,7 @@ * 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: bt_amp_hci.h 294267 2011-11-04 23:41:52Z $ + * $Id: bt_amp_hci.h 382882 2013-02-04 23:24:31Z $ */ #ifndef _bt_amp_hci_h diff --git a/drivers/net/wireless/bcmdhd/include/proto/eapol.h b/drivers/net/wireless/bcmdhd/include/proto/eapol.h index 8936d1641a3d..b59b84f85178 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/proto/eapol.h +++ b/drivers/net/wireless/bcmdhd/include/proto/eapol.h @@ -7,7 +7,7 @@ * * Copyright (C) 2002 Broadcom Corporation * - * $Id: eapol.h 241182 2011-02-17 21:50:03Z $ + * $Id: eapol.h 382882 2013-02-04 23:24:31Z $ */ #ifndef _eapol_h_ diff --git a/drivers/net/wireless/bcmdhd/include/proto/ethernet.h b/drivers/net/wireless/bcmdhd/include/proto/ethernet.h index 479bdb425995..2977c31aadc0 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/proto/ethernet.h +++ b/drivers/net/wireless/bcmdhd/include/proto/ethernet.h @@ -1,7 +1,7 @@ /* * From FreeBSD 2.2.7: Fundamental constants relating to ethernet. * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -21,10 +21,10 @@ * 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: ethernet.h 309193 2012-01-19 00:03:57Z $ + * $Id: ethernet.h 384540 2013-02-12 04:28:58Z $ */ -#ifndef _NET_ETHERNET_H_ /* use native BSD ethernet.h when available */ +#ifndef _NET_ETHERNET_H_ /* use native BSD ethernet.h when available */ #define _NET_ETHERNET_H_ #ifndef _TYPEDEFS_H_ @@ -83,11 +83,16 @@ #define ETHER_TYPE_IPV6 0x86dd /* IPv6 */ #define ETHER_TYPE_BRCM 0x886c /* Broadcom Corp. */ #define ETHER_TYPE_802_1X 0x888e /* 802.1x */ +#ifdef PLC +#define ETHER_TYPE_88E1 0x88e1 /* GIGLE */ +#define ETHER_TYPE_8912 0x8912 /* GIGLE */ +#define ETHER_TYPE_GIGLED 0xffff /* GIGLE */ +#endif /* PLC */ #define ETHER_TYPE_802_1X_PREAUTH 0x88c7 /* 802.1x preauthentication */ #define ETHER_TYPE_WAI 0x88b4 /* WAI */ #define ETHER_TYPE_89_0D 0x890d /* 89-0d frame for TDLS */ -#define ETHER_TYPE_IPV6 0x86dd /* IPV6 */ +#define ETHER_TYPE_PPP_SES 0x8864 /* PPPoE Session */ /* Broadcom subtype follows ethertype; First 2 bytes are reserved; Next 2 are subtype; */ #define ETHER_BRCM_SUBTYPE_LEN 4 /* Broadcom 4 byte subtype */ @@ -112,7 +117,7 @@ ((uint8 *)ea)[5] = ((mgrp_ip) >> 0) & 0xff; \ } -#ifndef __INCif_etherh /* Quick and ugly hack for VxWorks */ +#ifndef __INCif_etherh /* Quick and ugly hack for VxWorks */ /* * Structure of a 10Mb/s Ethernet header. */ @@ -150,32 +155,53 @@ BWL_PRE_PACKED_STRUCT struct ether_addr { /* compare two ethernet addresses - assumes the pointers can be referenced as shorts */ -#define ether_cmp(a, b) (!(((short*)(a))[0] == ((short*)(b))[0]) | \ - !(((short*)(a))[1] == ((short*)(b))[1]) | \ - !(((short*)(a))[2] == ((short*)(b))[2])) +#define eacmp(a, b) ((((const uint16 *)(a))[0] ^ ((const uint16 *)(b))[0]) | \ + (((const uint16 *)(a))[1] ^ ((const uint16 *)(b))[1]) | \ + (((const uint16 *)(a))[2] ^ ((const uint16 *)(b))[2])) + +#define ether_cmp(a, b) eacmp(a, b) /* copy an ethernet address - assumes the pointers can be referenced as shorts */ -#define ether_copy(s, d) { \ - ((short*)(d))[0] = ((const short*)(s))[0]; \ - ((short*)(d))[1] = ((const short*)(s))[1]; \ - ((short*)(d))[2] = ((const short*)(s))[2]; } +#define eacopy(s, d) \ +do { \ + ((uint16 *)(d))[0] = ((const uint16 *)(s))[0]; \ + ((uint16 *)(d))[1] = ((const uint16 *)(s))[1]; \ + ((uint16 *)(d))[2] = ((const uint16 *)(s))[2]; \ +} while (0) + +#define ether_copy(s, d) eacopy(s, d) + +/* Copy an ethernet address in reverse order */ +#define ether_rcopy(s, d) \ +do { \ + ((uint16 *)(d))[2] = ((uint16 *)(s))[2]; \ + ((uint16 *)(d))[1] = ((uint16 *)(s))[1]; \ + ((uint16 *)(d))[0] = ((uint16 *)(s))[0]; \ +} while (0) + static const struct ether_addr ether_bcast = {{255, 255, 255, 255, 255, 255}}; static const struct ether_addr ether_null = {{0, 0, 0, 0, 0, 0}}; - -#define ETHER_ISBCAST(ea) ((((uint8 *)(ea))[0] & \ - ((uint8 *)(ea))[1] & \ - ((uint8 *)(ea))[2] & \ - ((uint8 *)(ea))[3] & \ - ((uint8 *)(ea))[4] & \ - ((uint8 *)(ea))[5]) == 0xff) -#define ETHER_ISNULLADDR(ea) ((((uint8 *)(ea))[0] | \ - ((uint8 *)(ea))[1] | \ - ((uint8 *)(ea))[2] | \ - ((uint8 *)(ea))[3] | \ - ((uint8 *)(ea))[4] | \ - ((uint8 *)(ea))[5]) == 0) +static const struct ether_addr ether_ipv6_mcast = {{0x33, 0x33, 0x00, 0x00, 0x00, 0x01}}; + +#define ETHER_ISBCAST(ea) ((((const uint8 *)(ea))[0] & \ + ((const uint8 *)(ea))[1] & \ + ((const uint8 *)(ea))[2] & \ + ((const uint8 *)(ea))[3] & \ + ((const uint8 *)(ea))[4] & \ + ((const uint8 *)(ea))[5]) == 0xff) +#define ETHER_ISNULLADDR(ea) ((((const uint8 *)(ea))[0] | \ + ((const uint8 *)(ea))[1] | \ + ((const uint8 *)(ea))[2] | \ + ((const uint8 *)(ea))[3] | \ + ((const uint8 *)(ea))[4] | \ + ((const uint8 *)(ea))[5]) == 0) + +#define ETHER_ISNULLDEST(da) ((((const uint16 *)(da))[0] | \ + ((const uint16 *)(da))[1] | \ + ((const uint16 *)(da))[2]) == 0) +#define ETHER_ISNULLSRC(sa) ETHER_ISNULLDEST(sa) #define ETHER_MOVE_HDR(d, s) \ do { \ @@ -184,6 +210,8 @@ do { \ *(struct ether_header *)(d) = t; \ } while (0) +#define ETHER_ISUCAST(ea) ((((uint8 *)(ea))[0] & 0x01) == 0) + /* This marks the end of a packed structure section. */ #include <packed_section_end.h> diff --git a/drivers/net/wireless/bcmdhd/include/proto/p2p.h b/drivers/net/wireless/bcmdhd/include/proto/p2p.h index 6716e2a67247..295c0dee40f9 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/proto/p2p.h +++ b/drivers/net/wireless/bcmdhd/include/proto/p2p.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -21,7 +21,7 @@ * * Fundamental types and constants relating to WFA P2P (aka WiFi Direct) * - * $Id: p2p.h 356417 2012-09-12 16:41:24Z $ + * $Id: p2p.h 384536 2013-02-12 04:13:09Z $ */ #ifndef _P2P_H_ @@ -70,7 +70,7 @@ typedef struct wifi_p2p_ie wifi_p2p_ie_t; #define P2P_SEID_DEV_ID 3 /* P2P Device ID */ #define P2P_SEID_INTENT 4 /* Group Owner Intent */ #define P2P_SEID_CFG_TIMEOUT 5 /* Configuration Timeout */ -#define P2P_SEID_CHANNEL 6 /* Channel */ +#define P2P_SEID_CHANNEL 6 /* Listen channel */ #define P2P_SEID_GRP_BSSID 7 /* P2P Group BSSID */ #define P2P_SEID_XT_TIMING 8 /* Extended Listen Timing */ #define P2P_SEID_INTINTADDR 9 /* Intended P2P Interface Address */ @@ -407,6 +407,8 @@ typedef struct wifi_p2p_noa_se wifi_p2p_noa_se_t; #define P2P_NOA_SE_FIXED_LEN 5 +#define P2P_NOA_SE_MAX_DESC 2 /* max NoA descriptors in presence request */ + /* cnt_type field values */ #define P2P_NOA_DESC_CNT_RESERVED 0 /* reserved and should not be used */ #define P2P_NOA_DESC_CNT_REPEAT 255 /* continuous schedule */ diff --git a/drivers/net/wireless/bcmdhd/include/proto/sdspi.h b/drivers/net/wireless/bcmdhd/include/proto/sdspi.h index a4900edd4ac6..6263f40a8ae1 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/proto/sdspi.h +++ b/drivers/net/wireless/bcmdhd/include/proto/sdspi.h @@ -1,7 +1,7 @@ /* * SD-SPI Protocol Standard * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -21,7 +21,7 @@ * 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: sdspi.h 241182 2011-02-17 21:50:03Z $ + * $Id: sdspi.h 382882 2013-02-04 23:24:31Z $ */ #ifndef _SD_SPI_H #define _SD_SPI_H diff --git a/drivers/net/wireless/bcmdhd/include/proto/vlan.h b/drivers/net/wireless/bcmdhd/include/proto/vlan.h index 88502bf11e79..0fc334ba2a7f 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/proto/vlan.h +++ b/drivers/net/wireless/bcmdhd/include/proto/vlan.h @@ -1,7 +1,7 @@ /* * 802.1Q VLAN protocol definitions * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -21,7 +21,7 @@ * 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: vlan.h 241182 2011-02-17 21:50:03Z $ + * $Id: vlan.h 382883 2013-02-04 23:26:09Z $ */ #ifndef _vlan_h_ @@ -34,17 +34,28 @@ /* This marks the start of a packed structure section. */ #include <packed_section_start.h> +#ifndef VLAN_VID_MASK #define VLAN_VID_MASK 0xfff /* low 12 bits are vlan id */ +#endif + #define VLAN_CFI_SHIFT 12 /* canonical format indicator bit */ #define VLAN_PRI_SHIFT 13 /* user priority */ #define VLAN_PRI_MASK 7 /* 3 bits of priority */ +#define VLAN_TPID_OFFSET 12 /* offset of tag protocol id field */ +#define VLAN_TCI_OFFSET 14 /* offset of tag ctrl info field */ + #define VLAN_TAG_LEN 4 #define VLAN_TAG_OFFSET (2 * ETHER_ADDR_LEN) /* offset in Ethernet II packet only */ #define VLAN_TPID 0x8100 /* VLAN ethertype/Tag Protocol ID */ +struct vlan_header { + uint16 vlan_type; /* 0x8100 */ + uint16 vlan_tag; /* priority, cfi and vid */ +}; + struct ethervlan_header { uint8 ether_dhost[ETHER_ADDR_LEN]; uint8 ether_shost[ETHER_ADDR_LEN]; @@ -53,6 +64,21 @@ struct ethervlan_header { uint16 ether_type; }; +struct dot3_mac_llc_snapvlan_header { + uint8 ether_dhost[ETHER_ADDR_LEN]; /* dest mac */ + uint8 ether_shost[ETHER_ADDR_LEN]; /* src mac */ + uint16 length; /* frame length incl header */ + uint8 dsap; /* always 0xAA */ + uint8 ssap; /* always 0xAA */ + uint8 ctl; /* always 0x03 */ + uint8 oui[3]; /* RFC1042: 0x00 0x00 0x00 + * Bridge-Tunnel: 0x00 0x00 0xF8 + */ + uint16 vlan_type; /* 0x8100 */ + uint16 vlan_tag; /* priority, cfi and vid */ + uint16 ether_type; /* ethertype */ +}; + #define ETHERVLAN_HDR_LEN (ETHER_HDR_LEN + VLAN_TAG_LEN) diff --git a/drivers/net/wireless/bcmdhd/include/proto/wpa.h b/drivers/net/wireless/bcmdhd/include/proto/wpa.h index 1a0f5049f0b7..84492df5c6d8 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/proto/wpa.h +++ b/drivers/net/wireless/bcmdhd/include/proto/wpa.h @@ -1,7 +1,7 @@ /* * Fundamental types and constants relating to WPA * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -21,7 +21,7 @@ * 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: wpa.h 261155 2011-05-23 23:51:32Z $ + * $Id: wpa.h 384536 2013-02-12 04:13:09Z $ */ #ifndef _proto_wpa_h_ @@ -146,10 +146,10 @@ typedef BWL_PRE_PACKED_STRUCT struct #define RSN_CAP_2_REPLAY_CNTRS 1 #define RSN_CAP_4_REPLAY_CNTRS 2 #define RSN_CAP_16_REPLAY_CNTRS 3 -#ifdef MFP #define RSN_CAP_MFPR 0x0040 #define RSN_CAP_MFPC 0x0080 -#endif +#define RSN_CAP_SPPC 0x0400 +#define RSN_CAP_SPPR 0x0800 /* WPA capabilities defined in 802.11i */ #define WPA_CAP_4_REPLAY_CNTRS RSN_CAP_4_REPLAY_CNTRS diff --git a/drivers/net/wireless/bcmdhd/include/sbchipc.h b/drivers/net/wireless/bcmdhd/include/sbchipc.h index c6942913342a..d915d88abcc7 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/sbchipc.h +++ b/drivers/net/wireless/bcmdhd/include/sbchipc.h @@ -5,9 +5,9 @@ * JTAG, 0/1/2 UARTs, clock frequency control, a watchdog interrupt timer, * GPIO interface, extbus, and support for serial and parallel flashes. * - * $Id: sbchipc.h 347614 2012-07-27 10:24:51Z $ + * $Id: sbchipc.h 385540 2013-02-15 23:14:50Z $ * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -291,10 +291,10 @@ typedef volatile struct { uint32 pllcontrol_data; uint32 pmustrapopt; /* 0x668, corerev >= 28 */ uint32 pmu_xtalfreq; /* 0x66C, pmurev >= 10 */ - uint32 retention_ctl; /* 0x670 */ + uint32 retention_ctl; /* 0x670 */ uint32 PAD[3]; - uint32 retention_grpidx; /* 0x680 */ - uint32 retention_grpctl; /* 0x684 */ + uint32 retention_grpidx; /* 0x680 */ + uint32 retention_grpctl; /* 0x684 */ uint32 PAD[94]; uint16 sromotp[512]; /* 0x800 */ #ifdef NFLASH_SUPPORT @@ -362,14 +362,56 @@ typedef volatile struct { uint32 nand_ctrl_status; #endif /* NFLASH_SUPPORT */ uint32 gci_corecaps0; /* GCI starting at 0xC00 */ - uint32 gci_corecaps1; - uint32 gci_corecaps2; - uint32 gci_corectrl; - uint32 gci_corestat; /* 0xC10 */ - uint32 PAD[11]; - uint32 gci_indirect_addr; /* 0xC40 */ - uint32 PAD[111]; - uint32 gci_chipctrl; /* 0xE00 */ + uint32 gci_corecaps1; + uint32 gci_corecaps2; + uint32 gci_corectrl; + uint32 gci_corestat; /* 0xC10 */ + uint32 gci_intstat; /* 0xC14 */ + uint32 gci_intmask; /* 0xC18 */ + uint32 gci_wakemask; /* 0xC1C */ + uint32 gci_levelintstat; /* 0xC20 */ + uint32 gci_eventintstat; /* 0xC24 */ + uint32 PAD[6]; + uint32 gci_indirect_addr; /* 0xC40 */ + uint32 gci_gpioctl; /* 0xC44 */ + uint32 PAD; + uint32 gci_gpiomask; /* 0xC4C */ + uint32 PAD; + uint32 gci_miscctl; /* 0xC54 */ + uint32 PAD[2]; + uint32 gci_input[32]; /* C60 */ + uint32 gci_event[32]; /* CE0 */ + uint32 gci_output[4]; /* D60 */ + uint32 gci_control_0; /* 0xD70 */ + uint32 gci_control_1; /* 0xD74 */ + uint32 gci_level_polreg; /* 0xD78 */ + uint32 gci_levelintmask; /* 0xD7C */ + uint32 gci_eventintmask; /* 0xD80 */ + uint32 PAD[3]; + uint32 gci_inbandlevelintmask; /* 0xD90 */ + uint32 gci_inbandeventintmask; /* 0xD94 */ + uint32 PAD[2]; + uint32 gci_seciauxtx; /* 0xDA0 */ + uint32 gci_seciauxrx; /* 0xDA4 */ + uint32 gci_secitx_datatag; /* 0xDA8 */ + uint32 gci_secirx_datatag; /* 0xDAC */ + uint32 gci_secitx_datamask; /* 0xDB0 */ + uint32 gci_seciusef0tx_reg; /* 0xDB4 */ + uint32 gci_secif0tx_offset; /* 0xDB8 */ + uint32 gci_secif0rx_offset; /* 0xDBC */ + uint32 gci_secif1tx_offset; /* 0xDC0 */ + uint32 PAD[3]; + uint32 gci_uartescval; /* DD0 */ + uint32 PAD[3]; + uint32 gci_secibauddiv; /* DE0 */ + uint32 gci_secifcr; /* DE4 */ + uint32 gci_secilcr; /* DE8 */ + uint32 gci_secimcr; /* DEC */ + uint32 PAD[2]; + uint32 gci_baudadj; /* DF8 */ + uint32 PAD; + uint32 gci_chipctrl; /* 0xE00 */ + uint32 gci_chipsts; /* 0xE04 */ } chipcregs_t; #endif /* _LANGUAGE_ASSEMBLY */ @@ -475,8 +517,11 @@ typedef volatile struct { #define CC_CAP2_GSIO 0x00000002 /* GSIO (spi/i2c) present, rev >= 37 */ /* capabilities extension */ -#define CC_CAP_EXT_SECI_PRESENT 0x00000001 /* SECI present */ +#define CC_CAP_EXT_SECI_PRESENT 0x00000001 /* SECI present */ +#define CC_CAP_EXT_GCI_PRESENT 0x00000004 /* GCI present */ +/* WL Channel Info to BT via GCI - bits 40 - 47 */ +#define GCI_WL_CHN_INFO_MASK (0xFF00) /* PLL type */ #define PLL_NONE 0x00000000 #define PLL_TYPE1 0x00010000 /* 48MHz base, 3 dividers */ @@ -493,6 +538,28 @@ typedef volatile struct { /* ALP clock on pre-PMU chips */ #define ALP_CLOCK 20000000 +#ifdef CFG_SIM +#define NS_ALP_CLOCK 84922 +#define NS_SLOW_ALP_CLOCK 84922 +#define NS_CPU_CLOCK 534500 +#define NS_SLOW_CPU_CLOCK 534500 +#define NS_SI_CLOCK 271750 +#define NS_SLOW_SI_CLOCK 271750 +#define NS_FAST_MEM_CLOCK 271750 +#define NS_MEM_CLOCK 271750 +#define NS_SLOW_MEM_CLOCK 271750 +#else +#define NS_ALP_CLOCK 125000000 +#define NS_SLOW_ALP_CLOCK 100000000 +#define NS_CPU_CLOCK 1000000000 +#define NS_SLOW_CPU_CLOCK 800000000 +#define NS_SI_CLOCK 250000000 +#define NS_SLOW_SI_CLOCK 200000000 +#define NS_FAST_MEM_CLOCK 800000000 +#define NS_MEM_CLOCK 533000000 +#define NS_SLOW_MEM_CLOCK 400000000 +#endif /* CFG_SIM */ + /* HT clock */ #define HT_CLOCK 80000000 @@ -817,6 +884,33 @@ typedef volatile struct { #define PCTL_ILP_DIV_EN 0x00000002 #define PCTL_LPO_SEL 0x00000001 +/* Retention Control */ +#define PMU_RCTL_CLK_DIV_SHIFT 0 +#define PMU_RCTL_CHAIN_LEN_SHIFT 12 +#define PMU_RCTL_MACPHY_DISABLE_SHIFT 26 +#define PMU_RCTL_MACPHY_DISABLE_MASK (1 << 26) +#define PMU_RCTL_LOGIC_DISABLE_SHIFT 27 +#define PMU_RCTL_LOGIC_DISABLE_MASK (1 << 27) +#define PMU_RCTL_MEMSLP_LOG_SHIFT 28 +#define PMU_RCTL_MEMSLP_LOG_MASK (1 << 28) +#define PMU_RCTL_MEMRETSLP_LOG_SHIFT 29 +#define PMU_RCTL_MEMRETSLP_LOG_MASK (1 << 29) + +/* Retention Group Control */ +#define PMU_RCTLGRP_CHAIN_LEN_SHIFT 0 +#define PMU_RCTLGRP_RMODE_ENABLE_SHIFT 14 +#define PMU_RCTLGRP_RMODE_ENABLE_MASK (1 << 14) +#define PMU_RCTLGRP_DFT_ENABLE_SHIFT 15 +#define PMU_RCTLGRP_DFT_ENABLE_MASK (1 << 15) +#define PMU_RCTLGRP_NSRST_DISABLE_SHIFT 16 +#define PMU_RCTLGRP_NSRST_DISABLE_MASK (1 << 16) +/* Retention Group Control special for 4334 */ +#define PMU4334_RCTLGRP_CHAIN_LEN_GRP0 338 +#define PMU4334_RCTLGRP_CHAIN_LEN_GRP1 315 +/* Retention Group Control special for 43341 */ +#define PMU43341_RCTLGRP_CHAIN_LEN_GRP0 366 +#define PMU43341_RCTLGRP_CHAIN_LEN_GRP1 330 + /* Fields in clkstretch */ #define CSTRETCH_HT 0xffff0000 #define CSTRETCH_ALP 0x0000ffff @@ -884,6 +978,8 @@ typedef volatile struct { #define SFLASH_AT 0x200 /* Atmel serial flash */ #define NFLASH 0x300 #define PFLASH 0x700 /* Parallel flash */ +#define QSPIFLASH_ST 0x800 +#define QSPIFLASH_AT 0x900 /* Bits in the ExtBus config registers */ #define CC_CFG_EN 0x0001 /* Enable */ @@ -1079,6 +1175,7 @@ typedef volatile struct { /* PMU chip control0 register */ #define PMU_CHIPCTL0 0 +#define PMU43143_CC0_SDIO_DRSTR_OVR (1 << 31) /* sdio drive strength override enable */ /* clock req types */ #define PMU_CC1_CLKREQ_TYPE_SHIFT 19 @@ -1112,6 +1209,9 @@ typedef volatile struct { #define PMU_CC3_ENABLE_RF_SHIFT 22 #define PMU_CC3_RF_DISABLE_IVALUE_SHIFT 23 +/* PMU chip control5 register */ +#define PMU_CHIPCTL5 5 + /* PMU corerev and chip specific PLL controls. * PMU<rev>_PLL<num>_XX where <rev> is PMU corerev and <num> is an arbitrary number @@ -1500,6 +1600,10 @@ typedef volatile struct { #define CCTRL43217_EXTPA_C0 (1<<13) /* core0 extPA in ChipControl 1, bit 13 */ #define CCTRL43217_EXTPA_C1 (1<<8) /* core1 extPA in ChipControl 1, bit 8 */ +/* 43228 Chip specific ChipControl register bits */ +#define CCTRL43228_EXTPA_C0 (1<<14) /* core1 extPA in ChipControl 1, bit 14 */ +#define CCTRL43228_EXTPA_C1 (1<<9) /* core0 extPA in ChipControl 1, bit 1 */ + /* 4328 resources */ #define RES4328_EXT_SWITCHER_PWM 0 /* 0x00001 */ #define RES4328_BB_SWITCHER_PWM 1 /* 0x00002 */ @@ -1743,9 +1847,36 @@ typedef volatile struct { #define CST43239_CHIPMODE_GSPI(cs) (((cs) & (1 << 0)) == (1 << 0)) /* gSPI */ /* 4324 resources */ -#define RES4324_OTP_PU 10 +/* 43242 use same PMU as 4324 */ +#define RES4324_LPLDO_PU 0 +#define RES4324_RESET_PULLDN_DIS 1 +#define RES4324_PMU_BG_PU 2 +#define RES4324_HSIC_LDO_PU 3 +#define RES4324_CBUCK_LPOM_PU 4 +#define RES4324_CBUCK_PFM_PU 5 +#define RES4324_CLDO_PU 6 +#define RES4324_LPLDO2_LVM 7 +#define RES4324_LNLDO1_PU 8 +#define RES4324_LNLDO2_PU 9 +#define RES4324_LDO3P3_PU 10 +#define RES4324_OTP_PU 11 +#define RES4324_XTAL_PU 12 +#define RES4324_BBPLL_PU 13 +#define RES4324_LQ_AVAIL 14 +#define RES4324_WL_CORE_READY 17 +#define RES4324_ILP_REQ 18 +#define RES4324_ALP_AVAIL 19 +#define RES4324_PALDO_PU 20 +#define RES4324_RADIO_PU 21 +#define RES4324_SR_CLK_STABLE 22 +#define RES4324_SR_SAVE_RESTORE 23 +#define RES4324_SR_PHY_PWRSW 24 +#define RES4324_SR_PHY_PIC 25 +#define RES4324_SR_SUBCORE_PWRSW 26 +#define RES4324_SR_SUBCORE_PIC 27 +#define RES4324_SR_MEM_PM0 28 #define RES4324_HT_AVAIL 29 -#define RES4324_MACPHY_CLKAVAIL 30 +#define RES4324_MACPHY_CLKAVAIL 30 /* 4324 Chip specific ChipStatus register bits */ #define CST4324_SPROM_MASK 0x00000080 @@ -1756,6 +1887,9 @@ typedef volatile struct { #define CST4324_CHIPMODE_SDIOD(cs) ((~(cs)) & (1 << 2)) /* SDIO || gSPI */ #define CST4324_CHIPMODE_USB20D(cs) (((cs) & CST4324_CHIPMODE_MASK) == 0x6) /* USB || USBDA */ +/* 43242 Chip specific ChipStatus register bits */ +#define CST43242_SFLASH_MASK 0x00000008 + /* 4331 resources */ #define RES4331_REGULATOR 0 #define RES4331_ILP_REQUEST 1 @@ -1991,6 +2125,42 @@ typedef volatile struct { #define PMU_VREG0_DISABLE_PULLD_BT_SHIFT 2 #define PMU_VREG0_DISABLE_PULLD_WL_SHIFT 3 +#define PMU_VREG4_ADDR 4 + +#define PMU_VREG4_CLDO_PWM_SHIFT 4 +#define PMU_VREG4_CLDO_PWM_MASK 0x7 + +#define PMU_VREG4_LPLDO1_SHIFT 15 +#define PMU_VREG4_LPLDO1_MASK 0x7 +#define PMU_VREG4_LPLDO1_1p20V 0 +#define PMU_VREG4_LPLDO1_1p15V 1 +#define PMU_VREG4_LPLDO1_1p10V 2 +#define PMU_VREG4_LPLDO1_1p25V 3 +#define PMU_VREG4_LPLDO1_1p05V 4 +#define PMU_VREG4_LPLDO1_1p00V 5 +#define PMU_VREG4_LPLDO1_0p95V 6 +#define PMU_VREG4_LPLDO1_0p90V 7 + +#define PMU_VREG4_LPLDO2_LVM_SHIFT 18 +#define PMU_VREG4_LPLDO2_LVM_MASK 0x7 +#define PMU_VREG4_LPLDO2_HVM_SHIFT 21 +#define PMU_VREG4_LPLDO2_HVM_MASK 0x7 +#define PMU_VREG4_LPLDO2_LVM_HVM_MASK 0x3f +#define PMU_VREG4_LPLDO2_1p00V 0 +#define PMU_VREG4_LPLDO2_1p15V 1 +#define PMU_VREG4_LPLDO2_1p20V 2 +#define PMU_VREG4_LPLDO2_1p10V 3 +#define PMU_VREG4_LPLDO2_0p90V 4 /* 4 - 7 is 0.90V */ + +#define PMU_VREG4_HSICLDO_BYPASS_SHIFT 27 +#define PMU_VREG4_HSICLDO_BYPASS_MASK 0x1 + +#define PMU_VREG5_ADDR 5 +#define PMU_VREG5_HSICAVDD_PD_SHIFT 6 +#define PMU_VREG5_HSICAVDD_PD_MASK 0x1 +#define PMU_VREG5_HSICDVDD_PD_SHIFT 11 +#define PMU_VREG5_HSICDVDD_PD_MASK 0x1 + /* 4334 resources */ #define RES4334_LPLDO_PU 0 #define RES4334_RESET_PULLDN_DIS 1 @@ -2046,12 +2216,78 @@ typedef volatile struct { #define PCTL_4334_GPIO3_ENAB (1 << 3) /* 4334 Chip control */ +#define CCTRL4334_PMU_WAKEUP_GPIO1 (1 << 0) +#define CCTRL4334_PMU_WAKEUP_HSIC (1 << 1) +#define CCTRL4334_PMU_WAKEUP_AOS (1 << 2) +#define CCTRL4334_HSIC_WAKE_MODE (1 << 3) +#define CCTRL4334_HSIC_INBAND_GPIO1 (1 << 4) #define CCTRL4334_HSIC_LDO_PU (1 << 23) +/* 4334 Chip control 3 */ +#define CCTRL4334_BLOCK_EXTRNL_WAKE (1 << 4) +#define CCTRL4334_SAVERESTORE_FIX (1 << 5) + +/* 43341 Chip control 3 */ +#define CCTRL43341_BLOCK_EXTRNL_WAKE (1 << 13) +#define CCTRL43341_SAVERESTORE_FIX (1 << 14) +#define CCTRL43341_BT_ISO_SEL (1 << 16) + +/* 4334 Chip specific ChipControl1 register bits */ +#define CCTRL1_4334_GPIO_SEL (1 << 0) /* 1=select GPIOs to be muxed out */ +#define CCTRL1_4334_ERCX_SEL (1 << 1) /* 1=select ERCX BT coex to be muxed out */ +#define CCTRL1_4334_SDIO_HOST_WAKE (1 << 2) /* SDIO: 1=configure GPIO0 for host wake */ +#define CCTRL1_4334_JTAG_DISABLE (1 << 3) /* 1=disable JTAG interface on mux'd pins */ +#define CCTRL1_4334_UART_ON_4_5 (1 << 28) /* 1=UART_TX/UART_RX muxed on GPIO_4/5 (4334B0/1) */ + /* 4324 Chip specific ChipControl1 register bits */ #define CCTRL1_4324_GPIO_SEL (1 << 0) /* 1=select GPIOs to be muxed out */ #define CCTRL1_4324_SDIO_HOST_WAKE (1 << 2) /* SDIO: 1=configure GPIO0 for host wake */ +/* 43143 chip-specific ChipStatus register bits based on Confluence documentation */ +/* register contains strap values sampled during POR */ +#define CST43143_REMAP_TO_ROM (3 << 0) /* 00=Boot SRAM, 01=Boot ROM, 10=Boot SFLASH */ +#define CST43143_SDIO_EN (1 << 2) /* 0 = USB Enab, SDIO pins are GPIO or I2S */ +#define CST43143_SDIO_ISO (1 << 3) /* 1 = SDIO isolated */ +#define CST43143_USB_CPU_LESS (1 << 4) /* 1 = CPULess mode Enabled */ +#define CST43143_CBUCK_MODE (3 << 6) /* Indicates what controller mode CBUCK is in */ +#define CST43143_POK_CBUCK (1 << 8) /* 1 = 1.2V CBUCK voltage ready */ +#define CST43143_PMU_OVRSPIKE (1 << 9) +#define CST43143_PMU_OVRTEMP (0xF << 10) +#define CST43143_SR_FLL_CAL_DONE (1 << 14) +#define CST43143_USB_PLL_LOCKDET (1 << 15) +#define CST43143_PMU_PLL_LOCKDET (1 << 16) +#define CST43143_CHIPMODE_SDIOD(cs) (((cs) & CST43143_SDIO_EN) != 0) /* SDIO */ + +/* 43143 Chip specific ChipControl register bits */ +/* 00: SECI is disabled (JATG functional), 01: 2 wire, 10: 4 wire */ +#define CCTRL_43143_SECI (1<<0) +#define CCTRL_43143_BT_LEGACY (1<<1) +#define CCTRL_43143_I2S_MODE (1<<2) /* 0: SDIO enabled */ +#define CCTRL_43143_I2S_MASTER (1<<3) /* 0: I2S MCLK input disabled */ +#define CCTRL_43143_I2S_FULL (1<<4) /* 0: I2S SDIN and SPDIF_TX inputs disabled */ +#define CCTRL_43143_GSIO (1<<5) /* 0: sFlash enabled */ +#define CCTRL_43143_RF_SWCTRL_MASK (7<<6) /* 0: disabled */ +#define CCTRL_43143_RF_SWCTRL_0 (1<<6) +#define CCTRL_43143_RF_SWCTRL_1 (2<<6) +#define CCTRL_43143_RF_SWCTRL_2 (4<<6) +#define CCTRL_43143_RF_XSWCTRL (1<<9) /* 0: UART enabled */ +#define CCTRL_43143_HOST_WAKE0 (1<<11) /* 1: SDIO separate interrupt output from GPIO4 */ +#define CCTRL_43143_HOST_WAKE1 (1<<12) /* 1: SDIO separate interrupt output from GPIO16 */ + +/* 43143 resources, based on pmu_params.xls V1.19 */ +#define RES43143_EXT_SWITCHER_PWM 0 /* 0x00001 */ +#define RES43143_XTAL_PU 1 /* 0x00002 */ +#define RES43143_ILP_REQUEST 2 /* 0x00004 */ +#define RES43143_ALP_AVAIL 3 /* 0x00008 */ +#define RES43143_WL_CORE_READY 4 /* 0x00010 */ +#define RES43143_BBPLL_PWRSW_PU 5 /* 0x00020 */ +#define RES43143_HT_AVAIL 6 /* 0x00040 */ +#define RES43143_RADIO_PU 7 /* 0x00080 */ +#define RES43143_MACPHY_CLK_AVAIL 8 /* 0x00100 */ +#define RES43143_OTP_PU 9 /* 0x00200 */ +#define RES43143_LQ_AVAIL 10 /* 0x00400 */ + +#define PMU43143_XTAL_CORE_SIZE_MASK 0x3F /* 4313 resources */ #define RES4313_BB_PU_RSRC 0 @@ -2154,11 +2390,19 @@ typedef volatile struct { #define FLSTRCF4706_1ST_MADDR_SEG_256MB 0x00000070 /* 256MB */ /* 4360 Chip specific ChipControl register bits */ +#define CCTRL4360_I2C_MODE (1 << 0) +#define CCTRL4360_UART_MODE (1 << 1) #define CCTRL4360_SECI_MODE (1 << 2) #define CCTRL4360_BTSWCTRL_MODE (1 << 3) +#define CCTRL4360_DISCRETE_FEMCTRL_MODE (1 << 4) +#define CCTRL4360_DIGITAL_PACTRL_MODE (1 << 5) +#define CCTRL4360_BTSWCTRL_AND_DIGPA_PRESENT (1 << 6) +#define CCTRL4360_EXTRA_GPIO_MODE (1 << 7) #define CCTRL4360_EXTRA_FEMCTRL_MODE (1 << 8) #define CCTRL4360_BT_LGCY_MODE (1 << 9) #define CCTRL4360_CORE2FEMCTRL4_ON (1 << 21) +#define CCTRL4360_SECI_ON_GPIO01 (1 << 24) + /* 4360 PMU resources and chip status bits */ #define RES4360_REGULATOR 0 @@ -2189,6 +2433,13 @@ typedef volatile struct { #define CCTRL_4360_UART_SEL 0x2 +/* defines to detect active host interface in use */ +#define CHIP_HOSTIF_PCIEMODE 0x1 +#define CHIP_HOSTIF_USBMODE 0x2 +#define CHIP_HOSTIF_SDIOMODE 0x4 +#define CHIP_HOSTIF_PCIE(sih) (si_chip_hostif(sih) == CHIP_HOSTIF_PCIEMODE) +#define CHIP_HOSTIF_SDIO(sih) (si_chip_hostif(sih) == CHIP_HOSTIF_SDIOMODE) + /* 4335 resources */ #define RES4335_LPLDO_PO 0 #define RES4335_PMU_BG_PU 1 @@ -2237,11 +2488,227 @@ typedef volatile struct { #define CCTRL1_4335_GPIO_SEL (1 << 0) /* 1=select GPIOs to be muxed out */ #define CCTRL1_4335_SDIO_HOST_WAKE (1 << 2) /* SDIO: 1=configure GPIO0 for host wake */ +#define CR4_4335_RAM_BASE (0x180000) +#define PATCHTBL_SIZE (0x800) +#define CR4_4350_RAM_BASE (0x180000) +#define CR4_4360_RAM_BASE (0x0) + + +/* 4335 chip OTP present & OTP select bits. */ +#define SPROM4335_OTP_SELECT 0x00000010 +#define SPROM4335_OTP_PRESENT 0x00000020 -#define CR4_RAM_BASE (0x180000) +/* 4335 GCI specific bits. */ +#define CC4335_GCI_STRAP_OVERRIDE_SFLASH_PRESENT (1 << 24) +#define CC4335_GCI_STRAP_OVERRIDE_SFLASH_TYPE 25 +#define CC4335_GCI_FUNC_SEL_PAD_SDIO 0x00707770 + +/* SFLASH clkdev specific bits. */ +#define CC4335_SFLASH_CLKDIV_MASK 0x1F000000 +#define CC4335_SFLASH_CLKDIV_SHIFT 25 + +/* 4335 OTP bits for SFLASH. */ +#define CC4335_SROM_OTP_SFLASH 40 +#define CC4335_SROM_OTP_SFLASH_PRESENT 0x1 +#define CC4335_SROM_OTP_SFLASH_TYPE 0x2 +#define CC4335_SROM_OTP_SFLASH_CLKDIV_MASK 0x003C +#define CC4335_SROM_OTP_SFLASH_CLKDIV_SHIFT 2 /* 4335 resources--END */ + +/* 4350 Chipcommon ChipStatus bits */ +#define CST4350_SDIO_MODE 0x00000001 +#define CST4350_HSIC20D_MODE 0x00000002 +#define CST4350_BP_ON_HSIC_CLK 0x00000004 +#define CST4350_PCIE_MODE 0x00000008 +#define CST4350_USB20D_MODE 0x00000010 +#define CST4350_USB30D_MODE 0x00000020 +#define CST4350_SPROM_PRESENT 0x00000040 +#define CST4350_RSRC_INIT_MODE_0 0x00000080 +#define CST4350_RSRC_INIT_MODE_1 0x00000100 +#define CST4350_SEL0_SDIO 0x00000200 +#define CST4350_SEL1_SDIO 0x00000400 +#define CST4350_SDIO_PAD_MODE 0x00000800 +#define CST4350_BBPLL_LOCKED 0x00001000 +#define CST4350_USBPLL_LOCKED 0x00002000 +#define CST4350_LINE_STATE 0x0000C000 +#define CST4350_SERDES_PIPE_PLLLOCK 0x00010000 +#define CST4350_BT_READY 0x00020000 +#define CST4350_SFLASH_PRESENT 0x00040000 +#define CST4350_CPULESS_ENABLE 0x00080000 +#define CST4350_STRAP_HOST_IFC_1 0x00100000 +#define CST4350_STRAP_HOST_IFC_2 0x00200000 +#define CST4350_STRAP_HOST_IFC_3 0x00400000 +#define CST4350_RAW_SPROM_PRESENT 0x00800000 +#define CST4350_APP_CLK_SWITCH_SEL_RDBACK 0x01000000 +#define CST4350_RAW_RSRC_INIT_MODE_0 0x02000000 +#define CST4350_SDIO_PAD_VDDIO 0x04000000 +#define CST4350_GSPI_MODE 0x08000000 +#define CST4350_PACKAGE_OPTION 0xF0000000 + +/* strap_host_ifc strap value */ +#define CST4350_HOST_IFC_MASK 0x00700000 +#define CST4350_HOST_IFC_SHIFT 20 + +/* host_ifc raw mode */ +#define CST4350_IFC_MODE_SDIOD 0x0 +#define CST4350_IFC_MODE_HSIC20D 0x1 +#define CST4350_IFC_MODE_HSIC30D 0x2 +#define CST4350_IFC_MODE_PCIE 0x3 +#define CST4350_IFC_MODE_USB20D 0x4 +#define CST4350_IFC_MODE_USB30D 0x5 +#define CST4350_IFC_MODE_USB30D_WL 0x6 +#define CST4350_IFC_MODE_USB30D_BT 0x7 + +#define CST4350_IFC_MODE(cs) ((cs & CST4350_HOST_IFC_MASK) >> CST4350_HOST_IFC_SHIFT) + +#define CST4350_CHIPMODE_SDIOD(cs) (CST4350_IFC_MODE(cs) == (CST4350_IFC_MODE_SDIOD)) +#define CST4350_CHIPMODE_USB20D(cs) ((CST4350_IFC_MODE(cs)) == (CST4350_IFC_MODE_USB20D)) +#define CST4350_CHIPMODE_HSIC20D(cs) (CST4350_IFC_MODE(cs) == (CST4350_IFC_MODE_HSIC20D)) +#define CST4350_CHIPMODE_HSIC30D(cs) (CST4350_IFC_MODE(cs) == (CST4350_IFC_MODE_HSIC30D)) +#define CST4350_CHIPMODE_USB30D(cs) (CST4350_IFC_MODE(cs) == (CST4350_IFC_MODE_USB30D)) +#define CST4350_CHIPMODE_USB30D_WL(cs) (CST4350_IFC_MODE(cs) == (CST4350_IFC_MODE_USB30D_WL)) +#define CST4350_CHIPMODE_PCIE(cs) (CST4350_IFC_MODE(cs) == (CST4350_IFC_MODE_PCIE)) + +/* 4350 PMU resources */ +#define RES4350_LPLDO_PU 0 +#define RES4350_PMU_BG_PU 1 +#define RES4350_PMU_SLEEP 2 +#define RES4350_RSVD_3 3 +#define RES4350_CBUCK_LPOM_PU 4 +#define RES4350_CBUCK_PFM_PU 5 +#define RES4350_COLD_START_WAIT 6 +#define RES4350_RSVD_7 7 +#define RES4350_LNLDO_PU 8 +#define RES4350_XTALLDO_PU 9 +#define RES4350_LDO3P3_PU 10 +#define RES4350_OTP_PU 11 +#define RES4350_XTAL_PU 12 +#define RES4350_SR_CLK_START 13 +#define RES4350_LQ_AVAIL 14 +#define RES4350_LQ_START 15 +#define RES4350_RSVD_16 16 +#define RES4350_WL_CORE_RDY 17 +#define RES4350_ILP_REQ 18 +#define RES4350_ALP_AVAIL 19 +#define RES4350_MINI_PMU 20 +#define RES4350_RADIO_PU 21 +#define RES4350_SR_CLK_STABLE 22 +#define RES4350_SR_SAVE_RESTORE 23 +#define RES4350_SR_PHY_PWRSW 24 +#define RES4350_SR_VDDM_PWRSW 25 +#define RES4350_SR_SUBCORE_PWRSW 26 +#define RES4350_SR_SLEEP 27 +#define RES4350_HT_START 28 +#define RES4350_HT_AVAIL 29 +#define RES4350_MACPHY_CLKAVAIL 30 + +#define MUXENAB4350_UART_MASK (0x0000000f) + +/* 4350 GCI function sel values */ +#define CC4350_FNSEL_HWDEF (0) +#define CC4350_FNSEL_SAMEASPIN (1) +#define CC4350_FNSEL_UART (2) +#define CC4350_FNSEL_SFLASH (3) +#define CC4350_FNSEL_SPROM (4) +#define CC4350_FNSEL_I2C (5) +#define CC4350_FNSEL_MISC0 (6) +#define CC4350_FNSEL_GCI (7) +#define CC4350_FNSEL_MISC1 (8) +#define CC4350_FNSEL_MISC2 (9) +#define CC4350_FNSEL_PWDOG (10) +#define CC4350_FNSEL_IND (12) +#define CC4350_FNSEL_PDN (13) +#define CC4350_FNSEL_PUP (14) +#define CC4350_FNSEL_TRISTATE (15) + +/* 4350 GPIO */ +#define CC4350_PIN_GPIO_00 (0) +#define CC4350_PIN_GPIO_01 (1) +#define CC4350_PIN_GPIO_02 (2) +#define CC4350_PIN_GPIO_03 (3) +#define CC4350_PIN_GPIO_04 (4) +#define CC4350_PIN_GPIO_05 (5) +#define CC4350_PIN_GPIO_06 (6) +#define CC4350_PIN_GPIO_07 (7) +#define CC4350_PIN_GPIO_08 (8) +#define CC4350_PIN_GPIO_09 (9) +#define CC4350_PIN_GPIO_10 (10) +#define CC4350_PIN_GPIO_11 (11) +#define CC4350_PIN_GPIO_12 (12) +#define CC4350_PIN_GPIO_13 (13) +#define CC4350_PIN_GPIO_14 (14) +#define CC4350_PIN_GPIO_15 (15) + +#define CC2_4350_MEMLPLDO_PWRSW_EN_MASK (1 << 21) +#define CC2_4350_MEMLPLDO_PWRSW_EN_SHIFT (21) +#define CC2_4350_SDIO_AOS_WAKEUP_MASK (1 << 24) +#define CC2_4350_SDIO_AOS_WAKEUP_SHIFT (24) + +/* Applies to 4335/4350/4345 */ +#define CC3_SR_CLK_SR_MEM_MASK (1 << 0) +#define CC3_SR_CLK_SR_MEM_SHIFT (0) +#define CC3_SR_BIT1_TBD_MASK (1 << 1) +#define CC3_SR_BIT1_TBD_SHIFT (1) +#define CC3_SR_ENGINE_ENABLE_MASK (1 << 2) +#define CC3_SR_ENGINE_ENABLE_SHIFT (2) +#define CC3_SR_BIT3_TBD_MASK (1 << 3) +#define CC3_SR_BIT3_TBD_SHIFT (3) +#define CC3_SR_MINDIV_FAST_CLK_MASK (0xF << 4) +#define CC3_SR_MINDIV_FAST_CLK_SHIFT (4) +#define CC3_SR_R23_SR2_RISE_EDGE_TRIG_MASK (1 << 8) +#define CC3_SR_R23_SR2_RISE_EDGE_TRIG_SHIFT (8) +#define CC3_SR_R23_SR2_FALL_EDGE_TRIG_MASK (1 << 9) +#define CC3_SR_R23_SR2_FALL_EDGE_TRIG_SHIFT (9) +#define CC3_SR_R23_SR_RISE_EDGE_TRIG_MASK (1 << 10) +#define CC3_SR_R23_SR_RISE_EDGE_TRIG_SHIFT (10) +#define CC3_SR_R23_SR_FALL_EDGE_TRIG_MASK (1 << 11) +#define CC3_SR_R23_SR_FALL_EDGE_TRIG_SHIFT (11) +#define CC3_SR_NUM_CLK_HIGH_MASK (0x7 << 12) +#define CC3_SR_NUM_CLK_HIGH_SHIFT (12) +#define CC3_SR_BIT15_TBD_MASK (1 << 15) +#define CC3_SR_BIT15_TBD_SHIFT (15) +#define CC3_SR_PHY_FUNC_PIC_MASK (1 << 16) +#define CC3_SR_PHY_FUNC_PIC_SHIFT (16) +#define CC3_SR_BIT17_19_TBD_MASK (0x7 << 17) +#define CC3_SR_BIT17_19_TBD_SHIFT (17) +#define CC3_SR_CHIP_TRIGGER_1_MASK (1 << 20) +#define CC3_SR_CHIP_TRIGGER_1_SHIFT (20) +#define CC3_SR_CHIP_TRIGGER_2_MASK (1 << 21) +#define CC3_SR_CHIP_TRIGGER_2_SHIFT (21) +#define CC3_SR_CHIP_TRIGGER_3_MASK (1 << 22) +#define CC3_SR_CHIP_TRIGGER_3_SHIFT (22) +#define CC3_SR_CHIP_TRIGGER_4_MASK (1 << 23) +#define CC3_SR_CHIP_TRIGGER_4_SHIFT (23) +#define CC3_SR_ALLOW_SBC_FUNC_PIC_MASK (1 << 24) +#define CC3_SR_ALLOW_SBC_FUNC_PIC_SHIFT (24) +#define CC3_SR_BIT25_26_TBD_MASK (0x3 << 25) +#define CC3_SR_BIT25_26_TBD_SHIFT (25) +#define CC3_SR_ALLOW_SBC_STBY_MASK (1 << 27) +#define CC3_SR_ALLOW_SBC_STBY_SHIFT (27) +#define CC3_SR_GPIO_MUX_MASK (0xF << 28) +#define CC3_SR_GPIO_MUX_SHIFT (28) + +/* Applies to 4335/4350/4345 */ +#define CC4_SR_INIT_ADDR_MASK (0x3FF0000) +#define CC4_4350_SR_ASM_ADDR (0x30) +#define CC4_4335_SR_ASM_ADDR (0x48) +#define CC4_SR_INIT_ADDR_SHIFT (16) + +#define CC4_4350_EN_SR_CLK_ALP_MASK (1 << 30) +#define CC4_4350_EN_SR_CLK_ALP_SHIFT (30) +#define CC4_4350_EN_SR_CLK_HT_MASK (1 << 31) +#define CC4_4350_EN_SR_CLK_HT_SHIFT (31) + +#define VREG4_4350_MEMLPDO_PU_MASK (1 << 31) +#define VREG4_4350_MEMLPDO_PU_SHIFT 31 + +#define CC6_4350_PCIE_CLKREQ_WAKEUP_MASK (1 << 4) +#define CC6_4350_PCIE_CLKREQ_WAKEUP_SHIFT (4) +#define CC6_4350_PMU_WAKEUP_ALPAVAIL_MASK (1 << 6) +#define CC6_4350_PMU_WAKEUP_ALPAVAIL_SHIFT (6) + /* GCI chipcontrol register indices */ #define CC_GCI_CHIPCTRL_00 (0) #define CC_GCI_CHIPCTRL_01 (1) @@ -2253,6 +2720,9 @@ typedef volatile struct { #define CC_GCI_CHIPCTRL_07 (7) #define CC_GCI_CHIPCTRL_08 (8) +#define CC_GCI_06_JTAG_SEL_SHIFT 4 +#define CC_GCI_06_JTAG_SEL_MASK (1 << 4) + #define CC_GCI_NUMCHIPCTRLREGS(cap1) ((cap1 & 0xF00) >> 8) /* 4335 pins @@ -2321,6 +2791,11 @@ typedef volatile struct { */ #define MUXENAB4335_UART_MASK (0x0000000f) +#define MUXENAB4335_UART_SHIFT 0 +#define MUXENAB4335_HOSTWAKE_MASK (0x000000f0) /* configure GPIO for SDIO host_wake */ +#define MUXENAB4335_HOSTWAKE_SHIFT 4 +#define MUXENAB4335_GETIX(val, name) \ + ((((val) & MUXENAB4335_ ## name ## _MASK) >> MUXENAB4335_ ## name ## _SHIFT) - 1) /* defines to detect active host interface in use */ #define CHIP_HOSTIF_USB(sih) (si_chip_hostif(sih) & CST4360_MODE_USB) diff --git a/drivers/net/wireless/bcmdhd/include/sbconfig.h b/drivers/net/wireless/bcmdhd/include/sbconfig.h index 73ddadd4778a..84c98f2006cc 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/sbconfig.h +++ b/drivers/net/wireless/bcmdhd/include/sbconfig.h @@ -1,7 +1,7 @@ /* * Broadcom SiliconBackplane hardware register definitions. * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd/include/sbhnddma.h b/drivers/net/wireless/bcmdhd/include/sbhnddma.h index 40ebd8a85c2d..e27d98c5d148 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/sbhnddma.h +++ b/drivers/net/wireless/bcmdhd/include/sbhnddma.h @@ -2,7 +2,7 @@ * Generic Broadcom Home Networking Division (HND) DMA engine HW interface * This supports the following chips: BCM42xx, 44xx, 47xx . * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -22,7 +22,7 @@ * 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: sbhnddma.h 309193 2012-01-19 00:03:57Z $ + * $Id: sbhnddma.h 373617 2012-12-07 23:03:08Z $ */ #ifndef _sbhnddma_h_ @@ -247,10 +247,33 @@ typedef volatile struct { */ #define D64RINGALIGN_BITS 13 #define D64MAXRINGSZ (1 << D64RINGALIGN_BITS) -#define D64RINGALIGN (1 << D64RINGALIGN_BITS) +#define D64RINGBOUNDARY (1 << D64RINGALIGN_BITS) #define D64MAXDD (D64MAXRINGSZ / sizeof (dma64dd_t)) +/* for cores with large descriptor ring support, descriptor ring size can be up to 4096 */ +#define D64MAXDD_LARGE ((1 << 16) / sizeof (dma64dd_t)) + +/* for cores with large descriptor ring support (4k descriptors), descriptor ring cannot cross + * 64K boundary + */ +#define D64RINGBOUNDARY_LARGE (1 << 16) + +/* + * Default DMA Burstlen values for USBRev >= 12 and SDIORev >= 11. + * When this field contains the value N, the burst length is 2**(N + 4) bytes. + */ +#define D64_DEF_USBBURSTLEN 2 +#define D64_DEF_SDIOBURSTLEN 1 + + +#ifndef D64_USBBURSTLEN +#define D64_USBBURSTLEN DMA_BL_64 +#endif +#ifndef D64_SDIOBURSTLEN +#define D64_SDIOBURSTLEN DMA_BL_32 +#endif + /* transmit channel control */ #define D64_XC_XE 0x00000001 /* transmit enable */ #define D64_XC_SE 0x00000002 /* transmit suspend request */ @@ -272,7 +295,7 @@ typedef volatile struct { #define D64_XP_LD_MASK 0x00001fff /* last valid descriptor */ /* transmit channel status */ -#define D64_XS0_CD_MASK 0x00001fff /* current descriptor pointer */ +#define D64_XS0_CD_MASK (di->d64_xs0_cd_mask) /* current descriptor pointer */ #define D64_XS0_XS_MASK 0xf0000000 /* transmit state */ #define D64_XS0_XS_SHIFT 28 #define D64_XS0_XS_DISABLED 0x00000000 /* disabled */ @@ -281,7 +304,7 @@ typedef volatile struct { #define D64_XS0_XS_STOPPED 0x30000000 /* stopped */ #define D64_XS0_XS_SUSP 0x40000000 /* suspend pending */ -#define D64_XS1_AD_MASK 0x00001fff /* active descriptor */ +#define D64_XS1_AD_MASK (di->d64_xs1_ad_mask) /* active descriptor */ #define D64_XS1_XE_MASK 0xf0000000 /* transmit errors */ #define D64_XS1_XE_SHIFT 28 #define D64_XS1_XE_NOERR 0x00000000 /* no error */ @@ -299,6 +322,7 @@ typedef volatile struct { #define D64_RC_SH 0x00000200 /* separate rx header descriptor enable */ #define D64_RC_OC 0x00000400 /* overflow continue */ #define D64_RC_PD 0x00000800 /* parity check disable */ +#define D64_RC_GE 0x00004000 /* Glom enable */ #define D64_RC_AE 0x00030000 /* address extension bits */ #define D64_RC_AE_SHIFT 16 #define D64_RC_BL_MASK 0x001C0000 /* BurstLen bits */ @@ -320,7 +344,7 @@ typedef volatile struct { #define D64_RP_LD_MASK 0x00001fff /* last valid descriptor */ /* receive channel status */ -#define D64_RS0_CD_MASK 0x00001fff /* current descriptor pointer */ +#define D64_RS0_CD_MASK (di->d64_rs0_cd_mask) /* current descriptor pointer */ #define D64_RS0_RS_MASK 0xf0000000 /* receive state */ #define D64_RS0_RS_SHIFT 28 #define D64_RS0_RS_DISABLED 0x00000000 /* disabled */ diff --git a/drivers/net/wireless/bcmdhd/include/sbpcmcia.h b/drivers/net/wireless/bcmdhd/include/sbpcmcia.h index c4e9d4631fcb..a6e999f30e2d 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/sbpcmcia.h +++ b/drivers/net/wireless/bcmdhd/include/sbpcmcia.h @@ -1,7 +1,7 @@ /* * BCM43XX Sonics SiliconBackplane PCMCIA core hardware definitions. * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -21,7 +21,7 @@ * 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: sbpcmcia.h 326494 2012-04-09 13:29:57Z $ + * $Id: sbpcmcia.h 381094 2013-01-25 04:45:06Z $ */ #ifndef _SBPCMCIA_H diff --git a/drivers/net/wireless/bcmdhd/include/sbsdio.h b/drivers/net/wireless/bcmdhd/include/sbsdio.h index 8d0139d26411..7ce795ac696d 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/sbsdio.h +++ b/drivers/net/wireless/bcmdhd/include/sbsdio.h @@ -4,7 +4,7 @@ * * SDIO core support 1bit, 4 bit SDIO mode as well as SPI mode. * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -24,7 +24,7 @@ * 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: sbsdio.h 361940 2012-10-10 08:32:12Z $ + * $Id: sbsdio.h 383835 2013-02-07 23:32:39Z $ */ #ifndef _SBSDIO_H @@ -101,6 +101,7 @@ * => busy signal is asserted between data blocks. */ #define SBSDIO_MESBUSYCTRL_MASK 0x7f +#define SBSDIO_MESBUSYCTRL_ENAB 0x80 /* Enable busy capability for MES access */ /* SBSDIO_DEVICE_CTL */ #define SBSDIO_DEVCTL_SETBUSY 0x01 /* 1: device will assert busy signal when @@ -116,12 +117,9 @@ * external pads in tri-state; requires * sdio bus power cycle to clear (rev 9) */ -#define SBSDIO_DEVCTL_SB_RST_CTL 0x30 /* Force SD->SB reset mapping (rev 11) */ -#define SBSDIO_DEVCTL_RST_CORECTL 0x00 /* Determined by CoreControl bit */ -#define SBSDIO_DEVCTL_RST_BPRESET 0x10 /* Force backplane reset */ -#define SBSDIO_DEVCTL_RST_NOBPRESET 0x20 /* Force no backplane reset */ #define SBSDIO_DEVCTL_EN_F2_BLK_WATERMARK 0x10 /* Enable function 2 tx for each block */ - +#define SBSDIO_DEVCTL_F2WM_ENAB 0x10 /* Enable F2 Watermark */ +#define SBSDIO_DEVCTL_NONDAT_PADS_ISO 0x20 /* Isolate sdio clk and cmd (non-data) */ /* SBSDIO_FUNC1_CHIPCLKCSR */ #define SBSDIO_FORCE_ALP 0x01 /* Force ALP request to backplane */ diff --git a/drivers/net/wireless/bcmdhd/include/sbsdpcmdev.h b/drivers/net/wireless/bcmdhd/include/sbsdpcmdev.h index 10c7401a81c1..f655eeb139eb 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/sbsdpcmdev.h +++ b/drivers/net/wireless/bcmdhd/include/sbsdpcmdev.h @@ -2,7 +2,7 @@ * Broadcom SiliconBackplane SDIO/PCMCIA hardware-specific * device core support * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -22,7 +22,7 @@ * 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: sbsdpcmdev.h 347614 2012-07-27 10:24:51Z $ + * $Id: sbsdpcmdev.h 336848 2012-06-05 11:28:07Z $ */ #ifndef _sbsdpcmdev_h_ diff --git a/drivers/net/wireless/bcmdhd/include/sbsocram.h b/drivers/net/wireless/bcmdhd/include/sbsocram.h index 6455f2b535e1..8f4e7545cc47 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/sbsocram.h +++ b/drivers/net/wireless/bcmdhd/include/sbsocram.h @@ -1,7 +1,7 @@ /* * BCM47XX Sonics SiliconBackplane embedded ram core * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd/include/sdio.h b/drivers/net/wireless/bcmdhd/include/sdio.h index b8eee1ffb405..0c0dc472cbff 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/sdio.h +++ b/drivers/net/wireless/bcmdhd/include/sdio.h @@ -2,7 +2,7 @@ * SDIO spec header file * Protocol and standard (common) device definitions * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd/include/sdioh.h b/drivers/net/wireless/bcmdhd/include/sdioh.h index 5517a7185079..80cef235eccf 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/sdioh.h +++ b/drivers/net/wireless/bcmdhd/include/sdioh.h @@ -2,7 +2,7 @@ * SDIO Host Controller Spec header file * Register map and definitions for the Standard Host Controller * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -22,7 +22,7 @@ * 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: sdioh.h 347633 2012-07-27 11:02:02Z $ + * $Id: sdioh.h 345499 2012-07-18 06:59:05Z $ */ #ifndef _SDIOH_H @@ -90,8 +90,8 @@ #define SD3_PresetVal_SDR104 0x06c #define SD3_PresetVal_DDR50 0x06e /* SDIO3.0 Revx specific Registers */ -#define SD3_Tuning_Info_Register 0x0EC -#define SD3_WL_BT_reset_register 0x0F0 +#define SD3_Tuning_Info_Register 0x0EC +#define SD3_WL_BT_reset_register 0x0F0 /* preset value indices */ diff --git a/drivers/net/wireless/bcmdhd/include/sdiovar.h b/drivers/net/wireless/bcmdhd/include/sdiovar.h index 83f82de26497..7be782889d9f 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/sdiovar.h +++ b/drivers/net/wireless/bcmdhd/include/sdiovar.h @@ -2,7 +2,7 @@ * Structure used by apps whose drivers access SDIO drivers. * Pulled out separately so dhdu and wlu can both use it. * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd/include/siutils.h b/drivers/net/wireless/bcmdhd/include/siutils.h index acc72ee81539..4d114f1b20d1 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/siutils.h +++ b/drivers/net/wireless/bcmdhd/include/siutils.h @@ -2,7 +2,7 @@ * Misc utility routines for accessing the SOC Interconnects * of Broadcom HNBU chips. * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -22,7 +22,7 @@ * 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: siutils.h 347614 2012-07-27 10:24:51Z $ + * $Id: siutils.h 385510 2013-02-15 21:02:07Z $ */ #ifndef _siutils_h_ @@ -160,6 +160,7 @@ extern bool si_pci_war16165(si_t *sih); extern uint si_corelist(si_t *sih, uint coreid[]); extern uint si_coreid(si_t *sih); extern uint si_flag(si_t *sih); +extern uint si_flag_alt(si_t *sih); extern uint si_intflag(si_t *sih); extern uint si_coreidx(si_t *sih); extern uint si_coreunit(si_t *sih); @@ -170,6 +171,8 @@ extern void si_setosh(si_t *sih, osl_t *osh); extern uint si_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val); extern void *si_coreregs(si_t *sih); extern uint si_wrapperreg(si_t *sih, uint32 offset, uint32 mask, uint32 val); +extern uint si_core_wrapperreg(si_t *sih, uint32 coreidx, uint32 offset, uint32 mask, uint32 val); +extern void *si_wrapperregs(si_t *sih); extern uint32 si_core_cflags(si_t *sih, uint32 mask, uint32 val); extern void si_core_cflags_wo(si_t *sih, uint32 mask, uint32 val); extern uint32 si_core_sflags(si_t *sih, uint32 mask, uint32 val); @@ -187,6 +190,7 @@ extern int si_corebist(si_t *sih); extern void si_core_reset(si_t *sih, uint32 bits, uint32 resetbits); extern void si_core_disable(si_t *sih, uint32 bits); extern uint32 si_clock_rate(uint32 pll_type, uint32 n, uint32 m); +extern uint si_chip_hostif(si_t *sih); extern bool si_read_pmu_autopll(si_t *sih); extern uint32 si_clock(si_t *sih); extern uint32 si_alp_clock(si_t *sih); @@ -258,6 +262,8 @@ static INLINE void * si_eci_init(si_t *sih) {return NULL;} #define si_seci_upd(sih, a) do {} while (0) static INLINE void * si_seci_init(si_t *sih, uint8 use_seci) {return NULL;} #define si_seci_down(sih) do {} while (0) +#define si_gci(sih) 0 +static INLINE void * si_gci_init(si_t *sih) {return NULL;} /* OTP status */ extern bool si_is_otp_disabled(si_t *sih); @@ -297,6 +303,8 @@ extern char *si_coded_devpathvar(si_t *sih, char *varname, int var_len, const ch extern uint8 si_pcieclkreq(si_t *sih, uint32 mask, uint32 val); extern uint32 si_pcielcreg(si_t *sih, uint32 mask, uint32 val); +extern uint8 si_pcieltrenable(si_t *sih, uint32 mask, uint32 val); +extern void si_pcie_set_error_injection(si_t *sih, uint32 mode); extern void si_war42780_clkreq(si_t *sih, bool clkreq); extern void si_pci_down(si_t *sih); extern void si_pci_up(si_t *sih); @@ -320,6 +328,7 @@ extern void si_btc_enable_chipcontrol(si_t *sih); extern void si_btcombo_p250_4313_war(si_t *sih); extern void si_btcombo_43228_war(si_t *sih); extern void si_clk_pmu_htavail_set(si_t *sih, bool set_clear); +extern void si_pmu_synth_pwrsw_4313_war(si_t *sih); extern uint si_pll_reset(si_t *sih); /* === debug routines === */ @@ -327,10 +336,13 @@ extern bool si_taclear(si_t *sih, bool details); +extern uint32 si_ccreg(si_t *sih, uint32 offset, uint32 mask, uint32 val); extern uint32 si_pciereg(si_t *sih, uint32 offset, uint32 mask, uint32 val, uint type); extern uint32 si_pcieserdesreg(si_t *sih, uint32 mdioslave, uint32 offset, uint32 mask, uint32 val); extern void si_pcie_set_request_size(si_t *sih, uint16 size); extern uint16 si_pcie_get_request_size(si_t *sih); +extern void si_pcie_set_maxpayload_size(si_t *sih, uint16 size); +extern uint16 si_pcie_get_maxpayload_size(si_t *sih); extern uint16 si_pcie_get_ssid(si_t *sih); extern uint32 si_pcie_get_bar0(si_t *sih); extern int si_pcie_configspace_cache(si_t *sih); @@ -344,4 +356,27 @@ extern uint32 si_tcm_size(si_t *sih); extern int si_set_sromctl(si_t *sih, uint32 value); extern uint32 si_get_sromctl(si_t *sih); + +extern uint32 si_gci_direct(si_t *sih, uint offset, uint32 mask, uint32 val); +extern void si_gci_reset(si_t *sih); +extern void si_gci_set_functionsel(si_t *sih, uint32 pin, uint8 fnsel); +extern uint8 si_gci_get_chipctrlreg_idx(uint32 pin, uint32 *regidx, uint32 *pos); +extern uint32 si_gci_chipcontrol(si_t *sih, uint reg, uint32 mask, uint32 val); + +#define CHIPCTRLREG2 0x2 +#define CHIPCTRLREG3 0x3 +#define CHIPCTRLREG4 0x4 +#define MINRESMASKREG 0x618 +#define CHIPCTRLADDR 0x650 +#define CHIPCTRLDATA 0x654 +#define RSRCTABLEADDR 0x620 +#define RSRCUPDWNTIME 0x628 +#define PMUREG_RESREQ_MASK 0x68c + +void +si_update_masks(si_t *sih); + +void +si_force_islanding(si_t *sih, bool enable); + #endif /* _siutils_h_ */ diff --git a/drivers/net/wireless/bcmdhd/include/trxhdr.h b/drivers/net/wireless/bcmdhd/include/trxhdr.h index bf92a5651af0..84bd1aecb4f1 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/trxhdr.h +++ b/drivers/net/wireless/bcmdhd/include/trxhdr.h @@ -1,7 +1,7 @@ /* * TRX image file header format. * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -21,7 +21,7 @@ * 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: trxhdr.h 260898 2011-05-20 23:11:12Z $ + * $Id: trxhdr.h 349211 2012-08-07 09:45:24Z $ */ #ifndef _TRX_HDR_H @@ -30,23 +30,62 @@ #include <typedefs.h> #define TRX_MAGIC 0x30524448 /* "HDR0" */ -#define TRX_VERSION 1 /* Version 1 */ #define TRX_MAX_LEN 0x3B0000 /* Max length */ #define TRX_NO_HEADER 1 /* Do not write TRX header */ #define TRX_GZ_FILES 0x2 /* Contains up to TRX_MAX_OFFSET individual gzip files */ #define TRX_EMBED_UCODE 0x8 /* Trx contains embedded ucode image */ #define TRX_ROMSIM_IMAGE 0x10 /* Trx contains ROM simulation image */ #define TRX_UNCOMP_IMAGE 0x20 /* Trx contains uncompressed rtecdc.bin image */ -#define TRX_MAX_OFFSET 3 /* Max number of individual files */ +#define TRX_BOOTLOADER 0x40 /* the image is a bootloader */ +#define TRX_V1 1 +#define TRX_V1_MAX_OFFSETS 3 /* V1: Max number of individual files */ + +#ifndef BCMTRXV2 +#define TRX_VERSION TRX_V1 /* Version 1 */ +#define TRX_MAX_OFFSET TRX_V1_MAX_OFFSETS +#endif + +/* BMAC Host driver/application like bcmdl need to support both Ver 1 as well as + * Ver 2 of trx header. To make it generic, trx_header is structure is modified + * as below where size of "offsets" field will vary as per the TRX version. + * Currently, BMAC host driver and bcmdl are modified to support TRXV2 as well. + * To make sure, other applications like "dhdl" which are yet to be enhanced to support + * TRXV2 are not broken, new macro and structure defintion take effect only when BCMTRXV2 + * is defined. + */ struct trx_header { uint32 magic; /* "HDR0" */ uint32 len; /* Length of file including header */ uint32 crc32; /* 32-bit CRC from flag_version to end of file */ uint32 flag_version; /* 0:15 flags, 16:31 version */ +#ifndef BCMTRXV2 uint32 offsets[TRX_MAX_OFFSET]; /* Offsets of partitions from start of header */ +#else + uint32 offsets[1]; /* Offsets of partitions from start of header */ +#endif }; +#ifdef BCMTRXV2 +#define TRX_VERSION TRX_V2 /* Version 2 */ +#define TRX_MAX_OFFSET TRX_V2_MAX_OFFSETS + +#define TRX_V2 2 +/* V2: Max number of individual files + * To support SDR signature + Config data region + */ +#define TRX_V2_MAX_OFFSETS 5 +#define SIZEOF_TRXHDR_V1 (sizeof(struct trx_header)+(TRX_V1_MAX_OFFSETS-1)*sizeof(uint32)) +#define SIZEOF_TRXHDR_V2 (sizeof(struct trx_header)+(TRX_V2_MAX_OFFSETS-1)*sizeof(uint32)) +#define TRX_VER(trx) (trx->flag_version>>16) +#define ISTRX_V1(trx) (TRX_VER(trx) == TRX_V1) +#define ISTRX_V2(trx) (TRX_VER(trx) == TRX_V2) +/* For V2, return size of V2 size: others, return V1 size */ +#define SIZEOF_TRX(trx) (ISTRX_V2(trx) ? SIZEOF_TRXHDR_V2: SIZEOF_TRXHDR_V1) +#else +#define SIZEOF_TRX(trx) (sizeof(struct trx_header)) +#endif /* BCMTRXV2 */ + /* Compatibility */ typedef struct trx_header TRXHDR, *PTRXHDR; diff --git a/drivers/net/wireless/bcmdhd/include/typedefs.h b/drivers/net/wireless/bcmdhd/include/typedefs.h index fe1d16280711..61627bc9b04a 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/typedefs.h +++ b/drivers/net/wireless/bcmdhd/include/typedefs.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -18,7 +18,7 @@ * 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: typedefs.h 286783 2011-09-29 06:18:57Z $ + * $Id: typedefs.h 397286 2013-04-18 01:42:19Z $ */ #ifndef _TYPEDEFS_H_ @@ -81,6 +81,7 @@ typedef long unsigned int size_t; + #if defined(__sparc__) #define TYPEDEF_ULONG #endif @@ -121,7 +122,7 @@ typedef long unsigned int size_t; #if defined(__GNUC__) && defined(__STRICT_ANSI__) #define TYPEDEF_INT64 #define TYPEDEF_UINT64 -#endif +#endif /* defined(__GNUC__) && defined(__STRICT_ANSI__) */ /* ICL accepts unsigned 64 bit type only, and complains in ANSI mode * for signed or unsigned diff --git a/drivers/net/wireless/bcmdhd/include/wlfc_proto.h b/drivers/net/wireless/bcmdhd/include/wlfc_proto.h index 6b421b5df653..0f94ee211048 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/wlfc_proto.h +++ b/drivers/net/wireless/bcmdhd/include/wlfc_proto.h @@ -1,5 +1,5 @@ /* -* Copyright (C) 1999-2012, Broadcom Corporation +* Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -18,7 +18,7 @@ * 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: wlfc_proto.h 361006 2012-10-05 07:45:51Z $ +* $Id: wlfc_proto.h 381382 2013-01-27 07:13:00Z $ * */ #ifndef __wlfc_proto_definitions_h__ @@ -34,7 +34,8 @@ --------------------------------------------------------------------------- | 3 | 2 | (count, handle, prec_bmp)| Set the credit depth for a MAC dstn --------------------------------------------------------------------------- - | 4 | 4 | see pkttag comments | TXSTATUS + | 4 | 4+ | see pkttag comments | TXSTATUS + | | | TX status & timestamps | Present only when pkt timestamp is enabled --------------------------------------------------------------------------- | 5 | 4 | see pkttag comments | PKKTTAG [host->firmware] --------------------------------------------------------------------------- @@ -62,11 +63,9 @@ | 13 | 3 | (count, handle, prec_bmp)| One time request for packet to a specific | | | | MAC destination. --------------------------------------------------------------------------- - | 15 | 1 | interface ID | NIC period start + | 15 | 12 | (pkttag, timestamps) | Send TX timestamp at reception from host --------------------------------------------------------------------------- - | 16 | 1 | interface ID | NIC period end - --------------------------------------------------------------------------- - | 17 | 3 | (ifid, txs) | Action frame tx status + | 16 | 12 | (pkttag, timestamps) | Send WLAN RX timestamp along with RX frame --------------------------------------------------------------------------- | 255 | N/A | N/A | FILLER - This is a special type | | | | that has no length or value. @@ -82,7 +81,7 @@ #define WLFC_CTL_TYPE_MACDESC_ADD 6 #define WLFC_CTL_TYPE_MACDESC_DEL 7 -#define WLFC_CTL_TYPE_RSSI 8 +#define WLFC_CTL_TYPE_RSSI 8 #define WLFC_CTL_TYPE_INTERFACE_OPEN 9 #define WLFC_CTL_TYPE_INTERFACE_CLOSE 10 @@ -93,11 +92,12 @@ #define WLFC_CTL_TYPE_MAC_REQUEST_PACKET 13 #define WLFC_CTL_TYPE_HOST_REORDER_RXPKTS 14 -#define WLFC_CTL_TYPE_NIC_PRD_START 15 -#define WLFC_CTL_TYPE_NIC_PRD_END 16 -#define WLFC_CTL_TYPE_AF_TXS 17 -#define WLFC_CTL_TYPE_TRANS_ID 18 -#define WLFC_CTL_TYPE_COMP_TXSTATUS 19 +#define WLFC_CTL_TYPE_TX_ENTRY_STAMP 15 +#define WLFC_CTL_TYPE_RX_STAMP 16 + +#define WLFC_CTL_TYPE_TRANS_ID 18 +#define WLFC_CTL_TYPE_COMP_TXSTATUS 19 + #define WLFC_CTL_TYPE_FILLER 255 @@ -118,10 +118,6 @@ #define WLFC_CTL_VALUE_LEN_REQUEST_CREDIT 3 /* credit, MAC-handle, prec_bitmap */ #define WLFC_CTL_VALUE_LEN_REQUEST_PACKET 3 /* credit, MAC-handle, prec_bitmap */ -#define WLFC_CTL_VALUE_LEN_NIC_PRD_START 1 -#define WLFC_CTL_VALUE_LEN_NIC_PRD_END 1 -#define WLFC_CTL_VALUE_LEN_AF_TXS 3 - #define WLFC_PKTID_GEN_MASK 0x80000000 #define WLFC_PKTID_GEN_SHIFT 31 @@ -227,7 +223,8 @@ #define WLHOST_REORDERDATA_CURIDX_VALID 0x04 #define WLHOST_REORDERDATA_EXPIDX_VALID 0x08 #define WLHOST_REORDERDATA_NEW_HOLE 0x10 + /* transaction id data len byte 0: rsvd, byte 1: seqnumber, byte 2-5 will be used for timestampe */ -#define WLFC_CTL_TRANS_ID_LEN 6 +#define WLFC_CTL_TRANS_ID_LEN 6 #endif /* __wlfc_proto_definitions_h__ */ diff --git a/drivers/net/wireless/bcmdhd/include/wlioctl.h b/drivers/net/wireless/bcmdhd/include/wlioctl.h index 59c9202059b0..50f98790dbec 100644..100755 --- a/drivers/net/wireless/bcmdhd/include/wlioctl.h +++ b/drivers/net/wireless/bcmdhd/include/wlioctl.h @@ -4,7 +4,7 @@ * * Definitions subject to change without notice. * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -24,7 +24,7 @@ * 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: wlioctl.h 384902 2013-02-13 14:26:49Z $ + * $Id: wlioctl.h 432432 2013-10-28 15:52:47Z $ */ #ifndef _wlioctl_h_ @@ -32,6 +32,7 @@ #include <typedefs.h> #include <proto/ethernet.h> +#include <proto/bcmip.h> #include <proto/bcmeth.h> #include <proto/bcmevent.h> #include <proto/802.11.h> @@ -63,6 +64,12 @@ typedef struct remote_ioctl { } rem_ioctl_t; #define REMOTE_SIZE sizeof(rem_ioctl_t) + +typedef struct { + uint32 num; + chanspec_t list[1]; +} chanspec_list_t; + #define ACTION_FRAME_SIZE 1800 typedef struct wl_action_frame { @@ -209,8 +216,8 @@ typedef struct wl_bss_info { uint32 nbss_cap; /* 802.11N+AC BSS Capabilities */ uint8 ctl_ch; /* 802.11N BSS control channel number */ uint8 padding1[3]; /* explicit struct alignment padding */ - uint16 vht_rxmcsmap; /* VHT rx mcs map */ - uint16 vht_txmcsmap; /* VHT tx mcs map */ + uint16 vht_rxmcsmap; /* VHT rx mcs map (802.11ac VHT_CAP_MCS_MAP_*) */ + uint16 vht_txmcsmap; /* VHT tx mcs map (802.11ac VHT_CAP_MCS_MAP_*) */ uint8 flags; /* flags */ uint8 vht_cap; /* BSS is vht capable */ uint8 reserved[2]; /* Reserved for expansion of BSS properties */ @@ -358,6 +365,8 @@ typedef struct wl_extdscan_params { #define WL_SCANFLAGS_PASSIVE 0x01 /* force passive scan */ #define WL_SCANFLAGS_RESERVED 0x02 /* Reserved */ #define WL_SCANFLAGS_PROHIBITED 0x04 /* allow scanning prohibited channels */ +#define WL_SCANFLAGS_OFFCHAN 0x08 /* allow scanning/reporting off-channel APs */ +#define WL_SCANFLAGS_HOTSPOT 0x10 /* automatic ANQP to hotspot APs */ #define WL_SCAN_PARAMS_SSID_MAX 10 @@ -490,6 +499,7 @@ typedef struct wl_rateset_args { uint32 count; /* # rates in this set */ uint8 rates[WL_MAXRATES_IN_SET]; /* rates in 500kbps units w/hi bit set if basic */ uint8 mcs[MCSSET_LEN]; /* supported mcs index bit map */ + uint16 vht_mcs[VHT_CAP_MCS_MAP_NSS_MAX]; /* supported mcs index bit map per nss */ } wl_rateset_args_t; /* uint32 list */ @@ -503,10 +513,10 @@ typedef struct wl_uint32_list { /* used for association with a specific BSSID and chanspec list */ typedef struct wl_assoc_params { struct ether_addr bssid; /* 00:00:00:00:00:00: broadcast scan */ - uint16 bssid_cnt; /* 0: use chanspec_num, and the single bssid, - * otherwise count of chanspecs in chanspec_list - * AND paired bssids following chanspec_list - */ + uint16 bssid_cnt; /* 0: use chanspec_num, and the single bssid, + * otherwise count of chanspecs in chanspec_list + * AND paired bssids following chanspec_list + */ int32 chanspec_num; /* 0: all available channels, * otherwise count of chanspecs in chanspec_list */ @@ -595,6 +605,7 @@ typedef struct wl_extjoin_params { #define WL_RSPEC_BW_MASK 0x00070000 /* bandwidth mask */ #define WL_RSPEC_BW_SHIFT 16 /* bandwidth shift */ #define WL_RSPEC_STBC 0x00100000 /* STBC encoding, Nsts = 2 x Nss */ +#define WL_RSPEC_TXBF 0x00200000 /* bit indicates TXBF mode */ #define WL_RSPEC_LDPC 0x00400000 /* bit indicates adv coding in use */ #define WL_RSPEC_SGI 0x00800000 /* Short GI mode */ #define WL_RSPEC_ENCODING_MASK 0x03000000 /* Encoding of Rate/MCS field */ @@ -847,8 +858,16 @@ typedef enum sup_auth_status { #define CRYPTO_ALGO_AES_CCM 4 #define CRYPTO_ALGO_AES_OCB_MSDU 5 #define CRYPTO_ALGO_AES_OCB_MPDU 6 +#if !defined(BCMEXTCCX) #define CRYPTO_ALGO_NALG 7 +#else +#define CRYPTO_ALGO_CKIP 7 +#define CRYPTO_ALGO_CKIP_MMH 8 +#define CRYPTO_ALGO_WEP_MMH 9 +#define CRYPTO_ALGO_NALG 10 +#endif #define CRYPTO_ALGO_PMK 12 /* for 802.1x supp to set PMK before 4-way */ +#define CRYPTO_ALGO_BIP 13 /* 802.11w BIP (aes cmac) */ #define WSEC_GEN_MIC_ERROR 0x0001 #define WSEC_GEN_REPLAY 0x0002 @@ -859,8 +878,13 @@ typedef enum sup_auth_status { #define WL_SOFT_KEY (1 << 0) /* Indicates this key is using soft encrypt */ #define WL_PRIMARY_KEY (1 << 1) /* Indicates this key is the primary (ie tx) key */ +#if defined(BCMEXTCCX) +#define WL_CKIP_KP (1 << 4) /* CMIC */ +#define WL_CKIP_MMH (1 << 5) /* CKIP */ +#else #define WL_KF_RES_4 (1 << 4) /* Reserved for backward compat */ #define WL_KF_RES_5 (1 << 5) /* Reserved for backward compat */ +#endif #define WL_IBSS_PEER_GROUP_KEY (1 << 6) /* Indicates a group key for a IBSS PEER */ typedef struct wl_wsec_key { @@ -911,17 +935,19 @@ typedef struct { #define WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED)) #define WSEC_SES_OW_ENABLED(wsec) ((wsec) & SES_OW_ENABLED) -#ifdef MFP #define MFP_CAPABLE 0x0200 #define MFP_REQUIRED 0x0400 #define MFP_SHA256 0x0800 /* a special configuration for STA for WIFI test tool */ -#endif /* MFP */ /* WPA authentication mode bitvec */ #define WPA_AUTH_DISABLED 0x0000 /* Legacy (i.e., non-WPA) */ #define WPA_AUTH_NONE 0x0001 /* none (IBSS) */ #define WPA_AUTH_UNSPECIFIED 0x0002 /* over 802.1x */ #define WPA_AUTH_PSK 0x0004 /* Pre-shared key */ +#if defined(BCMEXTCCX) +#define WPA_AUTH_CCKM 0x0008 /* CCKM */ +#define WPA2_AUTH_CCKM 0x0010 /* CCKM2 */ +#endif /* #define WPA_AUTH_8021X 0x0020 */ /* 802.1x, reserved */ #define WPA2_AUTH_UNSPECIFIED 0x0040 /* over 802.1x */ #define WPA2_AUTH_PSK 0x0080 /* Pre-shared key */ @@ -1030,6 +1056,32 @@ typedef struct wme_tx_params_s wme_tx_params_t; #define WL_WME_TX_PARAMS_IO_BYTES (sizeof(wme_tx_params_t) * AC_COUNT) +typedef struct wl_plc_nodelist { + uint count; /* Number of nodes */ + struct _node { + struct ether_addr ea; /* Node ether address */ + uint32 node_type; /* Node type */ + uint32 cost; /* PLC affinity */ + } node[1]; +} wl_plc_nodelist_t; + +typedef struct wl_plc_params { + uint32 cmd; /* Command */ + bool plc_failover; /* PLC failover control/status */ + struct ether_addr node_ea; /* Node ether address */ + uint32 cost; /* Link cost or mac cost */ +} wl_plc_params_t; + +#define PLC_CMD_FAILOVER 1 +#define PLC_CMD_MAC_COST 2 +#define PLC_CMD_LINK_COST 3 +#define PLC_CMD_NODE_LIST 4 + +#define NODE_TYPE_UNKNOWN 0 /* Unknown link */ +#define NODE_TYPE_WIFI_ONLY 1 /* Pure Wireless STA node */ +#define NODE_TYPE_PLC_ONLY 2 /* Pure PLC only node */ +#define NODE_TYPE_WIFI_PLC 3 /* WiFi PLC capable node */ + /* defines used by poweridx iovar - it controls power in a-band */ /* current gain setting is maintained */ #define WL_PWRIDX_PCL_OFF -2 /* turn off PCL. */ @@ -1175,7 +1227,7 @@ typedef struct { /* Get MAC rate histogram response */ typedef struct { - uint32 rate[WLC_MAXRATE + 1]; /* Rates */ + uint32 rate[DOT11_RATE_MAX + 1]; /* Rates */ uint32 mcs[WL_RATESET_SZ_HT_MCS * WL_TX_CHAINS_MAX]; /* MCS counts */ uint32 vht[WL_RATESET_SZ_VHT_MCS][WL_TX_CHAINS_MAX]; /* VHT counts */ uint32 tsf_timer[2][2]; /* Start and End time for 8bytes value */ @@ -1233,6 +1285,7 @@ typedef struct wlc_rev_info { uint phyrev; /* phy revision */ uint anarev; /* anacore rev */ uint chippkg; /* chip package info */ + uint nvramrev; /* nvram revision number */ } wlc_rev_info_t; #define WL_REV_INFO_LEGACY_LENGTH 48 @@ -1566,7 +1619,9 @@ typedef struct wlc_iov_trx_s { #define WLC_NVRAM_SET 265 #define WLC_NVRAM_DUMP 266 #define WLC_REBOOT 267 +#endif /* LINUX_POSTMOGRIFY_REMOVAL */ #define WLC_SET_WSEC_PMK 268 +#ifndef LINUX_POSTMOGRIFY_REMOVAL #define WLC_GET_AUTH_MODE 269 #define WLC_SET_AUTH_MODE 270 #define WLC_GET_WAKEENTRY 271 @@ -1616,7 +1671,8 @@ typedef struct wlc_iov_trx_s { /* #define WLC_SET_WAI_REKEY 315 */ /* for WAPI, deprecated use iovar instead */ #define WLC_SET_NAT_CONFIG 316 /* for configuring NAT filter driver */ #define WLC_GET_NAT_STATE 317 -#define WLC_LAST 318 +#define WLC_GET_RSSI_QDB 318 /* qdB portion of the RSSI */ +#define WLC_LAST 319 #ifndef EPICTRL_COOKIE #define EPICTRL_COOKIE 0xABADCEDE @@ -1687,12 +1743,8 @@ typedef struct { /* WLC_GET_AUTH, WLC_SET_AUTH values */ #define WL_AUTH_OPEN_SYSTEM 0 /* d11 open authentication */ #define WL_AUTH_SHARED_KEY 1 /* d11 shared authentication */ -#ifdef BCM4330_CHIP -#define WL_AUTH_OPEN_SHARED 2 /* try open, then shared if open failed w/rc 13 */ -#else -/* BCM4334(Phoenex branch) value changed to 3 */ -#define WL_AUTH_OPEN_SHARED 3 /* try open, then shared if open failed w/rc 13 */ -#endif +#define WL_AUTH_OPEN_SHARED 2 /* try open, then shared if open failed w/rc 13 */ + #endif /* LINUX_POSTMOGRIFY_REMOVAL */ /* Bit masks for radio disabled status - returned by WL_GET_RADIO */ @@ -1705,6 +1757,17 @@ typedef struct { #define WL_SPURAVOID_ON1 1 #define WL_SPURAVOID_ON2 2 + +#define WL_4335_SPURAVOID_ON1 1 +#define WL_4335_SPURAVOID_ON2 2 +#define WL_4335_SPURAVOID_ON3 3 +#define WL_4335_SPURAVOID_ON4 4 +#define WL_4335_SPURAVOID_ON5 5 +#define WL_4335_SPURAVOID_ON6 6 +#define WL_4335_SPURAVOID_ON7 7 +#define WL_4335_SPURAVOID_ON8 8 +#define WL_4335_SPURAVOID_ON9 9 + /* Override bit for WLC_SET_TXPWR. if set, ignore other level limits */ #define WL_TXPWR_OVERRIDE (1U<<31) #define WL_TXPWR_NEG (1U<<30) @@ -1713,6 +1776,16 @@ typedef struct { #define WL_PHY_PAVARS_LEN 32 /* Phy type, Band range, chain, a1[0], b0[0], b1[0] ... */ #define WL_PHY_PAVAR_VER 1 /* pavars version */ +#define WL_PHY_PAVARS2_NUM 3 /* a1, b0, b1 */ +typedef struct wl_pavars2 { + uint16 ver; /* version of this struct */ + uint16 len; /* len of this structure */ + uint16 inuse; /* driver return 1 for a1,b0,b1 in current band range */ + uint16 phy_type; /* phy type */ + uint16 bandrange; + uint16 chain; + uint16 inpa[WL_PHY_PAVARS2_NUM]; /* phy pavars for one band range */ +} wl_pavars2_t; typedef struct wl_po { uint16 phy_type; /* Phy type */ @@ -1764,6 +1837,12 @@ typedef struct wl_po { #define WL_CHAN_FREQ_RANGE_5GM 2 #define WL_CHAN_FREQ_RANGE_5GH 3 +#define WL_CHAN_FREQ_RANGE_5GLL_5BAND 4 +#define WL_CHAN_FREQ_RANGE_5GLH_5BAND 5 +#define WL_CHAN_FREQ_RANGE_5GML_5BAND 6 +#define WL_CHAN_FREQ_RANGE_5GMH_5BAND 7 +#define WL_CHAN_FREQ_RANGE_5GH_5BAND 8 + #define WL_CHAN_FREQ_RANGE_5G_BAND0 1 #define WL_CHAN_FREQ_RANGE_5G_BAND1 2 #define WL_CHAN_FREQ_RANGE_5G_BAND2 3 @@ -1964,6 +2043,8 @@ typedef struct wl_samplecollect_args { uint8 module_sel1; uint8 module_sel2; uint16 nsamps; + int bitStart; + uint32 gpioCapMask; } wl_samplecollect_args_t; #define WL_SAMPLEDATA_HEADER_TYPE 1 @@ -1983,6 +2064,117 @@ typedef struct wl_sampledata { uint32 flag; /* bit def */ } wl_sampledata_t; +/* WL_OTA START */ + +#define WL_OTA_ARG_PARSE_BLK_SIZE 1200 +#define WL_OTA_TEST_MAX_NUM_RATE 30 +#define WL_OTA_TEST_MAX_NUM_SEQ 100 + +/* OTA Test Status */ +enum { + WL_OTA_TEST_IDLE, /* Default Idle state */ + WL_OTA_TEST_ACTIVE, /* Test Running */ + WL_OTA_TEST_SUCCESS, /* Successfully Finished Test */ + WL_OTA_TEST_FAIL /* Test Failed in the Middle */ +}; +/* OTA SYNC Status */ +enum { + WL_OTA_SYNC_IDLE, /* Idle state */ + WL_OTA_SYNC_ACTIVE, /* Waiting for Sync */ + WL_OTA_SYNC_FAIL /* Sync pkt not recieved */ +}; + +/* Various error states dut can get stuck during test */ +enum { + WL_OTA_SKIP_TEST_CAL_FAIL = 1, /* Phy calibration failed */ + WL_OTA_SKIP_TEST_SYNCH_FAIL, /* Sync Packet not recieved */ + WL_OTA_SKIP_TEST_FILE_DWNLD_FAIL, /* Cmd flow file download failed */ + WL_OTA_SKIP_TEST_NO_TEST_FOUND, /* No test found in Flow file */ + WL_OTA_SKIP_TEST_WL_NOT_UP, /* WL UP failed */ + WL_OTA_SKIP_TEST_UNKNOWN_CALL /* Unintentional scheduling on ota test */ +}; + +/* Differentiator for ota_tx and ota_rx */ +enum { + WL_OTA_TEST_TX, /* ota_tx */ + WL_OTA_TEST_RX /* ota_rx */ +}; + +/* Catch 3 modes of operation: 20Mhz, 40Mhz, 20 in 40 Mhz */ +enum { + WL_OTA_TEST_BW_20_IN_40MHZ, /* 20 in 40 operation */ + WL_OTA_TEST_BW_20MHZ, /* 20 Mhz operation */ + WL_OTA_TEST_BW_40MHZ /* full 40Mhz operation */ +}; +typedef struct ota_rate_info { + uint8 rate_cnt; /* Total number of rates */ + uint8 rate_val_mbps[WL_OTA_TEST_MAX_NUM_RATE]; /* array of rates from 1mbps to 130mbps */ + /* for legacy rates : ratein mbps * 2 */ + /* for HT rates : mcs index */ +} ota_rate_info_t; + +typedef struct ota_power_info { + int8 pwr_ctrl_on; /* power control on/off */ + int8 start_pwr; /* starting power/index */ + int8 delta_pwr; /* delta power/index */ + int8 end_pwr; /* end power/index */ +} ota_power_info_t; + +typedef struct ota_packetengine { + uint16 delay; /* Inter-packet delay */ + /* for ota_tx, delay is tx ifs in micro seconds */ + /* for ota_rx, delay is wait time in milliseconds */ + uint16 nframes; /* Number of frames */ + uint16 length; /* Packet length */ +} ota_packetengine_t; + +/* Test info vector */ +typedef struct wl_ota_test_args { + uint8 cur_test; /* test phase */ + uint8 chan; /* channel */ + uint8 bw; /* bandwidth */ + char control_band; /* control band */ + uint8 stf_mode; /* stf mode */ + ota_rate_info_t rt_info; /* Rate info */ + ota_packetengine_t pkteng; /* packeteng info */ + uint8 txant; /* tx antenna */ + uint8 rxant; /* rx antenna */ + ota_power_info_t pwr_info; /* power sweep info */ + uint8 wait_for_sync; /* wait for sync or not */ +} wl_ota_test_args_t; + +typedef struct wl_ota_test_vector { + wl_ota_test_args_t test_arg[WL_OTA_TEST_MAX_NUM_SEQ]; /* Test argument struct */ + uint16 test_cnt; /* Total no of test */ + bool file_dwnld_valid; /* File successfully downloaded */ + uint8 sync_timeout; /* sync packet timeout */ + int8 sync_fail_action; /* sync fail action */ + struct ether_addr sync_mac; /* macaddress for sync pkt */ + struct ether_addr tx_mac; /* macaddress for tx */ + struct ether_addr rx_mac; /* macaddress for rx */ + int8 loop_test; /* dbg feature to loop the test */ +} wl_ota_test_vector_t; + + +/* struct copied back form dongle to host to query the status */ +typedef struct wl_ota_test_status { + int16 cur_test_cnt; /* test phase */ + int8 skip_test_reason; /* skip test reasoin */ + wl_ota_test_args_t test_arg; /* cur test arg details */ + uint16 test_cnt; /* total no of test downloaded */ + bool file_dwnld_valid; /* file successfully downloaded ? */ + uint8 sync_timeout; /* sync timeout */ + int8 sync_fail_action; /* sync fail action */ + struct ether_addr sync_mac; /* macaddress for sync pkt */ + struct ether_addr tx_mac; /* tx mac address */ + struct ether_addr rx_mac; /* rx mac address */ + uint8 test_stage; /* check the test status */ + int8 loop_test; /* Debug feature to puts test enfine in a loop */ + uint8 sync_status; /* sync status */ +} wl_ota_test_status_t; + +/* WL_OTA END */ + /* wl_radar_args_t */ typedef struct { int npulses; /* required number of pulses at n * t_int */ @@ -2162,168 +2354,168 @@ typedef struct { typedef struct txppr { /* start of 20MHz tx power limits */ - uint8 b20_1x1dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ - uint8 b20_1x1ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM transmission */ - uint8 b20_1x1mcs0[WL_NUM_RATES_MCS_1STREAM]; /* SISO MCS 0-7 */ - - uint8 b20_1x2dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ - uint8 b20_1x2cdd_ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM CDD transmission */ - uint8 b20_1x2cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* CDD MCS 0-7 */ - uint8 b20_2x2stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ - uint8 b20_2x2sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* MCS 8-15 */ - - uint8 b20_1x3dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ - uint8 b20_1x3cdd_ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM CDD transmission */ - uint8 b20_1x3cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* 1 Nsts to 3 Tx Chain */ - uint8 b20_2x3stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ - uint8 b20_2x3sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* 2 Nsts to 3 Tx Chain */ - uint8 b20_3x3sdm_mcs16[WL_NUM_RATES_MCS_1STREAM]; /* 3 Nsts to 3 Tx Chain */ - - uint8 b20_1x1vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1 */ - uint8 b20_1x2cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD1 */ - uint8 b20_2x2stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC */ - uint8 b20_2x2sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2 */ - uint8 b20_1x3cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD2 */ - uint8 b20_2x3stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC_SPEXP1 */ - uint8 b20_2x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2_SPEXP1 */ - uint8 b20_3x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS3 */ + int8 b20_1x1dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ + int8 b20_1x1ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM transmission */ + int8 b20_1x1mcs0[WL_NUM_RATES_MCS_1STREAM]; /* SISO MCS 0-7 */ + + int8 b20_1x2dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ + int8 b20_1x2cdd_ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM CDD transmission */ + int8 b20_1x2cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* CDD MCS 0-7 */ + int8 b20_2x2stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ + int8 b20_2x2sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* MCS 8-15 */ + + int8 b20_1x3dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ + int8 b20_1x3cdd_ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM CDD transmission */ + int8 b20_1x3cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* 1 Nsts to 3 Tx Chain */ + int8 b20_2x3stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ + int8 b20_2x3sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* 2 Nsts to 3 Tx Chain */ + int8 b20_3x3sdm_mcs16[WL_NUM_RATES_MCS_1STREAM]; /* 3 Nsts to 3 Tx Chain */ + + int8 b20_1x1vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1 */ + int8 b20_1x2cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD1 */ + int8 b20_2x2stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC */ + int8 b20_2x2sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2 */ + int8 b20_1x3cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD2 */ + int8 b20_2x3stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC_SPEXP1 */ + int8 b20_2x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2_SPEXP1 */ + int8 b20_3x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS3 */ /* start of 40MHz tx power limits */ - uint8 b40_dummy1x1dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ - uint8 b40_1x1ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM transmission */ - uint8 b40_1x1mcs0[WL_NUM_RATES_MCS_1STREAM]; /* SISO MCS 0-7 */ - - uint8 b40_dummy1x2dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ - uint8 b40_1x2cdd_ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM CDD transmission */ - uint8 b40_1x2cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* CDD MCS 0-7 */ - uint8 b40_2x2stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ - uint8 b40_2x2sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* MCS 8-15 */ - - uint8 b40_dummy1x3dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ - uint8 b40_1x3cdd_ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM CDD transmission */ - uint8 b40_1x3cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* 1 Nsts to 3 Tx Chain */ - uint8 b40_2x3stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ - uint8 b40_2x3sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* 2 Nsts to 3 Tx Chain */ - uint8 b40_3x3sdm_mcs16[WL_NUM_RATES_MCS_1STREAM]; /* 3 Nsts to 3 Tx Chain */ - - uint8 b40_1x1vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1 */ - uint8 b40_1x2cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD1 */ - uint8 b40_2x2stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC */ - uint8 b40_2x2sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2 */ - uint8 b40_1x3cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD2 */ - uint8 b40_2x3stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC_SPEXP1 */ - uint8 b40_2x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2_SPEXP1 */ - uint8 b40_3x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS3 */ + int8 b40_dummy1x1dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ + int8 b40_1x1ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM transmission */ + int8 b40_1x1mcs0[WL_NUM_RATES_MCS_1STREAM]; /* SISO MCS 0-7 */ + + int8 b40_dummy1x2dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ + int8 b40_1x2cdd_ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM CDD transmission */ + int8 b40_1x2cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* CDD MCS 0-7 */ + int8 b40_2x2stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ + int8 b40_2x2sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* MCS 8-15 */ + + int8 b40_dummy1x3dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ + int8 b40_1x3cdd_ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM CDD transmission */ + int8 b40_1x3cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* 1 Nsts to 3 Tx Chain */ + int8 b40_2x3stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ + int8 b40_2x3sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* 2 Nsts to 3 Tx Chain */ + int8 b40_3x3sdm_mcs16[WL_NUM_RATES_MCS_1STREAM]; /* 3 Nsts to 3 Tx Chain */ + + int8 b40_1x1vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1 */ + int8 b40_1x2cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD1 */ + int8 b40_2x2stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC */ + int8 b40_2x2sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2 */ + int8 b40_1x3cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD2 */ + int8 b40_2x3stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC_SPEXP1 */ + int8 b40_2x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2_SPEXP1 */ + int8 b40_3x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS3 */ /* start of 20in40MHz tx power limits */ - uint8 b20in40_1x1dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ - uint8 b20in40_1x1ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM transmission */ - uint8 b20in40_1x1mcs0[WL_NUM_RATES_MCS_1STREAM]; /* SISO MCS 0-7 */ - - uint8 b20in40_1x2dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ - uint8 b20in40_1x2cdd_ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM CDD transmission */ - uint8 b20in40_1x2cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* CDD MCS 0-7 */ - uint8 b20in40_2x2stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ - uint8 b20in40_2x2sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* MCS 8-15 */ - - uint8 b20in40_1x3dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ - uint8 b20in40_1x3cdd_ofdm[WL_NUM_RATES_OFDM]; /* 20 in 40 MHz Legacy OFDM CDD */ - uint8 b20in40_1x3cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* 1 Nsts to 3 Tx Chain */ - uint8 b20in40_2x3stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ - uint8 b20in40_2x3sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* 2 Nsts to 3 Tx Chain */ - uint8 b20in40_3x3sdm_mcs16[WL_NUM_RATES_MCS_1STREAM]; /* 3 Nsts to 3 Tx Chain */ - - uint8 b20in40_1x1vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1 */ - uint8 b20in40_1x2cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD1 */ - uint8 b20in40_2x2stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC */ - uint8 b20in40_2x2sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2 */ - uint8 b20in40_1x3cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD2 */ - uint8 b20in40_2x3stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC_SPEXP1 */ - uint8 b20in40_2x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2_SPEXP1 */ - uint8 b20in40_3x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS3 */ + int8 b20in40_1x1dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ + int8 b20in40_1x1ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM transmission */ + int8 b20in40_1x1mcs0[WL_NUM_RATES_MCS_1STREAM]; /* SISO MCS 0-7 */ + + int8 b20in40_1x2dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ + int8 b20in40_1x2cdd_ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM CDD transmission */ + int8 b20in40_1x2cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* CDD MCS 0-7 */ + int8 b20in40_2x2stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ + int8 b20in40_2x2sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* MCS 8-15 */ + + int8 b20in40_1x3dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ + int8 b20in40_1x3cdd_ofdm[WL_NUM_RATES_OFDM]; /* 20 in 40 MHz Legacy OFDM CDD */ + int8 b20in40_1x3cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* 1 Nsts to 3 Tx Chain */ + int8 b20in40_2x3stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ + int8 b20in40_2x3sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* 2 Nsts to 3 Tx Chain */ + int8 b20in40_3x3sdm_mcs16[WL_NUM_RATES_MCS_1STREAM]; /* 3 Nsts to 3 Tx Chain */ + + int8 b20in40_1x1vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1 */ + int8 b20in40_1x2cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD1 */ + int8 b20in40_2x2stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC */ + int8 b20in40_2x2sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2 */ + int8 b20in40_1x3cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD2 */ + int8 b20in40_2x3stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC_SPEXP1 */ + int8 b20in40_2x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2_SPEXP1 */ + int8 b20in40_3x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS3 */ /* start of 80MHz tx power limits */ - uint8 b80_dummy1x1dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ - uint8 b80_1x1ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM transmission */ - uint8 b80_1x1mcs0[WL_NUM_RATES_MCS_1STREAM]; /* SISO MCS 0-7 */ - - uint8 b80_dummy1x2dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ - uint8 b80_1x2cdd_ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM CDD transmission */ - uint8 b80_1x2cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* CDD MCS 0-7 */ - uint8 b80_2x2stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ - uint8 b80_2x2sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* MCS 8-15 */ - - uint8 b80_dummy1x3dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ - uint8 b80_1x3cdd_ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM CDD transmission */ - uint8 b80_1x3cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* 1 Nsts to 3 Tx Chain */ - uint8 b80_2x3stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ - uint8 b80_2x3sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* 2 Nsts to 3 Tx Chain */ - uint8 b80_3x3sdm_mcs16[WL_NUM_RATES_MCS_1STREAM]; /* 3 Nsts to 3 Tx Chain */ - - uint8 b80_1x1vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1 */ - uint8 b80_1x2cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD1 */ - uint8 b80_2x2stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC */ - uint8 b80_2x2sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2 */ - uint8 b80_1x3cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD2 */ - uint8 b80_2x3stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC_SPEXP1 */ - uint8 b80_2x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2_SPEXP1 */ - uint8 b80_3x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS3 */ + int8 b80_dummy1x1dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ + int8 b80_1x1ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM transmission */ + int8 b80_1x1mcs0[WL_NUM_RATES_MCS_1STREAM]; /* SISO MCS 0-7 */ + + int8 b80_dummy1x2dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ + int8 b80_1x2cdd_ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM CDD transmission */ + int8 b80_1x2cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* CDD MCS 0-7 */ + int8 b80_2x2stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ + int8 b80_2x2sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* MCS 8-15 */ + + int8 b80_dummy1x3dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ + int8 b80_1x3cdd_ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM CDD transmission */ + int8 b80_1x3cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* 1 Nsts to 3 Tx Chain */ + int8 b80_2x3stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ + int8 b80_2x3sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* 2 Nsts to 3 Tx Chain */ + int8 b80_3x3sdm_mcs16[WL_NUM_RATES_MCS_1STREAM]; /* 3 Nsts to 3 Tx Chain */ + + int8 b80_1x1vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1 */ + int8 b80_1x2cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD1 */ + int8 b80_2x2stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC */ + int8 b80_2x2sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2 */ + int8 b80_1x3cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD2 */ + int8 b80_2x3stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC_SPEXP1 */ + int8 b80_2x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2_SPEXP1 */ + int8 b80_3x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS3 */ /* start of 20in80MHz tx power limits */ - uint8 b20in80_1x1dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ - uint8 b20in80_1x1ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM transmission */ - uint8 b20in80_1x1mcs0[WL_NUM_RATES_MCS_1STREAM]; /* SISO MCS 0-7 */ - - uint8 b20in80_1x2dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ - uint8 b20in80_1x2cdd_ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM CDD transmission */ - uint8 b20in80_1x2cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* CDD MCS 0-7 */ - uint8 b20in80_2x2stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ - uint8 b20in80_2x2sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* MCS 8-15 */ - - uint8 b20in80_1x3dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ - uint8 b20in80_1x3cdd_ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM CDD transmission */ - uint8 b20in80_1x3cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* 1 Nsts to 3 Tx Chain */ - uint8 b20in80_2x3stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ - uint8 b20in80_2x3sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* 2 Nsts to 3 Tx Chain */ - uint8 b20in80_3x3sdm_mcs16[WL_NUM_RATES_MCS_1STREAM]; /* 3 Nsts to 3 Tx Chain */ - - uint8 b20in80_1x1vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1 */ - uint8 b20in80_1x2cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD1 */ - uint8 b20in80_2x2stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC */ - uint8 b20in80_2x2sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2 */ - uint8 b20in80_1x3cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD2 */ - uint8 b20in80_2x3stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC_SPEXP1 */ - uint8 b20in80_2x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2_SPEXP1 */ - uint8 b20in80_3x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS3 */ + int8 b20in80_1x1dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ + int8 b20in80_1x1ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM transmission */ + int8 b20in80_1x1mcs0[WL_NUM_RATES_MCS_1STREAM]; /* SISO MCS 0-7 */ + + int8 b20in80_1x2dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ + int8 b20in80_1x2cdd_ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM CDD transmission */ + int8 b20in80_1x2cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* CDD MCS 0-7 */ + int8 b20in80_2x2stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ + int8 b20in80_2x2sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* MCS 8-15 */ + + int8 b20in80_1x3dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ + int8 b20in80_1x3cdd_ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM CDD transmission */ + int8 b20in80_1x3cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* 1 Nsts to 3 Tx Chain */ + int8 b20in80_2x3stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ + int8 b20in80_2x3sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* 2 Nsts to 3 Tx Chain */ + int8 b20in80_3x3sdm_mcs16[WL_NUM_RATES_MCS_1STREAM]; /* 3 Nsts to 3 Tx Chain */ + + int8 b20in80_1x1vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1 */ + int8 b20in80_1x2cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD1 */ + int8 b20in80_2x2stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC */ + int8 b20in80_2x2sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2 */ + int8 b20in80_1x3cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD2 */ + int8 b20in80_2x3stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC_SPEXP1 */ + int8 b20in80_2x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2_SPEXP1 */ + int8 b20in80_3x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS3 */ /* start of 40in80MHz tx power limits */ - uint8 b40in80_dummy1x1dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ - uint8 b40in80_1x1ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM transmission */ - uint8 b40in80_1x1mcs0[WL_NUM_RATES_MCS_1STREAM]; /* SISO MCS 0-7 */ - - uint8 b40in80_dummy1x2dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ - uint8 b40in80_1x2cdd_ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM CDD transmission */ - uint8 b40in80_1x2cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* CDD MCS 0-7 */ - uint8 b40in80_2x2stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ - uint8 b40in80_2x2sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* MCS 8-15 */ - - uint8 b40in80_dummy1x3dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ - uint8 b40in80_1x3cdd_ofdm[WL_NUM_RATES_OFDM]; /* MHz Legacy OFDM CDD */ - uint8 b40in80_1x3cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* 1 Nsts to 3 Tx Chain */ - uint8 b40in80_2x3stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ - uint8 b40in80_2x3sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* 2 Nsts to 3 Tx Chain */ - uint8 b40in80_3x3sdm_mcs16[WL_NUM_RATES_MCS_1STREAM]; /* 3 Nsts to 3 Tx Chain */ - - uint8 b40in80_1x1vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1 */ - uint8 b40in80_1x2cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD1 */ - uint8 b40in80_2x2stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC */ - uint8 b40in80_2x2sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2 */ - uint8 b40in80_1x3cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD2 */ - uint8 b40in80_2x3stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC_SPEXP1 */ - uint8 b40in80_2x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2_SPEXP1 */ - uint8 b40in80_3x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS3 */ - - uint8 mcs32; /* C_CHECK - THIS NEEDS TO BE REMOVED THROUGHOUT THE CODE */ + int8 b40in80_dummy1x1dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ + int8 b40in80_1x1ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM transmission */ + int8 b40in80_1x1mcs0[WL_NUM_RATES_MCS_1STREAM]; /* SISO MCS 0-7 */ + + int8 b40in80_dummy1x2dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ + int8 b40in80_1x2cdd_ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM CDD transmission */ + int8 b40in80_1x2cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* CDD MCS 0-7 */ + int8 b40in80_2x2stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ + int8 b40in80_2x2sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* MCS 8-15 */ + + int8 b40in80_dummy1x3dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ + int8 b40in80_1x3cdd_ofdm[WL_NUM_RATES_OFDM]; /* MHz Legacy OFDM CDD */ + int8 b40in80_1x3cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* 1 Nsts to 3 Tx Chain */ + int8 b40in80_2x3stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ + int8 b40in80_2x3sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* 2 Nsts to 3 Tx Chain */ + int8 b40in80_3x3sdm_mcs16[WL_NUM_RATES_MCS_1STREAM]; /* 3 Nsts to 3 Tx Chain */ + + int8 b40in80_1x1vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1 */ + int8 b40in80_1x2cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD1 */ + int8 b40in80_2x2stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC */ + int8 b40in80_2x2sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2 */ + int8 b40in80_1x3cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD2 */ + int8 b40in80_2x3stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC_SPEXP1 */ + int8 b40in80_2x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2_SPEXP1 */ + int8 b40in80_3x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS3 */ + + int8 mcs32; /* C_CHECK - THIS NEEDS TO BE REMOVED THROUGHOUT THE CODE */ } txppr_t; /* 20MHz */ @@ -2505,45 +2697,35 @@ typedef struct txppr { #define WL_TX_POWER_MCS20_SISO_FIRST_SSN WL_TX_POWER_MCS20_SISO_FIRST #define WL_TX_POWER_MCS40_SISO_FIRST_SSN WL_TX_POWER_MCS40_SISO_FIRST -/* tx_power_t.flags bits */ -#define WL_TX_POWER_F_ENABLED 1 -#define WL_TX_POWER_F_HW 2 -#define WL_TX_POWER_F_MIMO 4 -#define WL_TX_POWER_F_SISO 8 -#define WL_TX_POWER_F_HT 0x10 - typedef struct { uint16 ver; /* version of this struct */ uint16 len; /* length in bytes of this structure */ uint32 flags; chanspec_t chanspec; /* txpwr report for this channel */ chanspec_t local_chanspec; /* channel on which we are associated */ - uint8 ppr[WL_TX_POWER_RATES]; /* Latest target power */ + uint32 buflen; /* ppr buffer length */ + uint8 pprbuf[1]; /* Latest target power buffer */ } wl_txppr_t; #define WL_TXPPR_VERSION 0 #define WL_TXPPR_LENGTH (sizeof(wl_txppr_t)) -#define TX_POWER_T_VERSION 43 +#define TX_POWER_T_VERSION 44 /* Defines used with channel_bandwidth for curpower */ #define WL_BW_20MHZ 0 #define WL_BW_40MHZ 1 #define WL_BW_80MHZ 2 +#define WL_BW_160MHZ 3 /* tx_power_t.flags bits */ -#ifdef PPR_API -#define WL_TX_POWER2_F_ENABLED 1 -#define WL_TX_POWER2_F_HW 2 -#define WL_TX_POWER2_F_MIMO 4 -#define WL_TX_POWER2_F_SISO 8 -#define WL_TX_POWER2_F_HT 0x10 -#else +/* use for defined PPR_API */ #define WL_TX_POWER_F_ENABLED 1 #define WL_TX_POWER_F_HW 2 #define WL_TX_POWER_F_MIMO 4 #define WL_TX_POWER_F_SISO 8 #define WL_TX_POWER_F_HT 0x10 -#endif +#define WL_TX_POWER_F_VHT 0x20 + typedef struct { uint32 flags; chanspec_t chanspec; /* txpwr report for this channel */ @@ -2553,9 +2735,7 @@ typedef struct { int8 antgain[2]; /* Ant gain for each band - from SROM */ uint8 rf_cores; /* count of RF Cores being reported */ uint8 est_Pout[4]; /* Latest tx power out estimate per RF chain */ - uint8 est_Pout_act[4]; /* Latest tx power out estimate per RF chain - * without adjustment - */ + uint8 est_Pout_act[4]; /* Latest tx power out estimate per RF chain w/o adjustment */ uint8 est_Pout_cck; /* Latest CCK tx power out estimate */ uint8 tx_power_max[4]; /* Maximum target power among all rates */ uint tx_power_max_rate_ind[4]; /* Index of the rate with the max target power */ @@ -2569,11 +2749,10 @@ typedef struct { int8 channel_bandwidth; /* 20, 40 or 80 MHz bandwidth? */ uint8 version; /* Version of the data format wlu <--> driver */ uint8 display_core; /* Displayed curpower core */ -#ifdef PPR_API -} tx_power_new_t; -#else + int8 target_offsets[4]; /* Target power offsets for current rate per core */ + uint32 last_tx_ratespec; /* Ratespec for last transmition */ + int8 SARLIMIT[MAX_STREAMS_SUPPORTED]; } tx_power_t; -#endif typedef struct tx_inst_power { uint8 txpwr_est_Pout[2]; /* Latest estimate for 2.4 and 5 Ghz */ @@ -2716,7 +2895,20 @@ typedef struct wl_txchain_pwr_offsets { #define WL_PSTA_VAL 0x00008000 #define WL_TBTT_VAL 0x00010000 #define WL_NIC_VAL 0x00020000 -#define WL_PWRSEL_VAL 0x00040000 +#define WL_PWRSEL_VAL 0x00040000 +#define WL_TRF_MGMT_VAL 0x00080000 +#define WL_L2FILTER_VAL 0x00100000 +#define WL_TSO_VAL 0x00200000 +#define WL_MQ_VAL 0x00400000 +/* These 3 levels are currently not used in trunk but in Aardvark and Phoenix2 with != values */ +#define WL_LPC_VAL 0x00800000 +#define WL_TXBF_VAL 0x01000000 +#define WL_P2PO_VAL 0x02000000 +/* This level is synchronized with other branches */ +#define WL_WNM_VAL 0x04000000 +/* This level is currently not used in trunk but used in Phoenix2 */ +#define WL_SRSCAN_VAL 0x08000000 + /* use top-bit for WL_TIME_STAMP_VAL because this is a modifier * rather than a message-type of its own */ @@ -2749,7 +2941,9 @@ typedef struct wl_txchain_pwr_offsets { #define WL_LED_ASSOC_WITH_SEC 20 /* when connected with security */ /* keep on for 300 sec */ #define WL_LED_START_OFF 21 /* off upon boot, could be turned on later */ -#define WL_LED_NUMBEHAVIOR 22 +#define WL_LED_W6 22 /* off upon boot, could be turned on later */ +#define WL_LED_WI7 23 /* off upon boot, could be turned on later */ +#define WL_LED_NUMBEHAVIOR 24 /* led behavior numeric value format */ #define WL_LED_BEH_MASK 0x7f /* behavior mask */ @@ -2766,8 +2960,8 @@ typedef struct wl_txchain_pwr_offsets { #define WL_WDS_WPA_ROLE_SUP 1 /* supplicant */ #define WL_WDS_WPA_ROLE_AUTO 255 /* auto, based on mac addr value */ -/* number of bytes needed to define a 128-bit mask for MAC event reporting */ -#define WL_EVENTING_MASK_LEN 16 +/* number of bytes needed to define a mask for MAC event reporting */ +#define WL_EVENTING_MASK_LEN ((WLC_E_LAST + 7) / 8) /* * Join preference iovar value is an array of tuples. Each tuple has a one-byte type, @@ -2807,7 +3001,7 @@ typedef struct wl_txchain_pwr_offsets { * * 4. BAND RSSI - 2 octets * offset 0: band types - * offset 1: +ve RSSI boost balue in dB + * offset 1: +ve RSSI boost value in dB */ /* join preference types */ @@ -3071,6 +3265,12 @@ typedef struct { uint32 pstatxbcmc; /* count of bcmc frames transmitted on all psta */ uint32 cso_passthrough; /* hw cso required but passthrough */ + uint32 chained; /* number of frames chained */ + uint32 chainedsz1; /* number of chain size 1 frames */ + uint32 unchained; /* number of frames not chained */ + uint32 maxchainsz; /* max chain size so far */ + uint32 currchainsz; /* current chain size */ + uint32 cso_normal; /* hw cso hdr for normal process */ } wl_cnt_t; #ifndef LINUX_POSTMOGRIFY_REMOVAL @@ -3342,6 +3542,22 @@ typedef struct { uint32 rx486mbps; /* packets rx at 486 mbps */ uint32 rx540mbps; /* packets rx at 540 mbps */ } wl_delta_stats_t; + +/* structure to store per-rate rx statistics */ +typedef struct wl_scb_rx_rate_stats { + uint32 rx1mbps[2]; /* packets rx at 1Mbps */ + uint32 rx2mbps[2]; /* packets rx at 2Mbps */ + uint32 rx5mbps5[2]; /* packets rx at 5.5Mbps */ + uint32 rx6mbps[2]; /* packets rx at 6Mbps */ + uint32 rx9mbps[2]; /* packets rx at 9Mbps */ + uint32 rx11mbps[2]; /* packets rx at 11Mbps */ + uint32 rx12mbps[2]; /* packets rx at 12Mbps */ + uint32 rx18mbps[2]; /* packets rx at 18Mbps */ + uint32 rx24mbps[2]; /* packets rx at 24Mbps */ + uint32 rx36mbps[2]; /* packets rx at 36Mbps */ + uint32 rx48mbps[2]; /* packets rx at 48Mbps */ + uint32 rx54mbps[2]; /* packets rx at 54Mbps */ +} wl_scb_rx_rate_stats_t; #endif /* LINUX_POSTMOGRIFY_REMOVAL */ #define WL_WME_CNT_VERSION 1 /* current version of wl_wme_cnt_t */ @@ -3511,13 +3727,14 @@ struct tslist { #ifdef WLTDLS /* different ops for manual end point */ -#define TDLS_MANUAL_EP_CREATE 1 /* create manual dpt endpoint */ -#define TDLS_MANUAL_EP_MODIFY 2 /* modify manual dpt endpoint */ -#define TDLS_MANUAL_EP_DELETE 3 /* delete manual dpt endpoint */ +#define TDLS_MANUAL_EP_CREATE 1 /* create manual dpt endpoint */ +#define TDLS_MANUAL_EP_MODIFY 2 /* modify manual dpt endpoint */ +#define TDLS_MANUAL_EP_DELETE 3 /* delete manual dpt endpoint */ #define TDLS_MANUAL_EP_PM 4 /* put dpt endpoint in PM mode */ #define TDLS_MANUAL_EP_WAKE 5 /* wake up dpt endpoint from PM */ #define TDLS_MANUAL_EP_DISCOVERY 6 /* discover if endpoint is TDLS capable */ #define TDLS_MANUAL_EP_CHSW 7 /* channel switch */ +#define TDLS_MANUAL_EP_WFD_TPQ 8 /* WiFi-Display Tunneled Probe reQuest */ /* structure for tdls iovars */ typedef struct tdls_iovar { @@ -3528,14 +3745,16 @@ typedef struct tdls_iovar { } tdls_iovar_t; /* modes */ -#define TDLS_WFD_IE_TX 0 -#define TDLS_WFD_IE_RX 1 -#define TDLS_WFD_IE_SIZE 255 +#define TDLS_WFD_IE_TX 0 +#define TDLS_WFD_IE_RX 1 +#define TDLS_WFD_PROBE_IE_TX 2 +#define TDLS_WFD_PROBE_IE_RX 3 +#define TDLS_WFD_IE_SIZE 512 /* structure for tdls wfd ie */ typedef struct tdls_wfd_ie_iovar { struct ether_addr ea; /* Station address */ uint8 mode; - uint8 length; + uint16 length; uint8 data[TDLS_WFD_IE_SIZE]; } tdls_wfd_ie_iovar_t; #endif /* WLTDLS */ @@ -3598,11 +3817,11 @@ typedef struct wme_max_bandwidth { /* Software feature flag defines used by wlfeatureflag */ #ifdef WLAFTERBURNER -#define WL_SWFL_ABBFL 0x0001 /* Allow Afterburner on systems w/o hardware BFL */ -#define WL_SWFL_ABENCORE 0x0002 /* Allow AB on non-4318E chips */ +#define WL_SWFL_ABBFL 0x0001 /* Allow Afterburner on systems w/o hardware BFL */ +#define WL_SWFL_ABENCORE 0x0002 /* Allow AB on non-4318E chips */ #endif /* WLAFTERBURNER */ #define WL_SWFL_NOHWRADIO 0x0004 -#define WL_SWFL_FLOWCONTROL 0x0008 /* Enable backpressure to OS stack */ +#define WL_SWFL_FLOWCONTROL 0x0008 /* Enable backpressure to OS stack */ #define WL_SWFL_WLBSSSORT 0x0010 /* Per-port supports sorting of BSS */ #define WL_LIFETIME_MAX 0xFFFF /* Max value in ms */ @@ -3660,18 +3879,20 @@ enum { #define SORT_CRITERIA_BIT 0 #define AUTO_NET_SWITCH_BIT 1 -#define ENABLE_BKGRD_SCAN_BIT 2 +#define ENABLE_BKGRD_SCAN_BIT 2 #define IMMEDIATE_SCAN_BIT 3 #define AUTO_CONNECT_BIT 4 #define ENABLE_BD_SCAN_BIT 5 -#define ENABLE_ADAPTSCAN_BIT 6 +#define ENABLE_ADAPTSCAN_BIT 6 #define IMMEDIATE_EVENT_BIT 8 #define SUPPRESS_SSID_BIT 9 #define ENABLE_NET_OFFLOAD_BIT 10 +/* report found/lost events for SSID and BSSID networks seperately */ +#define REPORT_SEPERATELY_BIT 11 #define SORT_CRITERIA_MASK 0x0001 -#define AUTO_NET_SWITCH_MASK 0x0002 -#define ENABLE_BKGRD_SCAN_MASK 0x0004 +#define AUTO_NET_SWITCH_MASK 0x0002 +#define ENABLE_BKGRD_SCAN_MASK 0x0004 #define IMMEDIATE_SCAN_MASK 0x0008 #define AUTO_CONNECT_MASK 0x0010 @@ -3680,8 +3901,10 @@ enum { #define IMMEDIATE_EVENT_MASK 0x0100 #define SUPPRESS_SSID_MASK 0x0200 #define ENABLE_NET_OFFLOAD_MASK 0x0400 +/* report found/lost events for SSID and BSSID networks seperately */ +#define REPORT_SEPERATELY_MASK 0x0800 -#define PFN_VERSION 2 +#define PFN_VERSION 2 #define PFN_SCANRESULT_VERSION 1 #define MAX_PFN_LIST_COUNT 16 @@ -3691,7 +3914,10 @@ enum { #define DEFAULT_BESTN 2 #define DEFAULT_MSCAN 0 #define DEFAULT_REPEAT 10 -#define DEFAULT_EXP 2 +#define DEFAULT_EXP 2 + +#define PFN_PARTIAL_SCAN_BIT 0 +#define PFN_PARTIAL_SCAN_MASK 1 /* PFN network info structure */ typedef struct wl_pfn_subnet_info { @@ -3707,6 +3933,22 @@ typedef struct wl_pfn_net_info { uint16 timestamp; /* age in seconds */ } wl_pfn_net_info_t; +typedef struct wl_pfn_lnet_info { + wl_pfn_subnet_info_t pfnsubnet; /* BSSID + channel + SSID len + SSID */ + uint16 flags; /* partial scan, etc */ + int16 RSSI; /* receive signal strength (in dBm) */ + uint32 timestamp; /* age in miliseconds */ + uint16 rtt0; /* estimated distance to this AP in centimeters */ + uint16 rtt1; /* standard deviation of the distance to this AP in centimeters */ +} wl_pfn_lnet_info_t; + +typedef struct wl_pfn_lscanresults { + uint32 version; + uint32 status; + uint32 count; + wl_pfn_lnet_info_t netinfo[1]; +} wl_pfn_lscanresults_t; + typedef struct wl_pfn_scanresults { uint32 version; uint32 status; @@ -3719,57 +3961,127 @@ typedef struct wl_pfn_param { int32 version; /* PNO parameters version */ int32 scan_freq; /* Scan frequency */ int32 lost_network_timeout; /* Timeout in sec. to declare - * discovered network as lost - */ + * discovered network as lost + */ int16 flags; /* Bit field to control features - * of PFN such as sort criteria auto - * enable switch and background scan - */ + * of PFN such as sort criteria auto + * enable switch and background scan + */ int16 rssi_margin; /* Margin to avoid jitter for choosing a - * PFN based on RSSI sort criteria - */ - uint8 bestn; /* number of best networks in each scan */ - uint8 mscan; /* number of scans recorded */ - uint8 repeat; /* Minimum number of scan intervals - *before scan frequency changes in adaptive scan - */ - uint8 exp; /* Exponent of 2 for maximum scan interval */ - int32 slow_freq; /* slow scan period */ + * PFN based on RSSI sort criteria + */ + uint8 bestn; /* number of best networks in each scan */ + uint8 mscan; /* number of scans recorded */ + uint8 repeat; /* Minimum number of scan intervals + *before scan frequency changes in adaptive scan + */ + uint8 exp; /* Exponent of 2 for maximum scan interval */ + int32 slow_freq; /* slow scan period */ } wl_pfn_param_t; typedef struct wl_pfn_bssid { - struct ether_addr macaddr; + struct ether_addr macaddr; /* Bit4: suppress_lost, Bit3: suppress_found */ - uint16 flags; + uint16 flags; } wl_pfn_bssid_t; #define WL_PFN_SUPPRESSFOUND_MASK 0x08 #define WL_PFN_SUPPRESSLOST_MASK 0x10 +#define WL_PFN_RSSI_MASK 0xff00 +#define WL_PFN_RSSI_SHIFT 8 typedef struct wl_pfn_cfg { - uint32 reporttype; - int32 channel_num; - uint16 channel_list[WL_NUMCHANNELS]; + uint32 reporttype; + int32 channel_num; + uint16 channel_list[WL_NUMCHANNELS]; + uint32 flags; } wl_pfn_cfg_t; -#define WL_PFN_REPORT_ALLNET 0 -#define WL_PFN_REPORT_SSIDNET 1 -#define WL_PFN_REPORT_BSSIDNET 2 +#define WL_PFN_REPORT_ALLNET 0 +#define WL_PFN_REPORT_SSIDNET 1 +#define WL_PFN_REPORT_BSSIDNET 2 + +#define WL_PFN_CFG_FLAGS_PROHIBITED 0x00000001 /* Accept and use prohibited channels */ +#define WL_PFN_CFG_FLAGS_RESERVED 0xfffffffe /* Remaining reserved for future use */ typedef struct wl_pfn { - wlc_ssid_t ssid; /* ssid name and its length */ - int32 flags; /* bit2: hidden */ - int32 infra; /* BSS Vs IBSS */ - int32 auth; /* Open Vs Closed */ - int32 wpa_auth; /* WPA type */ - int32 wsec; /* wsec value */ + wlc_ssid_t ssid; /* ssid name and its length */ + int32 flags; /* bit2: hidden */ + int32 infra; /* BSS Vs IBSS */ + int32 auth; /* Open Vs Closed */ + int32 wpa_auth; /* WPA type */ + int32 wsec; /* wsec value */ } wl_pfn_t; -#define WL_PFN_HIDDEN_BIT 2 +typedef struct wl_pfn_list { + uint32 version; + uint32 enabled; + uint32 count; + wl_pfn_t pfn[1]; +} wl_pfn_list_t; +#define WL_PFN_HIDDEN_BIT 2 #define PNO_SCAN_MAX_FW 508*1000 /* max time scan time in msec */ #define PNO_SCAN_MAX_FW_SEC PNO_SCAN_MAX_FW/1000 /* max time scan time in SEC */ -#define PNO_SCAN_MIN_FW_SEC 10 /* min time scan time in SEC */ -#define WL_PFN_HIDDEN_MASK 0x4 +#define PNO_SCAN_MIN_FW_SEC 10 /* min time scan time in SEC */ +#define WL_PFN_HIDDEN_MASK 0x4 +#ifndef BESTN_MAX +#define BESTN_MAX 3 +#endif + +#ifndef MSCAN_MAX +#define MSCAN_MAX 90 +#endif #endif /* LINUX_POSTMOGRIFY_REMOVAL */ +/* Service discovery */ +typedef struct { + uint8 transaction_id; /* Transaction id */ + uint8 protocol; /* Service protocol type */ + uint16 query_len; /* Length of query */ + uint16 response_len; /* Length of response */ + uint8 qrbuf[1]; +} wl_p2po_qr_t; + +typedef struct { + uint16 period; /* extended listen period */ + uint16 interval; /* extended listen interval */ +} wl_p2po_listen_t; + +/* ANQP offload */ + +#define ANQPO_MAX_QUERY_SIZE 256 +typedef struct { + uint16 max_retransmit; /* -1 use default, max retransmit on no ACK from peer */ + uint16 response_timeout; /* -1 use default, msec to wait for resp after tx packet */ + uint16 max_comeback_delay; /* -1 use default, max comeback delay in resp else fail */ + uint16 max_retries; /* -1 use default, max retries on failure */ + uint16 query_len; /* length of ANQP query */ + uint8 query_data[1]; /* ANQP encoded query (max ANQPO_MAX_QUERY_SIZE) */ +} wl_anqpo_set_t; + +typedef struct { + uint16 channel; /* channel of the peer */ + struct ether_addr addr; /* addr of the peer */ +} wl_anqpo_peer_t; + +#define ANQPO_MAX_PEER_LIST 64 +typedef struct { + uint16 count; /* number of peers in list */ + wl_anqpo_peer_t peer[1]; /* max ANQPO_MAX_PEER_LIST */ +} wl_anqpo_peer_list_t; + +#define ANQPO_MAX_IGNORE_SSID 64 +typedef struct { + bool is_clear; /* set to clear list (not used on GET) */ + uint16 count; /* number of SSID in list */ + wlc_ssid_t ssid[1]; /* max ANQPO_MAX_IGNORE_SSID */ +} wl_anqpo_ignore_ssid_list_t; + +#define ANQPO_MAX_IGNORE_BSSID 64 +typedef struct { + bool is_clear; /* set to clear list (not used on GET) */ + uint16 count; /* number of addr in list */ + struct ether_addr bssid[1]; /* max ANQPO_MAX_IGNORE_BSSID */ +} wl_anqpo_ignore_bssid_list_t; + /* TCP Checksum Offload defines */ #define TOE_TX_CSUM_OL 0x00000001 #define TOE_RX_CSUM_OL 0x00000002 @@ -3822,7 +4134,7 @@ struct toe_ol_stats_t { #define ARP_ERRTEST_REPLY_HOST 0x2 #define ARP_MULTIHOMING_MAX 8 /* Maximum local host IP addresses */ -#define ND_MULTIHOMING_MAX 8 /* Maximum local host IP addresses */ +#define ND_MULTIHOMING_MAX 10 /* Maximum local host IP addresses */ /* Arp offload statistic counts */ struct arp_ol_stats_t { @@ -3871,10 +4183,23 @@ typedef struct wl_keep_alive_pkt { #define WL_KEEP_ALIVE_FIXED_LEN OFFSETOF(wl_keep_alive_pkt_t, data) +#ifdef PKT_FILTER_SUPPORT /* * Dongle pattern matching filter. */ +/* Packet filter operation mode */ +/* True: 1; False: 0 */ +#define PKT_FILTER_MODE_FORWARD_ON_MATCH 1 +/* Enable and disable pkt_filter as a whole */ +#define PKT_FILTER_MODE_DISABLE 2 +/* Cache first matched rx pkt(be queried by host later) */ +#define PKT_FILTER_MODE_PKT_CACHE_ON_MATCH 4 +/* If pkt_filter is enabled and no filter is set, don't forward anything */ +#define PKT_FILTER_MODE_PKT_FORWARD_OFF_DEFAULT 8 +/* Ports only filter mode */ +#define PKT_FILTER_MODE_PORTS_ONLY 16 + /* Packet filter types. Currently, only pattern matching is supported. */ typedef enum wl_pkt_filter_type { WL_PKT_FILTER_TYPE_PATTERN_MATCH /* Pattern matching filter */ @@ -3930,6 +4255,29 @@ typedef struct wl_pkt_filter_stats { uint32 num_pkts_discarded; /* # packets discarded by dongle for all filters */ } wl_pkt_filter_stats_t; +/* IOVAR "pkt_filter_ports" parameter */ +typedef struct wl_pkt_filter_ports { + uint8 version; /* Be proper */ + uint8 reserved; /* Be really proper */ + uint16 count; /* Number of ports following */ + /* End of fixed data */ + uint16 ports[1]; /* Placeholder for ports[<count>] */ +} wl_pkt_filter_ports_t; +#define WL_PKT_FILTER_PORTS_FIXED_LEN OFFSETOF(wl_pkt_filter_ports_t, ports) + +#define WL_PKT_FILTER_PORTS_VERSION 0 +#define WL_PKT_FILTER_PORTS_MAX 128 +#endif /* PKT_FILTER_SUPPORT */ + +#define RSN_KCK_LENGTH 16 +#define RSN_KEK_LENGTH 16 +#define RSN_REPLAY_LEN 8 +typedef struct _gtkrefresh { + uchar KCK[RSN_KCK_LENGTH]; + uchar KEK[RSN_KEK_LENGTH]; + uchar ReplayCounter[RSN_REPLAY_LEN]; +} gtk_keyinfo_t, *pgtk_keyinfo_t; + /* Sequential Commands ioctl */ typedef struct wl_seq_cmd_ioctl { uint32 cmd; /* common ioctl definition */ @@ -3962,6 +4310,8 @@ typedef struct wl_seq_cmd_ioctl { #define WL_PKTENG_SYNCHRONOUS 0x100 /* synchronous flag */ +#define WL_PKTENG_MAXPKTSZ 16384 /* max pktsz limit for pkteng */ + typedef struct wl_pkteng { uint32 flags; uint32 delay; /* Inter-packet delay */ @@ -3981,6 +4331,7 @@ typedef struct wl_pkteng_stats { int32 rssi; /* RSSI */ int32 snr; /* signal to noise ratio */ uint16 rxpktcnt[NUM_80211_RATES+1]; + uint8 rssi_qdb; /* qdB portion of the computed rssi */ } wl_pkteng_stats_t; @@ -4004,14 +4355,14 @@ typedef struct wl_pkteng_stats { #define MAGIC_PKT_MINLEN 102 /* Magic pkt min length is 6 * 0xFF + 16 * ETHER_ADDR_LEN */ #define WOWL_PATTEN_TYPE_ARP (1 << 0) /* ARP offload Pattern */ -#define WOWL_PATTEN_TYPE_NA (1 << 1) /* NA offload Pattern */ +#define WOWL_PATTEN_TYPE_NA (1 << 1) /* NA offload Pattern */ typedef struct { uint32 masksize; /* Size of the mask in #of bytes */ uint32 offset; /* Offset to start looking for the packet in # of bytes */ - uint32 patternoffset; /* Offset of start of pattern in the structure */ + uint32 patternoffset; /* Offset of start of pattern in the structure */ uint32 patternsize; /* Size of the pattern itself in #of bytes */ - uint32 id; /* id */ + uint32 id; /* id */ uint32 reasonsize; /* Size of the wakeup reason code */ uint32 flags; /* Flags to tell the pattern type and other properties */ /* Mask follows the structure above */ @@ -4145,6 +4496,37 @@ typedef struct { uint32 queue_capacity; /* the maximum capacity of the queue */ } pktq_log_counters_v01_t; +typedef struct { + uint32 requested; /* packets requested to be stored */ + uint32 stored; /* packets stored */ + uint32 saved; /* packets saved, + because a lowest priority queue has given away one packet + */ + uint32 selfsaved; /* packets saved, + because an older packet from the same queue has been dropped + */ + uint32 full_dropped; /* packets dropped, + because pktq is full with higher precedence packets + */ + uint32 dropped; /* packets dropped because pktq per that precedence is full */ + uint32 sacrificed; /* packets dropped, + in order to save one from a queue of a highest priority + */ + uint32 busy; /* packets droped because of hardware/transmission error */ + uint32 retry; /* packets re-sent because they were not received */ + uint32 ps_retry; /* packets retried again prior to moving power save mode */ + uint32 retry_drop; /* packets finally dropped after retry limit */ + uint32 max_avail; /* the high-water mark of the queue capacity for packets - + goes to zero as queue fills + */ + uint32 max_used; /* the high-water mark of the queue utilisation for packets - + increases with use ('inverse' of max_avail) + */ + uint32 queue_capacity; /* the maximum capacity of the queue */ + uint32 rtsfail; /* count of rts attempts that failed to receive cts */ + uint32 acked; /* count of packets sent (acked) successfully */ +} pktq_log_counters_v02_t; + #define sacrified sacrificed typedef struct { @@ -4153,12 +4535,21 @@ typedef struct { char headings[1]; } pktq_log_format_v01_t; +typedef struct { + uint8 num_prec[WL_IOV_MAC_PARAM_LEN]; + pktq_log_counters_v02_t counters[WL_IOV_MAC_PARAM_LEN][WL_IOV_PKTQ_LOG_PRECS]; + uint32 throughput[WL_IOV_MAC_PARAM_LEN][WL_IOV_PKTQ_LOG_PRECS]; + uint32 time_delta; + char headings[1]; +} pktq_log_format_v02_t; + typedef struct { uint32 version; wl_iov_mac_params_t params; union { pktq_log_format_v01_t v01; + pktq_log_format_v02_t v02; } pktq_log; } wl_iov_pktq_log_t; @@ -4293,6 +4684,36 @@ typedef struct { #endif /* LINUX_POSTMOGRIFY_REMOVAL */ +#define BSS_PEER_INFO_PARAM_CUR_VER 0 +/* Input structure for IOV_BSS_PEER_INFO */ +typedef BWL_PRE_PACKED_STRUCT struct { + uint16 version; + struct ether_addr ea; /* peer MAC address */ +} BWL_POST_PACKED_STRUCT bss_peer_info_param_t; + +#define BSS_PEER_INFO_CUR_VER 0 + +typedef BWL_PRE_PACKED_STRUCT struct { + uint16 version; + struct ether_addr ea; + int32 rssi; + uint32 tx_rate; /* current tx rate */ + uint32 rx_rate; /* current rx rate */ + wl_rateset_t rateset; /* rateset in use */ + uint32 age; /* age in seconds */ +} BWL_POST_PACKED_STRUCT bss_peer_info_t; + +#define BSS_PEER_LIST_INFO_CUR_VER 0 + +typedef BWL_PRE_PACKED_STRUCT struct { + uint16 version; + uint16 bss_peer_info_len; /* length of bss_peer_info_t */ + uint32 count; /* number of peer info */ + bss_peer_info_t peer_info[1]; /* peer info */ +} BWL_POST_PACKED_STRUCT bss_peer_list_info_t; + +#define BSS_PEER_LIST_INFO_FIXED_LEN OFFSETOF(bss_peer_list_info_t, peer_info) + /* no default structure packing */ #include <packed_section_end.h> @@ -4316,6 +4737,21 @@ typedef struct { #define VNDR_IE_IWAPID_FLAG 0x40 /* vendor IE in IW advertisement protocol ID field */ #define VNDR_IE_CUSTOM_FLAG 0x100 /* allow custom IE id */ +#if defined(WLP2P) +/* P2P Action Frames flags (spec ordered) */ +#define VNDR_IE_GONREQ_FLAG 0x001000 +#define VNDR_IE_GONRSP_FLAG 0x002000 +#define VNDR_IE_GONCFM_FLAG 0x004000 +#define VNDR_IE_INVREQ_FLAG 0x008000 +#define VNDR_IE_INVRSP_FLAG 0x010000 +#define VNDR_IE_DISREQ_FLAG 0x020000 +#define VNDR_IE_DISRSP_FLAG 0x040000 +#define VNDR_IE_PRDREQ_FLAG 0x080000 +#define VNDR_IE_PRDRSP_FLAG 0x100000 + +#define VNDR_IE_P2PAF_SHIFT 12 +#endif /* WLP2P */ + #define VNDR_IE_INFO_HDR_LEN (sizeof(uint32)) typedef BWL_PRE_PACKED_STRUCT struct { @@ -4390,8 +4826,57 @@ typedef BWL_PRE_PACKED_STRUCT struct { } BWL_POST_PACKED_STRUCT txfailinfo_t; #endif /* WLMEDIA_TXFAILEVENT */ +typedef BWL_PRE_PACKED_STRUCT struct { + uint32 flags; + chanspec_t chanspec; /* txpwr report for this channel */ + chanspec_t local_chanspec; /* channel on which we are associated */ + uint8 local_max; /* local max according to the AP */ + uint8 local_constraint; /* local constraint according to the AP */ + int8 antgain[2]; /* Ant gain for each band - from SROM */ + uint8 rf_cores; /* count of RF Cores being reported */ + uint8 est_Pout[4]; /* Latest tx power out estimate per RF chain */ + uint8 est_Pout_act[4]; /* Latest tx power out estimate per RF chain w/o adjustment */ + uint8 est_Pout_cck; /* Latest CCK tx power out estimate */ + uint8 tx_power_max[4]; /* Maximum target power among all rates */ + uint tx_power_max_rate_ind[4]; /* Index of the rate with the max target power */ + int8 clm_limits[WL_NUMRATES]; /* regulatory limits - 20, 40 or 80MHz */ + int8 clm_limits_subchan1[WL_NUMRATES]; /* regulatory limits - 20in40 or 40in80 */ + int8 clm_limits_subchan2[WL_NUMRATES]; /* regulatory limits - 20in80MHz */ + int8 sar; /* SAR limit for display by wl executable */ + int8 channel_bandwidth; /* 20, 40 or 80 MHz bandwidth? */ + uint8 version; /* Version of the data format wlu <--> driver */ + uint8 display_core; /* Displayed curpower core */ + int8 target_offsets[4]; /* Target power offsets for current rate per core */ + uint32 last_tx_ratespec; /* Ratespec for last transmition */ + uint user_target; /* user limit */ + uint32 board_limit_len; /* length of board limit buffer */ + uint32 target_len; /* length of target power buffer */ + int8 SARLIMIT[MAX_STREAMS_SUPPORTED]; + uint8 pprdata[1]; /* ppr serialization buffer */ +} BWL_POST_PACKED_STRUCT tx_pwr_rpt_t; + +typedef BWL_PRE_PACKED_STRUCT struct { + struct ipv4_addr ipv4_addr; + struct ether_addr nexthop; +} BWL_POST_PACKED_STRUCT ibss_route_entry_t; +typedef BWL_PRE_PACKED_STRUCT struct { + uint32 num_entry; + ibss_route_entry_t route_entry[1]; +} BWL_POST_PACKED_STRUCT ibss_route_tbl_t; + +#define MAX_IBSS_ROUTE_TBL_ENTRY 64 #endif /* LINUX_POSTMOGRIFY_REMOVAL */ +#define AIBSS_TXFAIL_CONFIG_VER_0 0 + +/* structure used to configure AIBSS beacon force xmit */ +typedef BWL_PRE_PACKED_STRUCT struct { + uint16 version; + uint16 len; + uint32 bcn_timeout; /* dur in seconds to receive 1 bcn */ + uint32 max_tx_retry; /* no of consecutive no acks to send txfail event */ +} BWL_POST_PACKED_STRUCT aibss_txfail_config_t; + /* no strict structure packing */ #include <packed_section_end.h> @@ -4428,10 +4913,12 @@ typedef struct assertlog_results { /* define for apcs reason code */ #define APCS_INIT 0 -#define APCS_IOCTL 1 -#define APCS_CHANIM 2 +#define APCS_IOCTL 1 +#define APCS_CHANIM 2 #define APCS_CSTIMER 3 #define APCS_BTA 4 +#define APCS_TXDLY 5 +#define APCS_NONACSD 6 /* number of ACS record entries */ #define CHANIM_ACS_RECORD 10 @@ -4703,7 +5190,9 @@ typedef struct wl_nic_cnx { uint8 SSID_len; uint8 SSID[32]; struct ether_addr abssid; - uint8 join_period; + uint16 beacon_interval; + uint16 sync_threshold; + uint16 beacon_wait_time; } wl_nic_cnx_t; /* opcode */ @@ -4717,16 +5206,23 @@ typedef struct wl_nic_cnx { typedef struct wl_nic_cfg { uint8 version; uint8 beacon_mode; - uint16 beacon_interval; uint8 diluted_beacon_period; - uint8 repeat_EQC; + uint8 beacon_probability; + uint8 num_awake_window_params; + struct { + uint8 channel_number; + uint8 awake_window_length; + uint8 repeat_EQC; + } awake_window_params[3]; uint8 scan_length; uint8 scan_interval; uint8 scan_probability; - uint8 awake_window_length; - int8 TSF_correction; uint8 ASID; uint8 channel_usage_mode; + uint8 CWmin_af; + uint8 NIC_priority; + uint8 NIC_data_ind; + uint8 allowed_wakeup_delay; } wl_nic_cfg_t; /* version */ @@ -4748,7 +5244,6 @@ typedef struct wl_nic_frm { } wl_nic_frm_t; /* type */ -#define WL_NIC_FRM_MYNET 1 #define WL_NIC_FRM_ACTION 2 /* i/f query */ @@ -4761,8 +5256,17 @@ typedef struct wl_nic_ifq { /* nic_dm iovar */ typedef struct wl_nic_dm { uint8 enab; + uint8 rsvd; + /* the following fields are valid when enabling... */ chanspec_t chspec; + uint8 DATA_priority; + uint8 NIC_priority; } wl_nic_dm_t; + +/* immediate scan request */ +typedef struct wl_nic_isq { + uint8 scan_length; +} wl_nic_isq_t; #endif /* WLNIC */ /* RFAWARE def */ @@ -4907,6 +5411,13 @@ enum { SPATIAL_MODE_MAX_IDX }; +#define WLC_TXCORE_MAX 4 /* max number of txcore supports */ +#define WLC_SUBBAND_MAX 4 /* max number of sub-band supports */ +typedef struct { + uint8 band2g[WLC_TXCORE_MAX]; + uint8 band5g[WLC_SUBBAND_MAX][WLC_TXCORE_MAX]; +} sar_limit_t; + /* IOVAR "mempool" parameter. Used to retrieve a list of memory pool statistics. */ typedef struct wl_mempool_stats { int num; /* Number of memory pools */ @@ -4942,15 +5453,23 @@ typedef struct { #define TRF_MGMT_MAX_PRIORITIES 3 #define TRF_MGMT_FLAG_ADD_DSCP 0x0001 /* Add DSCP to IP TOS field */ -#define TRF_MGMT_FLAG_DISABLE_SHAPING 0x0002 /* Only support traffic clasification */ -#define TRF_MGMT_FLAG_DISABLE_PRIORITY_TAGGING 0x0004 /* Don't override packet's priority */ +#define TRF_MGMT_FLAG_DISABLE_SHAPING 0x0002 /* Don't shape traffic */ +#define TRF_MGMT_FLAG_MANAGE_LOCAL_TRAFFIC 0x0008 /* Manage traffic over our local subnet */ +#define TRF_MGMT_FLAG_FILTER_ON_MACADDR 0x0010 /* filter on MAC address */ +#define TRF_MGMT_FLAG_NO_RX 0x0020 /* do not apply fiters to rx packets */ + +#define TRF_FILTER_MAC_ADDR 0x0001 /* L2 filter use dst mac address for filtering */ +#define TRF_FILTER_IP_ADDR 0x0002 /* L3 filter use ip ddress for filtering */ +#define TRF_FILTER_L4 0x0004 /* L4 filter use tcp/udp for filtering */ +#define TRF_FILTER_FAVORED 0x0010 /* Tag the packet FAVORED */ /* Traffic management priority classes */ typedef enum trf_mgmt_priority_class { - trf_mgmt_priority_low = 0, /* Maps to 802.1p BO */ - trf_mgmt_priority_medium = 1, /* Maps to 802.1p BE */ - trf_mgmt_priority_high = 2, /* Maps to 802.1p VI */ - trf_mgmt_priority_invalid = (trf_mgmt_priority_high + 1) + trf_mgmt_priority_low = 0, /* Maps to 802.1p BK */ + trf_mgmt_priority_medium = 1, /* Maps to 802.1p BE */ + trf_mgmt_priority_high = 2, /* Maps to 802.1p VI */ + trf_mgmt_priority_nochange = 3, /* do not update the priority */ + trf_mgmt_priority_invalid = (trf_mgmt_priority_nochange + 1) } trf_mgmt_priority_class_t; /* Traffic management configuration parameters */ @@ -5032,5 +5551,163 @@ typedef struct powersel_params { uint8 pwr_sel_exp_time; /* Time lapse for expiry of database */ } powersel_params_t; +/* tx pkt delay statistics */ +#define SCB_RETRY_SHORT_DEF 7 /* Default Short retry Limit */ +#define WLPKTDLY_HIST_NBINS 16 /* number of bins used in the Delay histogram */ + +/* structure to store per-AC delay statistics */ +typedef struct scb_delay_stats { + uint32 txmpdu_lost; /* number of MPDUs lost */ + uint32 txmpdu_cnt[SCB_RETRY_SHORT_DEF]; /* retry times histogram */ + uint32 delay_sum[SCB_RETRY_SHORT_DEF]; /* cumulative packet latency */ + uint32 delay_min; /* minimum packet latency observed */ + uint32 delay_max; /* maximum packet latency observed */ + uint32 delay_avg; /* packet latency average */ + uint32 delay_hist[WLPKTDLY_HIST_NBINS]; /* delay histogram */ +} scb_delay_stats_t; + +/* structure for txdelay event */ +typedef struct txdelay_event { + uint8 status; + int rssi; + chanim_stats_t chanim_stats; + scb_delay_stats_t delay_stats[AC_COUNT]; +} txdelay_event_t; + +/* structure for txdelay parameters */ +typedef struct txdelay_params { + uint16 ratio; /* Avg Txdelay Delta */ + uint8 cnt; /* Sample cnt */ + uint8 period; /* Sample period */ + uint8 tune; /* Debug */ +} txdelay_params_t; + +#define WL_RELMCAST_MAX_CLIENT 32 +#define WL_RELMCAST_FLAG_INBLACKLIST 1 +#define WL_RELMCAST_FLAG_ACTIVEACKER 2 +#define WL_RELMCAST_FLAG_RELMCAST 4 +#define WL_RELMCAST_MAX_TABLE_ENTRY 4 + +#define WL_RELMCAST_VER 1 +#define WL_RELMCAST_INDEX_ACK_ALL 255 +#define WL_RELMCAST_NUM_OF_MC_STREAMS 4 +#define WL_RELMCAST_MAX_TRS_PER_GROUP 1 +#define WL_RELMCAST_ACK_MCAST0 0x02 +#define WL_RELMCAST_ACK_MCAST_ALL 0x01 +#define WL_RELMCAST_ACTF_TIME_MIN 300 /* time in ms */ +#define WL_RELMCAST_ACTF_TIME_MAX 20000 /* time in ms */ + +enum { + RELMCAST_ENTRY_OP_DISABLE = 0, + RELMCAST_ENTRY_OP_DELETE, + RELMCAST_ENTRY_OP_ENABLE, + RELMCAST_ENTRY_OP_ACK_ALL +}; + +enum { + WL_RELMCAST_MODE_RECEIVER = 0, + WL_RELMCAST_MODE_TRANSMITTER, + WL_RELMCAST_MODE_INITIATOR +}; + +typedef struct wl_relmcast_client { + uint8 flag; + int16 rssi; + struct ether_addr addr; +} wl_relmcast_client_t; + +typedef struct wl_relmcast_st { + uint8 ver; + uint8 num; + wl_relmcast_client_t clients[WL_RELMCAST_MAX_CLIENT]; + uint16 err; +} wl_relmcast_status_t; + +typedef struct wl_relmcast_entry { + int8 flag; + struct ether_addr addr; +} wl_relmcast_entry_t; + +typedef struct wl_relmcast_entry_table { + int8 index; + int8 opcode; + wl_relmcast_entry_t entry[WL_RELMCAST_MAX_TABLE_ENTRY]; +} wl_relmcast_entry_table_t; + +typedef struct wl_tr_Info { + struct ether_addr addr; + uint32 timeVal; + uint16 seq; +} wl_tr_Info_t; + +typedef struct wl_mcGrpEntry { + struct ether_addr mcaddr; + struct ether_addr ar; + wl_tr_Info_t trInfo[WL_RELMCAST_MAX_TRS_PER_GROUP]; +} wl_mcGrpEntry_t; + +typedef struct wl_mcAckAllEntry { + struct ether_addr ar; + wl_tr_Info_t trInfo[WL_RELMCAST_NUM_OF_MC_STREAMS]; +} wl_mcAckAllEntry_t; + +typedef struct wl_relmcast_globalMcTbl { + uint8 activeMask; + wl_mcAckAllEntry_t ackAll; + wl_mcGrpEntry_t mcEntry[WL_RELMCAST_NUM_OF_MC_STREAMS]; +} wl_relmcast_globalMcTbl_t; #endif /* LINUX_POSTMOGRIFY_REMOVAL */ + +/* fbt_cap: FBT assoc / reassoc modes. */ +#define WLC_FBT_CAP_DRV_4WAY_AND_REASSOC 1 /* Driver 4-way handshake & reassoc (WLFBT). */ + +typedef struct bcnreq { + uint8 bcn_mode; + int dur; + int channel; + struct ether_addr da; + uint16 random_int; + wlc_ssid_t ssid; + uint16 reps; +} bcnreq_t; + +typedef struct rrmreq { + struct ether_addr da; + uint8 reg; + uint8 chan; + uint16 random_int; + uint16 dur; + uint16 reps; +} rrmreq_t; + +typedef struct framereq { + struct ether_addr da; + uint8 reg; + uint8 chan; + uint16 random_int; + uint16 dur; + struct ether_addr ta; + uint16 reps; +} framereq_t; + +typedef struct statreq { + struct ether_addr da; + struct ether_addr peer; + uint16 random_int; + uint16 dur; + uint8 group_id; + uint16 reps; +} statreq_t; + +typedef struct wl_el_set_params_s { + uint8 set; /* Set number */ + uint32 size; /* Size to make/expand */ +} wl_el_set_params_t; + +typedef struct wl_el_tag_params_s { + uint16 tag; + uint8 set; + uint8 flags; +} wl_el_tag_params_t; + #endif /* _wlioctl_h_ */ diff --git a/drivers/net/wireless/bcmdhd/linux_osl.c b/drivers/net/wireless/bcmdhd/linux_osl.c index 37fdb2ea766d..090753b11dcb 100644..100755 --- a/drivers/net/wireless/bcmdhd/linux_osl.c +++ b/drivers/net/wireless/bcmdhd/linux_osl.c @@ -1,7 +1,7 @@ /* * Linux OS Independent Layer * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -21,7 +21,7 @@ * 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: linux_osl.c 373382 2012-12-07 07:59:52Z $ + * $Id: linux_osl.c 412994 2013-07-17 12:38:03Z $ */ #define LINUX_PORT @@ -36,6 +36,7 @@ #include <pcicfg.h> + #include <linux/fs.h> #define PCI_CFG_RETRY 10 @@ -100,13 +101,29 @@ struct osl_info { uint magic; void *pdev; atomic_t malloced; + atomic_t pktalloced; /* Number of allocated packet buffers */ uint failed; uint bustype; bcm_mem_link_t *dbgmem_list; spinlock_t dbgmem_lock; +#ifdef BCMDBG_CTRACE + spinlock_t ctrace_lock; + struct list_head ctrace_list; + int ctrace_num; +#endif /* BCMDBG_CTRACE */ spinlock_t pktalloc_lock; }; +#define OSL_PKTTAG_CLEAR(p) \ +do { \ + struct sk_buff *s = (struct sk_buff *)(p); \ + ASSERT(OSL_PKTTAG_SZ == 32); \ + *(uint32 *)(&s->cb[0]) = 0; *(uint32 *)(&s->cb[4]) = 0; \ + *(uint32 *)(&s->cb[8]) = 0; *(uint32 *)(&s->cb[12]) = 0; \ + *(uint32 *)(&s->cb[16]) = 0; *(uint32 *)(&s->cb[20]) = 0; \ + *(uint32 *)(&s->cb[24]) = 0; *(uint32 *)(&s->cb[28]) = 0; \ +} while (0) + /* PCMCIA attribute space access macros */ /* Global ASSERT type flag */ @@ -156,15 +173,14 @@ static int16 linuxbcmerrormap[] = -ENODEV, /* BCME_NODEVICE */ -EINVAL, /* BCME_NMODE_DISABLED */ -ENODATA, /* BCME_NONRESIDENT */ + -EINVAL, /* BCME_SCANREJECT */ + -EINVAL, /* BCME_USAGE_ERROR */ + -EIO, /* BCME_IOCTL_ERROR */ + -EIO, /* BCME_SERIAL_PORT_ERR */ /* When an new error code is added to bcmutils.h, add os * specific error translation here as well */ -/* check if BCME_LAST changed since the last time this function was updated */ -#if BCME_LAST != -42 -#error "You need to add a OS error translation in the linuxbcmerrormap \ - for new error code defined in bcmutils.h" -#endif }; /* translate bcmerrors into linux errors */ @@ -186,8 +202,14 @@ osl_t * osl_attach(void *pdev, uint bustype, bool pkttag) { osl_t *osh; + gfp_t flags; - if (!(osh = kmalloc(sizeof(osl_t), GFP_ATOMIC))) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) + flags = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL; +#else + flags = GFP_ATOMIC; +#endif + if (!(osh = kmalloc(sizeof(osl_t), flags))) return osh; ASSERT(osh); @@ -229,6 +251,10 @@ osl_attach(void *pdev, uint bustype, bool pkttag) if (!(bcm_static_buf = (bcm_static_buf_t *)dhd_os_prealloc(osh, 3, STATIC_BUF_SIZE+ STATIC_BUF_TOTAL_LEN))) { printk("can not alloc static buf!\n"); + bcm_static_skb = NULL; + ASSERT(osh->magic == OS_HANDLE_MAGIC); + kfree(osh); + return NULL; } else printk("alloc static buf at %x!\n", (unsigned int)bcm_static_buf); @@ -244,16 +270,30 @@ osl_attach(void *pdev, uint bustype, bool pkttag) void *skb_buff_ptr = 0; bcm_static_skb = (bcm_static_pkt_t *)((char *)bcm_static_buf + 2048); skb_buff_ptr = dhd_os_prealloc(osh, 4, 0); + if (!skb_buff_ptr) { + printk("cannot alloc static buf!\n"); + bcm_static_buf = NULL; + bcm_static_skb = NULL; + ASSERT(osh->magic == OS_HANDLE_MAGIC); + kfree(osh); + return NULL; + } - bcopy(skb_buff_ptr, bcm_static_skb, sizeof(struct sk_buff *)* + bcopy(skb_buff_ptr, bcm_static_skb, sizeof(struct sk_buff *) * (STATIC_PKT_MAX_NUM * 2 + STATIC_PKT_4PAGE_NUM)); - for (i = 0; i < (STATIC_PKT_MAX_NUM * 2 + STATIC_PKT_4PAGE_NUM); i++) + for (i = 0; i < STATIC_PKT_MAX_NUM * 2 + STATIC_PKT_4PAGE_NUM; i++) bcm_static_skb->pkt_use[i] = 0; sema_init(&bcm_static_skb->osl_pkt_sem, 1); } #endif /* CONFIG_DHD_USE_STATIC_BUF */ +#ifdef BCMDBG_CTRACE + spin_lock_init(&osh->ctrace_lock); + INIT_LIST_HEAD(&osh->ctrace_list); + osh->ctrace_num = 0; +#endif /* BCMDBG_CTRACE */ + spin_lock_init(&(osh->pktalloc_lock)); return osh; @@ -278,13 +318,17 @@ osl_detach(osl_t *osh) kfree(osh); } -static struct sk_buff *osl_alloc_skb(unsigned int len) +static struct sk_buff *osl_alloc_skb(osl_t *osh, unsigned int len) { + struct sk_buff *skb; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25) - return __dev_alloc_skb(len, GFP_ATOMIC); + gfp_t flags = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL; + + skb = __dev_alloc_skb(len, flags); #else - return dev_alloc_skb(len); -#endif + skb = dev_alloc_skb(len); +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25) */ + return skb; } #ifdef CTFPOOL @@ -320,7 +364,7 @@ osl_ctfpool_add(osl_t *osh) } /* Allocate a new skb and add it to the ctfpool */ - skb = osl_alloc_skb(osh->ctfpool->obj_size); + skb = osl_alloc_skb(osh, osh->ctfpool->obj_size); if (skb == NULL) { printf("%s: skb alloc of len %d failed\n", __FUNCTION__, osh->ctfpool->obj_size); @@ -367,9 +411,15 @@ osl_ctfpool_replenish(osl_t *osh, uint thresh) int32 osl_ctfpool_init(osl_t *osh, uint numobj, uint size) { - osh->ctfpool = kmalloc(sizeof(ctfpool_t), GFP_ATOMIC); + gfp_t flags; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) + flags = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL; +#else + flags = GFP_ATOMIC; +#endif + osh->ctfpool = kzalloc(sizeof(ctfpool_t), flags); ASSERT(osh->ctfpool); - bzero(osh->ctfpool, sizeof(ctfpool_t)); osh->ctfpool->max_obj = numobj; osh->ctfpool->obj_size = size; @@ -482,9 +532,13 @@ osl_pktfastget(osl_t *osh, uint len) /* Init skb struct */ skb->next = skb->prev = NULL; +#if defined(__ARM_ARCH_7A__) + skb->data = skb->head + NET_SKB_PAD; + skb->tail = skb->head + NET_SKB_PAD; +#else skb->data = skb->head + 16; skb->tail = skb->head + 16; - +#endif /* __ARM_ARCH_7A__ */ skb->len = 0; skb->cloned = 0; #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14) @@ -492,6 +546,9 @@ osl_pktfastget(osl_t *osh, uint len) #endif atomic_set(&skb->users, 1); + PKTSETCLINK(skb, NULL); + PKTCCLRATTR(skb); + return skb; } #endif /* CTFPOOL */ @@ -503,22 +560,30 @@ osl_pktfastget(osl_t *osh, uint len) struct sk_buff * BCMFASTPATH osl_pkt_tonative(osl_t *osh, void *pkt) { -#ifndef WL_UMK struct sk_buff *nskb; - unsigned long flags; +#ifdef BCMDBG_CTRACE + struct sk_buff *nskb1, *nskb2; #endif if (osh->pub.pkttag) - bzero((void*)((struct sk_buff *)pkt)->cb, OSL_PKTTAG_SZ); + OSL_PKTTAG_CLEAR(pkt); -#ifndef WL_UMK /* Decrement the packet counter */ for (nskb = (struct sk_buff *)pkt; nskb; nskb = nskb->next) { - spin_lock_irqsave(&osh->pktalloc_lock, flags); - osh->pub.pktalloced--; - spin_unlock_irqrestore(&osh->pktalloc_lock, flags); + atomic_sub(PKTISCHAINED(nskb) ? PKTCCNT(nskb) : 1, &osh->pktalloced); + +#ifdef BCMDBG_CTRACE + for (nskb1 = nskb; nskb1 != NULL; nskb1 = nskb2) { + if (PKTISCHAINED(nskb1)) { + nskb2 = PKTCLINK(nskb1); + } + else + nskb2 = NULL; + + DEL_CTRACE(osh, nskb1); + } +#endif /* BCMDBG_CTRACE */ } -#endif /* WL_UMK */ return (struct sk_buff *)pkt; } @@ -526,49 +591,67 @@ osl_pkt_tonative(osl_t *osh, void *pkt) * In the process, native packet is destroyed, there is no copying * Also, a packettag is zeroed out */ +#ifdef BCMDBG_CTRACE +void * BCMFASTPATH +osl_pkt_frmnative(osl_t *osh, void *pkt, int line, char *file) +#else void * BCMFASTPATH osl_pkt_frmnative(osl_t *osh, void *pkt) +#endif /* BCMDBG_CTRACE */ { -#ifndef WL_UMK struct sk_buff *nskb; - unsigned long flags; +#ifdef BCMDBG_CTRACE + struct sk_buff *nskb1, *nskb2; #endif if (osh->pub.pkttag) - bzero((void*)((struct sk_buff *)pkt)->cb, OSL_PKTTAG_SZ); + OSL_PKTTAG_CLEAR(pkt); -#ifndef WL_UMK /* Increment the packet counter */ for (nskb = (struct sk_buff *)pkt; nskb; nskb = nskb->next) { - spin_lock_irqsave(&osh->pktalloc_lock, flags); - osh->pub.pktalloced++; - spin_unlock_irqrestore(&osh->pktalloc_lock, flags); + atomic_add(PKTISCHAINED(nskb) ? PKTCCNT(nskb) : 1, &osh->pktalloced); + +#ifdef BCMDBG_CTRACE + for (nskb1 = nskb; nskb1 != NULL; nskb1 = nskb2) { + if (PKTISCHAINED(nskb1)) { + nskb2 = PKTCLINK(nskb1); + } + else + nskb2 = NULL; + + ADD_CTRACE(osh, nskb1, file, line); + } +#endif /* BCMDBG_CTRACE */ } -#endif /* WL_UMK */ return (void *)pkt; } /* Return a new packet. zero out pkttag */ +#ifdef BCMDBG_CTRACE +void * BCMFASTPATH +osl_pktget(osl_t *osh, uint len, int line, char *file) +#else void * BCMFASTPATH osl_pktget(osl_t *osh, uint len) +#endif /* BCMDBG_CTRACE */ { struct sk_buff *skb; - unsigned long flags; #ifdef CTFPOOL /* Allocate from local pool */ skb = osl_pktfastget(osh, len); - if ((skb != NULL) || ((skb = osl_alloc_skb(len)) != NULL)) { + if ((skb != NULL) || ((skb = osl_alloc_skb(osh, len)) != NULL)) { #else /* CTFPOOL */ - if ((skb = osl_alloc_skb(len))) { + if ((skb = osl_alloc_skb(osh, len))) { #endif /* CTFPOOL */ - skb_put(skb, len); + skb->tail += len; + skb->len += len; skb->priority = 0; - - spin_lock_irqsave(&osh->pktalloc_lock, flags); - osh->pub.pktalloced++; - spin_unlock_irqrestore(&osh->pktalloc_lock, flags); +#ifdef BCMDBG_CTRACE + ADD_CTRACE(osh, skb, file, line); +#endif + atomic_inc(&osh->pktalloced); } return ((void*) skb); @@ -591,10 +674,17 @@ osl_pktfastfree(osl_t *osh, struct sk_buff *skb) /* We only need to init the fields that we change */ skb->dev = NULL; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) skb->dst = NULL; - memset(skb->cb, 0, sizeof(skb->cb)); +#endif + OSL_PKTTAG_CLEAR(skb); skb->ip_summed = 0; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) + skb_orphan(skb); +#else skb->destructor = NULL; +#endif ctfpool = (ctfpool_t *)CTFPOOLPTR(osh, skb); ASSERT(ctfpool != NULL); @@ -617,7 +707,12 @@ void BCMFASTPATH osl_pktfree(osl_t *osh, void *p, bool send) { struct sk_buff *skb, *nskb; - unsigned long flags; + + if (osh == NULL) + { + printk("%s: osh == NULL \n", __FUNCTION__); + return; + } skb = (struct sk_buff*) p; @@ -631,16 +726,21 @@ osl_pktfree(osl_t *osh, void *p, bool send) nskb = skb->next; skb->next = NULL; +#ifdef BCMDBG_CTRACE + DEL_CTRACE(osh, skb); +#endif #ifdef CTFPOOL - if ((PKTISFAST(osh, skb)) && (atomic_read(&skb->users) == 1)) + if (PKTISFAST(osh, skb)) { + if (atomic_read(&skb->users) == 1) + smp_rmb(); + else if (!atomic_dec_and_test(&skb->users)) + goto next_skb; osl_pktfastfree(osh, skb); - else { -#else /* CTFPOOL */ + } else +#endif { -#endif /* CTFPOOL */ - if (skb->destructor) /* cannot kfree_skb() on hard IRQ (net/core/skbuff.c) if * destructor exists @@ -652,9 +752,10 @@ osl_pktfree(osl_t *osh, void *p, bool send) */ dev_kfree_skb(skb); } - spin_lock_irqsave(&osh->pktalloc_lock, flags); - osh->pub.pktalloced--; - spin_unlock_irqrestore(&osh->pktalloc_lock, flags); +#ifdef CTFPOOL +next_skb: +#endif + atomic_dec(&osh->pktalloced); skb = nskb; } } @@ -666,10 +767,8 @@ osl_pktget_static(osl_t *osh, uint len) int i = 0; struct sk_buff *skb; - if (len > DHD_SKB_MAX_BUFSIZE) { - printk("osl_pktget_static: Do we really need this big skb??" - " len=%d\n", len); + printk("%s: attempt to allocate huge packet (0x%x)\n", __FUNCTION__, len); return osl_pktget(osh, len); } @@ -694,7 +793,6 @@ osl_pktget_static(osl_t *osh, uint len) } if (len <= DHD_SKB_2PAGE_BUFSIZE) { - for (i = 0; i < STATIC_PKT_MAX_NUM; i++) { if (bcm_static_skb->pkt_use[i + STATIC_PKT_MAX_NUM] == 0) @@ -726,7 +824,7 @@ osl_pktget_static(osl_t *osh, uint len) #endif up(&bcm_static_skb->osl_pkt_sem); - printk("osl_pktget_static: all static pkt in use!\n"); + printk("%s: all static pkt in use!\n", __FUNCTION__); return osl_pktget(osh, len); } @@ -757,18 +855,39 @@ osl_pktfree_static(osl_t *osh, void *p, bool send) } #ifdef ENHANCED_STATIC_BUF if (p == bcm_static_skb->skb_16k) { - bcm_static_skb->pkt_use[STATIC_PKT_MAX_NUM*2] = 0; + bcm_static_skb->pkt_use[STATIC_PKT_MAX_NUM * 2] = 0; up(&bcm_static_skb->osl_pkt_sem); return; } #endif up(&bcm_static_skb->osl_pkt_sem); - osl_pktfree(osh, p, send); - return; } #endif /* CONFIG_DHD_USE_STATIC_BUF */ +int osh_pktpadtailroom(osl_t *osh, void* p, int pad) +{ + int err; + int ntail; + struct sk_buff* skb = (struct sk_buff*)p; + + ntail = skb->data_len + pad - (skb->end - skb->tail); + if (likely(skb_cloned(skb) || ntail > 0)) { + err = pskb_expand_head(skb, 0, ntail, GFP_ATOMIC); + if (unlikely(err)) + goto done; + } + + err = skb_linearize(skb); + if (unlikely(err)) + goto done; + + memset(skb->data + skb->len, 0, pad); + +done: + return err; +} + uint32 osl_pci_read_config(osl_t *osh, uint offset, uint size) { @@ -825,7 +944,11 @@ osl_pci_slot(osl_t *osh) { ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev); +#if defined(__ARM_ARCH_7A__) && LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35) + return PCI_SLOT(((struct pci_dev *)osh->pdev)->devfn) + 1; +#else return PCI_SLOT(((struct pci_dev *)osh->pdev)->devfn); +#endif } /* return the pci device pointed by osh->pdev */ @@ -858,6 +981,7 @@ void * osl_malloc(osl_t *osh, uint size) { void *addr; + gfp_t flags; /* only ASSERT if osh is defined */ if (osh) @@ -897,7 +1021,12 @@ osl_malloc(osl_t *osh, uint size) original: #endif /* CONFIG_DHD_USE_STATIC_BUF */ - if ((addr = kmalloc(size, GFP_ATOMIC)) == NULL) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) + flags = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL; +#else + flags = GFP_ATOMIC; +#endif + if ((addr = kmalloc(size, flags)) == NULL) { if (osh) osh->failed++; return (NULL); @@ -964,6 +1093,7 @@ osl_dma_consistent_align(void) void* osl_dma_alloc_consistent(osl_t *osh, uint size, uint16 align_bits, uint *alloced, ulong *pap) { + void *va; uint16 align = (1 << align_bits); ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); @@ -971,7 +1101,14 @@ osl_dma_alloc_consistent(osl_t *osh, uint size, uint16 align_bits, uint *alloced size += align; *alloced = size; - return (pci_alloc_consistent(osh->pdev, size, (dma_addr_t*)pap)); +#ifdef __ARM_ARCH_7A__ + va = kmalloc(size, GFP_ATOMIC | __GFP_ZERO); + if (va) + *pap = (ulong)__virt_to_phys((ulong)va); +#else + va = pci_alloc_consistent(osh->pdev, size, (dma_addr_t*)pap); +#endif + return va; } void @@ -979,16 +1116,52 @@ osl_dma_free_consistent(osl_t *osh, void *va, uint size, ulong pa) { ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); +#ifdef __ARM_ARCH_7A__ + kfree(va); +#else pci_free_consistent(osh->pdev, size, va, (dma_addr_t)pa); +#endif } uint BCMFASTPATH -osl_dma_map(osl_t *osh, void *va, uint size, int direction) +osl_dma_map(osl_t *osh, void *va, uint size, int direction, void *p, hnddma_seg_map_t *dmah) { int dir; ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); dir = (direction == DMA_TX)? PCI_DMA_TODEVICE: PCI_DMA_FROMDEVICE; + +#if defined(__ARM_ARCH_7A__) && defined(BCMDMASGLISTOSL) + if (dmah != NULL) { + int32 nsegs, i, totsegs = 0, totlen = 0; + struct scatterlist *sg, _sg[MAX_DMA_SEGS * 2]; + struct sk_buff *skb; + for (skb = (struct sk_buff *)p; skb != NULL; skb = PKTNEXT(osh, skb)) { + sg = &_sg[totsegs]; + if (skb_is_nonlinear(skb)) { + nsegs = skb_to_sgvec(skb, sg, 0, PKTLEN(osh, skb)); + ASSERT((nsegs > 0) && (totsegs + nsegs <= MAX_DMA_SEGS)); + pci_map_sg(osh->pdev, sg, nsegs, dir); + } else { + nsegs = 1; + ASSERT(totsegs + nsegs <= MAX_DMA_SEGS); + sg->page_link = 0; + sg_set_buf(sg, PKTDATA(osh, skb), PKTLEN(osh, skb)); + pci_map_single(osh->pdev, PKTDATA(osh, skb), PKTLEN(osh, skb), dir); + } + totsegs += nsegs; + totlen += PKTLEN(osh, skb); + } + dmah->nsegs = totsegs; + dmah->origsize = totlen; + for (i = 0, sg = _sg; i < totsegs; i++, sg++) { + dmah->segs[i].addr = sg_phys(sg); + dmah->segs[i].length = sg->length; + } + return dmah->segs[0].addr; + } +#endif /* __ARM_ARCH_7A__ && BCMDMASGLISTOSL */ + return (pci_map_single(osh->pdev, va, size, dir)); } @@ -1017,10 +1190,11 @@ osl_assert(const char *exp, const char *file, int line) if (!basename) basename = file; +#ifdef BCMASSERT_LOG snprintf(tempbuf, 64, "\"%s\": file \"%s\", line %d\n", exp, basename, line); - printk("%s", tempbuf); +#endif /* BCMASSERT_LOG */ } @@ -1038,22 +1212,44 @@ osl_delay(uint usec) } } +void +osl_sleep(uint ms) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) + if (ms < 20) + usleep_range(ms*1000, ms*1000 + 1000); + else +#endif + msleep(ms); +} + + /* Clone a packet. * The pkttag contents are NOT cloned. */ +#ifdef BCMDBG_CTRACE +void * +osl_pktdup(osl_t *osh, void *skb, int line, char *file) +#else void * osl_pktdup(osl_t *osh, void *skb) +#endif /* BCMDBG_CTRACE */ { void * p; - unsigned long irqflags; + + ASSERT(!PKTISCHAINED(skb)); /* clear the CTFBUF flag if set and map the rest of the buffer * before cloning. */ PKTCTFMAP(osh, skb); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) + if ((p = pskb_copy((struct sk_buff *)skb, GFP_ATOMIC)) == NULL) +#else if ((p = skb_clone((struct sk_buff *)skb, GFP_ATOMIC)) == NULL) +#endif return NULL; #ifdef CTFPOOL @@ -1074,17 +1270,83 @@ osl_pktdup(osl_t *osh, void *skb) } #endif /* CTFPOOL */ + /* Clear PKTC context */ + PKTSETCLINK(p, NULL); + PKTCCLRFLAGS(p); + PKTCSETCNT(p, 1); + PKTCSETLEN(p, PKTLEN(osh, skb)); + /* skb_clone copies skb->cb.. we don't want that */ if (osh->pub.pkttag) - bzero((void*)((struct sk_buff *)p)->cb, OSL_PKTTAG_SZ); + OSL_PKTTAG_CLEAR(p); /* Increment the packet counter */ - spin_lock_irqsave(&osh->pktalloc_lock, irqflags); - osh->pub.pktalloced++; - spin_unlock_irqrestore(&osh->pktalloc_lock, irqflags); + atomic_inc(&osh->pktalloced); +#ifdef BCMDBG_CTRACE + ADD_CTRACE(osh, (struct sk_buff *)p, file, line); +#endif return (p); } +#ifdef BCMDBG_CTRACE +int osl_pkt_is_frmnative(osl_t *osh, struct sk_buff *pkt) +{ + unsigned long flags; + struct sk_buff *skb; + int ck = FALSE; + + spin_lock_irqsave(&osh->ctrace_lock, flags); + + list_for_each_entry(skb, &osh->ctrace_list, ctrace_list) { + if (pkt == skb) { + ck = TRUE; + break; + } + } + + spin_unlock_irqrestore(&osh->ctrace_lock, flags); + return ck; +} + +void osl_ctrace_dump(osl_t *osh, struct bcmstrbuf *b) +{ + unsigned long flags; + struct sk_buff *skb; + int idx = 0; + int i, j; + + spin_lock_irqsave(&osh->ctrace_lock, flags); + + if (b != NULL) + bcm_bprintf(b, " Total %d sbk not free\n", osh->ctrace_num); + else + printk(" Total %d sbk not free\n", osh->ctrace_num); + + list_for_each_entry(skb, &osh->ctrace_list, ctrace_list) { + if (b != NULL) + bcm_bprintf(b, "[%d] skb %p:\n", ++idx, skb); + else + printk("[%d] skb %p:\n", ++idx, skb); + + for (i = 0; i < skb->ctrace_count; i++) { + j = (skb->ctrace_start + i) % CTRACE_NUM; + if (b != NULL) + bcm_bprintf(b, " [%s(%d)]\n", skb->func[j], skb->line[j]); + else + printk(" [%s(%d)]\n", skb->func[j], skb->line[j]); + } + if (b != NULL) + bcm_bprintf(b, "\n"); + else + printk("\n"); + } + + spin_unlock_irqrestore(&osh->ctrace_lock, flags); + + return; +} +#endif /* BCMDBG_CTRACE */ + /* * OSLREGOPS specifies the use of osl_XXX routines to be used for register access @@ -1094,6 +1356,12 @@ osl_pktdup(osl_t *osh, void *skb) * BINOSL selects the slightly slower function-call-based binary compatible osl. */ +uint +osl_pktalloced(osl_t *osh) +{ + return (atomic_read(&osh->pktalloced)); +} + /* Linux Kernel: File Operations: start */ void * osl_os_open_image(char *filename) @@ -1135,4 +1403,21 @@ osl_os_close_image(void *image) if (image) filp_close((struct file *)image, NULL); } + +int +osl_os_image_size(void *image) +{ + int len = 0, curroffset; + + if (image) { + /* store the current offset */ + curroffset = generic_file_llseek(image, 0, 1); + /* goto end of file to get length */ + len = generic_file_llseek(image, 0, 2); + /* restore back the offset */ + generic_file_llseek(image, curroffset, 0); + } + return len; +} + /* Linux Kernel: File Operations: end */ diff --git a/drivers/net/wireless/bcmdhd/sbutils.c b/drivers/net/wireless/bcmdhd/sbutils.c index 68cfcb27a9c4..a118ecb9c657 100644..100755 --- a/drivers/net/wireless/bcmdhd/sbutils.c +++ b/drivers/net/wireless/bcmdhd/sbutils.c @@ -2,7 +2,7 @@ * Misc utility routines for accessing chip-specific features * of the SiliconBackplane-based Broadcom chips. * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -22,7 +22,7 @@ * 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: sbutils.c 310902 2012-01-26 19:45:33Z $ + * $Id: sbutils.c 379512 2013-01-17 22:49:08Z $ */ #include <bcm_cfg.h> @@ -510,10 +510,11 @@ _sb_scan(si_info_t *sii, uint32 sba, void *regs, uint bus, uint32 sbba, uint num uint32 ccrev = sb_corerev(&sii->pub); /* determine numcores - this is the total # cores in the chip */ - if (((ccrev == 4) || (ccrev >= 6))) + if (((ccrev == 4) || (ccrev >= 6))) { + ASSERT(cc); numcores = (R_REG(sii->osh, &cc->chipid) & CID_CC_MASK) >> CID_CC_SHIFT; - else { + } else { /* Older chips */ uint chip = CHIPID(sii->pub.chip); diff --git a/drivers/net/wireless/bcmdhd/siutils.c b/drivers/net/wireless/bcmdhd/siutils.c index 6b305cfc3a30..e0f7199b6fdc 100644..100755 --- a/drivers/net/wireless/bcmdhd/siutils.c +++ b/drivers/net/wireless/bcmdhd/siutils.c @@ -2,7 +2,7 @@ * Misc utility routines for accessing chip-specific features * of the SiliconBackplane-based Broadcom chips. * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -22,7 +22,7 @@ * 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: siutils.c 384898 2013-02-13 14:20:11Z $ + * $Id: siutils.c 414368 2013-07-24 15:00:23Z $ */ #include <bcm_cfg.h> @@ -45,6 +45,7 @@ #include <bcmsdpcm.h> #include <hndpmu.h> + #include "siutils_priv.h" /* local prototypes */ @@ -109,6 +110,7 @@ si_kattach(osl_t *osh) void *regs = NULL; regs = REG_MAP(SI_ENUM_BASE, SI_CORE_SIZE); + ASSERT(osh); if (si_doattach(&ksii, BCM4710_DEVICE_ID, osh, regs, SI_BUS, NULL, osh != SI_OSH ? &ksii.vars : NULL, @@ -316,7 +318,8 @@ si_doattach(si_info_t *sii, uint devid, osl_t *osh, void *regs, chipcregs_t *cc; char *pvars = NULL; uint origidx; - +#if !defined(_CFEZ_) || defined(CFG_WL) +#endif ASSERT(GOODREGS(regs)); bzero((uchar*)sii, sizeof(si_info_t)); @@ -369,6 +372,7 @@ si_doattach(si_info_t *sii, uint devid, osl_t *osh, void *regs, return NULL; } w = R_REG(osh, &cc->chipid); + if ((w & 0xfffff) == 148277) w -= 65532; sih->socitype = (w & CID_TYPE_MASK) >> CID_TYPE_SHIFT; /* Might as wll fill in chip id rev & pkg */ sih->chip = w & CID_ID_MASK; @@ -385,8 +389,12 @@ si_doattach(si_info_t *sii, uint devid, osl_t *osh, void *regs, if (CHIPTYPE(sii->pub.socitype) == SOCI_SB) { SI_MSG(("Found chip type SB (0x%08x)\n", w)); sb_scan(&sii->pub, regs, devid); - } else if (CHIPTYPE(sii->pub.socitype) == SOCI_AI) { - SI_MSG(("Found chip type AI (0x%08x)\n", w)); + } else if ((CHIPTYPE(sii->pub.socitype) == SOCI_AI) || + (CHIPTYPE(sii->pub.socitype) == SOCI_NAI)) { + if (CHIPTYPE(sii->pub.socitype) == SOCI_AI) + SI_MSG(("Found chip type AI (0x%08x)\n", w)); + else + SI_MSG(("Found chip type NAI (0x%08x)\n", w)); /* pass chipc address instead of original core base */ ai_scan(&sii->pub, (void *)(uintptr)cc, devid); } else if (CHIPTYPE(sii->pub.socitype) == SOCI_UBUS) { @@ -409,6 +417,7 @@ si_doattach(si_info_t *sii, uint devid, osl_t *osh, void *regs, goto exit; } +#if !defined(_CFEZ_) || defined(CFG_WL) if (CHIPID(sih->chip) == BCM4322_CHIP_ID && (((sih->chipst & CST4322_SPROM_OTP_SEL_MASK) >> CST4322_SPROM_OTP_SEL_SHIFT) == (CST4322_OTP_PRESENT | CST4322_SPROM_PRESENT))) { @@ -437,6 +446,7 @@ si_doattach(si_info_t *sii, uint devid, osl_t *osh, void *regs, if (bustype == PCI_BUS) { } +#endif pvars = NULL; BCM_REFERENCE(pvars); @@ -555,7 +565,7 @@ si_intflag(si_t *sih) if (CHIPTYPE(sih->socitype) == SOCI_SB) return sb_intflag(sih); - else if (CHIPTYPE(sih->socitype) == SOCI_AI) + else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) return R_REG(sii->osh, ((uint32 *)(uintptr) (sii->oob_router + OOB_STATUSA))); else { @@ -569,7 +579,7 @@ si_flag(si_t *sih) { if (CHIPTYPE(sih->socitype) == SOCI_SB) return sb_flag(sih); - else if (CHIPTYPE(sih->socitype) == SOCI_AI) + else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) return ai_flag(sih); else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) return ub_flag(sih); @@ -579,12 +589,23 @@ si_flag(si_t *sih) } } +uint +si_flag_alt(si_t *sih) +{ + if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) + return ai_flag_alt(sih); + else { + ASSERT(0); + return 0; + } +} + void si_setint(si_t *sih, int siflag) { if (CHIPTYPE(sih->socitype) == SOCI_SB) sb_setint(sih, siflag); - else if (CHIPTYPE(sih->socitype) == SOCI_AI) + else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) ai_setint(sih, siflag); else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) ub_setint(sih, siflag); @@ -641,7 +662,7 @@ si_corevendor(si_t *sih) { if (CHIPTYPE(sih->socitype) == SOCI_SB) return sb_corevendor(sih); - else if (CHIPTYPE(sih->socitype) == SOCI_AI) + else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) return ai_corevendor(sih); else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) return ub_corevendor(sih); @@ -662,7 +683,7 @@ si_corerev(si_t *sih) { if (CHIPTYPE(sih->socitype) == SOCI_SB) return sb_corerev(sih); - else if (CHIPTYPE(sih->socitype) == SOCI_AI) + else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) return ai_corerev(sih); else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) return ub_corerev(sih); @@ -706,6 +727,18 @@ si_corelist(si_t *sih, uint coreid[]) return (sii->numcores); } +/* return current wrapper mapping */ +void * +si_wrapperregs(si_t *sih) +{ + si_info_t *sii; + + sii = SI_INFO(sih); + ASSERT(GOODREGS(sii->curwrap)); + + return (sii->curwrap); +} + /* return current register mapping */ void * si_coreregs(si_t *sih) @@ -734,7 +767,7 @@ si_setcore(si_t *sih, uint coreid, uint coreunit) if (CHIPTYPE(sih->socitype) == SOCI_SB) return sb_setcoreidx(sih, idx); - else if (CHIPTYPE(sih->socitype) == SOCI_AI) + else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) return ai_setcoreidx(sih, idx); else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) return ub_setcoreidx(sih, idx); @@ -749,7 +782,7 @@ si_setcoreidx(si_t *sih, uint coreidx) { if (CHIPTYPE(sih->socitype) == SOCI_SB) return sb_setcoreidx(sih, coreidx); - else if (CHIPTYPE(sih->socitype) == SOCI_AI) + else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) return ai_setcoreidx(sih, coreidx); else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) return ub_setcoreidx(sih, coreidx); @@ -806,7 +839,7 @@ si_numaddrspaces(si_t *sih) { if (CHIPTYPE(sih->socitype) == SOCI_SB) return sb_numaddrspaces(sih); - else if (CHIPTYPE(sih->socitype) == SOCI_AI) + else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) return ai_numaddrspaces(sih); else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) return ub_numaddrspaces(sih); @@ -821,7 +854,7 @@ si_addrspace(si_t *sih, uint asidx) { if (CHIPTYPE(sih->socitype) == SOCI_SB) return sb_addrspace(sih, asidx); - else if (CHIPTYPE(sih->socitype) == SOCI_AI) + else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) return ai_addrspace(sih, asidx); else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) return ub_addrspace(sih, asidx); @@ -836,7 +869,7 @@ si_addrspacesize(si_t *sih, uint asidx) { if (CHIPTYPE(sih->socitype) == SOCI_SB) return sb_addrspacesize(sih, asidx); - else if (CHIPTYPE(sih->socitype) == SOCI_AI) + else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) return ai_addrspacesize(sih, asidx); else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) return ub_addrspacesize(sih, asidx); @@ -850,7 +883,7 @@ void si_coreaddrspaceX(si_t *sih, uint asidx, uint32 *addr, uint32 *size) { /* Only supported for SOCI_AI */ - if (CHIPTYPE(sih->socitype) == SOCI_AI) + if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) ai_coreaddrspaceX(sih, asidx, addr, size); else *size = 0; @@ -861,7 +894,7 @@ si_core_cflags(si_t *sih, uint32 mask, uint32 val) { if (CHIPTYPE(sih->socitype) == SOCI_SB) return sb_core_cflags(sih, mask, val); - else if (CHIPTYPE(sih->socitype) == SOCI_AI) + else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) return ai_core_cflags(sih, mask, val); else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) return ub_core_cflags(sih, mask, val); @@ -876,7 +909,7 @@ si_core_cflags_wo(si_t *sih, uint32 mask, uint32 val) { if (CHIPTYPE(sih->socitype) == SOCI_SB) sb_core_cflags_wo(sih, mask, val); - else if (CHIPTYPE(sih->socitype) == SOCI_AI) + else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) ai_core_cflags_wo(sih, mask, val); else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) ub_core_cflags_wo(sih, mask, val); @@ -889,7 +922,7 @@ si_core_sflags(si_t *sih, uint32 mask, uint32 val) { if (CHIPTYPE(sih->socitype) == SOCI_SB) return sb_core_sflags(sih, mask, val); - else if (CHIPTYPE(sih->socitype) == SOCI_AI) + else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) return ai_core_sflags(sih, mask, val); else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) return ub_core_sflags(sih, mask, val); @@ -904,7 +937,7 @@ si_iscoreup(si_t *sih) { if (CHIPTYPE(sih->socitype) == SOCI_SB) return sb_iscoreup(sih); - else if (CHIPTYPE(sih->socitype) == SOCI_AI) + else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) return ai_iscoreup(sih); else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) return ub_iscoreup(sih); @@ -918,7 +951,7 @@ uint si_wrapperreg(si_t *sih, uint32 offset, uint32 mask, uint32 val) { /* only for AI back plane chips */ - if (CHIPTYPE(sih->socitype) == SOCI_AI) + if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) return (ai_wrap_reg(sih, offset, mask, val)); return 0; } @@ -928,7 +961,7 @@ si_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val) { if (CHIPTYPE(sih->socitype) == SOCI_SB) return sb_corereg(sih, coreidx, regoff, mask, val); - else if (CHIPTYPE(sih->socitype) == SOCI_AI) + else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) return ai_corereg(sih, coreidx, regoff, mask, val); else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) return ub_corereg(sih, coreidx, regoff, mask, val); @@ -943,7 +976,7 @@ si_core_disable(si_t *sih, uint32 bits) { if (CHIPTYPE(sih->socitype) == SOCI_SB) sb_core_disable(sih, bits); - else if (CHIPTYPE(sih->socitype) == SOCI_AI) + else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) ai_core_disable(sih, bits); else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) ub_core_disable(sih, bits); @@ -954,7 +987,7 @@ si_core_reset(si_t *sih, uint32 bits, uint32 resetbits) { if (CHIPTYPE(sih->socitype) == SOCI_SB) sb_core_reset(sih, bits, resetbits); - else if (CHIPTYPE(sih->socitype) == SOCI_AI) + else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) ai_core_reset(sih, bits, resetbits); else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) ub_core_reset(sih, bits, resetbits); @@ -1084,6 +1117,7 @@ si_clock_rate(uint32 pll_type, uint32 n, uint32 m) } + /* set chip watchdog reset timer to fire in 'ticks' */ void si_watchdog(si_t *sih, uint ticks) @@ -1092,6 +1126,7 @@ si_watchdog(si_t *sih, uint ticks) if (PMUCTL_ENAB(sih)) { +#if !defined(_CFEZ_) || defined(CFG_WL) if ((CHIPID(sih->chip) == BCM4319_CHIP_ID) && (CHIPREV(sih->chiprev) == 0) && (ticks != 0)) { si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, clk_ctl_st), ~0, 0x2); @@ -1099,6 +1134,7 @@ si_watchdog(si_t *sih, uint ticks) si_core_disable(sih, 1); si_setcore(sih, CC_CORE_ID, 0); } +#endif nb = (sih->ccrev < 26) ? 16 : ((sih->ccrev >= 37) ? 32 : 24); /* The mips compiler uses the sllv instruction, @@ -1161,6 +1197,7 @@ si_slowclk_src(si_info_t *sii) return (SCC_SS_XTAL); } else if (sii->pub.ccrev < 10) { cc = (chipcregs_t *)si_setcoreidx(&sii->pub, sii->curidx); + ASSERT(cc); return (R_REG(sii->osh, &cc->slow_clk_ctl) & SCC_SS_MASK); } else /* Insta-clock */ return (SCC_SS_XTAL); @@ -1240,7 +1277,7 @@ si_clkctl_init(si_t *sih) chipcregs_t *cc; bool fast; - if (sih == NULL || !CCCTL_ENAB(sih)) + if (!CCCTL_ENAB(sih)) return; sii = SI_INFO(sih); @@ -1249,10 +1286,8 @@ si_clkctl_init(si_t *sih) origidx = sii->curidx; if ((cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0)) == NULL) return; - } else { - cc = (chipcregs_t *)CCREGS_FAST(sii); - } - + } else if ((cc = (chipcregs_t *)CCREGS_FAST(sii)) == NULL) + return; ASSERT(cc != NULL); /* set all Instaclk chip ILP to 1 MHz */ @@ -1262,6 +1297,8 @@ si_clkctl_init(si_t *sih) si_clkctl_setdelay(sii, (void *)(uintptr)cc); + OSL_DELAY(20000); + if (!fast) si_setcoreidx(sih, origidx); } @@ -2049,6 +2086,7 @@ done: } +#if !defined(_CFEZ_) || defined(CFG_WL) void si_btcgpiowar(si_t *sih) { @@ -2245,6 +2283,7 @@ si_chipcontrl_epa4331_wowl(si_t *sih, bool enter_wowl) } si_setcoreidx(sih, origidx); } +#endif uint si_pll_reset(si_t *sih) @@ -2279,6 +2318,12 @@ si_clk_pmu_htavail_set(si_t *sih, bool set_clear) { } +/* Re-enable synth_pwrsw resource in min_res_mask for 4313 */ +void +si_pmu_synth_pwrsw_4313_war(si_t *sih) +{ +} + /* WL/BT control for 4313 btcombo boards >= P250 */ void si_btcombo_p250_4313_war(si_t *sih) @@ -2370,6 +2415,7 @@ si_is_sprom_available(si_t *sih) sii = SI_INFO(sih); origidx = sii->curidx; cc = si_setcoreidx(sih, SI_CC_IDX); + ASSERT(cc); sromctrl = R_REG(sii->osh, &cc->sromcontrol); si_setcoreidx(sih, origidx); return (sromctrl & SRC_PRESENT); @@ -2408,11 +2454,14 @@ si_is_sprom_available(si_t *sih) return ((sih->chipst & CST43239_SPROM_MASK) && !(sih->chipst & CST43239_SFLASH_MASK)); case BCM4324_CHIP_ID: + case BCM43242_CHIP_ID: return ((sih->chipst & CST4324_SPROM_MASK) && !(sih->chipst & CST4324_SFLASH_MASK)); case BCM4335_CHIP_ID: return ((sih->chipst & CST4335_SPROM_MASK) && !(sih->chipst & CST4335_SFLASH_MASK)); + case BCM4350_CHIP_ID: + return (sih->chipst & CST4350_SPROM_PRESENT) != 0; case BCM43131_CHIP_ID: case BCM43217_CHIP_ID: case BCM43227_CHIP_ID: @@ -2466,3 +2515,20 @@ int si_set_sromctl(si_t *sih, uint32 value) return BCME_OK; } + +uint +si_core_wrapperreg(si_t *sih, uint32 coreidx, uint32 offset, uint32 mask, uint32 val) +{ + uint origidx; + uint ret_val; + + origidx = si_coreidx(sih); + + si_setcoreidx(sih, coreidx); + + ret_val = si_wrapperreg(sih, offset, mask, val); + + /* return to the original core */ + si_setcoreidx(sih, origidx); + return ret_val; +} diff --git a/drivers/net/wireless/bcmdhd/siutils_priv.h b/drivers/net/wireless/bcmdhd/siutils_priv.h index 9a3270f74242..0d6442919eb4 100644..100755 --- a/drivers/net/wireless/bcmdhd/siutils_priv.h +++ b/drivers/net/wireless/bcmdhd/siutils_priv.h @@ -1,7 +1,7 @@ /* * Include file private to the SOC Interconnect support files. * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -21,7 +21,7 @@ * 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: siutils_priv.h 309193 2012-01-19 00:03:57Z $ + * $Id: siutils_priv.h 385510 2013-02-15 21:02:07Z $ */ #ifndef _siutils_priv_h_ @@ -146,6 +146,7 @@ typedef struct si_info { #define ILP_DIV_5MHZ 0 /* ILP = 5 MHz */ #define ILP_DIV_1MHZ 4 /* ILP = 1 MHz */ +/* Force fast clock for 4360b0 */ #define PCI_FORCEHT(si) \ (((PCIE_GEN1(si)) && (si->pub.chip == BCM4311_CHIP_ID) && ((si->pub.chiprev <= 1))) || \ ((PCI(si) || PCIE_GEN1(si)) && (si->pub.chip == BCM4321_CHIP_ID)) || \ @@ -203,6 +204,7 @@ extern si_t *ai_kattach(osl_t *osh); extern void ai_scan(si_t *sih, void *regs, uint devid); extern uint ai_flag(si_t *sih); +extern uint ai_flag_alt(si_t *sih); extern void ai_setint(si_t *sih, int siflag); extern uint ai_coreidx(si_t *sih); extern uint ai_corevendor(si_t *sih); diff --git a/drivers/net/wireless/bcmdhd/uamp_api.h b/drivers/net/wireless/bcmdhd/uamp_api.h index 673dce08aad7..31e0d4b020a6 100644..100755 --- a/drivers/net/wireless/bcmdhd/uamp_api.h +++ b/drivers/net/wireless/bcmdhd/uamp_api.h @@ -3,7 +3,7 @@ * * Description: Universal AMP API * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd/wl_android.c b/drivers/net/wireless/bcmdhd/wl_android.c index d3eda18b1866..f29f0e5de55d 100644..100755 --- a/drivers/net/wireless/bcmdhd/wl_android.c +++ b/drivers/net/wireless/bcmdhd/wl_android.c @@ -1,14 +1,14 @@ /* * Linux cfg80211 driver - Android related functions * - * Copyright (C) 1999-2012, Broadcom Corporation - * + * Copyright (C) 1999-2013, Broadcom Corporation + * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2 (the "GPL"), * available at http://www.broadcom.com/licenses/GPLv2.php, with the * following added to such license: - * + * * As a special exception, the copyright holders of this software give you * permission to link this software with independent modules, and to copy and * distribute the resulting executable under terms of your choice, provided that @@ -16,16 +16,18 @@ * the license of that module. An independent module is a module which is not * derived from this software. The special exception does not apply to any * modifications of the software. - * + * * Notwithstanding the above, under no circumstances may you combine this * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: wl_android.c 386796 2013-02-21 23:38:44Z $ + * $Id: wl_android.c 432432 2013-10-28 15:52:47Z $ */ #include <linux/module.h> #include <linux/netdevice.h> +#include <linux/of_gpio.h> +#include <linux/regulator/consumer.h> #include <wl_android.h> #include <wldev_common.h> @@ -35,6 +37,9 @@ #include <dhd_dbg.h> #include <dngl_stats.h> #include <dhd.h> +#ifdef PNO_SUPPORT +#include <dhd_pno.h> +#endif #include <bcmsdbus.h> #ifdef WL_CFG80211 #include <wl_cfg80211.h> @@ -62,10 +67,14 @@ #define CMD_SCAN_PASSIVE "SCAN-PASSIVE" #define CMD_RSSI "RSSI" #define CMD_LINKSPEED "LINKSPEED" +#ifdef PKT_FILTER_SUPPORT #define CMD_RXFILTER_START "RXFILTER-START" #define CMD_RXFILTER_STOP "RXFILTER-STOP" #define CMD_RXFILTER_ADD "RXFILTER-ADD" #define CMD_RXFILTER_REMOVE "RXFILTER-REMOVE" +#define CMD_PKT_FILTER_MODE "PKT_FILTER_MODE" +#define CMD_PKT_FILTER_PORTS "PKT_FILTER_PORTS" +#endif /* PKT_FILTER_SUPPORT */ #define CMD_BTCOEXSCAN_START "BTCOEXSCAN-START" #define CMD_BTCOEXSCAN_STOP "BTCOEXSCAN-STOP" #define CMD_BTCOEXMODE "BTCOEXMODE" @@ -78,23 +87,23 @@ #define CMD_COUNTRY "COUNTRY" #define CMD_P2P_SET_NOA "P2P_SET_NOA" #if !defined WL_ENABLE_P2P_IF -#define CMD_P2P_GET_NOA "P2P_GET_NOA" -#endif +#define CMD_P2P_GET_NOA "P2P_GET_NOA" +#endif /* WL_ENABLE_P2P_IF */ #define CMD_P2P_SD_OFFLOAD "P2P_SD_" #define CMD_P2P_SET_PS "P2P_SET_PS" #define CMD_SET_AP_WPS_P2P_IE "SET_AP_WPS_P2P_IE" #define CMD_SETROAMMODE "SETROAMMODE" +#define CMD_SETIBSSBEACONOUIDATA "SETIBSSBEACONOUIDATA" +#define CMD_MIRACAST "MIRACAST" #if defined(WL_SUPPORT_AUTO_CHANNEL) -#define CMD_SET_HAPD_AUTO_CHANNEL "HAPD_AUTO_CHANNEL" -#define CMD_GET_BEST_CHANNELS "GET_BEST_CHANNELS" +#define CMD_GET_BEST_CHANNELS "GET_BEST_CHANNELS" #endif /* WL_SUPPORT_AUTO_CHANNEL */ -#if defined(SUPPORT_TRIGGER_HANG_EVENT) -#define CMD_TEST_FORCE_HANG "TEST_FORCE_HANG" -#endif + #define CMD_SETMIRACAST "SETMIRACAST" #define CMD_ASSOCRESPIE "ASSOCRESPIE" #define CMD_MAXLINKSPEED "MAXLINKSPEED" +#define CMD_RXRATESTATS "RXRATESTATS" /* CCX Private Commands */ @@ -103,73 +112,64 @@ #define CMD_PNOSETUP_SET "PNOSETUP " #define CMD_PNOENABLE_SET "PNOFORCE" #define CMD_PNODEBUG_SET "PNODEBUG" - -#define PNO_TLV_PREFIX 'S' -#define PNO_TLV_VERSION '1' -#define PNO_TLV_SUBVERSION '2' -#define PNO_TLV_RESERVED '0' -#define PNO_TLV_TYPE_SSID_IE 'S' -#define PNO_TLV_TYPE_TIME 'T' -#define PNO_TLV_FREQ_REPEAT 'R' -#define PNO_TLV_FREQ_EXPO_MAX 'M' - -typedef struct cmd_tlv { - char prefix; - char version; - char subver; - char reserved; -} cmd_tlv_t; +#define CMD_WLS_BATCHING "WLS_BATCHING" #endif /* PNO_SUPPORT */ #define CMD_OKC_SET_PMK "SET_PMK" #define CMD_OKC_ENABLE "OKC_ENABLE" +#define CMD_HAPD_MAC_FILTER "HAPD_MAC_FILTER" +/* hostap mac mode */ +#define MACLIST_MODE_DISABLED 0 +#define MACLIST_MODE_DENY 1 +#define MACLIST_MODE_ALLOW 2 -typedef struct android_wifi_priv_cmd { - char *buf; - int used_len; - int total_len; -} android_wifi_priv_cmd; - -#ifdef WL_GENL -static s32 wl_genl_handle_msg(struct sk_buff *skb, struct genl_info *info); -static int wl_genl_init(void); -static int wl_genl_deinit(void); +/* max number of assoc list */ +#define MAX_NUM_OF_ASSOCLIST 64 -extern struct net init_net; -/* attribute policy: defines which attribute has which type (e.g int, char * etc) - * possible values defined in net/netlink.h +/* max number of mac filter list + * restrict max number to 10 as maximum cmd string size is 255 */ -static struct nla_policy wl_genl_policy[BCM_GENL_ATTR_MAX + 1] = { - [BCM_GENL_ATTR_STRING] = { .type = NLA_NUL_STRING }, - [BCM_GENL_ATTR_MSG] = { .type = NLA_BINARY }, -}; +#define MAX_NUM_MAC_FILT 10 -#define WL_GENL_VER 1 -/* family definition */ -static struct genl_family wl_genl_family = { - .id = GENL_ID_GENERATE, /* Genetlink would generate the ID */ - .hdrsize = 0, - .name = "bcm-genl", /* Netlink I/F for Android */ - .version = WL_GENL_VER, /* Version Number */ - .maxattr = BCM_GENL_ATTR_MAX, -}; -/* commands: mapping between the command enumeration and the actual function */ -struct genl_ops wl_genl_ops = { - .cmd = BCM_GENL_CMD_MSG, - .flags = 0, - .policy = wl_genl_policy, - .doit = wl_genl_handle_msg, - .dumpit = NULL, -}; -static struct genl_multicast_group wl_genl_mcast = { - .id = GENL_ID_GENERATE, /* Genetlink would generate the ID */ - .name = "bcm-genl-mcast", + +/* miracast related definition */ +#define MIRACAST_MODE_OFF 0 +#define MIRACAST_MODE_SOURCE 1 +#define MIRACAST_MODE_SINK 2 + +#ifndef MIRACAST_AMPDU_SIZE +#define MIRACAST_AMPDU_SIZE 8 +#endif + +#ifndef MIRACAST_MCHAN_ALGO +#define MIRACAST_MCHAN_ALGO 1 +#endif + +#ifndef MIRACAST_MCHAN_BW +#define MIRACAST_MCHAN_BW 25 +#endif + +static LIST_HEAD(miracast_resume_list); +static u8 miracast_cur_mode; + +struct io_cfg { + s8 *iovar; + s32 param; + u32 ioctl; + void *arg; + u32 len; + struct list_head list; }; -#endif /* WL_GENL */ +typedef struct android_wifi_priv_cmd { + char *buf; + int used_len; + int total_len; +} android_wifi_priv_cmd; + /** * Extern function declarations (TODO: move them to dhd_linux.h) @@ -180,6 +180,7 @@ int dhd_dev_init_ioctl(struct net_device *dev); #ifdef WL_CFG80211 int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr); int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, char *command); +int wl_cfg80211_get_ioctl_version(void); #else int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr) { return 0; } @@ -189,28 +190,24 @@ int wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len) { return 0; } int wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len) { return 0; } -#endif /* WL_CFG80211 */ - -extern int dhd_os_check_wakelock(void *dhdp); +#endif /* WK_CFG80211 */ extern int dhd_os_check_if_up(void *dhdp); +#ifdef BCMLXSDMMC extern void *bcmsdh_get_drvdata(void); +#endif /* BCMLXSDMMC */ -#if defined(PROP_TXSTATUS) && !defined(PROP_TXSTATUS_VSDB) -extern int dhd_wlfc_init(dhd_pub_t *dhd); -extern void dhd_wlfc_deinit(dhd_pub_t *dhd); -#endif -#ifdef ENABLE_WiFI_BT_TURN_ON_SYNC -extern void bt_wlan_lock(void); -extern void bt_wlan_unlock(void); -#endif +#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 */ extern bool ap_fw_loaded; #if defined(CUSTOMER_HW2) extern char iface_name[IFNAMSIZ]; -#endif +#endif -#define WIFI_TURNOFF_DELAY 0 /** * Local (static) functions and variables */ @@ -221,6 +218,11 @@ extern char iface_name[IFNAMSIZ]; */ static int g_wifi_on = TRUE; +#if defined(WIFIEDP) +static int g_edp_reg = FALSE; +static struct mutex edp_reg_mutex; +#endif + /** * Local (static) function definitions */ @@ -292,17 +294,18 @@ static int wl_android_set_suspendmode(struct net_device *dev, char *command, int { int ret = 0; +#if !defined(CONFIG_HAS_EARLYSUSPEND) || !defined(DHD_USE_EARLYSUSPEND) int suspend_flag; suspend_flag = *(command + strlen(CMD_SETSUSPENDMODE) + 1) - '0'; - if (suspend_flag != 0) suspend_flag = 1; if (!(ret = net_os_set_suspend(dev, suspend_flag, 0))) DHD_INFO(("%s: Suspend Mode %d\n", __FUNCTION__, suspend_flag)); else - DHD_ERROR(("%s: failed %d\n",__FUNCTION__,ret)); + DHD_ERROR(("%s: failed %d\n", __FUNCTION__, ret)); +#endif return ret; } @@ -321,8 +324,116 @@ static int wl_android_get_band(struct net_device *dev, char *command, int total_ } +#ifdef PNO_SUPPORT +#define PNO_PARAM_SIZE 50 +#define VALUE_SIZE 50 +static int +wls_parse_batching_cmd(struct net_device *dev, char *command, int total_len) +{ + int err = BCME_OK; + uint i, tokens; + char *pos, *pos2, *token, *token2, *delim; + char param[PNO_PARAM_SIZE], value[VALUE_SIZE]; + struct dhd_pno_batch_params batch_params; + DHD_PNO(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len)); + if (total_len < strlen(CMD_WLS_BATCHING)) { + DHD_ERROR(("%s argument=%d less min size\n", __FUNCTION__, total_len)); + err = BCME_ERROR; + goto exit; + } + pos = command + strlen(CMD_WLS_BATCHING) + 1; + memset(&batch_params, 0, sizeof(struct dhd_pno_batch_params)); -#if defined(PNO_SUPPORT) && !defined(WL_SCHED_SCAN) + if (!strncmp(pos, PNO_BATCHING_SET, strlen(PNO_BATCHING_SET))) { + pos += strlen(PNO_BATCHING_SET) + 1; + while ((token = strsep(&pos, PNO_PARAMS_DELIMETER)) != NULL) { + memset(param, 0, sizeof(param)); + memset(value, 0, sizeof(value)); + if (token == NULL || !*token) + break; + if (*token == '\0') + continue; + delim = strchr(token, PNO_PARAM_VALUE_DELLIMETER); + if (delim != NULL) + *delim = ' '; + + tokens = sscanf(token, "%s %s", param, value); + if (!strncmp(param, PNO_PARAM_SCANFREQ, strlen(PNO_PARAM_MSCAN))) { + batch_params.scan_fr = simple_strtol(value, NULL, 0); + DHD_PNO(("scan_freq : %d\n", batch_params.scan_fr)); + } else if (!strncmp(param, PNO_PARAM_BESTN, strlen(PNO_PARAM_MSCAN))) { + batch_params.bestn = simple_strtol(value, NULL, 0); + DHD_PNO(("bestn : %d\n", batch_params.bestn)); + } else if (!strncmp(param, PNO_PARAM_MSCAN, strlen(PNO_PARAM_MSCAN))) { + batch_params.mscan = simple_strtol(value, NULL, 0); + DHD_PNO(("mscan : %d\n", batch_params.mscan)); + } else if (!strncmp(param, PNO_PARAM_CHANNEL, strlen(PNO_PARAM_MSCAN))) { + i = 0; + pos2 = value; + tokens = sscanf(value, "<%s>", value); + if (tokens != 1) { + err = BCME_ERROR; + DHD_ERROR(("%s : invalid format for channel" + " <> params\n", __FUNCTION__)); + goto exit; + } + while ((token2 = strsep(&pos2, + PNO_PARAM_CHANNEL_DELIMETER)) != NULL) { + if (token2 == NULL || !*token2) + break; + if (*token2 == '\0') + continue; + if (*token2 == 'A' || *token2 == 'B') { + batch_params.band = (*token2 == 'A')? + WLC_BAND_5G : WLC_BAND_2G; + DHD_PNO(("band : %s\n", + (*token2 == 'A')? "A" : "B")); + } else { + batch_params.chan_list[i++] = + simple_strtol(token2, NULL, 0); + batch_params.nchan++; + DHD_PNO(("channel :%d\n", + batch_params.chan_list[i-1])); + } + } + } else if (!strncmp(param, PNO_PARAM_RTT, strlen(PNO_PARAM_MSCAN))) { + batch_params.rtt = simple_strtol(value, NULL, 0); + DHD_PNO(("rtt : %d\n", batch_params.rtt)); + } else { + DHD_ERROR(("%s : unknown param: %s\n", __FUNCTION__, param)); + err = BCME_ERROR; + goto exit; + } + } + err = dhd_dev_pno_set_for_batch(dev, &batch_params); + if (err < 0) { + DHD_ERROR(("failed to configure batch scan\n")); + } else { + memset(command, 0, total_len); + err = sprintf(command, "%d", err); + } + } else if (!strncmp(pos, PNO_BATCHING_GET, strlen(PNO_BATCHING_GET))) { + err = dhd_dev_pno_get_for_batch(dev, command, total_len); + if (err < 0) { + DHD_ERROR(("failed to getting batching results\n")); + } + } else if (!strncmp(pos, PNO_BATCHING_STOP, strlen(PNO_BATCHING_STOP))) { + err = dhd_dev_pno_stop_for_batch(dev); + if (err < 0) { + DHD_ERROR(("failed to stop batching scan\n")); + } else { + memset(command, 0, total_len); + err = sprintf(command, "OK"); + } + } else { + DHD_ERROR(("%s : unknown command\n", __FUNCTION__)); + err = BCME_ERROR; + goto exit; + } +exit: + return err; +} +#ifndef WL_SCHED_SCAN static int wl_android_set_pno_setup(struct net_device *dev, char *command, int total_len) { wlc_ssid_t ssids_local[MAX_PFN_LIST_COUNT]; @@ -355,23 +466,16 @@ static int wl_android_set_pno_setup(struct net_device *dev, char *command, int t 0x00 }; #endif /* PNO_SET_DEBUG */ - - DHD_INFO(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len)); + DHD_PNO(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len)); if (total_len < (strlen(CMD_PNOSETUP_SET) + sizeof(cmd_tlv_t))) { DHD_ERROR(("%s argument=%d less min size\n", __FUNCTION__, total_len)); goto exit_proc; } - - #ifdef PNO_SET_DEBUG memcpy(command, pno_in_example, sizeof(pno_in_example)); - for (i = 0; i < sizeof(pno_in_example); i++) - printf("%02X ", command[i]); - printf("\n"); total_len = sizeof(pno_in_example); #endif - str_ptr = command + strlen(CMD_PNOSETUP_SET); tlv_size_left = total_len - strlen(CMD_PNOSETUP_SET); @@ -380,7 +484,7 @@ static int wl_android_set_pno_setup(struct net_device *dev, char *command, int t if ((cmd_tlv_temp->prefix == PNO_TLV_PREFIX) && (cmd_tlv_temp->version == PNO_TLV_VERSION) && - (cmd_tlv_temp->subver == PNO_TLV_SUBVERSION)) { + (cmd_tlv_temp->subtype == PNO_TLV_SUBTYPE_LEGACY_PNO)) { str_ptr += sizeof(cmd_tlv_t); tlv_size_left -= sizeof(cmd_tlv_t); @@ -397,7 +501,7 @@ static int wl_android_set_pno_setup(struct net_device *dev, char *command, int t } str_ptr++; pno_time = simple_strtoul(str_ptr, &str_ptr, 16); - DHD_INFO(("%s: pno_time=%d\n", __FUNCTION__, pno_time)); + DHD_PNO(("%s: pno_time=%d\n", __FUNCTION__, pno_time)); if (str_ptr[0] != 0) { if ((str_ptr[0] != PNO_TLV_FREQ_REPEAT)) { @@ -407,7 +511,7 @@ static int wl_android_set_pno_setup(struct net_device *dev, char *command, int t } str_ptr++; pno_repeat = simple_strtoul(str_ptr, &str_ptr, 16); - DHD_INFO(("%s :got pno_repeat=%d\n", __FUNCTION__, pno_repeat)); + DHD_PNO(("%s :got pno_repeat=%d\n", __FUNCTION__, pno_repeat)); if (str_ptr[0] != PNO_TLV_FREQ_EXPO_MAX) { DHD_ERROR(("%s FREQ_EXPO_MAX corrupted field size\n", __FUNCTION__)); @@ -415,7 +519,7 @@ static int wl_android_set_pno_setup(struct net_device *dev, char *command, int t } str_ptr++; pno_freq_expo_max = simple_strtoul(str_ptr, &str_ptr, 16); - DHD_INFO(("%s: pno_freq_expo_max=%d\n", + DHD_PNO(("%s: pno_freq_expo_max=%d\n", __FUNCTION__, pno_freq_expo_max)); } } @@ -424,12 +528,13 @@ static int wl_android_set_pno_setup(struct net_device *dev, char *command, int t goto exit_proc; } - res = dhd_dev_pno_set(dev, ssids_local, nssid, pno_time, pno_repeat, pno_freq_expo_max); - + res = dhd_dev_pno_set_for_ssid(dev, ssids_local, nssid, pno_time, pno_repeat, + pno_freq_expo_max, NULL, 0); exit_proc: return res; } -#endif /* PNO_SUPPORT && !WL_SCHED_SCAN */ +#endif /* !WL_SCHED_SCAN */ +#endif /* PNO_SUPPORT */ static int wl_android_get_p2p_dev_addr(struct net_device *ndev, char *command, int total_len) { @@ -444,6 +549,131 @@ static int wl_android_get_p2p_dev_addr(struct net_device *ndev, char *command, i } +static int +wl_android_set_ap_mac_list(struct net_device *dev, int macmode, struct maclist *maclist) +{ + int i, j, match; + int ret = 0; + char mac_buf[MAX_NUM_OF_ASSOCLIST * + sizeof(struct ether_addr) + sizeof(uint)] = {0}; + struct maclist *assoc_maclist = (struct maclist *)mac_buf; + + /* set filtering mode */ + if ((ret = wldev_ioctl(dev, WLC_SET_MACMODE, &macmode, sizeof(macmode), true)) != 0) { + DHD_ERROR(("%s : WLC_SET_MACMODE error=%d\n", __FUNCTION__, ret)); + return ret; + } + if (macmode != MACLIST_MODE_DISABLED) { + /* set the MAC filter list */ + if ((ret = wldev_ioctl(dev, WLC_SET_MACLIST, maclist, + sizeof(int) + sizeof(struct ether_addr) * maclist->count, true)) != 0) { + DHD_ERROR(("%s : WLC_SET_MACLIST error=%d\n", __FUNCTION__, ret)); + return ret; + } + /* get the current list of associated STAs */ + assoc_maclist->count = MAX_NUM_OF_ASSOCLIST; + if ((ret = wldev_ioctl(dev, WLC_GET_ASSOCLIST, assoc_maclist, + sizeof(mac_buf), false)) != 0) { + DHD_ERROR(("%s : WLC_GET_ASSOCLIST error=%d\n", __FUNCTION__, ret)); + return ret; + } + /* do we have any STA associated? */ + if (assoc_maclist->count) { + /* iterate each associated STA */ + for (i = 0; i < assoc_maclist->count; i++) { + match = 0; + /* compare with each entry */ + for (j = 0; j < maclist->count; j++) { + DHD_INFO(("%s : associated="MACDBG " list="MACDBG "\n", + __FUNCTION__, MAC2STRDBG(assoc_maclist->ea[i].octet), + MAC2STRDBG(maclist->ea[j].octet))); + if (memcmp(assoc_maclist->ea[i].octet, + maclist->ea[j].octet, ETHER_ADDR_LEN) == 0) { + match = 1; + break; + } + } + /* do conditional deauth */ + /* "if not in the allow list" or "if in the deny list" */ + if ((macmode == MACLIST_MODE_ALLOW && !match) || + (macmode == MACLIST_MODE_DENY && match)) { + scb_val_t scbval; + + scbval.val = htod32(1); + memcpy(&scbval.ea, &assoc_maclist->ea[i], + ETHER_ADDR_LEN); + if ((ret = wldev_ioctl(dev, + WLC_SCB_DEAUTHENTICATE_FOR_REASON, + &scbval, sizeof(scb_val_t), true)) != 0) + DHD_ERROR(("%s WLC_SCB_DEAUTHENTICATE error=%d\n", + __FUNCTION__, ret)); + } + } + } + } + return ret; +} + +/* + * HAPD_MAC_FILTER mac_mode mac_cnt mac_addr1 mac_addr2 + * + */ +static int +wl_android_set_mac_address_filter(struct net_device *dev, const char* str) +{ + int i; + int ret = 0; + int macnum = 0; + int macmode = MACLIST_MODE_DISABLED; + struct maclist *list; + char eabuf[ETHER_ADDR_STR_LEN]; + + /* string should look like below (macmode/macnum/maclist) */ + /* 1 2 00:11:22:33:44:55 00:11:22:33:44:ff */ + + /* get the MAC filter mode */ + macmode = bcm_atoi(strsep((char**)&str, " ")); + + if (macmode < MACLIST_MODE_DISABLED || macmode > MACLIST_MODE_ALLOW) { + DHD_ERROR(("%s : invalid macmode %d\n", __FUNCTION__, macmode)); + return -1; + } + + macnum = bcm_atoi(strsep((char**)&str, " ")); + if (macnum < 0 || macnum > MAX_NUM_MAC_FILT) { + DHD_ERROR(("%s : invalid number of MAC address entries %d\n", + __FUNCTION__, macnum)); + return -1; + } + /* allocate memory for the MAC list */ + list = (struct maclist*)kmalloc(sizeof(int) + + sizeof(struct ether_addr) * macnum, GFP_KERNEL); + if (!list) { + DHD_ERROR(("%s : failed to allocate memory\n", __FUNCTION__)); + return -1; + } + /* prepare the MAC list */ + list->count = htod32(macnum); + bzero((char *)eabuf, ETHER_ADDR_STR_LEN); + for (i = 0; i < list->count; i++) { + strncpy(eabuf, strsep((char**)&str, " "), ETHER_ADDR_STR_LEN - 1); + if (!(ret = bcm_ether_atoe(eabuf, &list->ea[i]))) { + DHD_ERROR(("%s : mac parsing err index=%d, addr=%s\n", + __FUNCTION__, i, eabuf)); + list->count--; + break; + } + DHD_INFO(("%s : %d/%d MACADDR=%s", __FUNCTION__, i, list->count, eabuf)); + } + /* set the list */ + if ((ret = wl_android_set_ap_mac_list(dev, macmode, list)) != 0) + DHD_ERROR(("%s : Setting MAC list failed error=%d\n", __FUNCTION__, ret)); + + kfree(list); + + return 0; +} + /** * Global function definitions (declared in wl_android.h) */ @@ -480,9 +710,6 @@ int wl_android_wifi_on(struct net_device *dev) if (dhd_dev_init_ioctl(dev) < 0) ret = -EFAULT; } -#if defined(PROP_TXSTATUS) && !defined(PROP_TXSTATUS_VSDB) - dhd_wlfc_init(bcmsdh_get_drvdata()); -#endif g_wifi_on = TRUE; } @@ -504,9 +731,6 @@ int wl_android_wifi_off(struct net_device *dev) dhd_net_if_lock(dev); if (g_wifi_on) { -#if defined(PROP_TXSTATUS) && !defined(PROP_TXSTATUS_VSDB) - dhd_wlfc_deinit(bcmsdh_get_drvdata()); -#endif ret = dhd_dev_reset(dev, TRUE); sdioh_stop(NULL); dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF); @@ -534,76 +758,6 @@ static int wl_android_set_fwpath(struct net_device *net, char *command, int tota } -#if defined(WL_SUPPORT_AUTO_CHANNEL) -static int -wl_android_set_auto_channel(struct net_device *dev, const char* string_num, - char* command, int total_len) -{ - int channel; - int chosen = 0; - int retry = 0; - int ret = 0; - - /* Restrict channel to 1 - 7: 2GHz, 20MHz BW, No SB */ - u32 req_buf[8] = {7, 0x2B01, 0x2B02, 0x2B03, 0x2B04, 0x2B05, 0x2B06, - 0x2B07}; - - /* Auto channel select */ - wl_uint32_list_t request; - - channel = bcm_atoi(string_num); - DHD_INFO(("%s : HAPD_AUTO_CHANNEL = %d\n", __FUNCTION__, channel)); - - if (channel == 20) - ret = wldev_ioctl(dev, WLC_START_CHANNEL_SEL, (void *)&req_buf, - sizeof(req_buf), true); - else { /* channel == 0 */ - request.count = htod32(0); - ret = wldev_ioctl(dev, WLC_START_CHANNEL_SEL, (void *)&request, - sizeof(request), true); - } - - if (ret < 0) { - DHD_ERROR(("%s: can't start auto channel scan, err = %d\n", - __FUNCTION__, ret)); - channel = 0; - goto done; - } - - /* Wait for auto channel selection, max 2500 ms */ - bcm_mdelay(500); - - retry = 10; - while (retry--) { - ret = wldev_ioctl(dev, WLC_GET_CHANNEL_SEL, &chosen, sizeof(chosen), - false); - if (ret < 0 || dtoh32(chosen) == 0) { - DHD_INFO(("%s: %d tried, ret = %d, chosen = %d\n", - __FUNCTION__, (10 - retry), ret, chosen)); - bcm_mdelay(200); - } - else { - channel = (u16)chosen & 0x00FF; - DHD_ERROR(("%s: selected channel = %d\n", __FUNCTION__, channel)); - break; - } - } - - if (retry == 0) { - DHD_ERROR(("%s: auto channel timed out, failed\n", __FUNCTION__)); - channel = 0; - } - -done: - snprintf(command, 4, "%d", channel); - DHD_INFO(("%s: command result is %s\n", __FUNCTION__, command)); - - return 4; -} -#endif /* WL_SUPPORT_AUTO_CHANNEL */ - - - static int wl_android_set_pmk(struct net_device *dev, char *command, int total_len) { @@ -643,6 +797,8 @@ wl_android_okc_enable(struct net_device *dev, char *command, int total_len) okc_enable ? "enable" : "disable", error)); } + wldev_iovar_setint(dev, "ccx_enable", 0); + return error; } @@ -670,6 +826,262 @@ int wl_android_set_roam_mode(struct net_device *dev, char *command, int total_le return 0; } +int wl_android_set_ibss_beacon_ouidata(struct net_device *dev, char *command, int total_len) +{ + char ie_buf[VNDR_IE_MAX_LEN]; + char *ioctl_buf = NULL; + char hex[] = "XX"; + char *pcmd = NULL; + int ielen = 0, datalen = 0, idx = 0, tot_len = 0; + vndr_ie_setbuf_t *vndr_ie = NULL; + s32 iecount; + uint32 pktflag; + u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + s32 err = BCME_OK; + + /* Check the VSIE (Vendor Specific IE) which was added. + * If exist then send IOVAR to delete it + */ + if (wl_cfg80211_ibss_vsie_delete(dev) != BCME_OK) { + return -EINVAL; + } + + pcmd = command + strlen(CMD_SETIBSSBEACONOUIDATA) + 1; + for (idx = 0; idx < DOT11_OUI_LEN; idx++) { + hex[0] = *pcmd++; + hex[1] = *pcmd++; + ie_buf[idx] = (uint8)simple_strtoul(hex, NULL, 16); + } + pcmd++; + while ((*pcmd != '\0') && (idx < VNDR_IE_MAX_LEN)) { + hex[0] = *pcmd++; + hex[1] = *pcmd++; + ie_buf[idx++] = (uint8)simple_strtoul(hex, NULL, 16); + datalen++; + } + tot_len = sizeof(vndr_ie_setbuf_t) + (datalen - 1); + vndr_ie = (vndr_ie_setbuf_t *) kzalloc(tot_len, kflags); + if (!vndr_ie) { + WL_ERR(("IE memory alloc failed\n")); + return -ENOMEM; + } + /* Copy the vndr_ie SET command ("add"/"del") to the buffer */ + strncpy(vndr_ie->cmd, "add", VNDR_IE_CMD_LEN - 1); + vndr_ie->cmd[VNDR_IE_CMD_LEN - 1] = '\0'; + + /* Set the IE count - the buffer contains only 1 IE */ + iecount = htod32(1); + memcpy((void *)&vndr_ie->vndr_ie_buffer.iecount, &iecount, sizeof(s32)); + + /* Set packet flag to indicate that BEACON's will contain this IE */ + pktflag = htod32(VNDR_IE_BEACON_FLAG | VNDR_IE_PRBRSP_FLAG); + memcpy((void *)&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].pktflag, &pktflag, + sizeof(u32)); + /* Set the IE ID */ + vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.id = (uchar) DOT11_MNG_PROPR_ID; + + memcpy(&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui, &ie_buf, + DOT11_OUI_LEN); + memcpy(&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.data, + &ie_buf[DOT11_OUI_LEN], datalen); + + ielen = DOT11_OUI_LEN + datalen; + vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.len = (uchar) ielen; + + ioctl_buf = kmalloc(WLC_IOCTL_MEDLEN, GFP_KERNEL); + if (!ioctl_buf) { + WL_ERR(("ioctl memory alloc failed\n")); + if (vndr_ie) { + kfree(vndr_ie); + } + return -ENOMEM; + } + memset(ioctl_buf, 0, WLC_IOCTL_MEDLEN); /* init the buffer */ + err = wldev_iovar_setbuf(dev, "ie", vndr_ie, tot_len, ioctl_buf, WLC_IOCTL_MEDLEN, NULL); + + + if (err != BCME_OK) { + err = -EINVAL; + if (vndr_ie) { + kfree(vndr_ie); + } + } + else { + /* do NOT free 'vndr_ie' for the next process */ + wl_cfg80211_ibss_vsie_set_buffer(vndr_ie, tot_len); + } + + if (ioctl_buf) { + kfree(ioctl_buf); + } + + return err; +} + +static int +wl_android_iolist_add(struct net_device *dev, struct list_head *head, struct io_cfg *config) +{ + struct io_cfg *resume_cfg; + s32 ret; + + resume_cfg = kzalloc(sizeof(struct io_cfg), GFP_KERNEL); + if (!resume_cfg) + return -ENOMEM; + + if (config->iovar) { + ret = wldev_iovar_getint(dev, config->iovar, &resume_cfg->param); + if (ret) { + DHD_ERROR(("%s: Failed to get current %s value\n", + __FUNCTION__, config->iovar)); + goto error; + } + + ret = wldev_iovar_setint(dev, config->iovar, config->param); + if (ret) { + DHD_ERROR(("%s: Failed to set %s to %d\n", __FUNCTION__, + config->iovar, config->param)); + goto error; + } + + resume_cfg->iovar = config->iovar; + } else { + resume_cfg->arg = kzalloc(config->len, GFP_KERNEL); + if (!resume_cfg->arg) { + ret = -ENOMEM; + goto error; + } + ret = wldev_ioctl(dev, config->ioctl, resume_cfg->arg, config->len, false); + if (ret) { + DHD_ERROR(("%s: Failed to get ioctl %d\n", __FUNCTION__, + config->ioctl)); + goto error; + } + ret = wldev_ioctl(dev, config->ioctl + 1, config->arg, config->len, true); + if (ret) { + DHD_ERROR(("%s: Failed to set %s to %d\n", __FUNCTION__, + config->iovar, config->param)); + goto error; + } + if (config->ioctl + 1 == WLC_SET_PM) + wl_cfg80211_update_power_mode(dev); + resume_cfg->ioctl = config->ioctl; + resume_cfg->len = config->len; + } + + list_add(&resume_cfg->list, head); + + return 0; +error: + kfree(resume_cfg->arg); + kfree(resume_cfg); + return ret; +} + +static void +wl_android_iolist_resume(struct net_device *dev, struct list_head *head) +{ + struct io_cfg *config; + struct list_head *cur, *q; + s32 ret = 0; + + list_for_each_safe(cur, q, head) { + config = list_entry(cur, struct io_cfg, list); + if (config->iovar) { + if (!ret) + ret = wldev_iovar_setint(dev, config->iovar, + config->param); + } else { + if (!ret) + ret = wldev_ioctl(dev, config->ioctl + 1, + config->arg, config->len, true); + if (config->ioctl + 1 == WLC_SET_PM) + wl_cfg80211_update_power_mode(dev); + kfree(config->arg); + } + list_del(cur); + kfree(config); + } +} + +static int +wl_android_set_miracast(struct net_device *dev, char *command, int total_len) +{ + int mode, val; + int ret = 0; + struct io_cfg config; + + if (sscanf(command, "%*s %d", &mode) != 1) { + DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__)); + return -1; + } + + DHD_INFO(("%s: enter miracast mode %d\n", __FUNCTION__, mode)); + + if (miracast_cur_mode == mode) + return 0; + + wl_android_iolist_resume(dev, &miracast_resume_list); + miracast_cur_mode = MIRACAST_MODE_OFF; + + switch (mode) { + case MIRACAST_MODE_SOURCE: + /* setting mchan_algo to platform specific value */ + config.iovar = "mchan_algo"; + config.param = MIRACAST_MCHAN_ALGO; + ret = wl_android_iolist_add(dev, &miracast_resume_list, &config); + if (ret) + goto resume; + + /* setting mchan_bw to platform specific value */ + config.iovar = "mchan_bw"; + config.param = MIRACAST_MCHAN_BW; + ret = wl_android_iolist_add(dev, &miracast_resume_list, &config); + if (ret) + goto resume; + + /* setting apmdu to platform specific value */ + config.iovar = "ampdu_mpdu"; + config.param = MIRACAST_AMPDU_SIZE; + ret = wl_android_iolist_add(dev, &miracast_resume_list, &config); + if (ret) + goto resume; + /* FALLTROUGH */ + /* Source mode shares most configurations with sink mode. + * Fall through here to avoid code duplication + */ + case MIRACAST_MODE_SINK: + /* disable internal roaming */ + config.iovar = "roam_off"; + config.param = 1; + ret = wl_android_iolist_add(dev, &miracast_resume_list, &config); + if (ret) + goto resume; + /* tunr off pm */ + val = 0; + config.iovar = NULL; + config.ioctl = WLC_GET_PM; + config.arg = &val; + config.len = sizeof(int); + ret = wl_android_iolist_add(dev, &miracast_resume_list, &config); + if (ret) + goto resume; + + break; + case MIRACAST_MODE_OFF: + default: + break; + } + miracast_cur_mode = mode; + + return 0; + +resume: + DHD_ERROR(("%s: turnoff miracast mode because of err%d\n", __FUNCTION__, ret)); + wl_android_iolist_resume(dev, &miracast_resume_list); + return ret; +} + + int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) { #define PRIVATE_COMMAND_MAX_LEN 8192 @@ -692,8 +1104,9 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) { DHD_ERROR(("%s: too long priavte command\n", __FUNCTION__)); ret = -EINVAL; + goto exit; } - command = kmalloc(priv_cmd.total_len, GFP_KERNEL); + command = kmalloc((priv_cmd.total_len + 1), GFP_KERNEL); if (!command) { DHD_ERROR(("%s: failed to allocate memory\n", __FUNCTION__)); @@ -704,6 +1117,8 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) ret = -EFAULT; goto exit; } + command[priv_cmd.total_len] = '\0'; + DHD_INFO(("%s: Android private cmd \"%s\" on %s\n", __FUNCTION__, command, ifr->ifr_name)); if (strnicmp(command, CMD_START, strlen(CMD_START)) == 0) { @@ -751,6 +1166,13 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) int filter_num = *(command + strlen(CMD_RXFILTER_REMOVE) + 1) - '0'; bytes_written = net_os_rxfilter_add_remove(net, FALSE, filter_num); } + else if (strnicmp(command, CMD_PKT_FILTER_MODE, strlen(CMD_PKT_FILTER_MODE)) == 0) { + dhd_set_packet_filter_mode(net, &command[strlen(CMD_PKT_FILTER_MODE) + 1]); + } else if (strnicmp(command, CMD_PKT_FILTER_PORTS, strlen(CMD_PKT_FILTER_PORTS)) == 0) { + bytes_written = dhd_set_packet_filter_ports(net, + &command[strlen(CMD_PKT_FILTER_PORTS) + 1]); + ret = bytes_written; + } #endif /* PKT_FILTER_SUPPORT */ else if (strnicmp(command, CMD_BTCOEXSCAN_START, strlen(CMD_BTCOEXSCAN_START)) == 0) { /* TBD: BTCOEXSCAN-START */ @@ -780,16 +1202,7 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) } else if (strnicmp(command, CMD_SETBAND, strlen(CMD_SETBAND)) == 0) { uint band = *(command + strlen(CMD_SETBAND) + 1) - '0'; -#ifdef WL_HOST_BAND_MGMT - if (wl_cfg80211_set_band(net, band) < 0) { - bytes_written = -1; - goto exit; - } - if (band == WLC_BAND_AUTO) - bytes_written = wldev_set_band(net, band); -#else bytes_written = wldev_set_band(net, band); -#endif /* WL_HOST_BAND_MGMT */ } else if (strnicmp(command, CMD_GETBAND, strlen(CMD_GETBAND)) == 0) { bytes_written = wl_android_get_band(net, command, priv_cmd.total_len); @@ -801,18 +1214,25 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) bytes_written = wldev_set_country(net, country_code, true, true); } #endif /* WL_CFG80211 */ -#if defined(PNO_SUPPORT) && !defined(WL_SCHED_SCAN) + + +#ifdef PNO_SUPPORT else if (strnicmp(command, CMD_PNOSSIDCLR_SET, strlen(CMD_PNOSSIDCLR_SET)) == 0) { - bytes_written = dhd_dev_pno_reset(net); + bytes_written = dhd_dev_pno_stop_for_ssid(net); } +#ifndef WL_SCHED_SCAN else if (strnicmp(command, CMD_PNOSETUP_SET, strlen(CMD_PNOSETUP_SET)) == 0) { bytes_written = wl_android_set_pno_setup(net, command, priv_cmd.total_len); } +#endif /* !WL_SCHED_SCAN */ else if (strnicmp(command, CMD_PNOENABLE_SET, strlen(CMD_PNOENABLE_SET)) == 0) { - uint pfn_enabled = *(command + strlen(CMD_PNOENABLE_SET) + 1) - '0'; - bytes_written = dhd_dev_pno_enable(net, pfn_enabled); + int enable = *(command + strlen(CMD_PNOENABLE_SET) + 1) - '0'; + bytes_written = (enable)? 0 : dhd_dev_pno_stop_for_ssid(net); + } + else if (strnicmp(command, CMD_WLS_BATCHING, strlen(CMD_WLS_BATCHING)) == 0) { + bytes_written = wls_parse_batching_cmd(net, command, priv_cmd.total_len); } -#endif /* PNO_SUPPORT && !WL_SCHED_SCAN */ +#endif /* PNO_SUPPORT */ else if (strnicmp(command, CMD_P2P_DEV_ADDR, strlen(CMD_P2P_DEV_ADDR)) == 0) { bytes_written = wl_android_get_p2p_dev_addr(net, command, priv_cmd.total_len); } @@ -821,22 +1241,6 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) bytes_written = wl_cfg80211_set_p2p_noa(net, command + skip, priv_cmd.total_len - skip); } -#ifdef WL_SDO - else if (strnicmp(command, CMD_P2P_SD_OFFLOAD, strlen(CMD_P2P_SD_OFFLOAD)) == 0) { - u8 *buf = command; - u8 *cmd_id = NULL; - int len; - - cmd_id = strsep((char **)&buf, " "); - /* if buf == NULL, means no arg */ - if (buf == NULL) - len = 0; - else - len = strlen(buf); - - bytes_written = wl_cfg80211_sd_offload(net, cmd_id, buf, len); - } -#endif /* WL_SDO */ #if !defined WL_ENABLE_P2P_IF else if (strnicmp(command, CMD_P2P_GET_NOA, strlen(CMD_P2P_GET_NOA)) == 0) { bytes_written = wl_cfg80211_get_p2p_noa(net, command, priv_cmd.total_len); @@ -855,41 +1259,39 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) priv_cmd.total_len - skip, *(command + skip - 2) - '0'); } #endif /* WL_CFG80211 */ + else if (strnicmp(command, CMD_OKC_SET_PMK, strlen(CMD_OKC_SET_PMK)) == 0) + bytes_written = wl_android_set_pmk(net, command, priv_cmd.total_len); + else if (strnicmp(command, CMD_OKC_ENABLE, strlen(CMD_OKC_ENABLE)) == 0) + bytes_written = wl_android_okc_enable(net, command, priv_cmd.total_len); #if defined(WL_SUPPORT_AUTO_CHANNEL) - else if (strnicmp(command, CMD_SET_HAPD_AUTO_CHANNEL, - strlen(CMD_SET_HAPD_AUTO_CHANNEL)) == 0) { - int skip = strlen(CMD_SET_HAPD_AUTO_CHANNEL) + 3; - bytes_written = wl_android_set_auto_channel(net, (const char*)command+skip, command, - priv_cmd.total_len); - } else if (strnicmp(command, CMD_GET_BEST_CHANNELS, strlen(CMD_GET_BEST_CHANNELS)) == 0) { bytes_written = wl_cfg80211_get_best_channels(net, command, priv_cmd.total_len); } #endif /* WL_SUPPORT_AUTO_CHANNEL */ -#if defined(SUPPORT_TRIGGER_HANG_EVENT) - else if (strnicmp(command, CMD_TEST_FORCE_HANG, - strlen(CMD_TEST_FORCE_HANG)) == 0) { - net_os_send_hang_message(net); - } -#endif /* SUPPORT_TRIGGER_HANG_EVENT */ - else if (strnicmp(command, CMD_SETMIRACAST, strlen(CMD_SETMIRACAST)) == 0) { - bytes_written = wldev_miracast_tuning(net, command, priv_cmd.total_len); - } else if (strnicmp(command, CMD_ASSOCRESPIE, strlen(CMD_ASSOCRESPIE)) -== 0) - bytes_written = wldev_get_assoc_resp_ie(net, command, -priv_cmd.total_len); else if (strnicmp(command, CMD_MAXLINKSPEED, strlen(CMD_MAXLINKSPEED)) == 0) bytes_written = wldev_get_max_linkspeed(net, command, priv_cmd.total_len); - else if (strnicmp(command, CMD_OKC_SET_PMK, strlen(CMD_OKC_SET_PMK)) == 0) - bytes_written = wl_android_set_pmk(net, command, priv_cmd.total_len); - else if (strnicmp(command, CMD_OKC_ENABLE, strlen(CMD_OKC_ENABLE)) == 0) - bytes_written = wl_android_okc_enable(net, command, priv_cmd.total_len); + else if (strnicmp(command, CMD_HAPD_MAC_FILTER, strlen(CMD_HAPD_MAC_FILTER)) == 0) { + int skip = strlen(CMD_HAPD_MAC_FILTER) + 1; + wl_android_set_mac_address_filter(net, (const char*)command+skip); + } else if (strnicmp(command, CMD_SETROAMMODE, strlen(CMD_SETROAMMODE)) == 0) bytes_written = wl_android_set_roam_mode(net, command, priv_cmd.total_len); + else if (strnicmp(command, CMD_MIRACAST, strlen(CMD_MIRACAST)) == 0) + bytes_written = wl_android_set_miracast(net, command, priv_cmd.total_len); + else if (strnicmp(command, CMD_SETMIRACAST, strlen(CMD_SETMIRACAST)) == 0) + bytes_written = wldev_miracast_tuning(net, command, priv_cmd.total_len); + else if (strnicmp(command, CMD_ASSOCRESPIE, strlen(CMD_ASSOCRESPIE)) == 0) + bytes_written = wldev_get_assoc_resp_ie(net, command, priv_cmd.total_len); + else if (strnicmp(command, CMD_RXRATESTATS, strlen(CMD_RXRATESTATS)) == 0) + bytes_written = wldev_get_rx_rate_stats(net, command, priv_cmd.total_len); + else if (strnicmp(command, CMD_SETIBSSBEACONOUIDATA, + strlen(CMD_SETIBSSBEACONOUIDATA)) == 0) + bytes_written = wl_android_set_ibss_beacon_ouidata(net, command, + priv_cmd.total_len); else { DHD_ERROR(("Unknown PRIVATE command %s - ignored\n", command)); snprintf(command, 3, "OK"); @@ -928,7 +1330,6 @@ int wl_android_init(void) { int ret = 0; - dhd_msg_level |= DHD_ERROR_VAL; #ifdef ENABLE_INSMOD_NO_FW_LOAD dhd_download_fw_on_driverload = FALSE; #endif /* ENABLE_INSMOD_NO_FW_LOAD */ @@ -937,11 +1338,8 @@ int wl_android_init(void) memset(iface_name, 0, IFNAMSIZ); bcm_strncpy_s(iface_name, IFNAMSIZ, "wlan", IFNAMSIZ); } -#endif +#endif -#ifdef WL_GENL - wl_genl_init(); -#endif return ret; } @@ -950,258 +1348,37 @@ int wl_android_exit(void) { int ret = 0; -#ifdef WL_GENL - wl_genl_deinit(); -#endif /* WL_GENL */ return ret; } void wl_android_post_init(void) { + +#ifdef ENABLE_4335BT_WAR + bcm_bt_unlock(lock_cookie_wifi); + printk("%s: btlock released\n", __FUNCTION__); +#endif /* ENABLE_4335BT_WAR */ + if (!dhd_download_fw_on_driverload) { /* Call customer gpio to turn off power with WL_REG_ON signal */ dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF); - g_wifi_on = 0; - } -} - -#ifdef WL_GENL -/* Generic Netlink Initializaiton */ -static int wl_genl_init(void) -{ - int ret; - - WL_DBG(("GEN Netlink Init\n\n")); - - /* register new family */ - ret = genl_register_family(&wl_genl_family); - if (ret != 0) - goto failure; - - /* register functions (commands) of the new family */ - ret = genl_register_ops(&wl_genl_family, &wl_genl_ops); - if (ret != 0) { - WL_ERR(("register ops failed: %i\n", ret)); - genl_unregister_family(&wl_genl_family); - goto failure; - } - - ret = genl_register_mc_group(&wl_genl_family, &wl_genl_mcast); - if (ret != 0) { - WL_ERR(("register mc_group failed: %i\n", ret)); - genl_unregister_ops(&wl_genl_family, &wl_genl_ops); - genl_unregister_family(&wl_genl_family); - goto failure; - } - - return 0; - -failure: - WL_ERR(("Registering Netlink failed!!\n")); - return -1; -} - -/* Generic netlink deinit */ -static int wl_genl_deinit(void) -{ - if (genl_unregister_ops(&wl_genl_family, &wl_genl_ops) < 0) - WL_ERR(("Unregister wl_genl_ops failed\n")); - - if (genl_unregister_family(&wl_genl_family) < 0) - WL_ERR(("Unregister wl_genl_ops failed\n")); - - return 0; -} - -s32 wl_event_to_bcm_event(u16 event_type) -{ - u16 event = -1; - - switch (event_type) { - case WLC_E_SERVICE_FOUND: - event = BCM_E_SVC_FOUND; - break; - case WLC_E_P2PO_ADD_DEVICE: - event = BCM_E_DEV_FOUND; - break; - case WLC_E_P2PO_DEL_DEVICE: - event = BCM_E_DEV_LOST; - break; - /* Above events are supported from BCM Supp ver 47 Onwards */ - - default: - WL_ERR(("Event not supported\n")); - } - - return event; -} - -s32 -wl_genl_send_msg( - struct net_device *ndev, - u32 event_type, - u8 *buf, - u16 len, - u8 *subhdr, - u16 subhdr_len) -{ - int ret = 0; - struct sk_buff *skb; - void *msg; - u32 attr_type = 0; - bcm_event_hdr_t *hdr = NULL; - int mcast = 1; /* By default sent as mutlicast type */ - int pid = 0; - u8 *ptr = NULL, *p = NULL; - u32 tot_len = sizeof(bcm_event_hdr_t) + subhdr_len + len; - u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - - - WL_DBG(("Enter \n")); - - /* Decide between STRING event and Data event */ - if (event_type == 0) - attr_type = BCM_GENL_ATTR_STRING; - else - attr_type = BCM_GENL_ATTR_MSG; - - skb = genlmsg_new(NLMSG_GOODSIZE, kflags); - if (skb == NULL) { - ret = -ENOMEM; - goto out; - } - - msg = genlmsg_put(skb, 0, 0, &wl_genl_family, 0, BCM_GENL_CMD_MSG); - if (msg == NULL) { - ret = -ENOMEM; - goto out; - } - - - if (attr_type == BCM_GENL_ATTR_STRING) { - /* Add a BCM_GENL_MSG attribute. Since it is specified as a string. - * make sure it is null terminated - */ - if (subhdr || subhdr_len) { - WL_ERR(("No sub hdr support for the ATTR STRING type \n")); - ret = -EINVAL; - goto out; - } - - ret = nla_put_string(skb, BCM_GENL_ATTR_STRING, buf); - if (ret != 0) { - WL_ERR(("nla_put_string failed\n")); - goto out; - } - } else { - /* ATTR_MSG */ - - /* Create a single buffer for all */ - p = ptr = kzalloc(tot_len, kflags); - if (!ptr) { - ret = -ENOMEM; - WL_ERR(("ENOMEM!!\n")); - goto out; - } - - /* Include the bcm event header */ - hdr = (bcm_event_hdr_t *)ptr; - hdr->event_type = wl_event_to_bcm_event(event_type); - hdr->len = len + subhdr_len; - ptr += sizeof(bcm_event_hdr_t); - - /* Copy subhdr (if any) */ - if (subhdr && subhdr_len) { - memcpy(ptr, subhdr, subhdr_len); - ptr += subhdr_len; - } - - /* Copy the data */ - if (buf && len) { - memcpy(ptr, buf, len); - } - - ret = nla_put(skb, BCM_GENL_ATTR_MSG, tot_len, p); - if (ret != 0) { - WL_ERR(("nla_put_string failed\n")); - goto out; - } - } - - if (mcast) { - int err = 0; - /* finalize the message */ - genlmsg_end(skb, msg); - /* NETLINK_CB(skb).dst_group = 1; */ - if ((err = genlmsg_multicast(skb, 0, wl_genl_mcast.id, GFP_ATOMIC)) < 0) - WL_ERR(("genlmsg_multicast for attr(%d) failed. Error:%d \n", - attr_type, err)); - else - WL_DBG(("Multicast msg sent successfully. attr_type:%d len:%d \n", - attr_type, tot_len)); - } else { - NETLINK_CB(skb).dst_group = 0; /* Not in multicast group */ - - /* finalize the message */ - genlmsg_end(skb, msg); - - /* send the message back */ - if (genlmsg_unicast(&init_net, skb, pid) < 0) - WL_ERR(("genlmsg_unicast failed\n")); + g_wifi_on = FALSE; } - -out: - if (p) - kfree(p); - if (ret) - nlmsg_free(skb); - - return ret; } -static s32 -wl_genl_handle_msg( - struct sk_buff *skb, - struct genl_info *info) -{ - struct nlattr *na; - u8 *data = NULL; - - WL_DBG(("Enter \n")); - - if (info == NULL) { - return -EINVAL; - } - - na = info->attrs[BCM_GENL_ATTR_MSG]; - if (!na) { - WL_ERR(("nlattribute NULL\n")); - return -EINVAL; - } - - data = (char *)nla_data(na); - if (!data) { - WL_ERR(("Invalid data\n")); - return -EINVAL; - } else { - /* Handle the data */ - WL_DBG(("Data received from pid (%d) \n", info->snd_pid)); - } - - return 0; -} -#endif /* WL_GENL */ /** * Functions for Android WiFi card detection */ #if defined(CONFIG_WIFI_CONTROL_FUNC) +bool g_wifi_poweron = FALSE; static int g_wifidev_registered = 0; static struct semaphore wifi_control_sem; static struct wifi_platform_data *wifi_control_data = NULL; static struct resource *wifi_irqres = NULL; +static struct regulator *wifi_regulator = NULL; static int wifi_add_dev(void); static void wifi_del_dev(void); @@ -1266,25 +1443,78 @@ int wifi_get_irq_number(unsigned long *irq_flags_ptr) #endif } +#if defined(WIFIEDP) +static int wifi_request_edp_state(struct edp_client *pinfo, int new_state) +{ + int approved = 0; + DHD_TRACE(("%s edp_state = %d\n", __func__, new_state)); + + if ((!pinfo) || (new_state < EDP_STATE_ON) || (new_state > EDP_STATE_OFF)) { + DHD_ERROR(("Error while moving to a different power state\n")); + return -EINVAL; + } + + approved = edp_update_client_request(pinfo, new_state, NULL); + + if (approved < 0) + DHD_ERROR(("Error in moving to requested power state\n")); + + return approved; +} +#endif + int wifi_set_power(int on, unsigned long msec) { - DHD_ERROR(("%s = %d\n", __FUNCTION__, on)); - if (wifi_control_data && wifi_control_data->set_power) { -#ifdef ENABLE_WiFI_BT_TURN_ON_SYNC - bt_wlan_lock(); - if (on) - msleep(600); - else - msleep(50); + int ret = 0; +#if defined(WIFIEDP) + struct edp_client *pinfo = NULL; #endif - wifi_control_data->set_power(on); -#ifdef ENABLE_WiFI_BT_TURN_ON_SYNC - bt_wlan_unlock(); + DHD_ERROR(("%s = %d\n", __FUNCTION__, on)); + if (wifi_regulator && on) + ret = regulator_enable(wifi_regulator); + if (wifi_control_data) { +#if defined(WIFIEDP) + mutex_lock(&edp_reg_mutex); + if (g_edp_reg == TRUE) { + /* Move to EDP_ON/OFF state depending + * on wifi power state + */ + pinfo = &(wifi_control_data->client_info); + if (wifi_request_edp_state(pinfo, + on ? EDP_STATE_ON : EDP_STATE_OFF)) { + DHD_ERROR(("edp state transit failed\n")); + mutex_unlock(&edp_reg_mutex); + return -EACCES; + } + } + mutex_unlock(&edp_reg_mutex); #endif + +#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 */ + + if (wifi_control_data->set_power) + ret = wifi_control_data->set_power(on); + + if (wifi_regulator && !on) + ret = regulator_disable(wifi_regulator); + + if (msec) + OSL_SLEEP(msec); + return 0; } - if (msec) - msleep(msec); - return 0; + + return -EINVAL; } #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) @@ -1322,33 +1552,158 @@ static int wifi_set_carddetect(int on) return 0; } +#if defined(WIFIEDP) +static int wifi_register_edp_client(struct edp_client *pinfo) +{ + int ret = 0; + struct edp_manager *pbatman = edp_get_manager("battery"); + DHD_TRACE(("%s\n", __func__)); + + if (!pbatman || !pinfo) { + DHD_ERROR(("%s:edp registration failed\n", __func__)); + ret = -EINVAL; + goto error; + } + + if (!pinfo->states) { + DHD_ERROR(("No edp states for wifi\n")); + ret = -EINVAL; + goto error; + } + + if (g_edp_reg == TRUE) { + DHD_ERROR(("already registered edp client")); + goto error; + } + + if (edp_register_client(pbatman, pinfo)) { + DHD_ERROR(("Error registering the client\n")); + ret = -EPERM; + } + +error: + mutex_lock(&edp_reg_mutex); + if (ret == 0) + g_edp_reg = TRUE; + else + g_edp_reg = FALSE; + mutex_unlock(&edp_reg_mutex); + return ret; +} +#endif + +static struct resource *get_wifi_irqres_from_of(struct platform_device *pdev) +{ + static struct resource gpio_wifi_irqres; + int irq; + int gpio = of_get_gpio(pdev->dev.of_node, 0); + if (gpio < 0) + return NULL; + irq = gpio_to_irq(gpio); + if (irq < 0) + return NULL; + + gpio_wifi_irqres.name = "bcmdhd_wlan_irq"; + gpio_wifi_irqres.start = irq; + gpio_wifi_irqres.end = irq; + gpio_wifi_irqres.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | + IORESOURCE_IRQ_SHAREABLE; + + return &gpio_wifi_irqres; +} + static int wifi_probe(struct platform_device *pdev) { + int err; + struct regulator *regulator; struct wifi_platform_data *wifi_ctrl = (struct wifi_platform_data *)(pdev->dev.platform_data); + if (!wifi_ctrl) { + regulator = regulator_get(&pdev->dev, "wlreg_on"); + if (IS_ERR(regulator)) + return PTR_ERR(regulator); + wifi_regulator = regulator; + } + wifi_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "bcmdhd_wlan_irq"); if (wifi_irqres == NULL) wifi_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "bcm4329_wlan_irq"); + if (wifi_irqres == NULL) + wifi_irqres = get_wifi_irqres_from_of(pdev); wifi_control_data = wifi_ctrl; - wifi_set_power(1, 0); /* Power On */ - wifi_set_carddetect(1); /* CardDetect (0->1) */ +#if defined(WIFIEDP) + mutex_init(&edp_reg_mutex); + wifi_register_edp_client(&(wifi_ctrl->client_info)); +#endif + err = wifi_set_power(1, 200); /* Power On */ + if (unlikely(err)) { + DHD_ERROR(("%s: set_power failed. err=%d\n", __FUNCTION__, err)); + wifi_set_power(0, WIFI_TURNOFF_DELAY); + /* WL_REG_ON state unknown, Power off forcely */ + } else { + wifi_set_carddetect(1); /* CardDetect (0->1) */ + g_wifi_poweron = TRUE; + } up(&wifi_control_sem); return 0; } +#if defined(WIFIEDP) +static int wifi_unregister_edp_client(struct edp_client *pinfo) +{ + DHD_ERROR(("%s\n", __func__)); + mutex_lock(&edp_reg_mutex); + if (g_edp_reg == FALSE) { + DHD_ERROR(("Wifi edp client not registered!")); + mutex_unlock(&edp_reg_mutex); + return -EINVAL; + } + mutex_unlock(&edp_reg_mutex); + + if (!pinfo) { + DHD_ERROR(("## %s Invalid arguments\n", __func__)); + return -EINVAL; + } + + if (!edp_unregister_client(pinfo)) + DHD_ERROR(("Deregistration to edp failed!\n")); + + mutex_lock(&edp_reg_mutex); + g_edp_reg = FALSE; + mutex_unlock(&edp_reg_mutex); + + return 0; +} +#endif + static int wifi_remove(struct platform_device *pdev) { struct wifi_platform_data *wifi_ctrl = (struct wifi_platform_data *)(pdev->dev.platform_data); + struct io_cfg *cur, *q; DHD_ERROR(("## %s\n", __FUNCTION__)); wifi_control_data = wifi_ctrl; + if (g_wifi_poweron) { wifi_set_power(0, WIFI_TURNOFF_DELAY); /* Power Off */ wifi_set_carddetect(0); /* CardDetect (1->0) */ +#if defined(WIFIEDP) + wifi_unregister_edp_client(&(wifi_ctrl->client_info)); +#endif + g_wifi_poweron = FALSE; + list_for_each_entry_safe(cur, q, &miracast_resume_list, list) { + list_del(&cur->list); + kfree(cur); + } + } + if (wifi_regulator) { + regulator_put(wifi_regulator); + wifi_regulator = NULL; + } up(&wifi_control_sem); return 0; @@ -1373,6 +1728,12 @@ static int wifi_resume(struct platform_device *pdev) return 0; } +static const struct of_device_id wifi_device_dt_match[] = { + { .compatible = "android,bcmdhd_wlan", }, + {}, +}; +MODULE_DEVICE_TABLE(of, wifi_device_dt_match); + static struct platform_driver wifi_device = { .probe = wifi_probe, .remove = wifi_remove, @@ -1380,6 +1741,7 @@ static struct platform_driver wifi_device = { .resume = wifi_resume, .driver = { .name = "bcmdhd_wlan", + .of_match_table = wifi_device_dt_match, } }; diff --git a/drivers/net/wireless/bcmdhd/wl_android.h b/drivers/net/wireless/bcmdhd/wl_android.h index 15b396eeb495..ed01f5add71b 100644..100755 --- a/drivers/net/wireless/bcmdhd/wl_android.h +++ b/drivers/net/wireless/bcmdhd/wl_android.h @@ -1,7 +1,7 @@ /* * Linux cfg80211 driver - Android related functions * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -21,7 +21,7 @@ * 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: wl_android.h 367273 2012-11-07 09:58:55Z $ + * $Id: wl_android.h 431563 2013-10-24 01:50:16Z $ */ #include <linux/module.h> @@ -31,14 +31,11 @@ /* If any feature uses the Generic Netlink Interface, put it here to enable WL_GENL * automatically */ -#ifdef WL_SDO +#if defined(BCMCCX_S69) #define WL_GENL #endif -#ifdef WL_GENL -#include <net/genetlink.h> -#endif /** * Android platform dependent functions, feel free to add Android specific functions here @@ -67,44 +64,3 @@ int wifi_set_power(int on, unsigned long msec); int wifi_get_mac_addr(unsigned char *buf); void *wifi_get_country_code(char *ccode); #endif /* CONFIG_WIFI_CONTROL_FUNC */ - -#ifdef WL_GENL -typedef struct bcm_event_hdr { - u16 event_type; - u16 len; -} bcm_event_hdr_t; - -/* attributes (variables): the index in this enum is used as a reference for the type, - * userspace application has to indicate the corresponding type - * the policy is used for security considerations - */ -enum { - BCM_GENL_ATTR_UNSPEC, - BCM_GENL_ATTR_STRING, - BCM_GENL_ATTR_MSG, - __BCM_GENL_ATTR_MAX -}; -#define BCM_GENL_ATTR_MAX (__BCM_GENL_ATTR_MAX - 1) - -/* commands: enumeration of all commands (functions), - * used by userspace application to identify command to be ececuted - */ -enum { - BCM_GENL_CMD_UNSPEC, - BCM_GENL_CMD_MSG, - __BCM_GENL_CMD_MAX -}; -#define BCM_GENL_CMD_MAX (__BCM_GENL_CMD_MAX - 1) - -/* Enum values used by the BCM supplicant to identify the events */ -enum { - BCM_E_UNSPEC, - BCM_E_SVC_FOUND, - BCM_E_DEV_FOUND, - BCM_E_DEV_LOST, - BCM_E_MAX -}; - -s32 wl_genl_send_msg(struct net_device *ndev, u32 event_type, - u8 *string, u16 len, u8 *hdr, u16 hdrlen); -#endif /* WL_GENL */ diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c index 184f0a5508b3..d670d67d2e04 100644..100755 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c @@ -1,14 +1,15 @@ + /* * Linux cfg80211 driver * - * Copyright (C) 1999-2012, Broadcom Corporation - * + * Copyright (C) 1999-2013, Broadcom Corporation + * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2 (the "GPL"), * available at http://www.broadcom.com/licenses/GPLv2.php, with the * following added to such license: - * + * * As a special exception, the copyright holders of this software give you * permission to link this software with independent modules, and to copy and * distribute the resulting executable under terms of your choice, provided that @@ -16,14 +17,14 @@ * the license of that module. An independent module is a module which is not * derived from this software. The special exception does not apply to any * modifications of the software. - * + * * Notwithstanding the above, under no circumstances may you combine this * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: wl_cfg80211.c 387950 2013-02-27 19:07:56Z $ + * $Id: wl_cfg80211.c 432088 2013-10-25 15:02:04Z $ */ - +/* */ #include <typedefs.h> #include <linuxver.h> #include <osl.h> @@ -42,6 +43,9 @@ #include <dhdioctl.h> #include <wlioctl.h> #include <dhd_cfg80211.h> +#ifdef PNO_SUPPORT +#include <dhd_pno.h> +#endif /* PNO_SUPPORT */ #include <proto/ethernet.h> #include <linux/kernel.h> @@ -54,6 +58,7 @@ #include <linux/wait.h> #include <net/cfg80211.h> #include <net/rtnetlink.h> + #include <wlioctl.h> #include <wldev_common.h> #include <wl_cfg80211.h> @@ -64,18 +69,6 @@ #include <dhd_wlfc.h> #endif -#ifdef WL11U -#ifndef WL_ENABLE_P2P_IF -#error "You should enable WL_ENABLE_P2P_IF and Only supported in JB" -#endif -#endif /* WL11U */ - -#ifdef WLFBT -#if !defined(WLAN_AKM_SUITE_FT_8021X) || !defined(WLAN_CIPHER_SUITE_PMK) || \ - !defined(WLAN_AKM_SUITE_FT_PSK) -#error "PMK, FT-PSK, FT-8021X should be defined in your Kernel" -#endif -#endif /* WLFBT */ #define IW_WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED)) @@ -88,15 +81,16 @@ u32 wl_dbg_level = WL_DBG_ERR; #ifdef VSDB /* sleep time to keep STA's connecting or connection for continuous af tx or finding a peer */ -#define DEFAULT_SLEEP_TIME_VSDB 200 +#define DEFAULT_SLEEP_TIME_VSDB 120 #define OFF_CHAN_TIME_THRESHOLD_MS 200 +#define AF_RETRY_DELAY_TIME 40 /* if sta is connected or connecting, sleep for a while before retry af tx or finding a peer */ #define WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(wl) \ do { \ if (wl_get_drv_status(wl, CONNECTED, wl_to_prmry_ndev(wl)) || \ wl_get_drv_status(wl, CONNECTING, wl_to_prmry_ndev(wl))) { \ - msleep(DEFAULT_SLEEP_TIME_VSDB); \ + OSL_SLEEP(DEFAULT_SLEEP_TIME_VSDB); \ } \ } while (0) #else /* VSDB */ @@ -145,6 +139,74 @@ static const struct ieee80211_regdomain brcm_regdom = { REG_RULE(5470-10, 5850+10, 40, 6, 20, 0), } }; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \ + (defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF)) +/* + * Possible interface combinations supported by driver + * + * ADHOC Mode - #ADHOC <= 1 on channels = 1 + * SoftAP Mode - #AP <= 1 on channels = 1 + * STA + P2P Mode - #STA <= 2, #{P2P-GO, P2P-client} <= 1, #P2P-device <= 1 + * on channels = 2 + */ +static const struct ieee80211_iface_limit softap_limits[] = { + { + .max = 1, + .types = BIT(NL80211_IFTYPE_AP), + }, +}; + +static const struct ieee80211_iface_limit sta_p2p_limits[] = { + /* + * During P2P-GO removal, P2P-GO is first changed to STA and later only + * removed. So setting maximum possible number of STA interfaces as 3 to + * accommodate the above behaviour. + */ + { +#ifdef WL_ENABLE_P2P_IF + .max = 3, +#else + .max = 2, +#endif /* WL_ENABLE_P2P_IF */ + + .types = BIT(NL80211_IFTYPE_STATION), + }, + { + .max = 2, + .types = BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_CLIENT), + }, +#if defined(WL_CFG80211_P2P_DEV_IF) + { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_DEVICE), + }, +#endif /* WL_CFG80211_P2P_DEV_IF */ + { + .max = 1, + .types = BIT(NL80211_IFTYPE_ADHOC), + }, +}; + +static const struct ieee80211_iface_combination +softap_iface_combinations[] = { + { + .num_different_channels = 1, + .max_interfaces = 1, + .limits = softap_limits, + .n_limits = ARRAY_SIZE(softap_limits), + }, +}; + +static const struct ieee80211_iface_combination +sta_p2p_iface_combinations[] = { + { + .num_different_channels = 2, + .max_interfaces = 3, + .limits = sta_p2p_limits, + .n_limits = ARRAY_SIZE(sta_p2p_limits), + }, +}; +#endif /* LINUX_VER >= 3.0 && (WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF) */ /* Data Element Definitions */ #define WPS_ID_CONFIG_METHODS 0x1008 @@ -183,11 +245,14 @@ static const struct ieee80211_regdomain brcm_regdom = { #define PM_ENABLE 0 -#ifdef MFP -#define WL_AKM_SUITE_MFP_1X 0x000FAC05 -#define WL_AKM_SUITE_MFP_PSK 0x000FAC06 -#endif /* MFP */ +#ifndef IBSS_COALESCE_ALLOWED +#define IBSS_COALESCE_ALLOWED 0 +#endif + +#ifndef IBSS_INITIAL_SCAN_ALLOWED +#define IBSS_INITIAL_SCAN_ALLOWED 0 +#endif /* * cfg80211_ops api/callback list */ @@ -197,8 +262,14 @@ static s32 wl_frame_get_mgmt(u16 fc, const struct ether_addr *da, static s32 __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_scan_request *request, struct cfg80211_ssid *this_ssid); -static s32 wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, +#if defined(WL_CFG80211_P2P_DEV_IF) +static s32 +wl_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request); +#else +static s32 +wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_scan_request *request); +#endif /* WL_CFG80211_P2P_DEV_IF */ static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed); static s32 wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_ibss_params *params); @@ -214,10 +285,21 @@ static int wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_connect_params *sme); static s32 wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, u16 reason_code); -static s32 wl_cfg80211_set_tx_power(struct wiphy *wiphy, - enum nl80211_tx_power_setting type, - s32 dbm); +#if defined(WL_CFG80211_P2P_DEV_IF) +static s32 +wl_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, + enum nl80211_tx_power_setting type, s32 mbm); +#else +static s32 +wl_cfg80211_set_tx_power(struct wiphy *wiphy, + enum nl80211_tx_power_setting type, s32 dbm); +#endif /* WL_CFG80211_P2P_DEV_IF */ +#if defined(WL_CFG80211_P2P_DEV_IF) +static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, + struct wireless_dev *wdev, s32 *dbm); +#else static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm); +#endif /* WL_CFG80211_P2P_DEV_IF */ static s32 wl_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *dev, u8 key_idx, bool unicast, bool multicast); @@ -236,13 +318,11 @@ static s32 wl_cfg80211_resume(struct wiphy *wiphy); #if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \ 2, 0)) static s32 wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, - struct net_device *dev, u64 cookie); + bcm_struct_cfgdev *cfgdev, u64 cookie); static s32 wl_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev, u8* mac_addr); -static s32 wl_cfg80211_change_station(struct wiphy *wiphy, - struct net_device *dev, u8 *mac, struct station_parameters *params); #endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VER >= KERNEL_VERSION(3, 2, 0)) */ -#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39) +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || 0 static s32 wl_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow); #else static s32 wl_cfg80211_suspend(struct wiphy *wiphy); @@ -253,8 +333,14 @@ static s32 wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_pmksa *pmksa); static s32 wl_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *dev); +static void wl_cfg80211_scan_abort(struct wl_priv *wl); static s32 wl_notify_escan_complete(struct wl_priv *wl, struct net_device *ndev, bool aborted, bool fw_abort); +#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || 0 +static s32 wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, + u8 *peer, enum nl80211_tdls_operation oper); +#endif + /* * event & event Q handlers for cfg80211 interfaces */ @@ -275,18 +361,16 @@ static void wl_wakeup_event(struct wl_priv *wl); static s32 wl_notify_connect_status_ap(struct wl_priv *wl, struct net_device *ndev, const wl_event_msg_t *e, void *data); static s32 wl_notify_connect_status(struct wl_priv *wl, - struct net_device *ndev, - const wl_event_msg_t *e, void *data); + bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data); static s32 wl_notify_roaming_status(struct wl_priv *wl, - struct net_device *ndev, - const wl_event_msg_t *e, void *data); -static s32 wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev, + bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data); +static s32 wl_notify_scan_status(struct wl_priv *wl, bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data); static s32 wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev, const wl_event_msg_t *e, void *data, bool completed); static s32 wl_bss_roaming_done(struct wl_priv *wl, struct net_device *ndev, const wl_event_msg_t *e, void *data); -static s32 wl_notify_mic_status(struct wl_priv *wl, struct net_device *ndev, +static s32 wl_notify_mic_status(struct wl_priv *wl, bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data); #ifdef WL_SCHED_SCAN static s32 @@ -294,16 +378,19 @@ wl_notify_sched_scan_results(struct wl_priv *wl, struct net_device *ndev, const wl_event_msg_t *e, void *data); #endif /* WL_SCHED_SCAN */ #ifdef PNO_SUPPORT -static s32 wl_notify_pfn_status(struct wl_priv *wl, struct net_device *ndev, +static s32 wl_notify_pfn_status(struct wl_priv *wl, bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data); #endif /* PNO_SUPPORT */ static s32 wl_notifier_change_state(struct wl_priv *wl, struct net_info *_net_info, enum wl_status state, bool set); -#ifdef WL_SDO -static s32 wl_svc_resp_handler(struct wl_priv *wl, struct net_device *ndev, + +#ifdef WLTDLS +static s32 wl_tdls_event_handler(struct wl_priv *wl, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data); +#endif /* WLTDLS */ +#ifdef BCMCCX_S69 +static s32 wl_ccx_s69_response(struct wl_priv *wl, bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data); -static s32 wl_notify_device_discovery(struct wl_priv *wl, struct net_device *ndev, - const wl_event_msg_t *e, void *data); #endif /* * register/deregister parent device @@ -351,22 +438,13 @@ static void wl_ch_to_chanspec(int ch, */ static void wl_rst_ie(struct wl_priv *wl); static __used s32 wl_add_ie(struct wl_priv *wl, u8 t, u8 l, u8 *v); +static void wl_update_hidden_ap_ie(struct wl_bss_info *bi, u8 *ie_stream, u32 *ie_size); static s32 wl_mrg_ie(struct wl_priv *wl, u8 *ie_stream, u16 ie_size); static s32 wl_cp_ie(struct wl_priv *wl, u8 *dst, u16 dst_size); static u32 wl_get_ielen(struct wl_priv *wl); -#ifdef MFP -static int wl_cfg80211_get_rsn_capa(bcm_tlv_t *wpa2ie, u8* capa); -#endif -#ifdef WL11U -bcm_tlv_t * -wl_cfg80211_find_interworking_ie(u8 *parse, u32 len); -static s32 -wl_cfg80211_add_iw_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssidx, s32 pktflag, - uint8 ie_id, uint8 *data, uint8 data_len); -#endif /* WL11U */ -static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *dev); +static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *dev, void *data); static void wl_free_wdev(struct wl_priv *wl); #ifdef CONFIG_CFG80211_INTERNAL_REGDB static int @@ -374,16 +452,13 @@ wl_cfg80211_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request #endif /* CONFIG_CFG80211_INTERNAL_REGDB */ static s32 wl_inform_bss(struct wl_priv *wl); -static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi, u8 is_roam_done); -static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev, u8 is_roam_done); +static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi); +static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev); static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy); s32 wl_cfg80211_channel_to_freq(u32 channel); -#if defined(DHCP_SCAN_SUPPRESS) -static void wl_cfg80211_work_handler(struct work_struct *work); -static void wl_cfg80211_scan_supp_timerfunc(ulong data); -#endif /* DHCP_SCAN_SUPPRESS */ +static void wl_cfg80211_work_handler(struct work_struct *work); static s32 wl_add_keyext(struct wiphy *wiphy, struct net_device *dev, u8 key_idx, const u8 *mac_addr, struct key_params *params); @@ -451,10 +526,14 @@ static __used u32 wl_find_msb(u16 bit16); */ static int wl_setup_rfkill(struct wl_priv *wl, bool setup); static int wl_rfkill_set(void *data, bool blocked); +#ifdef DEBUGFS_CFG80211 +static s32 wl_setup_debugfs(struct wl_priv *wl); +static s32 wl_free_debugfs(struct wl_priv *wl); +#endif static wl_scan_params_t *wl_cfg80211_scan_alloc_params(int channel, int nprobes, int *out_params_size); -static void get_primary_mac(struct wl_priv *wl, struct ether_addr *mac); +static bool check_dev_role_integrity(struct wl_priv *wl, u32 dev_role); /* * Some external functions, TODO: move them to dhd_linux.h @@ -466,18 +545,15 @@ int dhd_monitor_uninit(void); int dhd_start_xmit(struct sk_buff *skb, struct net_device *net); -#ifdef WL_SDO -s32 wl_cfg80211_sdo_init(struct wl_priv *wl); -s32 wl_cfg80211_sdo_deinit(struct wl_priv *wl); -#define MAX_SDO_PROTO 5 -wl_sdo_proto_t wl_sdo_protos [] = { - { "all", SVC_RPOTYPE_ALL }, - { "upnp", SVC_RPOTYPE_UPNP }, - { "bonjour", SVC_RPOTYPE_BONJOUR }, - { "wsd", SVC_RPOTYPE_WSD }, - { "vendor", SVC_RPOTYPE_VENDOR }, -}; -#endif + +#define RETURN_EIO_IF_NOT_UP(wlpriv) \ +do { \ + struct net_device *checkSysUpNDev = wl_to_prmry_ndev(wlpriv); \ + if (unlikely(!wl_get_drv_status(wlpriv, READY, checkSysUpNDev))) { \ + WL_INFO(("device is not ready\n")); \ + return -EIO; \ + } \ +} while (0) #ifdef RSSI_OFFSET static s32 wl_rssi_offset(s32 rssi) @@ -491,16 +567,6 @@ static s32 wl_rssi_offset(s32 rssi) #define wl_rssi_offset(x) x #endif -#define CHECK_SYS_UP(wlpriv) \ -do { \ - struct net_device *ndev = wl_to_prmry_ndev(wlpriv); \ - if (unlikely(!wl_get_drv_status(wlpriv, READY, ndev))) { \ - WL_INFO(("device is not ready\n")); \ - return -EIO; \ - } \ -} while (0) - - #define IS_WPA_AKM(akm) ((akm) == RSN_AKM_NONE || \ (akm) == RSN_AKM_UNSPECIFIED || \ (akm) == RSN_AKM_PSK) @@ -513,7 +579,6 @@ extern int dhd_wlfc_init(dhd_pub_t *dhd); extern void dhd_wlfc_deinit(dhd_pub_t *dhd); #endif /* PROP_TXSTATUS_VSDB */ - #if (WL_DBG_LEVEL > 0) #define WL_DBG_ESTR_MAX 50 static s8 wl_dbg_estr[][WL_DBG_ESTR_MAX] = { @@ -570,18 +635,18 @@ static s8 wl_dbg_estr[][WL_DBG_ESTR_MAX] = { } static struct ieee80211_rate __wl_rates[] = { - RATETAB_ENT(WLC_RATE_1M, 0), - RATETAB_ENT(WLC_RATE_2M, IEEE80211_RATE_SHORT_PREAMBLE), - RATETAB_ENT(WLC_RATE_5M5, IEEE80211_RATE_SHORT_PREAMBLE), - RATETAB_ENT(WLC_RATE_11M, IEEE80211_RATE_SHORT_PREAMBLE), - RATETAB_ENT(WLC_RATE_6M, 0), - RATETAB_ENT(WLC_RATE_9M, 0), - RATETAB_ENT(WLC_RATE_12M, 0), - RATETAB_ENT(WLC_RATE_18M, 0), - RATETAB_ENT(WLC_RATE_24M, 0), - RATETAB_ENT(WLC_RATE_36M, 0), - RATETAB_ENT(WLC_RATE_48M, 0), - RATETAB_ENT(WLC_RATE_54M, 0) + RATETAB_ENT(DOT11_RATE_1M, 0), + RATETAB_ENT(DOT11_RATE_2M, IEEE80211_RATE_SHORT_PREAMBLE), + RATETAB_ENT(DOT11_RATE_5M5, IEEE80211_RATE_SHORT_PREAMBLE), + RATETAB_ENT(DOT11_RATE_11M, IEEE80211_RATE_SHORT_PREAMBLE), + RATETAB_ENT(DOT11_RATE_6M, 0), + RATETAB_ENT(DOT11_RATE_9M, 0), + RATETAB_ENT(DOT11_RATE_12M, 0), + RATETAB_ENT(DOT11_RATE_18M, 0), + RATETAB_ENT(DOT11_RATE_24M, 0), + RATETAB_ENT(DOT11_RATE_36M, 0), + RATETAB_ENT(DOT11_RATE_48M, 0), + RATETAB_ENT(DOT11_RATE_54M, 0) }; #define wl_a_rates (__wl_rates + 4) @@ -645,14 +710,57 @@ static const u32 __wl_cipher_suites[] = { WLAN_CIPHER_SUITE_TKIP, WLAN_CIPHER_SUITE_CCMP, WLAN_CIPHER_SUITE_AES_CMAC, -#if defined(WLFBT) - WLAN_CIPHER_SUITE_PMK, -#endif }; +#if defined(USE_DYNAMIC_MAXPKT_RXGLOM) +static int maxrxpktglom = 0; +#endif + /* IOCtl version read from targeted driver */ static int ioctl_version; +#ifdef DEBUGFS_CFG80211 +#define S_SUBLOGLEVEL 20 +static const struct { + u32 log_level; + char *sublogname; +} sublogname_map[] = { + {WL_DBG_ERR, "ERR"}, + {WL_DBG_INFO, "INFO"}, + {WL_DBG_DBG, "DBG"}, + {WL_DBG_SCAN, "SCAN"}, + {WL_DBG_TRACE, "TRACE"}, + {WL_DBG_P2P_ACTION, "P2PACTION"} +}; +#endif + + +static void wl_add_remove_pm_enable_work(struct wl_priv *wl, bool add_remove, + enum wl_handler_del_type type) +{ + if (wl->pm_enable_work_on) { + if (add_remove) { + schedule_delayed_work(&wl->pm_enable_work, + msecs_to_jiffies(WL_PM_ENABLE_TIMEOUT)); + } else { + cancel_delayed_work_sync(&wl->pm_enable_work); + switch (type) { + case WL_HANDLER_MAINTAIN: + schedule_delayed_work(&wl->pm_enable_work, + msecs_to_jiffies(WL_PM_ENABLE_TIMEOUT)); + break; + case WL_HANDLER_PEND: + schedule_delayed_work(&wl->pm_enable_work, + msecs_to_jiffies(WL_PM_ENABLE_TIMEOUT*2)); + break; + case WL_HANDLER_DEL: + default: + wl->pm_enable_work_on = false; + break; + } + } + } +} /* Return a new chanspec given a legacy chanspec * Returns INVCHANSPEC on error @@ -844,7 +952,14 @@ wl_cfg80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = { BIT(IEEE80211_STYPE_AUTH >> 4) | BIT(IEEE80211_STYPE_DEAUTH >> 4) | BIT(IEEE80211_STYPE_ACTION >> 4) - } + }, +#if defined(WL_CFG80211_P2P_DEV_IF) + [NL80211_IFTYPE_P2P_DEVICE] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) + }, +#endif /* WL_CFG80211_P2P_DEV_IF */ }; static void swap_key_from_BE(struct wl_wsec_key *key) @@ -869,7 +984,7 @@ static void swap_key_to_BE(struct wl_wsec_key *key) key->iv_initialized = dtoh32(key->iv_initialized); } -#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0) +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) && !0 /* For debug: Dump the contents of the encoded wps ie buffe */ static void wl_validate_wps_ie(char *wps_ie, s32 wps_ie_len, bool *pbc) @@ -953,7 +1068,7 @@ wl_validate_wps_ie(char *wps_ie, s32 wps_ie_len, bool *pbc) subel += subelt_len; } } -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0) */ +#endif static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy) { @@ -983,14 +1098,16 @@ static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy) else { bss = (struct wl_bss_info *) (wl->extra_buf + 4); chspec = bss->chanspec; + WL_DBG(("Valid BSS Found. chanspec:%d \n", chspec)); } return chspec; } -static struct net_device* wl_cfg80211_add_monitor_if(char *name) +static bcm_struct_cfgdev * +wl_cfg80211_add_monitor_if(char *name) { -#if defined(WLP2P) && defined(WL_ENABLE_P2P_IF) +#if defined(WL_ENABLE_P2P_IF) || defined(WL_CFG80211_P2P_DEV_IF) WL_INFO(("wl_cfg80211_add_monitor_if: No more support monitor interface\n")); return ERR_PTR(-EOPNOTSUPP); #else @@ -998,12 +1115,17 @@ static struct net_device* wl_cfg80211_add_monitor_if(char *name) dhd_add_monitor(name, &ndev); WL_INFO(("wl_cfg80211_add_monitor_if net device returned: 0x%p\n", ndev)); - return ndev; -#endif /* defined(WLP2P) && defined(WL_ENABLE_P2P_IF) */ + return ndev_to_cfgdev(ndev); +#endif /* WL_ENABLE_P2P_IF || WL_CFG80211_P2P_DEV_IF */ } -static struct net_device * -wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, +static bcm_struct_cfgdev * +wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, +#if defined(WL_CFG80211_P2P_DEV_IF) + const char *name, +#else + char *name, +#endif /* WL_CFG80211_P2P_DEV_IF */ enum nl80211_iftype type, u32 *flags, struct vif_params *params) { @@ -1031,7 +1153,6 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, dhd = (dhd_pub_t *)(wl->pub); #endif /* PROP_TXSTATUS_VSDB */ - /* Use primary I/F for sending cmds down to firmware */ _ndev = wl_to_prmry_ndev(wl); @@ -1045,7 +1166,11 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, mode = WL_MODE_IBSS; return NULL; case NL80211_IFTYPE_MONITOR: - return wl_cfg80211_add_monitor_if(name); + return wl_cfg80211_add_monitor_if((char *)name); +#if defined(WL_CFG80211_P2P_DEV_IF) + case NL80211_IFTYPE_P2P_DEVICE: + return wl_cfgp2p_add_p2p_disc_if(); +#endif /* WL_CFG80211_P2P_DEV_IF */ case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_STATION: wlif_type = WL_P2P_IF_CLIENT; @@ -1067,6 +1192,7 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, return NULL; } if (wl->p2p_supported && (wlif_type != -1)) { + ASSERT(wl->p2p); /* ensure expectation of p2p initialization */ if (wl_get_p2p_status(wl, IF_DELETING)) { /* wait till IF_DEL is complete * release the lock for the unregister to proceed @@ -1118,9 +1244,9 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, memset(wl->p2p->vir_ifname, 0, IFNAMSIZ); strncpy(wl->p2p->vir_ifname, name, IFNAMSIZ - 1); - wl_notify_escan_complete(wl, _ndev, true, true); + wl_cfg80211_scan_abort(wl); #ifdef PROP_TXSTATUS_VSDB - if (!wl->wlfc_on && !disable_proptx) { + if (dhd->op_mode != DHD_FLAG_IBSS_MODE && !wl->wlfc_on && !disable_proptx) { dhd->wlfc_enabled = true; dhd_wlfc_init(dhd); err = wldev_ioctl(_ndev, WLC_UP, &up, sizeof(s32), true); @@ -1183,6 +1309,10 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, val = 1; /* Disable firmware roaming for P2P interface */ wldev_iovar_setint(_ndev, "roam_off", val); + + if (mode != WL_MODE_AP) + wldev_iovar_setint(_ndev, "buf_key_b4_m4", 1); + WL_ERR((" virtual interface(%s) is " "created net attach done\n", wl->p2p->vir_ifname)); if (mode == WL_MODE_AP) @@ -1192,6 +1322,10 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, else if (type == NL80211_IFTYPE_P2P_GO) dhd_mode = DHD_FLAG_P2P_GO_MODE; DNGL_FUNC(dhd_cfg80211_set_p2p_info, (wl, dhd_mode)); +#ifdef PROP_TXSTATUS_VSDB + if (dhd->op_mode != DHD_FLAG_IBSS_MODE && dhd->plat_enable) + dhd->plat_enable((void *)dhd); +#endif /* PROP_TXSTATUS_VSDB */ /* reinitialize completion to clear previous count */ INIT_COMPLETION(wl->iface_disable); } else { @@ -1203,17 +1337,18 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, /* put back the rtnl_lock again */ if (rollback_lock) rtnl_lock(); - return _ndev; - + return ndev_to_cfgdev(_ndev); } else { wl_clr_p2p_status(wl, IF_ADD); WL_ERR((" virtual interface(%s) is not created \n", wl->p2p->vir_ifname)); memset(wl->p2p->vir_ifname, '\0', IFNAMSIZ); wl->p2p->vif_created = false; #ifdef PROP_TXSTATUS_VSDB - if (dhd->wlfc_enabled && wl->wlfc_on) { + if (dhd->op_mode != DHD_FLAG_IBSS_MODE && dhd->wlfc_enabled && wl->wlfc_on) { dhd->wlfc_enabled = false; dhd_wlfc_deinit(dhd); + if (dhd->plat_deinit) + dhd->plat_deinit((void *)dhd); wl->wlfc_on = false; } #endif /* PROP_TXSTATUS_VSDB */ @@ -1226,21 +1361,27 @@ fail: } static s32 -wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev) +wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev) { + struct net_device *dev = NULL; struct ether_addr p2p_mac; struct wl_priv *wl = wiphy_priv(wiphy); s32 timeout = -1; s32 ret = 0; + s32 index = -1; WL_DBG(("Enter\n")); - if (wl->p2p_net == dev) { - /* Since there is no ifidx corresponding to p2p0, cmds to - * firmware should be routed through primary I/F - */ - dev = wl_to_prmry_ndev(wl); +#if defined(WL_CFG80211_P2P_DEV_IF) + if (cfgdev->iftype == NL80211_IFTYPE_P2P_DEVICE) { + return wl_cfgp2p_del_p2p_disc_if(cfgdev); } +#endif /* WL_CFG80211_P2P_DEV_IF */ + dev = cfgdev_to_wlc_ndev(cfgdev, wl); + if (wl_cfgp2p_find_idx(wl, dev, &index) != BCME_OK) { + WL_ERR(("Find p2p index from ndev(%p) failed\n", dev)); + return BCME_ERROR; + } if (wl->p2p_supported) { memcpy(p2p_mac.octet, wl->p2p->int_addr.octet, ETHER_ADDR_LEN); @@ -1253,12 +1394,13 @@ wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev) wl_notify_escan_complete(wl, dev, true, true); } wldev_iovar_setint(dev, "mpc", 1); + /* Delete pm_enable_work */ + wl_add_remove_pm_enable_work(wl, FALSE, WL_HANDLER_DEL); /* for GC */ if (wl_get_drv_status(wl, DISCONNECTING, dev) && (wl_get_mode_by_netdev(wl, dev) != WL_MODE_AP)) { WL_ERR(("Wait for Link Down event for GC !\n")); - INIT_COMPLETION(wl->iface_disable); wait_for_completion_timeout (&wl->iface_disable, msecs_to_jiffies(500)); } @@ -1275,14 +1417,17 @@ wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev) */ if (ret == 0) { WL_ERR(("Wait for Link Down event for GO !!!\n")); - INIT_COMPLETION(wl->iface_disable); wait_for_completion_timeout(&wl->iface_disable, msecs_to_jiffies(500)); - } else { + } else if (ret != BCME_UNSUPPORTED) { msleep(300); } } - wl_cfgp2p_clear_management_ie(wl, wl_cfgp2p_find_idx(wl, dev)); + wl_cfgp2p_clear_management_ie(wl, index); + + if (wl_get_mode_by_netdev(wl, dev) != WL_MODE_AP) + wldev_iovar_setint(dev, "buf_key_b4_m4", 0); + /* delete interface after link down */ ret = wl_cfgp2p_ifdel(wl, &p2p_mac); /* Firmware could not delete the interface so we will not get WLC_E_IF @@ -1320,8 +1465,10 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev, { s32 ap = 0; s32 infra = 0; + s32 ibss = 0; s32 wlif_type; s32 mode = 0; + s32 err = BCME_OK; chanspec_t chspec; struct wl_priv *wl = wiphy_priv(wiphy); dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); @@ -1336,6 +1483,7 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev, break; case NL80211_IFTYPE_ADHOC: mode = WL_MODE_IBSS; + ibss = 1; break; case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_P2P_CLIENT: @@ -1399,6 +1547,16 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev, WL_DBG(("Change_virtual_iface for transition from GO/AP to client/STA")); } + if (ibss) { + infra = 0; + wl_set_mode_by_netdev(wl, ndev, mode); + err = wldev_ioctl(ndev, WLC_SET_INFRA, &infra, sizeof(s32), true); + if (err < 0) { + WL_ERR(("SET Adhoc error %d\n", err)); + return -EINVAL; + } + } + ndev->ieee80211_ptr->iftype = type; return 0; } @@ -1448,7 +1606,9 @@ wl_cfg80211_ifdel_ops(struct net_device *ndev) { struct wl_priv *wl = wlcfg_drv_priv; bool rollback_lock = false; - s32 index = 0; + s32 type = -1; + s32 bssidx = -1; + #ifdef PROP_TXSTATUS_VSDB dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); #endif /* PROP_TXSTATUS_VSDB */ @@ -1472,20 +1632,29 @@ wl_cfg80211_ifdel_ops(struct net_device *ndev) if (rollback_lock) rtnl_unlock(); } - WL_ERR(("IF_DEL event called from dongle, net %x, vif name: %s\n", - (unsigned int)ndev, wl->p2p->vir_ifname)); + WL_ERR(("IF_DEL event called from dongle, net %p, vif name: %s\n", + ndev, wl->p2p->vir_ifname)); memset(wl->p2p->vir_ifname, '\0', IFNAMSIZ); - index = wl_cfgp2p_find_idx(wl, ndev); - wl_to_p2p_bss_ndev(wl, index) = NULL; - wl_to_p2p_bss_bssidx(wl, index) = WL_INVALID; + if (wl_cfgp2p_find_idx(wl, ndev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p bssidx from ndev(%p) failed\n", ndev)); + return BCME_ERROR; + } + if (wl_cfgp2p_find_type(wl, bssidx, &type) != BCME_OK) { + WL_ERR(("Find p2p type from bssidx(%d) failed\n", bssidx)); + return BCME_ERROR; + } + wl_to_p2p_bss_ndev(wl, type) = NULL; + wl_to_p2p_bss_bssidx(wl, type) = WL_INVALID; wl->p2p->vif_created = false; - WL_DBG(("index : %d\n", index)); + WL_DBG(("type : %d\n", type)); #ifdef PROP_TXSTATUS_VSDB - if (dhd->wlfc_enabled && wl->wlfc_on) { + if (dhd->op_mode != DHD_FLAG_IBSS_MODE && dhd->wlfc_enabled && wl->wlfc_on) { dhd->wlfc_enabled = false; dhd_wlfc_deinit(dhd); + if (dhd->plat_deinit) + dhd->plat_deinit((void *)dhd); wl->wlfc_on = false; } #endif /* PROP_TXSTATUS_VSDB */ @@ -1531,13 +1700,14 @@ wl_cfg80211_notify_ifchange(void) /* Find listen channel */ static s32 wl_find_listen_channel(struct wl_priv *wl, - u8 *ie, u32 ie_len) + const u8 *ie, u32 ie_len) { wifi_p2p_ie_t *p2p_ie; u8 *end, *pos; s32 listen_channel; - p2p_ie = wl_cfgp2p_find_p2pie(ie, ie_len); + pos = (u8 *)ie; + p2p_ie = wl_cfgp2p_find_p2pie(pos, ie_len); if (p2p_ie == NULL) return 0; @@ -1637,20 +1807,8 @@ static void wl_scan_prep(struct wl_scan_params *params, struct cfg80211_scan_req continue; if (request->channels[i]->band == IEEE80211_BAND_2GHZ) { -#ifdef WL_HOST_BAND_MGMT - if (wl->curr_band == WLC_BAND_5G) { - WL_DBG(("In 5G only mode, omit 2G channel:%d\n", channel)); - continue; - } -#endif /* WL_HOST_BAND_MGMT */ chanspec |= WL_CHANSPEC_BAND_2G; } else { -#ifdef WL_HOST_BAND_MGMT - if (wl->curr_band == WLC_BAND_2G) { - WL_DBG(("In 2G only mode, omit 5G channel:%d\n", channel)); - continue; - } -#endif /* WL_HOST_BAND_MGMT */ chanspec |= WL_CHANSPEC_BAND_5G; } @@ -1695,8 +1853,9 @@ static void wl_scan_prep(struct wl_scan_params *params, struct cfg80211_scan_req htod32((n_ssids << WL_SCAN_PARAMS_NSSID_SHIFT) | (n_channels & WL_SCAN_PARAMS_COUNT_MASK)); - if (n_channels == 1 && wl_get_drv_status_all(wl, CONNECTED)) { - params->active_time = WL_SCAN_CONNECT_DWELL_TIME_MS; + if (n_channels == 1) { + params->active_time = htod32(WL_SCAN_CONNECT_DWELL_TIME_MS); + params->nprobes = htod32(params->active_time / WL_SCAN_JOIN_PROBE_INTERVAL_MS); } } @@ -1797,6 +1956,11 @@ wl_get_valid_channels(struct net_device *ndev, u8 *valid_chan_list, s32 size) return err; } +#if defined(USE_INITIAL_SHORT_DWELL_TIME) +#define FIRST_SCAN_ACTIVE_DWELL_TIME_MS 40 +static bool +g_first_broadcast_scan = TRUE; +#endif static s32 wl_run_escan(struct wl_priv *wl, struct net_device *ndev, @@ -1816,9 +1980,14 @@ wl_run_escan(struct wl_priv *wl, struct net_device *ndev, u16 *default_chan_list = NULL; wl_uint32_list_t *list; struct net_device *dev = NULL; +#if defined(USE_INITIAL_SHORT_DWELL_TIME) + bool is_first_init_2g_scan = false; +#endif + p2p_scan_purpose_t p2p_scan_purpose = P2P_SCAN_PURPOSE_MIN; WL_DBG(("Enter \n")); + /* scan request can come with empty request : perform all default scan */ if (!wl) { err = -EINVAL; goto exit; @@ -1827,10 +1996,19 @@ wl_run_escan(struct wl_priv *wl, struct net_device *ndev, /* LEGACY SCAN TRIGGER */ WL_SCAN((" LEGACY E-SCAN START\n")); +#if defined(USE_INITIAL_SHORT_DWELL_TIME) + if (!request) { + err = -EINVAL; + goto exit; + } + if (ndev == wl_to_prmry_ndev(wl) && g_first_broadcast_scan == true) { + is_first_init_2g_scan = true; + g_first_broadcast_scan = false; + } +#endif + /* if scan request is not empty parse scan request paramters */ if (request != NULL) { - - n_channels = request->n_channels; n_ssids = request->n_ssids; /* Allocate space for populating ssids in wl_iscan_params struct */ @@ -1850,10 +2028,15 @@ wl_run_escan(struct wl_priv *wl, struct net_device *ndev, } wl_scan_prep(¶ms->params, request); +#if defined(USE_INITIAL_SHORT_DWELL_TIME) + /* Override active_time to reduce scan time if it's first bradcast scan. */ + if (is_first_init_2g_scan) + params->params.active_time = FIRST_SCAN_ACTIVE_DWELL_TIME_MS; +#endif params->version = htod32(ESCAN_REQ_VERSION); params->action = htod16(action); - params->sync_id = htod16(0x1234); + wl_escan_set_sync_id(params->sync_id, wl); if (params_size + sizeof("escan") >= WLC_IOCTL_MEDLEN) { WL_ERR(("ioctl buffer length not sufficient\n")); kfree(params); @@ -1890,19 +2073,8 @@ wl_run_escan(struct wl_priv *wl, struct net_device *ndev, n_valid_chan = dtoh32(list->count); for (i = 0; i < num_chans; i++) { -#ifdef WL_HOST_BAND_MGMT - int channel_band = 0; -#endif /* WL_HOST_BAND_MGMT */ _freq = request->channels[i]->center_freq; channel = ieee80211_frequency_to_channel(_freq); -#ifdef WL_HOST_BAND_MGMT - channel_band = (channel > CH_MAX_2G_CHANNEL) ? - WLC_BAND_5G : WLC_BAND_2G; - if ((wl->curr_band != WLC_BAND_AUTO) && - (wl->curr_band != channel_band) && - !IS_P2P_SOCIAL_CHANNEL(channel)) - continue; -#endif /* WL_HOST_BAND_MGMT */ /* ignore DFS channels */ if (request->channels[i]->flags & @@ -1921,12 +2093,13 @@ wl_run_escan(struct wl_priv *wl, struct net_device *ndev, } } - if (num_chans == 3 && ( + if (num_chans == SOCIAL_CHAN_CNT && ( (default_chan_list[0] == SOCIAL_CHAN_1) && (default_chan_list[1] == SOCIAL_CHAN_2) && (default_chan_list[2] == SOCIAL_CHAN_3))) { /* SOCIAL CHANNELS 1, 6, 11 */ search_state = WL_P2P_DISC_ST_SEARCH; + p2p_scan_purpose = P2P_SCAN_SOCIAL_CHANNEL; WL_INFO(("P2P SEARCH PHASE START \n")); } else if ((dev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION)) && (wl_get_mode_by_netdev(wl, dev) == WL_MODE_AP)) { @@ -1934,16 +2107,32 @@ wl_run_escan(struct wl_priv *wl, struct net_device *ndev, WL_INFO(("Already a GO. Do SEARCH Only")); search_state = WL_P2P_DISC_ST_SEARCH; num_chans = n_nodfs; + p2p_scan_purpose = P2P_SCAN_NORMAL; + } else if (num_chans == 1) { + p2p_scan_purpose = P2P_SCAN_CONNECT_TRY; + } else if (num_chans == SOCIAL_CHAN_CNT + 1) { + /* SOCIAL_CHAN_CNT + 1 takes care of the Progressive scan supported by + * the supplicant + */ + p2p_scan_purpose = P2P_SCAN_SOCIAL_CHANNEL; } else { WL_INFO(("P2P SCAN STATE START \n")); num_chans = n_nodfs; + p2p_scan_purpose = P2P_SCAN_NORMAL; } - + } else { + err = -EINVAL; + goto exit; } err = wl_cfgp2p_escan(wl, ndev, wl->active_scan, num_chans, default_chan_list, search_state, action, - wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE), NULL); + wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE), NULL, + p2p_scan_purpose); + + if (!err) + wl->p2p->search_state = search_state; + kfree(default_chan_list); } exit: @@ -1967,7 +2156,8 @@ wl_do_escan(struct wl_priv *wl, struct wiphy *wiphy, struct net_device *ndev, wl_scan_results_t *results; WL_SCAN(("Enter \n")); mutex_lock(&wl->usr_sync); - results = (wl_scan_results_t *) wl->escan_info.escan_buf; + + results = wl_escan_get_buf(wl, FALSE); results->version = 0; results->count = 0; results->buflen = WL_SCAN_RESULTS_FIXED_SIZE; @@ -2002,9 +2192,6 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, bool iscan_req; bool escan_req = false; bool p2p_ssid; -#ifdef WL11U - bcm_tlv_t *interworking_ie; -#endif s32 err = 0; s32 bssidx = -1; s32 i; @@ -2020,12 +2207,7 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, return -EINVAL; } - /* If scan req comes for p2p0, send it over primary I/F - * Scan results will be delivered corresponding to cfg80211_scan_request - */ - if (ndev == wl->p2p_net) { - ndev = wl_to_prmry_ndev(wl); - } + ndev = ndev_to_wlc_ndev(ndev, wl); if (WL_DRV_STATUS_SENDING_AF_FRM_EXT(wl)) { WL_ERR(("Sending Action Frames. Try it again.\n")); @@ -2057,11 +2239,6 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, } #endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ -#ifdef WL_SDO - if (wl_get_p2p_status(wl, DISC_IN_PROGRESS)) { - wl_cfg80211_pause_sdo(ndev, wl); - } -#endif /* Arm scan timeout timer */ mod_timer(&wl->scan_timeout, jiffies + msecs_to_jiffies(WL_SCAN_TIMER_INTERVAL_MS)); @@ -2117,30 +2294,13 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, } } if (!wl->p2p_supported || !p2p_scan(wl)) { - bssidx = wl_cfgp2p_find_idx(wl, ndev); - -#ifdef WL11U - if ((interworking_ie = wl_cfg80211_find_interworking_ie( - (u8 *)request->ie, request->ie_len)) != NULL) { - err = wl_cfg80211_add_iw_ie(wl, ndev, bssidx, - VNDR_IE_CUSTOM_FLAG, interworking_ie->id, - interworking_ie->data, interworking_ie->len); - if (unlikely(err)) { - goto scan_out; - } - } else if (wl->iw_ie_len != 0) { - /* we have to clear IW IE and disable gratuitous APR */ - wl_cfg80211_add_iw_ie(wl, ndev, bssidx, - VNDR_IE_CUSTOM_FLAG, - DOT11_MNG_INTERWORKING_ID, - 0, 0); - - wldev_iovar_setint_bsscfg(ndev, "grat_arp", 0, - bssidx); - /* we don't care about error */ + if (wl_cfgp2p_find_idx(wl, ndev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from ndev(%p) failed\n", + ndev)); + err = BCME_ERROR; + goto scan_out; } -#endif /* WL11U */ err = wl_cfgp2p_set_management_ie(wl, ndev, bssidx, VNDR_IE_PRBREQ_FLAG, (u8 *)request->ie, request->ie_len); @@ -2170,23 +2330,12 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, if (wl->p2p_supported) { if (p2p_on(wl) && p2p_scan(wl)) { -#ifdef WL_SDO - if (wl_get_p2p_status(wl, DISC_IN_PROGRESS)) { - /* We shouldn't be getting p2p_find while discovery - * offload is in progress - */ - WL_SD(("P2P_FIND: Discovery offload is in progress." - " Do nothing\n")); - err = -EINVAL; - goto scan_out; - } -#endif /* find my listen channel */ wl->afx_hdl->my_listen_chan = - wl_find_listen_channel(wl, (u8 *)request->ie, + wl_find_listen_channel(wl, request->ie, request->ie_len); err = wl_cfgp2p_enable_discovery(wl, ndev, - request->ie, request->ie_len); + request->ie, request->ie_len); if (unlikely(err)) { goto scan_out; @@ -2234,13 +2383,11 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, } scan_success: - busy_count = 0; return 0; scan_out: - if (err == BCME_BUSY || err == BCME_NOTREADY) { WL_ERR(("Scan err = (%d), busy?%d", err, -EBUSY)); err = -EBUSY; @@ -2267,15 +2414,16 @@ scan_out: if ((ret = wldev_ioctl(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false)) == 0) WL_ERR(("FW is connected with " MACDBG "/n", - MAC2STRDBG(bssid.octet))); + MAC2STRDBG(bssid.octet))); else WL_ERR(("GET BSSID failed with %d\n", ret)); - wl_cfg80211_disconnect(wiphy, ndev, DOT11_RC_DISASSOC_LEAVING); + wl_cfg80211_scan_abort(wl); } } else { busy_count = 0; } + wl_clr_drv_status(wl, SCANNING, ndev); if (timer_pending(&wl->scan_timeout)) del_timer_sync(&wl->scan_timeout); @@ -2283,23 +2431,26 @@ scan_out: wl->scan_request = NULL; spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); -#ifdef WL_SDO - if (wl_get_p2p_status(wl, DISC_IN_PROGRESS)) { - wl_cfg80211_resume_sdo(ndev, wl); - } -#endif return err; } +#if defined(WL_CFG80211_P2P_DEV_IF) +static s32 +wl_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) +#else static s32 wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_scan_request *request) +#endif /* WL_CFG80211_P2P_DEV_IF */ { s32 err = 0; struct wl_priv *wl = wiphy_priv(wiphy); +#if defined(WL_CFG80211_P2P_DEV_IF) + struct net_device *ndev = wl_to_prmry_ndev(wl); +#endif /* WL_CFG80211_P2P_DEV_IF */ WL_DBG(("Enter \n")); - CHECK_SYS_UP(wl); + RETURN_EIO_IF_NOT_UP(wl); err = __wl_cfg80211_scan(wiphy, ndev, request, NULL); if (unlikely(err)) { @@ -2357,7 +2508,7 @@ static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) struct net_device *ndev = wl_to_prmry_ndev(wl); s32 err = 0; - CHECK_SYS_UP(wl); + RETURN_EIO_IF_NOT_UP(wl); WL_DBG(("Enter\n")); if (changed & WIPHY_PARAM_RTS_THRESHOLD && (wl->conf->rts_threshold != wiphy->rts_threshold)) { @@ -2391,6 +2542,151 @@ static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) return err; } +static chanspec_t +channel_to_chanspec(struct wiphy *wiphy, struct net_device *dev, u32 channel, u32 bw_cap) +{ + struct wl_priv *wl = wiphy_priv(wiphy); + u8 *buf = NULL; + wl_uint32_list_t *list; + int err = BCME_OK; + chanspec_t c = 0, ret_c = 0; + int bw = 0, tmp_bw = 0; + int i; + u32 tmp_c, sb; + u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; +#define LOCAL_BUF_SIZE 1024 + buf = (u8 *) kzalloc(LOCAL_BUF_SIZE, kflags); + if (!buf) { + WL_ERR(("buf memory alloc failed\n")); + goto exit; + } + list = (wl_uint32_list_t *)(void *)buf; + list->count = htod32(WL_NUMCHANSPECS); + err = wldev_iovar_getbuf_bsscfg(dev, "chanspecs", NULL, + 0, buf, LOCAL_BUF_SIZE, 0, &wl->ioctl_buf_sync); + if (err != BCME_OK) { + WL_ERR(("get chanspecs failed with %d\n", err)); + goto exit; + } + for (i = 0; i < dtoh32(list->count); i++) { + c = dtoh32(list->element[i]); + if (channel <= CH_MAX_2G_CHANNEL) { + if (!CHSPEC_IS20(c)) + continue; + if (channel == CHSPEC_CHANNEL(c)) { + ret_c = c; + bw = 20; + goto exit; + } + } + if (CHSPEC_IS20(c)) { + tmp_c = CHSPEC_CHANNEL(c); + tmp_bw = WLC_BW_CAP_20MHZ; + } + else if (CHSPEC_IS40(c)) { + tmp_c = CHSPEC_CHANNEL(c); + if (CHSPEC_SB_UPPER(c)) { + tmp_c += CH_10MHZ_APART; + } else { + tmp_c -= CH_10MHZ_APART; + } + tmp_bw = WLC_BW_CAP_40MHZ; + } + else { + tmp_c = CHSPEC_CHANNEL(c); + sb = c & WL_CHANSPEC_CTL_SB_MASK; + if (sb == WL_CHANSPEC_CTL_SB_LL) { + tmp_c -= (CH_10MHZ_APART + CH_20MHZ_APART); + } else if (sb == WL_CHANSPEC_CTL_SB_LU) { + tmp_c -= CH_10MHZ_APART; + } else if (sb == WL_CHANSPEC_CTL_SB_UL) { + tmp_c += CH_10MHZ_APART; + } else { + /* WL_CHANSPEC_CTL_SB_UU */ + tmp_c += (CH_10MHZ_APART + CH_20MHZ_APART); + } + tmp_bw = WLC_BW_CAP_80MHZ; + } + if (tmp_c != channel) + continue; + + if ((tmp_bw > bw) && (tmp_bw <= bw_cap)) { + bw = tmp_bw; + ret_c = c; + if (bw == bw_cap) + goto exit; + } + } +exit: + if (buf) + kfree(buf); +#undef LOCAL_BUF_SIZE + WL_INFO(("return chanspec %x %d\n", ret_c, bw)); + return ret_c; +} + +void +wl_cfg80211_ibss_vsie_set_buffer(vndr_ie_setbuf_t *ibss_vsie, int ibss_vsie_len) +{ + struct wl_priv *wl = wlcfg_drv_priv; + + if (wl != NULL && ibss_vsie != NULL) { + if (wl->ibss_vsie != NULL) { + kfree(wl->ibss_vsie); + } + wl->ibss_vsie = ibss_vsie; + wl->ibss_vsie_len = ibss_vsie_len; + } +} + +static void +wl_cfg80211_ibss_vsie_free(struct wl_priv *wl) +{ + /* free & initiralize VSIE (Vendor Specific IE) */ + if (wl->ibss_vsie != NULL) { + kfree(wl->ibss_vsie); + wl->ibss_vsie = NULL; + wl->ibss_vsie_len = 0; + } +} + +s32 +wl_cfg80211_ibss_vsie_delete(struct net_device *dev) +{ + struct wl_priv *wl = wlcfg_drv_priv; + char *ioctl_buf = NULL; + s32 ret = BCME_OK; + + if (wl != NULL && wl->ibss_vsie != NULL) { + ioctl_buf = kmalloc(WLC_IOCTL_MEDLEN, GFP_KERNEL); + if (!ioctl_buf) { + WL_ERR(("ioctl memory alloc failed\n")); + return -ENOMEM; + } + + /* change the command from "add" to "del" */ + strncpy(wl->ibss_vsie->cmd, "del", VNDR_IE_CMD_LEN - 1); + wl->ibss_vsie->cmd[VNDR_IE_CMD_LEN - 1] = '\0'; + + ret = wldev_iovar_setbuf(dev, "ie", + wl->ibss_vsie, wl->ibss_vsie_len, + ioctl_buf, WLC_IOCTL_MEDLEN, NULL); + WL_ERR(("ret=%d\n", ret)); + + if (ret == BCME_OK) { + /* free & initiralize VSIE */ + kfree(wl->ibss_vsie); + wl->ibss_vsie = NULL; + wl->ibss_vsie_len = 0; + } + + if (ioctl_buf) { + kfree(ioctl_buf); + } + } + + return ret; +} static s32 wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, @@ -2403,49 +2699,87 @@ wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_ssid ssid; s32 scan_retry = 0; s32 err = 0; - bool rollback_lock = false; + int scan_suppress = 1; + size_t join_params_size; + chanspec_t chanspec = 0; + u32 param[2] = {0, 0}; + u32 bw_cap = 0; WL_TRACE(("In\n")); - CHECK_SYS_UP(wl); - if (params->bssid) { - WL_ERR(("Invalid bssid\n")); - return -EOPNOTSUPP; + RETURN_EIO_IF_NOT_UP(wl); + WL_INFO(("JOIN BSSID:" MACDBG "\n", MAC2STRDBG(params->bssid))); + if (!params->ssid || params->ssid_len <= 0) { + WL_ERR(("Invalid parameter\n")); + return -EINVAL; + } + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) + chan = params->chandef.chan; +#else + chan = params->channel; +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) */ + if (chan) + wl->channel = ieee80211_frequency_to_channel(chan->center_freq); + if (wl_get_drv_status(wl, CONNECTED, dev)) { + struct wlc_ssid *ssid = (struct wlc_ssid *)wl_read_prof(wl, dev, WL_PROF_SSID); + u8 *bssid = (u8 *)wl_read_prof(wl, dev, WL_PROF_BSSID); + u32 *channel = (u32 *)wl_read_prof(wl, dev, WL_PROF_CHAN); + if (!params->bssid || ((memcmp(params->bssid, bssid, ETHER_ADDR_LEN) == 0) && + (memcmp(params->ssid, ssid->SSID, ssid->SSID_len) == 0) && + (*channel == wl->channel))) { + WL_ERR(("Connection already existed to " MACDBG "\n", + MAC2STRDBG((u8 *)wl_read_prof(wl, dev, WL_PROF_BSSID)))); + return -EISCONN; + } + WL_ERR(("Ignore Previous connecton to %s (" MACDBG ")\n", + ssid->SSID, MAC2STRDBG(bssid))); } + + /* remove the VSIE */ + wl_cfg80211_ibss_vsie_delete(dev); + bss = cfg80211_get_ibss(wiphy, NULL, params->ssid, params->ssid_len); if (!bss) { - memcpy(ssid.ssid, params->ssid, params->ssid_len); - ssid.ssid_len = params->ssid_len; - do { - if (unlikely - (__wl_cfg80211_scan(wiphy, dev, NULL, &ssid) == - -EBUSY)) { - wl_delay(150); - } else { - break; - } - } while (++scan_retry < WL_SCAN_RETRY_MAX); - /* to allow scan_inform to propagate to cfg80211 plane */ - if (rtnl_is_locked()) { - rtnl_unlock(); - rollback_lock = true; - } + if (IBSS_INITIAL_SCAN_ALLOWED == TRUE) { + memcpy(ssid.ssid, params->ssid, params->ssid_len); + ssid.ssid_len = params->ssid_len; + do { + if (unlikely + (__wl_cfg80211_scan(wiphy, dev, NULL, &ssid) == + -EBUSY)) { + wl_delay(150); + } else { + break; + } + } while (++scan_retry < WL_SCAN_RETRY_MAX); - /* wait 4 secons till scan done.... */ - schedule_timeout_interruptible(msecs_to_jiffies(4000)); - if (rollback_lock) - rtnl_lock(); - bss = cfg80211_get_ibss(wiphy, NULL, - params->ssid, params->ssid_len); + /* wait 4 secons till scan done.... */ + schedule_timeout_interruptible(msecs_to_jiffies(4000)); + bss = cfg80211_get_ibss(wiphy, NULL, + params->ssid, params->ssid_len); + } } - if (bss) { + if (bss && ((IBSS_COALESCE_ALLOWED == TRUE) || + ((IBSS_COALESCE_ALLOWED == FALSE) && params->bssid && + !memcmp(bss->bssid, params->bssid, ETHER_ADDR_LEN)))) { wl->ibss_starter = false; WL_DBG(("Found IBSS\n")); } else { wl->ibss_starter = true; } - chan = params->channel; - if (chan) - wl->channel = ieee80211_frequency_to_channel(chan->center_freq); + if (chan) { + if (chan->band == IEEE80211_BAND_5GHZ) + param[0] = WLC_BAND_5G; + else if (chan->band == IEEE80211_BAND_2GHZ) + param[0] = WLC_BAND_2G; + err = wldev_iovar_getint(dev, "bw_cap", param); + if (unlikely(err)) { + WL_ERR(("Get bw_cap Failed (%d)\n", err)); + return err; + } + bw_cap = param[0]; + chanspec = channel_to_chanspec(wiphy, dev, wl->channel, bw_cap); + } /* * Join with specific BSSID and cached SSID * If SSID is zero join based on BSSID only @@ -2454,18 +2788,57 @@ wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, memcpy((void *)join_params.ssid.SSID, (void *)params->ssid, params->ssid_len); join_params.ssid.SSID_len = htod32(params->ssid_len); - if (params->bssid) - memcpy(&join_params.params.bssid, params->bssid, - ETHER_ADDR_LEN); - else + if (params->bssid) { + memcpy(&join_params.params.bssid, params->bssid, ETHER_ADDR_LEN); + err = wldev_ioctl(dev, WLC_SET_DESIRED_BSSID, &join_params.params.bssid, + ETHER_ADDR_LEN, true); + if (unlikely(err)) { + WL_ERR(("Error (%d)\n", err)); + return err; + } + } else memset(&join_params.params.bssid, 0, ETHER_ADDR_LEN); + wldev_iovar_setint(dev, "ibss_coalesce_allowed", IBSS_COALESCE_ALLOWED); + + if (IBSS_INITIAL_SCAN_ALLOWED == FALSE) { + scan_suppress = TRUE; + /* Set the SCAN SUPRESS Flag in the firmware to skip join scan */ + err = wldev_ioctl(dev, WLC_SET_SCANSUPPRESS, &scan_suppress, sizeof(int), true); + if (unlikely(err)) { + WL_ERR(("Scan Supress Setting failed(%d)\n", err)); + return err; + } + } + + join_params.params.chanspec_list[0] = chanspec; + join_params.params.chanspec_num = 1; + wldev_iovar_setint(dev, "chanspec", chanspec); + join_params_size = sizeof(join_params); + + /* Disable Authentication, IBSS will add key if it required */ + wldev_iovar_setint(dev, "wpa_auth", WPA_AUTH_DISABLED); + wldev_iovar_setint(dev, "wsec", 0); + err = wldev_ioctl(dev, WLC_SET_SSID, &join_params, - sizeof(join_params), true); + join_params_size, true); if (unlikely(err)) { WL_ERR(("Error (%d)\n", err)); return err; } + + if (IBSS_INITIAL_SCAN_ALLOWED == FALSE) { + scan_suppress = FALSE; + /* Restore the SCAN SUPPRESS Falg */ + err = wldev_ioctl(dev, WLC_SET_SCANSUPPRESS, + &scan_suppress, sizeof(int), true); + if (unlikely(err)) { + WL_ERR(("Reset SCAN Suppress Flag failed (%d)\n", err)); + return err; + } + } + wl_update_prof(wl, dev, NULL, &join_params.ssid, WL_PROF_SSID); + wl_update_prof(wl, dev, NULL, &wl->channel, WL_PROF_CHAN); return err; } @@ -2473,50 +2846,30 @@ static s32 wl_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) { struct wl_priv *wl = wiphy_priv(wiphy); s32 err = 0; + scb_val_t scbval; + u8 *curbssid; - CHECK_SYS_UP(wl); + RETURN_EIO_IF_NOT_UP(wl); wl_link_down(wl); + WL_ERR(("Leave IBSS\n")); + curbssid = wl_read_prof(wl, dev, WL_PROF_BSSID); + wl_set_drv_status(wl, DISCONNECTING, dev); + scbval.val = 0; + memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN); + err = wldev_ioctl(dev, WLC_DISASSOC, &scbval, + sizeof(scb_val_t), true); + if (unlikely(err)) { + wl_clr_drv_status(wl, DISCONNECTING, dev); + WL_ERR(("error(%d)\n", err)); + return err; + } + + /* remove the VSIE */ + wl_cfg80211_ibss_vsie_delete(dev); return err; } -#ifdef MFP -static int wl_cfg80211_get_rsn_capa(bcm_tlv_t *wpa2ie, u8* capa) -{ - u16 suite_count; - wpa_suite_mcast_t *mcast; - wpa_suite_ucast_t *ucast; - u16 len; - wpa_suite_auth_key_mgmt_t *mgmt; - - if (!wpa2ie) - return -1; - - len = wpa2ie->len; - mcast = (wpa_suite_mcast_t *)&wpa2ie->data[WPA2_VERSION_LEN]; - if ((len -= WPA_SUITE_LEN) <= 0) - return BCME_BADLEN; - ucast = (wpa_suite_ucast_t *)&mcast[1]; - suite_count = ltoh16_ua(&ucast->count); - if ((suite_count > NL80211_MAX_NR_CIPHER_SUITES) || - (len -= (WPA_IE_SUITE_COUNT_LEN + - (WPA_SUITE_LEN * suite_count))) <= 0) - return BCME_BADLEN; - - mgmt = (wpa_suite_auth_key_mgmt_t *)&ucast->list[suite_count]; - suite_count = ltoh16_ua(&mgmt->count); - - if ((suite_count > NL80211_MAX_NR_CIPHER_SUITES) || - (len -= (WPA_IE_SUITE_COUNT_LEN + - (WPA_SUITE_LEN * suite_count))) >= RSN_CAP_LEN) { - capa[0] = *(u8 *)&mgmt->list[suite_count]; - capa[1] = *((u8 *)&mgmt->list[suite_count] + 1); - } else - return BCME_BADLEN; - - return 0; -} -#endif /* MFP */ static s32 wl_set_wpa_version(struct net_device *dev, struct cfg80211_connect_params *sme) @@ -2525,7 +2878,11 @@ wl_set_wpa_version(struct net_device *dev, struct cfg80211_connect_params *sme) struct wl_security *sec; s32 val = 0; s32 err = 0; - s32 bssidx = wl_cfgp2p_find_idx(wl, dev); + s32 bssidx; + if (wl_cfgp2p_find_idx(wl, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1) val = WPA_AUTH_PSK | @@ -2558,7 +2915,12 @@ wl_set_auth_type(struct net_device *dev, struct cfg80211_connect_params *sme) struct wl_security *sec; s32 val = 0; s32 err = 0; - s32 bssidx = wl_cfgp2p_find_idx(wl, dev); + s32 bssidx; + if (wl_cfgp2p_find_idx(wl, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } + switch (sme->auth_type) { case NL80211_AUTHTYPE_OPEN_SYSTEM: val = WL_AUTH_OPEN_SYSTEM; @@ -2573,7 +2935,7 @@ wl_set_auth_type(struct net_device *dev, struct cfg80211_connect_params *sme) WL_DBG(("automatic\n")); break; default: - val = WL_AUTH_OPEN_SHARED; + val = 2; WL_ERR(("invalid auth type (%d)\n", sme->auth_type)); break; } @@ -2597,13 +2959,12 @@ wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme) s32 gval = 0; s32 err = 0; s32 wsec_val = 0; -#ifdef MFP - s32 mfp = 0; - bcm_tlv_t *wpa2_ie; - u8 rsn_cap[2]; -#endif /* MFP */ - s32 bssidx = wl_cfgp2p_find_idx(wl, dev); + s32 bssidx; + if (wl_cfgp2p_find_idx(wl, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } if (sme->crypto.n_ciphers_pairwise) { switch (sme->crypto.ciphers_pairwise[0]) { @@ -2615,8 +2976,6 @@ wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme) pval = TKIP_ENABLED; break; case WLAN_CIPHER_SUITE_CCMP: - pval = AES_ENABLED; - break; case WLAN_CIPHER_SUITE_AES_CMAC: pval = AES_ENABLED; break; @@ -2660,41 +3019,6 @@ wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme) WL_DBG((" NO, is_wps_conn, Set pval | gval to WSEC")); wsec_val = pval | gval; -#ifdef MFP - if (pval == AES_ENABLED) { - if (((wpa2_ie = bcm_parse_tlvs((u8 *)sme->ie, sme->ie_len, - DOT11_MNG_RSN_ID)) != NULL) && - (wl_cfg80211_get_rsn_capa(wpa2_ie, rsn_cap) == 0)) { - - if (rsn_cap[0] & RSN_CAP_MFPC) { - /* MFP Capability advertised by supplicant. Check - * whether MFP is supported in the firmware - */ - if ((err = wldev_iovar_getint_bsscfg(dev, - "mfp", &mfp, bssidx)) < 0) { - WL_ERR(("Get MFP failed! " - "Check MFP support in FW \n")); - return -1; - } - - if ((sme->crypto.n_akm_suites == 1) && - ((sme->crypto.akm_suites[0] == - WL_AKM_SUITE_MFP_PSK) || - (sme->crypto.akm_suites[0] == - WL_AKM_SUITE_MFP_1X))) { - wsec_val |= MFP_SHA256; - } else if (sme->crypto.n_akm_suites > 1) { - WL_ERR(("Multiple AKM Specified \n")); - return -EINVAL; - } - - wsec_val |= MFP_CAPABLE; - if (rsn_cap[0] & RSN_CAP_MFPR) - wsec_val |= MFP_REQUIRED; - } - } - } -#endif /* MFP */ WL_DBG((" Set WSEC to fW 0x%x \n", wsec_val)); err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec_val, bssidx); @@ -2718,7 +3042,11 @@ wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme) struct wl_security *sec; s32 val = 0; s32 err = 0; - s32 bssidx = wl_cfgp2p_find_idx(wl, dev); + s32 bssidx; + if (wl_cfgp2p_find_idx(wl, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } if (sme->crypto.n_akm_suites) { err = wldev_iovar_getint(dev, "wpa_auth", &val); @@ -2746,25 +3074,9 @@ wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme) case WLAN_AKM_SUITE_8021X: val = WPA2_AUTH_UNSPECIFIED; break; -#ifdef MFP - case WL_AKM_SUITE_MFP_1X: - val = WPA2_AUTH_UNSPECIFIED; - break; - case WL_AKM_SUITE_MFP_PSK: - val = WPA2_AUTH_PSK; - break; -#endif case WLAN_AKM_SUITE_PSK: val = WPA2_AUTH_PSK; break; -#if defined(WLFBT) - case WLAN_AKM_SUITE_FT_8021X: - val = WPA2_AUTH_UNSPECIFIED | WPA2_AUTH_FT; - break; - case WLAN_AKM_SUITE_FT_PSK: - val = WPA2_AUTH_PSK | WPA2_AUTH_FT; - break; -#endif /* WLFBT */ default: WL_ERR(("invalid cipher group (%d)\n", sme->crypto.cipher_group)); @@ -2773,6 +3085,7 @@ wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme) } WL_DBG(("setting wpa_auth to %d\n", val)); + err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", val, bssidx); if (unlikely(err)) { WL_ERR(("could not set wpa_auth (%d)\n", err)); @@ -2794,7 +3107,11 @@ wl_set_set_sharedkey(struct net_device *dev, struct wl_wsec_key key; s32 val; s32 err = 0; - s32 bssidx = wl_cfgp2p_find_idx(wl, dev); + s32 bssidx; + if (wl_cfgp2p_find_idx(wl, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } WL_DBG(("key len (%d)\n", sme->key_len)); if (sme->key_len) { @@ -2852,10 +3169,11 @@ wl_set_set_sharedkey(struct net_device *dev, return err; } -#ifdef ESCAN_RESULT_PATCH +#if defined(ESCAN_RESULT_PATCH) static u8 connect_req_bssid[6]; static u8 broad_bssid[6]; -#endif +#endif /* ESCAN_RESULT_PATCH */ + static s32 @@ -2874,6 +3192,7 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, u32 wpaie_len = 0; u32 chan_cnt = 0; struct ether_addr bssid; + s32 bssidx; int ret; int wait_cnt; @@ -2884,7 +3203,13 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, return -EOPNOTSUPP; } - CHECK_SYS_UP(wl); + if (unlikely(sme->ssid_len > DOT11_MAX_SSID_LEN)) { + WL_ERR(("Invalid SSID info: SSID=%s, length=%d\n", + sme->ssid, sme->ssid_len)); + return -EINVAL; + } + + RETURN_EIO_IF_NOT_UP(wl); /* * Cancel ongoing scan to sync up with sme state machine of cfg80211. @@ -2894,16 +3219,16 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, wl_notify_escan_complete(wl, dev, true, true); } #endif -#ifdef ESCAN_RESULT_PATCH - if (sme->bssid) { +#if defined(ESCAN_RESULT_PATCH) + if (sme->bssid) memcpy(connect_req_bssid, sme->bssid, ETHER_ADDR_LEN); - } - else { + else bzero(connect_req_bssid, ETHER_ADDR_LEN); - } bzero(broad_bssid, ETHER_ADDR_LEN); #endif - +#if defined(USE_DYNAMIC_MAXPKT_RXGLOM) + maxrxpktglom = 0; +#endif bzero(&bssid, sizeof(bssid)); if (!wl_get_drv_status(wl, CONNECTED, dev)&& (ret = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false)) == 0) { @@ -2928,7 +3253,7 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, WL_DBG(("Waiting for disconnection terminated, wait_cnt: %d\n", wait_cnt)); wait_cnt--; - msleep(10); + OSL_SLEEP(10); } } else WL_DBG(("Currently not associated!\n")); @@ -2938,7 +3263,7 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, while (wl_get_drv_status(wl, DISCONNECTING, dev) && wait_cnt) { WL_DBG(("Waiting for disconnection terminated, wait_cnt: %d\n", wait_cnt)); wait_cnt--; - msleep(10); + OSL_SLEEP(10); } } @@ -2949,7 +3274,11 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, if (p2p_is_on(wl) && (dev != wl_to_prmry_ndev(wl))) { /* we only allow to connect using virtual interface in case of P2P */ - wl_cfgp2p_set_management_ie(wl, dev, wl_cfgp2p_find_idx(wl, dev), + if (wl_cfgp2p_find_idx(wl, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } + wl_cfgp2p_set_management_ie(wl, dev, bssidx, VNDR_IE_ASSOCREQ_FLAG, sme->ie, sme->ie_len); } else if (dev == wl_to_prmry_ndev(wl)) { /* find the RSN_IE */ @@ -2973,7 +3302,11 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync); } - err = wl_cfgp2p_set_management_ie(wl, dev, wl_cfgp2p_find_idx(wl, dev), + if (wl_cfgp2p_find_idx(wl, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } + err = wl_cfgp2p_set_management_ie(wl, dev, bssidx, VNDR_IE_ASSOCREQ_FLAG, (u8 *)sme->ie, sme->ie_len); if (unlikely(err)) { return err; @@ -3034,14 +3367,14 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, wl_update_prof(wl, dev, NULL, &ext_join_params->ssid, WL_PROF_SSID); ext_join_params->ssid.SSID_len = htod32(ext_join_params->ssid.SSID_len); /* increate dwell time to receive probe response or detect Beacon - * from target AP at a noisy air only during connect command + * from target AP at a noisy air only when channel info is provided in connect command */ - ext_join_params->scan.active_time = WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS; - ext_join_params->scan.passive_time = WL_SCAN_JOIN_PASSIVE_DWELL_TIME_MS; + ext_join_params->scan.active_time = chan_cnt ? WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS : -1; + ext_join_params->scan.passive_time = chan_cnt ? WL_SCAN_JOIN_PASSIVE_DWELL_TIME_MS : -1; /* Set up join scan parameters */ ext_join_params->scan.scan_type = -1; - ext_join_params->scan.nprobes - = (ext_join_params->scan.active_time/WL_SCAN_JOIN_PROBE_INTERVAL_MS); + ext_join_params->scan.nprobes = chan_cnt ? + (ext_join_params->scan.active_time/WL_SCAN_JOIN_PROBE_INTERVAL_MS) : -1; ext_join_params->scan.home_time = -1; if (sme->bssid) @@ -3069,8 +3402,18 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, ext_join_params->ssid.SSID_len)); } wl_set_drv_status(wl, CONNECTING, dev); + + if (wl_cfgp2p_find_idx(wl, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } err = wldev_iovar_setbuf_bsscfg(dev, "join", ext_join_params, join_params_size, - wl->ioctl_buf, WLC_IOCTL_MAXLEN, wl_cfgp2p_find_idx(wl, dev), &wl->ioctl_buf_sync); + wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync); + + WL_ERR(("Connectting with" MACDBG " channel (%d) ssid \"%s\", len (%d)\n\n", + MAC2STRDBG((u8*)(&ext_join_params->assoc.bssid)), wl->channel, + ext_join_params->ssid.SSID, ext_join_params->ssid.SSID_len)); + kfree(ext_join_params); if (err) { wl_clr_drv_status(wl, CONNECTING, dev); @@ -3096,7 +3439,7 @@ set_ssid: memcpy(&join_params.params.bssid, ðer_bcast, ETH_ALEN); wl_ch_to_chanspec(wl->channel, &join_params, &join_params_size); - WL_DBG(("join_param_size %d\n", join_params_size)); + WL_DBG(("join_param_size %zu\n", join_params_size)); if (join_params.ssid.SSID_len < IEEE80211_MAX_SSID_LEN) { WL_INFO(("ssid \"%s\", len (%d)\n", join_params.ssid.SSID, @@ -3122,7 +3465,7 @@ wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, s32 err = 0; u8 *curbssid; WL_ERR(("Reason %d\n", reason_code)); - CHECK_SYS_UP(wl); + RETURN_EIO_IF_NOT_UP(wl); act = *(bool *) wl_read_prof(wl, dev, WL_PROF_ACT); curbssid = wl_read_prof(wl, dev, WL_PROF_BSSID); if (act) { @@ -3151,9 +3494,15 @@ wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, return err; } +#if defined(WL_CFG80211_P2P_DEV_IF) +static s32 +wl_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, + enum nl80211_tx_power_setting type, s32 mbm) +#else static s32 wl_cfg80211_set_tx_power(struct wiphy *wiphy, enum nl80211_tx_power_setting type, s32 dbm) +#endif /* WL_CFG80211_P2P_DEV_IF */ { struct wl_priv *wl = wiphy_priv(wiphy); @@ -3161,8 +3510,15 @@ wl_cfg80211_set_tx_power(struct wiphy *wiphy, u16 txpwrmw; s32 err = 0; s32 disable = 0; - - CHECK_SYS_UP(wl); + s32 txpwrqdbm; +#if defined(WL_CFG80211_P2P_DEV_IF) + s32 dbm = MBM_TO_DBM(mbm); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) || \ + defined(WL_COMPAT_WIRELESS) || defined(WL_SUPPORT_BACKPORTED_KPATCHES) + dbm = MBM_TO_DBM(dbm); +#endif /* WL_CFG80211_P2P_DEV_IF */ + + RETURN_EIO_IF_NOT_UP(wl); switch (type) { case NL80211_TX_POWER_AUTOMATIC: break; @@ -3192,8 +3548,14 @@ wl_cfg80211_set_tx_power(struct wiphy *wiphy, txpwrmw = 0xffff; else txpwrmw = (u16) dbm; - err = wldev_iovar_setint(ndev, "qtxpower", - (s32) (bcm_mw_to_qdbm(txpwrmw))); + txpwrqdbm = (s32)bcm_mw_to_qdbm(txpwrmw); +#ifdef SUPPORT_WL_TXPOWER + if (type == NL80211_TX_POWER_AUTOMATIC) + txpwrqdbm = 127; + else + txpwrqdbm |= WL_TXPWR_OVERRIDE; +#endif /* SUPPORT_WL_TXPOWER */ + err = wldev_iovar_setint(ndev, "qtxpower", txpwrqdbm); if (unlikely(err)) { WL_ERR(("qtxpower error (%d)\n", err)); return err; @@ -3203,7 +3565,12 @@ wl_cfg80211_set_tx_power(struct wiphy *wiphy, return err; } +#if defined(WL_CFG80211_P2P_DEV_IF) +static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, + struct wireless_dev *wdev, s32 *dbm) +#else static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm) +#endif /* WL_CFG80211_P2P_DEV_IF */ { struct wl_priv *wl = wiphy_priv(wiphy); struct net_device *ndev = wl_to_prmry_ndev(wl); @@ -3211,7 +3578,7 @@ static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm) u8 result; s32 err = 0; - CHECK_SYS_UP(wl); + RETURN_EIO_IF_NOT_UP(wl); err = wldev_iovar_getint(ndev, "qtxpower", &txpwrdbm); if (unlikely(err)) { WL_ERR(("error (%d)\n", err)); @@ -3231,16 +3598,21 @@ wl_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *dev, u32 index; s32 wsec; s32 err = 0; - s32 bssidx = wl_cfgp2p_find_idx(wl, dev); + s32 bssidx; + if (wl_cfgp2p_find_idx(wl, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } WL_DBG(("key index (%d)\n", key_idx)); - CHECK_SYS_UP(wl); + RETURN_EIO_IF_NOT_UP(wl); err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx); if (unlikely(err)) { WL_ERR(("WLC_GET_WSEC error (%d)\n", err)); return err; } - if (wsec & WEP_ENABLED) { + /* fix IOT issue with Apple Airport */ + if (wsec == WEP_ENABLED) { /* Just select a new current key */ index = (u32) key_idx; index = htod32(index); @@ -3260,8 +3632,12 @@ wl_add_keyext(struct wiphy *wiphy, struct net_device *dev, struct wl_priv *wl = wiphy_priv(wiphy); struct wl_wsec_key key; s32 err = 0; - s32 bssidx = wl_cfgp2p_find_idx(wl, dev); + s32 bssidx; s32 mode = wl_get_mode_by_netdev(wl, dev); + if (wl_cfgp2p_find_idx(wl, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } memset(&key, 0, sizeof(key)); key.index = (u32) key_idx; @@ -3358,9 +3734,12 @@ wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev, struct wl_priv *wl = wiphy_priv(wiphy); s32 mode = wl_get_mode_by_netdev(wl, dev); WL_DBG(("key index (%d)\n", key_idx)); - CHECK_SYS_UP(wl); + RETURN_EIO_IF_NOT_UP(wl); - bssidx = wl_cfgp2p_find_idx(wl, dev); + if (wl_cfgp2p_find_idx(wl, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } if (mac_addr && ((params->cipher != WLAN_CIPHER_SUITE_WEP40) && @@ -3412,36 +3791,16 @@ wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev, val = AES_ENABLED; WL_DBG(("WLAN_CIPHER_SUITE_CCMP\n")); break; -#ifdef WLFBT - case WLAN_CIPHER_SUITE_PMK: { - int j; - wsec_pmk_t pmk; - char keystring[WSEC_MAX_PSK_LEN + 1]; - char* charptr = keystring; - uint len; - - /* copy the raw hex key to the appropriate format */ - for (j = 0; j < (WSEC_MAX_PSK_LEN / 2); j++) { - sprintf(charptr, "%02x", params->key[j]); - charptr += 2; - } - len = strlen(keystring); - pmk.key_len = htod16(len); - bcopy(keystring, pmk.key, len); - pmk.flags = htod16(WSEC_PASSPHRASE); - - err = wldev_ioctl(dev, WLC_SET_WSEC_PMK, &pmk, sizeof(pmk), true); - if (err) - return err; - } break; -#endif /* WLFBT */ - default: WL_ERR(("Invalid cipher (0x%x)\n", params->cipher)); return -EINVAL; } /* Set the new key/index */ + if ((mode == WL_MODE_IBSS) && (val & (TKIP_ENABLED | AES_ENABLED))) { + WL_ERR(("IBSS KEY setted\n")); + wldev_iovar_setint(dev, "wpa_auth", WPA_AUTH_NONE); + } swap_key_from_BE(&key); err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync); @@ -3474,14 +3833,19 @@ wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev, struct wl_wsec_key key; struct wl_priv *wl = wiphy_priv(wiphy); s32 err = 0; - s32 bssidx = wl_cfgp2p_find_idx(wl, dev); - + s32 bssidx; + if (wl_cfgp2p_find_idx(wl, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } WL_DBG(("Enter\n")); + #ifndef IEEE80211W if ((key_idx >= DOT11_MAX_DEFAULT_KEYS) && (key_idx < DOT11_MAX_DEFAULT_KEYS+2)) return -EINVAL; #endif - CHECK_SYS_UP(wl); + + RETURN_EIO_IF_NOT_UP(wl); memset(&key, 0, sizeof(key)); key.flags = WL_PRIMARY_KEY; @@ -3518,10 +3882,13 @@ wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev, struct wl_security *sec; s32 wsec; s32 err = 0; - s32 bssidx = wl_cfgp2p_find_idx(wl, dev); - + s32 bssidx; + if (wl_cfgp2p_find_idx(wl, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } WL_DBG(("key index (%d)\n", key_idx)); - CHECK_SYS_UP(wl); + RETURN_EIO_IF_NOT_UP(wl); memset(&key, 0, sizeof(key)); key.index = key_idx; swap_key_to_BE(&key); @@ -3529,7 +3896,7 @@ wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev, params.key_len = (u8) min_t(u8, DOT11_MAX_KEY_SIZE, key.len); memcpy(params.key, key.data, params.key_len); - wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx); + err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx); if (unlikely(err)) { WL_ERR(("WLC_GET_WSEC error (%d)\n", err)); return err; @@ -3580,11 +3947,11 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, s32 rate; s32 err = 0; sta_info_t *sta; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) || 0 s8 eabuf[ETHER_ADDR_STR_LEN]; #endif dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); - CHECK_SYS_UP(wl); + RETURN_EIO_IF_NOT_UP(wl); if (wl_get_mode_by_netdev(wl, dev) == WL_MODE_AP) { err = wldev_iovar_getbuf(dev, "sta_info", (struct ether_addr *)mac, ETHER_ADDR_LEN, wl->ioctl_buf, WLC_IOCTL_SMLEN, &wl->ioctl_buf_sync); @@ -3600,7 +3967,7 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, sta->idle = dtoh32(sta->idle); sta->in = dtoh32(sta->in); sinfo->inactive_time = sta->idle * 1000; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) || 0 if (sta->flags & WL_STA_ASSOC) { sinfo->filled |= STATION_INFO_CONNECTED_TIME; sinfo->connected_time = sta->in; @@ -3609,7 +3976,8 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, bcm_ether_ntoa((const struct ether_addr *)mac, eabuf), sinfo->inactive_time, sta->idle * 1000)); #endif - } else if (wl_get_mode_by_netdev(wl, dev) == WL_MODE_BSS) { + } else if (wl_get_mode_by_netdev(wl, dev) == WL_MODE_BSS || + wl_get_mode_by_netdev(wl, dev) == WL_MODE_IBSS) { get_pktcnt_t pktcnt; u8 *curmacp = wl_read_prof(wl, dev, WL_PROF_BSSID); if (!wl_get_drv_status(wl, CONNECTED, dev) || @@ -3630,10 +3998,28 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, if (err) { WL_ERR(("Could not get rate (%d)\n", err)); } else { +#if defined(USE_DYNAMIC_MAXPKT_RXGLOM) + int rxpktglom; +#endif rate = dtoh32(rate); sinfo->filled |= STATION_INFO_TX_BITRATE; sinfo->txrate.legacy = rate * 5; WL_DBG(("Rate %d Mbps\n", (rate / 2))); +#if defined(USE_DYNAMIC_MAXPKT_RXGLOM) + rxpktglom = ((rate/2) > 150) ? 20 : 10; + + if (maxrxpktglom != rxpktglom) { + maxrxpktglom = rxpktglom; + WL_DBG(("Rate %d Mbps, update bus:maxtxpktglom=%d\n", (rate/2), + maxrxpktglom)); + err = wldev_iovar_setbuf(dev, "bus:maxtxpktglom", + (char*)&maxrxpktglom, 4, wl->ioctl_buf, + WLC_IOCTL_MAXLEN, NULL); + if (err < 0) { + WL_ERR(("set bus:maxtxpktglom failed, %d\n", err)); + } + } +#endif } memset(&scb_val, 0, sizeof(scb_val)); @@ -3663,12 +4049,15 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, get_station_err: if (err && (err != -ERESTARTSYS)) { /* Disconnect due to zero BSSID or error to get RSSI */ - WL_ERR(("force cfg80211_disconnected\n")); + WL_ERR(("force cfg80211_disconnected: %d\n", err)); wl_clr_drv_status(wl, CONNECTED, dev); cfg80211_disconnected(dev, 0, NULL, 0, GFP_KERNEL); wl_link_down(wl); } } + else { + WL_ERR(("Invalid device mode %d\n", wl_get_mode_by_netdev(wl, dev))); + } return err; } @@ -3684,12 +4073,13 @@ int wl_cfg80211_update_power_mode(struct net_device *dev) WL_ERR(("error (%d)\n", err)); } else { pm = (pm == PM_OFF) ? false : true; - WL_DBG(("%d\n", pm)); + WL_DBG(("%s: %d\n", __func__, pm)); if (dev->ieee80211_ptr) dev->ieee80211_ptr->ps = pm; } return err; } + static s32 wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, bool enabled, s32 timeout) @@ -3701,24 +4091,31 @@ wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, #if !defined(SUPPORT_PM2_ONLY) dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); #endif /* (OEM_ANDROID) */ - CHECK_SYS_UP(wl); - - if (wl->p2p_net == dev || _net_info == NULL) { + RETURN_EIO_IF_NOT_UP(wl); + WL_DBG(("Enter\n")); +#if defined(WL_ENABLE_P2P_IF) + if (wl->p2p_net == dev || _net_info == NULL || wl->vsdb_mode || + !wl_get_drv_status(wl, CONNECTED, dev)) { +#else + if (_net_info == NULL || wl->vsdb_mode || + !wl_get_drv_status(wl, CONNECTED, dev)) { +#endif /* WL_ENABLE_P2P_IF */ return err; } WL_DBG(("%s: Enter power save enabled %d\n", dev->name, enabled)); + /* Delete pm_enable_work */ + wl_add_remove_pm_enable_work(wl, FALSE, WL_HANDLER_PEND); + #if !defined(SUPPORT_PM2_ONLY) /* android has special hooks to change pm when kernel suspended */ pm = enabled ? ((dhd->in_suspend) ? PM_MAX : PM_FAST) : PM_OFF; #else pm = enabled ? PM_FAST : PM_OFF; #endif /* SUPPORT_PM2_ONLY */ - - if (_net_info->pm_block || wl->vsdb_mode) { - /* Do not enable the power save if it is p2p interface or vsdb mode is set */ - WL_DBG(("%s:Do not enable the power save for pm_block %d or vsdb_mode %d\n", - dev->name, _net_info->pm_block, wl->vsdb_mode)); + if (_net_info->pm_block) { + WL_ERR(("%s:Do not enable the power save for pm_block %d\n", + dev->name, _net_info->pm_block)); pm = PM_OFF; } pm = htod32(pm); @@ -3777,7 +4174,7 @@ static s32 wl_cfg80211_resume(struct wiphy *wiphy) return err; } -#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39) +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || 0 static s32 wl_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow) #else static s32 wl_cfg80211_suspend(struct wiphy *wiphy) @@ -3846,7 +4243,7 @@ wl_update_pmklist(struct net_device *dev, struct wl_pmk_list *pmk_list, } if (likely(!err)) { err = wldev_iovar_setbuf(dev, "pmkid_info", (char *)pmk_list, - sizeof(*pmk_list), wl->ioctl_buf, WLC_IOCTL_MAXLEN, NULL); + sizeof(*pmk_list), wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync); } return err; @@ -3860,7 +4257,7 @@ wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev, s32 err = 0; int i; - CHECK_SYS_UP(wl); + RETURN_EIO_IF_NOT_UP(wl); for (i = 0; i < wl->pmk_list->pmkids.npmkid; i++) if (!memcmp(pmksa->bssid, &wl->pmk_list->pmkids.pmkid[i].BSSID, ETHER_ADDR_LEN)) @@ -3893,11 +4290,11 @@ wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_pmksa *pmksa) { struct wl_priv *wl = wiphy_priv(wiphy); - struct _pmkid_list pmkid; + struct _pmkid_list pmkid = {0}; s32 err = 0; int i; - CHECK_SYS_UP(wl); + RETURN_EIO_IF_NOT_UP(wl); memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETHER_ADDR_LEN); memcpy(pmkid.pmkid[0].PMKID, pmksa->pmkid, WPA2_PMKID_LEN); @@ -3940,7 +4337,7 @@ wl_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *dev) { struct wl_priv *wl = wiphy_priv(wiphy); s32 err = 0; - CHECK_SYS_UP(wl); + RETURN_EIO_IF_NOT_UP(wl); memset(wl->pmk_list, 0, sizeof(*wl->pmk_list)); err = wl_update_pmklist(dev, wl->pmk_list, err); return err; @@ -3988,29 +4385,30 @@ wl_cfg80211_scan_alloc_params(int channel, int nprobes, int *out_params_size) return params; } +#if defined(WL_CFG80211_P2P_DEV_IF) +static s32 +wl_cfg80211_remain_on_channel(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, + struct ieee80211_channel *channel, unsigned int duration, u64 *cookie) +#else static s32 -wl_cfg80211_remain_on_channel(struct wiphy *wiphy, struct net_device *dev, +wl_cfg80211_remain_on_channel(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, struct ieee80211_channel * channel, enum nl80211_channel_type channel_type, unsigned int duration, u64 *cookie) +#endif /* WL_CFG80211_P2P_DEV_IF */ { s32 target_channel; u32 id; + s32 err = BCME_OK; struct ether_addr primary_mac; struct net_device *ndev = NULL; - - s32 err = BCME_OK; struct wl_priv *wl = wiphy_priv(wiphy); - WL_DBG(("Enter, ifindex: %d, channel: %d, duration ms (%d) SCANNING ?? %s \n", - dev->ifindex, ieee80211_frequency_to_channel(channel->center_freq), - duration, (wl_get_drv_status(wl, SCANNING, ndev)) ? "YES":"NO")); + ndev = cfgdev_to_wlc_ndev(cfgdev, wl); - if (wl->p2p_net == dev) { - ndev = wl_to_prmry_ndev(wl); - } else { - ndev = dev; - } + WL_DBG(("Enter, channel: %d, duration ms (%d) SCANNING ?? %s \n", + ieee80211_frequency_to_channel(channel->center_freq), + duration, (wl_get_drv_status(wl, SCANNING, ndev)) ? "YES":"NO")); if (!wl->p2p) { WL_ERR(("wl->p2p is not initialized\n")); @@ -4019,14 +4417,16 @@ wl_cfg80211_remain_on_channel(struct wiphy *wiphy, struct net_device *dev, } #ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST - if (wl_get_drv_status(wl, SCANNING, ndev)) { - wl_notify_escan_complete(wl, ndev, true, true); + if (wl_get_drv_status_all(wl, SCANNING)) { + wl_notify_escan_complete(wl, wl->escan_info.ndev, true, true); } #endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ target_channel = ieee80211_frequency_to_channel(channel->center_freq); memcpy(&wl->remain_on_chan, channel, sizeof(struct ieee80211_channel)); +#if defined(WL_ENABLE_P2P_IF) wl->remain_on_chan_type = channel_type; +#endif /* WL_ENABLE_P2P_IF */ id = ++wl->last_roc_id; if (id == 0) id = ++wl->last_roc_id; @@ -4105,8 +4505,13 @@ wl_cfg80211_remain_on_channel(struct wiphy *wiphy, struct net_device *dev, exit: if (err == BCME_OK) { WL_INFO(("Success\n")); - cfg80211_ready_on_channel(dev, *cookie, channel, +#if defined(WL_CFG80211_P2P_DEV_IF) + cfg80211_ready_on_channel(cfgdev, *cookie, channel, + duration, GFP_KERNEL); +#else + cfg80211_ready_on_channel(cfgdev, *cookie, channel, channel_type, duration, GFP_KERNEL); +#endif /* WL_CFG80211_P2P_DEV_IF */ } else { WL_ERR(("Fail to Set (err=%d cookie:%llu)\n", err, *cookie)); } @@ -4114,11 +4519,18 @@ exit: } static s32 -wl_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, struct net_device *dev, - u64 cookie) +wl_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, + bcm_struct_cfgdev *cfgdev, u64 cookie) { s32 err = 0; - WL_DBG((" enter ) netdev_ifidx: %d \n", dev->ifindex)); + +#if defined(WL_CFG80211_P2P_DEV_IF) + if (cfgdev->iftype == NL80211_IFTYPE_P2P_DEVICE) { + WL_DBG((" enter ) on P2P dedicated discover interface\n")); + } +#else + WL_DBG((" enter ) netdev_ifidx: %d \n", cfgdev->ifindex)); +#endif /* WL_CFG80211_P2P_DEV_IF */ return err; } @@ -4133,7 +4545,7 @@ wl_cfg80211_afx_handler(struct work_struct *work) if (afx_instance != NULL && wl->afx_hdl->is_active) { if (wl->afx_hdl->is_listen && wl->afx_hdl->my_listen_chan) { ret = wl_cfgp2p_discover_listen(wl, wl->afx_hdl->my_listen_chan, - (100 * (1 + (random32() % 3)))); /* 100ms ~ 300ms */ + (100 * (1 + (RANDOM32() % 3)))); /* 100ms ~ 300ms */ } else { ret = wl_cfgp2p_act_frm_search(wl, wl->afx_hdl->dev, wl->afx_hdl->bssidx, wl->afx_hdl->peer_listen_chan, @@ -4172,7 +4584,7 @@ wl_cfg80211_af_searching_channel(struct wl_priv *wl, struct net_device *dev) /* search peer on peer's listen channel */ schedule_work(&wl->afx_hdl->work); wait_for_completion_timeout(&wl->act_frm_scan, - msecs_to_jiffies(MAX_WAIT_TIME)); + msecs_to_jiffies(WL_AF_SEARCH_TIME_MAX)); if ((wl->afx_hdl->peer_chan != WL_INVALID) || !(wl_get_drv_status(wl, FINDING_COMMON_CHANNEL, dev))) @@ -4185,7 +4597,7 @@ wl_cfg80211_af_searching_channel(struct wl_priv *wl, struct net_device *dev) wl->afx_hdl->is_listen = TRUE; schedule_work(&wl->afx_hdl->work); wait_for_completion_timeout(&wl->act_frm_scan, - msecs_to_jiffies(MAX_WAIT_TIME)); + msecs_to_jiffies(WL_AF_SEARCH_TIME_MAX)); } if ((wl->afx_hdl->peer_chan != WL_INVALID) || !(wl_get_drv_status(wl, FINDING_COMMON_CHANNEL, dev))) @@ -4233,6 +4645,7 @@ wl_cfg80211_config_p2p_pub_af_tx(struct wiphy *wiphy, config_af_params->search_channel = false; config_af_params->max_tx_retry = WL_AF_TX_MAX_RETRY; config_af_params->mpc_onoff = -1; + wl->next_af_subtype = P2P_PAF_SUBTYPE_INVALID; switch (act_frm->subtype) { case P2P_PAF_GON_REQ: { @@ -4251,7 +4664,7 @@ wl_cfg80211_config_p2p_pub_af_tx(struct wiphy *wiphy, case P2P_PAF_GON_RSP: { wl->next_af_subtype = act_frm->subtype + 1; /* increase dwell time to wait for CONF frame */ - af_params->dwell_time = WL_MED_DWELL_TIME; + af_params->dwell_time = WL_MED_DWELL_TIME + 100; break; } case P2P_PAF_GON_CONF: { @@ -4317,8 +4730,7 @@ wl_cfg80211_config_p2p_pub_af_tx(struct wiphy *wiphy, } case P2P_PAF_PROVDIS_RSP: { wl->next_af_subtype = P2P_PAF_GON_REQ; - /* increase dwell time to MED level */ - af_params->dwell_time = WL_MED_DWELL_TIME; + af_params->dwell_time = WL_MIN_DWELL_TIME; #ifdef WL_CFG80211_SYNC_GON config_af_params->extra_listen = false; #endif /* WL_CFG80211_SYNC_GON */ @@ -4333,9 +4745,10 @@ wl_cfg80211_config_p2p_pub_af_tx(struct wiphy *wiphy, } + static bool wl_cfg80211_send_action_frame(struct wiphy *wiphy, struct net_device *dev, - struct net_device *ndev, wl_af_params_t *af_params, + bcm_struct_cfgdev *cfgdev, wl_af_params_t *af_params, wl_action_frame_t *action_frame, u16 action_frame_len, s32 bssidx) { struct wl_priv *wl = wiphy_priv(wiphy); @@ -4395,7 +4808,7 @@ wl_cfg80211_send_action_frame(struct wiphy *wiphy, struct net_device *dev, } else { WL_DBG(("Unknown Frame: category 0x%x, action 0x%x, length %d\n", category, action, action_frame_len)); - } + } } else if (category == P2P_AF_CATEGORY) { /* do not configure anything. it will be sent with a default configuration */ } else { @@ -4420,23 +4833,19 @@ wl_cfg80211_send_action_frame(struct wiphy *wiphy, struct net_device *dev, config_af_params.search_channel = false; } -#ifdef WL11U - if (ndev == wl_to_prmry_ndev(wl)) - config_af_params.search_channel = false; -#endif /* WL11U */ - #ifdef VSDB /* if connecting on primary iface, sleep for a while before sending af tx for VSDB */ if (wl_get_drv_status(wl, CONNECTING, wl_to_prmry_ndev(wl))) { - msleep(50); + OSL_SLEEP(50); } #endif /* if scan is ongoing, abort current scan. */ if (wl_get_drv_status_all(wl, SCANNING)) { - wl_notify_escan_complete(wl, ndev, true, true); + wl_notify_escan_complete(wl, wl->escan_info.ndev, true, true); } + /* set status and destination address before sending af */ if (wl->next_af_subtype != P2P_PAF_SUBTYPE_INVALID) { /* set this status to cancel the remained dwell time in rx process */ @@ -4453,7 +4862,10 @@ wl_cfg80211_send_action_frame(struct wiphy *wiphy, struct net_device *dev, /* search peer's channel */ if (config_af_params.search_channel) { /* initialize afx_hdl */ - wl->afx_hdl->bssidx = wl_cfgp2p_find_idx(wl, dev); + if (wl_cfgp2p_find_idx(wl, dev, &wl->afx_hdl->bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + goto exit; + } wl->afx_hdl->dev = dev; wl->afx_hdl->retry = 0; wl->afx_hdl->peer_chan = WL_INVALID; @@ -4498,7 +4910,8 @@ wl_cfg80211_send_action_frame(struct wiphy *wiphy, struct net_device *dev, OFF_CHAN_TIME_THRESHOLD_MS) { WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(wl); off_chan_started_jiffies = jiffies; - } + } else + OSL_SLEEP(AF_RETRY_DELAY_TIME); } #endif /* VSDB */ ack = wl_cfgp2p_tx_action_frame(wl, dev, af_params, bssidx) ? @@ -4555,20 +4968,28 @@ exit: return ack; } -#define MAX_NUM_OF_ASSOCIATED_DEV 64 +#define MAX_NUM_OF_ASSOCIATED_DEV 64 +#if defined(WL_CFG80211_P2P_DEV_IF) +static s32 +wl_cfg80211_mgmt_tx(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, + struct ieee80211_channel *channel, bool offchan, + unsigned int wait, const u8* buf, size_t len, bool no_cck, + bool dont_wait_for_ack, u64 *cookie) +#else static s32 -wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, +wl_cfg80211_mgmt_tx(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, struct ieee80211_channel *channel, bool offchan, enum nl80211_channel_type channel_type, bool channel_type_valid, unsigned int wait, const u8* buf, size_t len, -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) || 0 bool no_cck, #endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) || 0 bool dont_wait_for_ack, #endif u64 *cookie) +#endif /* WL_CFG80211_P2P_DEV_IF */ { wl_action_frame_t *action_frame; wl_af_params_t *af_params; @@ -4584,19 +5005,12 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, WL_DBG(("Enter \n")); - if (ndev == wl->p2p_net) { - dev = wl_to_prmry_ndev(wl); - } else { - /* If TX req is for any valid ifidx. Use as is */ - dev = ndev; - } - - /* find bssidx based on ndev */ - bssidx = wl_cfgp2p_find_idx(wl, dev); - if (bssidx == -1) { + dev = cfgdev_to_wlc_ndev(cfgdev, wl); - WL_ERR(("Can not find the bssidx for dev( %p )\n", dev)); - return -ENODEV; + /* find bssidx based on dev */ + if (wl_cfgp2p_find_idx(wl, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; } if (p2p_is_on(wl)) { /* Suspend P2P discovery search-listen to prevent it from changing the @@ -4619,9 +5033,9 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, s32 ie_len = len - ie_offset; if (dev == wl_to_prmry_ndev(wl)) bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE); - wl_cfgp2p_set_management_ie(wl, dev, bssidx, + wl_cfgp2p_set_management_ie(wl, dev, bssidx, VNDR_IE_PRBRSP_FLAG, (u8 *)(buf + ie_offset), ie_len); - cfg80211_mgmt_tx_status(ndev, *cookie, buf, len, true, GFP_KERNEL); + cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, true, GFP_KERNEL); goto exit; } else if (ieee80211_is_disassoc(mgmt->frame_control) || ieee80211_is_deauth(mgmt->frame_control)) { @@ -4632,7 +5046,7 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, if (!bcmp((const uint8 *)BSSID_BROADCAST, (const struct ether_addr *)mgmt->da, ETHER_ADDR_LEN)) { assoc_maclist->count = MAX_NUM_OF_ASSOCIATED_DEV; - err = wldev_ioctl(ndev, WLC_GET_ASSOCLIST, + err = wldev_ioctl(dev, WLC_GET_ASSOCLIST, assoc_maclist, sizeof(mac_buf), false); if (err < 0) WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err)); @@ -4645,13 +5059,14 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, sizeof(scb_val_t), true); if (err < 0) WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON error %d\n", err)); - WL_DBG(("Disconnect STA : %s scb_val.val %d\n", + WL_ERR(("Disconnect STA : %s scb_val.val %d\n", bcm_ether_ntoa((const struct ether_addr *)mgmt->da, eabuf), scb_val.val)); - if (num_associated) { + + if (num_associated > 0 && ETHER_ISBCAST(mgmt->da)) wl_delay(400); - } - cfg80211_mgmt_tx_status(ndev, *cookie, buf, len, true, GFP_KERNEL); + + cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, true, GFP_KERNEL); goto exit; } else if (ieee80211_is_action(mgmt->frame_control)) { @@ -4712,10 +5127,9 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN], action_frame->len); - ack = wl_cfg80211_send_action_frame(wiphy, dev, ndev, af_params, + ack = wl_cfg80211_send_action_frame(wiphy, dev, cfgdev, af_params, action_frame, action_frame->len, bssidx); - - cfg80211_mgmt_tx_status(ndev, *cookie, buf, len, ack, GFP_KERNEL); + cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, ack, GFP_KERNEL); kfree(af_params); exit: @@ -4724,7 +5138,7 @@ exit: static void -wl_cfg80211_mgmt_frame_register(struct wiphy *wiphy, struct net_device *dev, +wl_cfg80211_mgmt_frame_register(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, u16 frame_type, bool reg) { @@ -4781,9 +5195,7 @@ wl_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev, } param = {0, 0}; struct wl_priv *wl = wiphy_priv(wiphy); - if (wl->p2p_net == dev) { - dev = wl_to_prmry_ndev(wl); - } + dev = ndev_to_wlc_ndev(dev, wl); _chan = ieee80211_frequency_to_channel(chan->center_freq); WL_ERR(("netdev_ifidx(%d), chan_type(%d) target channel(%d) \n", dev->ifindex, channel_type, _chan)); @@ -5225,7 +5637,7 @@ wl_cfg80211_bcn_validate_sec( } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || 0 static s32 wl_cfg80211_bcn_set_params( struct cfg80211_ap_settings *info, struct net_device *dev, @@ -5277,7 +5689,7 @@ static s32 wl_cfg80211_bcn_set_params( return err; } -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) */ +#endif static s32 wl_cfg80211_parse_ies(u8 *ptr, u32 len, struct parsed_ies *ies) @@ -5323,6 +5735,9 @@ wl_cfg80211_bcn_bringup_ap( s32 infra = 1; s32 join_params_size = 0; s32 ap = 1; +#ifdef DISABLE_11H_SOFTAP + s32 spect = 0; +#endif /* DISABLE_11H_SOFTAP */ s32 err = BCME_OK; WL_DBG(("Enter dev_role: %d\n", dev_role)); @@ -5347,9 +5762,10 @@ wl_cfg80211_bcn_bringup_ap( WL_ERR(("GO SSID setting error %d\n", err)); goto exit; } + /* Do abort scan before creating GO */ - if (wl->escan_info.ndev) - wl_notify_escan_complete(wl, wl->escan_info.ndev, true, true); + wl_cfg80211_scan_abort(wl); + if ((err = wl_cfgp2p_bss(wl, dev, bssidx, 1)) < 0) { WL_ERR(("GO Bring up error %d\n", err)); goto exit; @@ -5373,6 +5789,14 @@ wl_cfg80211_bcn_bringup_ap( WL_ERR(("setting AP mode failed %d \n", err)); goto exit; } +#ifdef DISABLE_11H_SOFTAP + err = wldev_ioctl(dev, WLC_SET_SPECT_MANAGMENT, + &spect, sizeof(s32), true); + if (err < 0) { + WL_ERR(("SET SPECT_MANAGMENT error %d\n", err)); + goto exit; + } +#endif /* DISABLE_11H_SOFTAP */ err = wldev_ioctl(dev, WLC_UP, &ap, sizeof(s32), true); if (unlikely(err)) { @@ -5401,7 +5825,7 @@ exit: return err; } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || 0 s32 wl_cfg80211_parse_ap_ies( struct net_device *dev, @@ -5411,13 +5835,10 @@ wl_cfg80211_parse_ap_ies( struct parsed_ies prb_ies; struct wl_priv *wl = wlcfg_drv_priv; dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); - u8 *vndr; - u32 vndr_ie_len; + u8 *vndr = NULL; + u32 vndr_ie_len = 0; s32 err = BCME_OK; - memset(ies, 0, sizeof(struct parsed_ies)); - memset(&prb_ies, 0, sizeof(struct parsed_ies)); - /* Parse Beacon IEs */ if (wl_cfg80211_parse_ies((u8 *)info->tail, info->tail_len, ies) < 0) { @@ -5426,18 +5847,18 @@ wl_cfg80211_parse_ap_ies( goto fail; } - if ((dhd->op_mode & DHD_FLAG_HOSTAP_MODE) && - (info->probe_resp_len > 0)) { + vndr = (u8 *)info->proberesp_ies; + vndr_ie_len = info->proberesp_ies_len; + + if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) { /* SoftAP mode */ struct ieee80211_mgmt *mgmt; mgmt = (struct ieee80211_mgmt *)info->probe_resp; - vndr = (u8 *)&mgmt->u.probe_resp.variable; - vndr_ie_len = info->probe_resp_len - - offsetof(struct ieee80211_mgmt, u.probe_resp.variable); - } else { - /* Other mode */ - vndr = (u8 *)info->proberesp_ies; - vndr_ie_len = info->proberesp_ies_len; + if (mgmt != NULL) { + vndr = (u8 *)&mgmt->u.probe_resp.variable; + vndr_ie_len = info->probe_resp_len - + offsetof(struct ieee80211_mgmt, u.probe_resp.variable); + } } /* Parse Probe Response IEs */ @@ -5459,8 +5880,8 @@ wl_cfg80211_set_ies( { struct wl_priv *wl = wlcfg_drv_priv; dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); - u8 *vndr; - u32 vndr_ie_len; + u8 *vndr = NULL; + u32 vndr_ie_len = 0; s32 err = BCME_OK; /* Set Beacon IEs to FW */ @@ -5472,18 +5893,18 @@ wl_cfg80211_set_ies( WL_DBG(("Applied Vndr IEs for Beacon \n")); } - if ((dhd->op_mode & DHD_FLAG_HOSTAP_MODE) && - (info->probe_resp_len > 0)) { + vndr = (u8 *)info->proberesp_ies; + vndr_ie_len = info->proberesp_ies_len; + + if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) { /* SoftAP mode */ struct ieee80211_mgmt *mgmt; mgmt = (struct ieee80211_mgmt *)info->probe_resp; - vndr = (u8 *)&mgmt->u.probe_resp.variable; - vndr_ie_len = info->probe_resp_len - - offsetof(struct ieee80211_mgmt, u.probe_resp.variable); - } else { - /* Other mode */ - vndr = (u8 *)info->proberesp_ies; - vndr_ie_len = info->proberesp_ies_len; + if (mgmt != NULL) { + vndr = (u8 *)&mgmt->u.probe_resp.variable; + vndr_ie_len = info->probe_resp_len - + offsetof(struct ieee80211_mgmt, u.probe_resp.variable); + } } /* Set Probe Response IEs to FW */ @@ -5496,7 +5917,7 @@ wl_cfg80211_set_ies( return err; } -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) */ +#endif static s32 wl_cfg80211_hostapd_sec( struct net_device *dev, @@ -5578,10 +5999,11 @@ wl_cfg80211_del_station( struct wl_priv *wl = wiphy_priv(wiphy); scb_val_t scb_val; s8 eabuf[ETHER_ADDR_STR_LEN]; + int err; char mac_buf[MAX_NUM_OF_ASSOCIATED_DEV * sizeof(struct ether_addr) + sizeof(uint)] = {0}; struct maclist *assoc_maclist = (struct maclist *)mac_buf; - int num_associated = 0, err; + int num_associated = 0; WL_DBG(("Entry\n")); if (mac_addr == NULL) { @@ -5589,11 +6011,7 @@ wl_cfg80211_del_station( return 0; } - if (ndev == wl->p2p_net) { - dev = wl_to_prmry_ndev(wl); - } else { - dev = ndev; - } + dev = ndev_to_wlc_ndev(ndev, wl); if (p2p_is_on(wl)) { /* Suspend P2P discovery search-listen to prevent it from changing the @@ -5619,47 +6037,18 @@ wl_cfg80211_del_station( sizeof(scb_val_t), true); if (err < 0) WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON err %d\n", err)); - WL_DBG(("Disconnect STA : %s scb_val.val %d\n", + WL_ERR(("Disconnect STA : %s scb_val.val %d\n", bcm_ether_ntoa((const struct ether_addr *)mac_addr, eabuf), scb_val.val)); - if (num_associated) - wl_delay(400); - return 0; -} -static s32 -wl_cfg80211_change_station( - struct wiphy *wiphy, - struct net_device *dev, - u8 *mac, - struct station_parameters *params) -{ - struct wl_priv *wl = wiphy_priv(wiphy); - int err; - - /* Processing only primary interface */ - if (dev == wl->p2p_net) - return -ENOTSUPP; - - /* Processing only authorize/de-authorize flag for now */ - if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED))) - return -ENOTSUPP; - - if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))) { - err = wldev_ioctl(dev, WLC_SCB_DEAUTHORIZE, mac, ETH_ALEN, true); - if (err) - WL_ERR(("WLC_SCB_DEAUTHORIZE error (%d)\n", err)); - return err; - } + if (num_associated > 0 && ETHER_ISBCAST(mac_addr)) + wl_delay(400); - err = wldev_ioctl(dev, WLC_SCB_AUTHORIZE, mac, ETH_ALEN, true); - if (err) - WL_ERR(("WLC_SCB_AUTHORIZE error (%d)\n", err)); - return err; + return 0; } #endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VER >= KERNEL_VERSION(3, 2, 0)) */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || 0 static s32 wl_cfg80211_start_ap( struct wiphy *wiphy, @@ -5676,14 +6065,19 @@ wl_cfg80211_start_ap( if (dev == wl_to_prmry_ndev(wl)) { WL_DBG(("Start AP req on primary iface: Softap\n")); dev_role = NL80211_IFTYPE_AP; - } else if (dev == wl->p2p_net) { + } +#if defined(WL_ENABLE_P2P_IF) + else if (dev == wl->p2p_net) { /* Group Add request on p2p0 */ WL_DBG(("Start AP req on P2P iface: GO\n")); dev = wl_to_prmry_ndev(wl); dev_role = NL80211_IFTYPE_P2P_GO; } - - bssidx = wl_cfgp2p_find_idx(wl, dev); +#endif /* WL_ENABLE_P2P_IF */ + if (wl_cfgp2p_find_idx(wl, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } if (p2p_is_on(wl) && (bssidx == wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_CONNECTION))) { @@ -5691,6 +6085,18 @@ wl_cfg80211_start_ap( WL_DBG(("Start AP req on P2P connection iface\n")); } + if (!check_dev_role_integrity(wl, dev_role)) + goto fail; + +#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) && !0) + if ((err = wl_cfg80211_set_channel(wiphy, dev, + dev->ieee80211_ptr->preset_chandef.chan, + NL80211_CHAN_HT20) < 0)) { + WL_ERR(("Set channel failed \n")); + goto fail; + } +#endif + if ((err = wl_cfg80211_bcn_set_params(info, dev, dev_role, bssidx)) < 0) { WL_ERR(("Beacon params set failed \n")); @@ -5698,7 +6104,7 @@ wl_cfg80211_start_ap( } /* Parse IEs */ - if ((err = wl_cfg80211_parse_ap_ies(dev, &info->beacon, &ies) < 0)) { + if ((err = wl_cfg80211_parse_ap_ies(dev, &info->beacon, &ies)) < 0) { WL_ERR(("Set IEs failed \n")); goto fail; } @@ -5719,7 +6125,7 @@ wl_cfg80211_start_ap( WL_DBG(("** AP/GO Created **\n")); /* Set IEs to FW */ - if ((err = wl_cfg80211_set_ies(dev, &info->beacon, bssidx) < 0)) + if ((err = wl_cfg80211_set_ies(dev, &info->beacon, bssidx)) < 0) WL_ERR(("Set IEs failed \n")); fail: @@ -5746,30 +6152,39 @@ wl_cfg80211_stop_ap( WL_DBG(("Enter \n")); if (dev == wl_to_prmry_ndev(wl)) { dev_role = NL80211_IFTYPE_AP; - } else if (dev == wl->p2p_net) { + } +#if defined(WL_ENABLE_P2P_IF) + else if (dev == wl->p2p_net) { /* Group Add request on p2p0 */ dev = wl_to_prmry_ndev(wl); dev_role = NL80211_IFTYPE_P2P_GO; } - bssidx = wl_cfgp2p_find_idx(wl, dev); +#endif /* WL_ENABLE_P2P_IF */ + if (wl_cfgp2p_find_idx(wl, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } if (p2p_is_on(wl) && (bssidx == wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_CONNECTION))) { dev_role = NL80211_IFTYPE_P2P_GO; } + if (!check_dev_role_integrity(wl, dev_role)) + goto exit; + if (dev_role == NL80211_IFTYPE_AP) { /* SoftAp on primary Interface. * Shut down AP and turn on MPC */ - err = wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), true); - if (err < 0) { - WL_ERR(("SET INFRA error %d\n", err)); + if ((err = wldev_ioctl(dev, WLC_SET_AP, &ap, sizeof(s32), true)) < 0) { + WL_ERR(("setting AP mode failed %d \n", err)); err = -ENOTSUPP; goto exit; } - if ((err = wldev_ioctl(dev, WLC_SET_AP, &ap, sizeof(s32), true)) < 0) { - WL_ERR(("setting AP mode failed %d \n", err)); + err = wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), true); + if (err < 0) { + WL_ERR(("SET INFRA error %d\n", err)); err = -ENOTSUPP; goto exit; } @@ -5784,6 +6199,13 @@ wl_cfg80211_stop_ap( wl_clr_drv_status(wl, AP_CREATED, dev); /* Turn on the MPC */ wldev_iovar_setint(dev, "mpc", 1); + if (wl->ap_info) { + kfree(wl->ap_info->wpa_ie); + kfree(wl->ap_info->rsn_ie); + kfree(wl->ap_info->wps_ie); + kfree(wl->ap_info); + wl->ap_info = NULL; + } } else { WL_DBG(("Stopping P2P GO \n")); } @@ -5808,27 +6230,35 @@ wl_cfg80211_change_beacon( if (dev == wl_to_prmry_ndev(wl)) { dev_role = NL80211_IFTYPE_AP; - } else if (dev == wl->p2p_net) { + } +#if defined(WL_ENABLE_P2P_IF) + else if (dev == wl->p2p_net) { /* Group Add request on p2p0 */ dev = wl_to_prmry_ndev(wl); dev_role = NL80211_IFTYPE_P2P_GO; } - - bssidx = wl_cfgp2p_find_idx(wl, dev); +#endif /* WL_ENABLE_P2P_IF */ + if (wl_cfgp2p_find_idx(wl, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } if (p2p_is_on(wl) && (bssidx == wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_CONNECTION))) { dev_role = NL80211_IFTYPE_P2P_GO; } + if (!check_dev_role_integrity(wl, dev_role)) + goto fail; + /* Parse IEs */ - if ((err = wl_cfg80211_parse_ap_ies(dev, info, &ies) < 0)) { + if ((err = wl_cfg80211_parse_ap_ies(dev, info, &ies)) < 0) { WL_ERR(("Parse IEs failed \n")); goto fail; } /* Set IEs to FW */ - if ((err = wl_cfg80211_set_ies(dev, info, bssidx) < 0)) { + if ((err = wl_cfg80211_set_ies(dev, info, bssidx)) < 0) { WL_ERR(("Set IEs failed \n")); goto fail; } @@ -5862,19 +6292,27 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev, if (dev == wl_to_prmry_ndev(wl)) { dev_role = NL80211_IFTYPE_AP; - } else if (dev == wl->p2p_net) { + } +#if defined(WL_ENABLE_P2P_IF) + else if (dev == wl->p2p_net) { /* Group Add request on p2p0 */ dev = wl_to_prmry_ndev(wl); dev_role = NL80211_IFTYPE_P2P_GO; } - - bssidx = wl_cfgp2p_find_idx(wl, dev); +#endif /* WL_ENABLE_P2P_IF */ + if (wl_cfgp2p_find_idx(wl, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } if (p2p_is_on(wl) && (bssidx == wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_CONNECTION))) { dev_role = NL80211_IFTYPE_P2P_GO; } + if (!check_dev_role_integrity(wl, dev_role)) + goto fail; + ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN; /* find the SSID */ if ((ssid_ie = bcm_parse_tlvs((u8 *)&info->head[ie_offset], @@ -5963,7 +6401,7 @@ fail: return err; } -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0) */ +#endif #ifdef WL_SCHED_SCAN #define PNO_TIME 30 @@ -6020,17 +6458,11 @@ int wl_cfg80211_sched_scan_start(struct wiphy *wiphy, } if (ssid_count) { - if ((ret = dhd_dev_pno_set(dev, ssids_local, request->n_match_sets, - pno_time, pno_repeat, pno_freq_expo_max)) < 0) { + if ((ret = dhd_dev_pno_set_for_ssid(dev, ssids_local, request->n_match_sets, + pno_time, pno_repeat, pno_freq_expo_max, NULL, 0)) < 0) { WL_ERR(("PNO setup failed!! ret=%d \n", ret)); return -EINVAL; } - - /* Enable the PNO */ - if (dhd_dev_pno_enable(dev, 1) < 0) { - WL_ERR(("PNO enable failed!! ret=%d \n", ret)); - return -EINVAL; - } wl->sched_scan_req = request; } else { return -EINVAL; @@ -6046,11 +6478,8 @@ int wl_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev) WL_DBG(("Enter \n")); WL_PNO((">>> SCHED SCAN STOP\n")); - if (dhd_dev_pno_enable(dev, 0) < 0) - WL_ERR(("PNO disable failed")); - - if (dhd_dev_pno_reset(dev) < 0) - WL_ERR(("PNO reset failed")); + if (dhd_dev_pno_stop_for_ssid(dev) < 0) + WL_ERR(("PNO Stop for SSID failed")); if (wl->scan_request && wl->sched_scan_running) { WL_PNO((">>> Sched scan running. Aborting it..\n")); @@ -6068,6 +6497,10 @@ static struct cfg80211_ops wl_cfg80211_ops = { .add_virtual_intf = wl_cfg80211_add_virtual_iface, .del_virtual_intf = wl_cfg80211_del_virtual_iface, .change_virtual_intf = wl_cfg80211_change_virtual_iface, +#if defined(WL_CFG80211_P2P_DEV_IF) + .start_p2p_device = wl_cfgp2p_start_p2p_device, + .stop_p2p_device = wl_cfgp2p_stop_p2p_device, +#endif /* WL_CFG80211_P2P_DEV_IF */ .scan = wl_cfg80211_scan, .set_wiphy_params = wl_cfg80211_set_wiphy_params, .join_ibss = wl_cfg80211_join_ibss, @@ -6093,15 +6526,17 @@ static struct cfg80211_ops wl_cfg80211_ops = { .mgmt_tx = wl_cfg80211_mgmt_tx, .mgmt_frame_register = wl_cfg80211_mgmt_frame_register, .change_bss = wl_cfg80211_change_bss, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) || 0 .set_channel = wl_cfg80211_set_channel, -#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0) +#endif +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) && !0 .set_beacon = wl_cfg80211_add_set_beacon, .add_beacon = wl_cfg80211_add_set_beacon, #else .change_beacon = wl_cfg80211_change_beacon, .start_ap = wl_cfg80211_start_ap, .stop_ap = wl_cfg80211_stop_ap, -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0) */ +#endif #ifdef WL_SCHED_SCAN .sched_scan_start = wl_cfg80211_sched_scan_start, .sched_scan_stop = wl_cfg80211_sched_scan_stop, @@ -6109,9 +6544,11 @@ static struct cfg80211_ops wl_cfg80211_ops = { #if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \ 2, 0)) .del_station = wl_cfg80211_del_station, - .change_station = wl_cfg80211_change_station, .mgmt_tx_cancel_wait = wl_cfg80211_mgmt_tx_cancel_wait, #endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VERSION >= (3,2,0) */ +#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || 0 + .tdls_oper = wl_cfg80211_tdls_oper +#endif }; s32 wl_mode_to_nl80211_iftype(s32 mode) @@ -6132,11 +6569,11 @@ s32 wl_mode_to_nl80211_iftype(s32 mode) return err; } +#ifdef CONFIG_CFG80211_INTERNAL_REGDB /* Kernel Network Support->Wireless->Regulatory rules database options should be enabled and regulatory CRDA regdb table populated in Kernel for proper country reg notification */ -#ifdef CONFIG_CFG80211_INTERNAL_REGDB static int wl_cfg80211_reg_notifier( struct wiphy *wiphy, @@ -6153,9 +6590,7 @@ wl_cfg80211_reg_notifier( WL_DBG(("ccode: %c%c Initiator: %d\n", request->alpha2[0], request->alpha2[1], request->initiator)); - /* We support only REGDOM_SET_BY_USER and by - NL80211_REGDOM_SET_BY_COUNTRY_IE (11d) right now - */ + /* We support only REGDOM_SET_BY_USER as of now */ if ((request->initiator != NL80211_REGDOM_SET_BY_USER) && (request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE)) { WL_ERR(("reg_notifier for intiator:%d not supported : set default\n", @@ -6178,9 +6613,14 @@ wl_cfg80211_reg_notifier( } #endif /* CONFIG_CFG80211_INTERNAL_REGDB */ -static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev) +static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev, void *data) { s32 err = 0; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \ + (defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF)) + dhd_pub_t *dhd = (dhd_pub_t *)data; +#endif /* LINUX_VER >= 3.0 && (WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF) */ + wdev->wiphy = wiphy_new(&wl_cfg80211_ops, sizeof(struct wl_priv)); if (unlikely(!wdev->wiphy)) { @@ -6201,13 +6641,36 @@ static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev #endif /* WL_SCHED_SCAN */ wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) -#if !(defined(WLP2P) && defined(WL_ENABLE_P2P_IF)) + | BIT(NL80211_IFTYPE_ADHOC) +#if !defined(WL_ENABLE_P2P_IF) | BIT(NL80211_IFTYPE_MONITOR) -#endif +#endif /* !WL_ENABLE_P2P_IF */ +#if defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF) + | BIT(NL80211_IFTYPE_P2P_CLIENT) + | BIT(NL80211_IFTYPE_P2P_GO) +#endif /* WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF */ +#if defined(WL_CFG80211_P2P_DEV_IF) + | BIT(NL80211_IFTYPE_P2P_DEVICE) +#endif /* WL_CFG80211_P2P_DEV_IF */ | BIT(NL80211_IFTYPE_AP); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \ + (defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF)) + if (dhd && dhd->op_mode == DHD_FLAG_HOSTAP_MODE) { + WL_DBG(("Setting interface combinations for SoftAP mode\n")); + wdev->wiphy->iface_combinations = softap_iface_combinations; + wdev->wiphy->n_iface_combinations = + ARRAY_SIZE(softap_iface_combinations); + } else { + WL_DBG(("Setting interface combinations for STA+P2P mode\n")); + wdev->wiphy->iface_combinations = sta_p2p_iface_combinations; + wdev->wiphy->n_iface_combinations = + ARRAY_SIZE(sta_p2p_iface_combinations); + } +#endif /* LINUX_VER >= 3.0 && (WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF) */ + wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; - wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a; + wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; wdev->wiphy->cipher_suites = __wl_cipher_suites; wdev->wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites); @@ -6220,7 +6683,7 @@ static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev #endif /* !WL_POWERSAVE_DISABLED */ wdev->wiphy->flags |= WIPHY_FLAG_NETNS_OK | WIPHY_FLAG_4ADDR_AP | -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39) +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && !0 WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS | #endif WIPHY_FLAG_4ADDR_STATION; @@ -6236,7 +6699,7 @@ static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) /* wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM; */ #endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) || 0 wdev->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | WIPHY_FLAG_OFFCHAN_TX; #endif @@ -6246,25 +6709,25 @@ static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev * to remove the patch from supplicant */ wdev->wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) - /* Supplicant distinguish between the SoftAP mode and other - * modes (e.g. P2P, WPS, HS2.0) when it builds the probe - * response frame from Supplicant MR1 and Kernel 3.4.0 or - * later version. To add Vendor specific IE into the - * probe response frame in case of SoftAP mode, - * AP_PROBE_RESP_OFFLOAD flag is set to wiphy->flags variable. - */ - if (strstr(fw_path, "_apsta") != NULL) { - wdev->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; - wdev->wiphy->probe_resp_offload = 0; - } -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) */ #endif /* WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) */ #ifdef CONFIG_CFG80211_INTERNAL_REGDB wdev->wiphy->reg_notifier = wl_cfg80211_reg_notifier; #endif /* CONFIG_CFG80211_INTERNAL_REGDB */ +#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || 0 + wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS; +#endif + +#if defined(CONFIG_PM) && defined(WL_CFG80211_P2P_DEV_IF) + /* + * From linux-3.10 kernel, wowlan packet filter is mandated to avoid the + * disconnection of connected network before suspend. So a dummy wowlan + * filter is configured for kernels linux-3.8 and above. + */ + wdev->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY; +#endif /* CONFIG_PM && WL_CFG80211_P2P_DEV_IF */ + WL_DBG(("Registering custom regulatory)\n")); wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; wiphy_apply_custom_regulatory(wdev->wiphy, &brcm_regdom); @@ -6274,6 +6737,12 @@ static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev WL_ERR(("Couldn not register wiphy device (%d)\n", err)); wiphy_free(wdev->wiphy); } + +#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && (LINUX_VERSION_CODE <= \ + KERNEL_VERSION(3, 3, 0))) && defined(WL_IFACE_COMB_NUM_CHANNELS) + wdev->wiphy->flags &= ~WIPHY_FLAG_ENFORCE_COMBINATIONS; +#endif /* ((LINUX_VER >= 3.0) && (LINUX_VER <= 3.3)) && WL_IFACE_COMB_NUM_CHANNELS */ + return err; } @@ -6307,14 +6776,14 @@ static s32 wl_inform_bss(struct wl_priv *wl) WL_DBG(("scanned AP count (%d)\n", bss_list->count)); bi = next_bss(bss_list, bi); for_each_bss(bss_list, bi, i) { - err = wl_inform_single_bss(wl, bi, 0); + err = wl_inform_single_bss(wl, bi); if (unlikely(err)) break; } return err; } -static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi, u8 is_roam_done) +static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi) { struct wiphy *wiphy = wl_to_wiphy(wl); struct ieee80211_mgmt *mgmt; @@ -6329,7 +6798,6 @@ static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi, u8 i u32 freq; s32 err = 0; gfp_t aflags; - u8 *ie_offset = NULL; if (unlikely(dtoh32(bi->length) > WL_BSS_INFO_MAX)) { WL_DBG(("Beacon is larger than buffer. Discarding\n")); @@ -6369,42 +6837,13 @@ static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi, u8 i beacon_proberesp->beacon_int = cpu_to_le16(bi->beacon_period); beacon_proberesp->capab_info = cpu_to_le16(bi->capability); wl_rst_ie(wl); - - ie_offset = ((u8 *) bi) + bi->ie_offset; - - if (is_roam_done && ((int)(*(ie_offset)) == WLAN_EID_SSID && - ((int)(*(ie_offset+1)) == 0 || (int)(*(ie_offset+2)) == 0))) { - u8 *ie_new_offset = NULL; - uint8 ie_new_length; - - WL_ERR(("WAR trace: Changing the SSID Info, from beacon %d\n", - bi->flags & WL_BSS_FLAGS_FROM_BEACON)); - - ie_new_offset = (u8 *)kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL); - if (ie_new_offset) { - *(ie_new_offset) = WLAN_EID_SSID; - *(ie_new_offset+1) = bi->SSID_len; - memcpy(ie_new_offset+2, bi->SSID, bi->SSID_len); - ie_new_length = bi->ie_length - *(ie_offset+1) + bi->SSID_len; - - /* Copy the remaining IE apart from SSID IE from bi */ - memcpy(ie_new_offset+2 + bi->SSID_len, - ie_offset+2 + *(ie_offset+1), - bi->ie_length - 2 - *(ie_offset+1)); - wl_mrg_ie(wl, ie_new_offset, ie_new_length); - kfree(ie_new_offset); - } else { - wl_mrg_ie(wl, ((u8 *) bi) + bi->ie_offset, bi->ie_length); - } - } else { - wl_mrg_ie(wl, ((u8 *) bi) + bi->ie_offset, bi->ie_length); - } - + wl_update_hidden_ap_ie(bi, ((u8 *) bi) + bi->ie_offset, &bi->ie_length); + wl_mrg_ie(wl, ((u8 *) bi) + bi->ie_offset, bi->ie_length); wl_cp_ie(wl, beacon_proberesp->variable, WL_BSS_INFO_MAX - offsetof(struct wl_cfg80211_bss_info, frame_buf)); notif_bss_info->frame_len = offsetof(struct ieee80211_mgmt, u.beacon.variable) + wl_get_ielen(wl); -#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS) +#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) freq = ieee80211_channel_to_frequency(notif_bss_info->channel); (void)band->band; #else @@ -6429,7 +6868,7 @@ static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi, u8 i signal = notif_bss_info->rssi * 100; if (!mgmt->u.probe_resp.timestamp) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) struct timespec ts; get_monotonic_boottime(&ts); mgmt->u.probe_resp.timestamp = ((u64)ts.tv_sec*1000000) @@ -6451,7 +6890,11 @@ static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi, u8 i return -EINVAL; } +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)) + cfg80211_put_bss(wiphy, cbss); +#else cfg80211_put_bss(cbss); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */ kfree(notif_bss_info); return err; } @@ -6529,7 +6972,8 @@ wl_notify_connect_status_ap(struct wl_priv *wl, struct net_device *ndev, u32 reason = ntoh32(e->reason); u32 len = ntoh32(e->datalen); -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !defined(WL_CFG80211_STA_EVENT) +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !defined(WL_CFG80211_STA_EVENT) \ + && !0 bool isfree = false; u8 *mgmt_frame; u8 bsscfgidx = e->bsscfgidx; @@ -6545,7 +6989,7 @@ wl_notify_connect_status_ap(struct wl_priv *wl, struct net_device *ndev, channel_info_t ci; #else struct station_info sinfo; -#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !WL_CFG80211_STA_EVENT */ +#endif WL_DBG(("event %d status %d reason %d\n", event, ntoh32(e->status), reason)); /* if link down, bsscfg is disabled. */ @@ -6557,7 +7001,8 @@ wl_notify_connect_status_ap(struct wl_priv *wl, struct net_device *ndev, return 0; } -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !defined(WL_CFG80211_STA_EVENT) +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !defined(WL_CFG80211_STA_EVENT) \ + && !0 WL_DBG(("Enter \n")); if (!len && (event == WLC_E_DEAUTH)) { len = 2; /* reason code field */ @@ -6593,12 +7038,18 @@ wl_notify_connect_status_ap(struct wl_priv *wl, struct net_device *ndev, break; case WLC_E_DISASSOC_IND: fc = FC_DISASSOC; + WL_ERR(("event %s(%d) status %d reason %d\n", + bcmevent_names[event].name, event, ntoh32(e->status), reason)); break; case WLC_E_DEAUTH_IND: fc = FC_DISASSOC; + WL_ERR(("event %s(%d) status %d reason %d\n", + bcmevent_names[event].name, event, ntoh32(e->status), reason)); break; case WLC_E_DEAUTH: fc = FC_DISASSOC; + WL_ERR(("event %s(%d) status %d reason %d\n", + bcmevent_names[event].name, event, ntoh32(e->status), reason)); break; default: fc = 0; @@ -6620,7 +7071,7 @@ wl_notify_connect_status_ap(struct wl_priv *wl, struct net_device *ndev, kfree(body); return -EINVAL; } -#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS) +#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) freq = ieee80211_channel_to_frequency(channel); (void)band->band; #else @@ -6634,23 +7085,23 @@ wl_notify_connect_status_ap(struct wl_priv *wl, struct net_device *ndev, isfree = true; if (event == WLC_E_ASSOC_IND && reason == DOT11_SC_SUCCESS) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || 0 cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC); #else cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC); -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) */ +#endif } else if (event == WLC_E_DISASSOC_IND) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || 0 cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC); #else cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC); -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) */ +#endif } else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || 0 cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC); #else cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC); -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) */ +#endif } exit: @@ -6658,8 +7109,7 @@ exit: kfree(mgmt_frame); if (body) kfree(body); - return err; -#else /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0) && !WL_CFG80211_STA_EVENT */ +#else /* LINUX_VERSION < VERSION(3,2,0) && !WL_CFG80211_STA_EVENT && !WL_COMPAT_WIRELESS */ sinfo.filled = 0; if (((event == WLC_E_ASSOC_IND) || (event == WLC_E_REASSOC_IND)) && reason == DOT11_SC_SUCCESS) { @@ -6676,7 +7126,7 @@ exit: } else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) { cfg80211_del_sta(ndev, e->addr.octet, GFP_ATOMIC); } -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0) && !WL_CFG80211_STA_EVENT */ +#endif return err; } @@ -6702,39 +7152,97 @@ wl_get_auth_assoc_status(struct wl_priv *wl, struct net_device *ndev, } static s32 -wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev, +wl_notify_connect_status_ibss(struct wl_priv *wl, struct net_device *ndev, + const wl_event_msg_t *e, void *data) +{ + s32 err = 0; + u32 event = ntoh32(e->event_type); + u16 flags = ntoh16(e->flags); + u32 status = ntoh32(e->status); + bool active; + + if (event == WLC_E_JOIN) { + WL_DBG(("joined in IBSS network\n")); + } + if (event == WLC_E_START) { + WL_DBG(("started IBSS network\n")); + } + if (event == WLC_E_JOIN || event == WLC_E_START || + (event == WLC_E_LINK && (flags == WLC_EVENT_MSG_LINK))) { + if (wl_get_drv_status(wl, CONNECTED, ndev)) { + /* ROAM or Redundant */ + u8 *cur_bssid = wl_read_prof(wl, ndev, WL_PROF_BSSID); + if (memcmp(cur_bssid, &e->addr, ETHER_ADDR_LEN) == 0) { + WL_DBG(("IBSS connected event from same BSSID(" + MACDBG "), ignore it\n", MAC2STRDBG(cur_bssid))); + return err; + } + WL_INFO(("IBSS BSSID is changed from " MACDBG " to " MACDBG "\n", + MAC2STRDBG(cur_bssid), MAC2STRDBG((u8 *)&e->addr))); + wl_get_assoc_ies(wl, ndev); + wl_update_prof(wl, ndev, NULL, (void *)&e->addr, WL_PROF_BSSID); + wl_update_bss_info(wl, ndev); + cfg80211_ibss_joined(ndev, (s8 *)&e->addr, GFP_KERNEL); + } + else { + /* New connection */ + WL_INFO(("IBSS connected to " MACDBG "\n", MAC2STRDBG((u8 *)&e->addr))); + wl_link_up(wl); + wl_get_assoc_ies(wl, ndev); + wl_update_prof(wl, ndev, NULL, (void *)&e->addr, WL_PROF_BSSID); + wl_update_bss_info(wl, ndev); + cfg80211_ibss_joined(ndev, (s8 *)&e->addr, GFP_KERNEL); + wl_set_drv_status(wl, CONNECTED, ndev); + active = true; + wl_update_prof(wl, ndev, NULL, (void *)&active, WL_PROF_ACT); + } + } else if ((event == WLC_E_LINK && !(flags & WLC_EVENT_MSG_LINK)) || + event == WLC_E_DEAUTH_IND || event == WLC_E_DISASSOC_IND) { + wl_clr_drv_status(wl, CONNECTED, ndev); + wl_link_down(wl); + wl_init_prof(wl, ndev); + } + else if (event == WLC_E_SET_SSID && status == WLC_E_STATUS_NO_NETWORKS) { + WL_DBG(("no action - join fail (IBSS mode)\n")); + } + else { + WL_DBG(("no action (IBSS mode)\n")); + } + return err; +} + +static s32 +wl_notify_connect_status(struct wl_priv *wl, bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data) { bool act; + struct net_device *ndev = NULL; s32 err = 0; u32 event = ntoh32(e->event_type); + ndev = cfgdev_to_wlc_ndev(cfgdev, wl); + if (wl_get_mode_by_netdev(wl, ndev) == WL_MODE_AP) { - wl_notify_connect_status_ap(wl, ndev, e, data); - } else { + err = wl_notify_connect_status_ap(wl, ndev, e, data); + } else if (wl_get_mode_by_netdev(wl, ndev) == WL_MODE_IBSS) { + err = wl_notify_connect_status_ibss(wl, ndev, e, data); + } else if (wl_get_mode_by_netdev(wl, ndev) == WL_MODE_BSS) { WL_DBG(("wl_notify_connect_status : event %d status : %d ndev %p\n", ntoh32(e->event_type), ntoh32(e->status), ndev)); if (event == WLC_E_ASSOC || event == WLC_E_AUTH) { wl_get_auth_assoc_status(wl, ndev, e); - return err; + return 0; } if (wl_is_linkup(wl, e, ndev)) { wl_link_up(wl); act = true; - if (wl_is_ibssmode(wl, ndev)) { - printk("cfg80211_ibss_joined\n"); - cfg80211_ibss_joined(ndev, (s8 *)&e->addr, - GFP_KERNEL); - WL_DBG(("joined in IBSS network\n")); - } else { - if (!wl_get_drv_status(wl, DISCONNECTING, ndev)) { + if (!wl_get_drv_status(wl, DISCONNECTING, ndev)) { printk("wl_bss_connect_done succeeded with " MACDBG "\n", MAC2STRDBG((u8*)(&e->addr))); wl_bss_connect_done(wl, ndev, e, data, true); WL_DBG(("joined in BSS network \"%s\"\n", ((struct wlc_ssid *) wl_read_prof(wl, ndev, WL_PROF_SSID))->SSID)); - } } wl_update_prof(wl, ndev, e, &act, WL_PROF_ACT); wl_update_prof(wl, ndev, NULL, (void *)&e->addr, WL_PROF_BSSID); @@ -6788,6 +7296,7 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev, } } else if (wl_get_drv_status(wl, CONNECTING, ndev)) { + printk("link down, during connecting\n"); #ifdef ESCAN_RESULT_PATCH if ((memcmp(connect_req_bssid, broad_bssid, ETHER_ADDR_LEN) == 0) || @@ -6820,19 +7329,27 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev, } else { printk("%s nothing\n", __FUNCTION__); } + } else { + WL_ERR(("Invalid ndev status %d\n", wl_get_mode_by_netdev(wl, ndev))); } return err; } + static s32 -wl_notify_roaming_status(struct wl_priv *wl, struct net_device *ndev, +wl_notify_roaming_status(struct wl_priv *wl, bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data) { bool act; + struct net_device *ndev = NULL; s32 err = 0; u32 event = be32_to_cpu(e->event_type); u32 status = be32_to_cpu(e->status); + WL_DBG(("Enter \n")); + + ndev = cfgdev_to_wlc_ndev(cfgdev, wl); + if (event == WLC_E_ROAM && status == WLC_E_STATUS_SUCCESS) { if (wl_get_drv_status(wl, CONNECTED, ndev)) wl_bss_roaming_done(wl, ndev, e, data); @@ -6947,7 +7464,7 @@ static void wl_ch_to_chanspec(int ch, struct wl_join_params *join_params, } } -static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev, u8 is_roam_done) +static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev) { struct cfg80211_bss *bss; struct wl_bss_info *bi; @@ -6957,16 +7474,12 @@ static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev, u8 is s32 dtim_period; size_t ie_len; u8 *ie; - u8 *ssidie; u8 *curbssid; s32 err = 0; struct wiphy *wiphy; wiphy = wl_to_wiphy(wl); - if (wl_is_ibssmode(wl, ndev)) - return err; - ssid = (struct wlc_ssid *)wl_read_prof(wl, ndev, WL_PROF_SSID); curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID); bss = cfg80211_get_bss(wiphy, NULL, curbssid, @@ -6985,17 +7498,11 @@ static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev, u8 is } bi = (struct wl_bss_info *)(wl->extra_buf + 4); if (memcmp(bi->BSSID.octet, curbssid, ETHER_ADDR_LEN)) { + WL_ERR(("Bssid doesn't match\n")); err = -EIO; goto update_bss_info_out; } - - ie = ((u8 *)bi) + bi->ie_offset; - ie_len = bi->ie_length; - ssidie = (u8 *)cfg80211_find_ie(WLAN_EID_SSID, ie, ie_len); - if (ssidie && ssidie[1] == bi->SSID_len && !ssidie[2] && bi->SSID[0]) - memcpy(ssidie + 2, bi->SSID, bi->SSID_len); - - err = wl_inform_single_bss(wl, bi, is_roam_done); + err = wl_inform_single_bss(wl, bi); if (unlikely(err)) goto update_bss_info_out; @@ -7004,10 +7511,19 @@ static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev, u8 is beacon_interval = cpu_to_le16(bi->beacon_period); } else { WL_DBG(("Found the AP in the list - BSSID %pM\n", bss->bssid)); +#if defined(WL_CFG80211_P2P_DEV_IF) + ie = (u8 *)bss->ies->data; + ie_len = bss->ies->len; +#else ie = bss->information_elements; ie_len = bss->len_information_elements; +#endif /* WL_CFG80211_P2P_DEV_IF */ beacon_interval = bss->beacon_interval; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)) + cfg80211_put_bss(wiphy, bss); +#else cfg80211_put_bss(bss); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */ } tim = bcm_parse_tlvs(ie, ie_len, WLAN_EID_TIM); @@ -7031,6 +7547,9 @@ static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev, u8 is wl_update_prof(wl, ndev, NULL, &dtim_period, WL_PROF_DTIMPERIOD); update_bss_info_out: + if (unlikely(err)) { + WL_ERR(("Failed with error %d\n", err)); + } mutex_unlock(&wl->usr_sync); return err; } @@ -7042,21 +7561,51 @@ wl_bss_roaming_done(struct wl_priv *wl, struct net_device *ndev, struct wl_connect_info *conn_info = wl_to_conn(wl); s32 err = 0; u8 *curbssid; +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || 0 + struct wl_bss_info *bss_info; + struct wiphy *wiphy = wl_to_wiphy(wl); + struct ieee80211_supported_band *band; + struct ieee80211_channel *notify_channel = NULL; + u8 *buf; + u16 channel; + u32 freq; +#endif wl_get_assoc_ies(wl, ndev); wl_update_prof(wl, ndev, NULL, (void *)(e->addr.octet), WL_PROF_BSSID); curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID); - wl_update_bss_info(wl, ndev, 1); + wl_update_bss_info(wl, ndev); wl_update_pmklist(ndev, wl->pmk_list, err); + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || 0 + /* channel info for cfg80211_roamed introduced in 2.6.39-rc1 */ + buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL); + if (!buf) + goto done; + + *(__le32 *)buf = htod32(WL_EXTRA_BUF_MAX); + err = wldev_ioctl(ndev, WLC_GET_BSS_INFO, buf, WL_EXTRA_BUF_MAX, false); + if (err) + goto done; + + bss_info = (struct wl_bss_info *)(buf + 4); + channel = bss_info->ctl_ch ? bss_info->ctl_ch : + CHSPEC_CHANNEL(wl_chspec_driver_to_host(bss_info->chanspec)); + if (channel <= CH_MAX_2G_CHANNEL) + band = wiphy->bands[IEEE80211_BAND_2GHZ]; + else + band = wiphy->bands[IEEE80211_BAND_5GHZ]; + freq = ieee80211_channel_to_frequency(channel, band->band); + notify_channel = ieee80211_get_channel(wiphy, freq); +done: + kfree(buf); +#endif printk("wl_bss_roaming_done succeeded to " MACDBG "\n", MAC2STRDBG((u8*)(&e->addr))); cfg80211_roamed(ndev, - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0) - NULL, /* struct cfg80211_bss *bss */ -#elif LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39) - NULL, +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || 0 + notify_channel, #endif curbssid, conn_info->req_ie, conn_info->req_ie_len, @@ -7101,12 +7650,13 @@ wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev, } #endif /* ESCAN_RESULT_PATCH */ if (wl_get_drv_status(wl, CONNECTING, ndev)) { + wl_cfg80211_scan_abort(wl); wl_clr_drv_status(wl, CONNECTING, ndev); if (completed) { wl_get_assoc_ies(wl, ndev); wl_update_prof(wl, ndev, NULL, (void *)(e->addr.octet), WL_PROF_BSSID); curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID); - wl_update_bss_info(wl, ndev, 0); + wl_update_bss_info(wl, ndev); wl_update_pmklist(ndev, wl->pmk_list, err); wl_set_drv_status(wl, CONNECTED, ndev); if (ndev != wl_to_prmry_ndev(wl)) { @@ -7134,12 +7684,15 @@ wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev, } static s32 -wl_notify_mic_status(struct wl_priv *wl, struct net_device *ndev, +wl_notify_mic_status(struct wl_priv *wl, bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data) { + struct net_device *ndev = NULL; u16 flags = ntoh16(e->flags); enum nl80211_key_type key_type; + ndev = cfgdev_to_wlc_ndev(cfgdev, wl); + mutex_lock(&wl->usr_sync); if (flags & WLC_EVENT_MSG_GROUP) key_type = NL80211_KEYTYPE_GROUP; @@ -7155,11 +7708,15 @@ wl_notify_mic_status(struct wl_priv *wl, struct net_device *ndev, #ifdef PNO_SUPPORT static s32 -wl_notify_pfn_status(struct wl_priv *wl, struct net_device *ndev, +wl_notify_pfn_status(struct wl_priv *wl, bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data) { + struct net_device *ndev = NULL; + WL_ERR((">>> PNO Event\n")); + ndev = cfgdev_to_wlc_ndev(cfgdev, wl); + #ifndef WL_SCHED_SCAN mutex_lock(&wl->usr_sync); /* TODO: Use cfg80211_sched_scan_results(wiphy); */ @@ -7176,11 +7733,12 @@ wl_notify_pfn_status(struct wl_priv *wl, struct net_device *ndev, #endif /* PNO_SUPPORT */ static s32 -wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev, +wl_notify_scan_status(struct wl_priv *wl, bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data) { struct channel_info channel_inform; struct wl_scan_results *bss_list; + struct net_device *ndev = NULL; u32 len = WL_SCAN_BUF_MAX; s32 err = 0; unsigned long flags; @@ -7193,6 +7751,8 @@ wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev, if (wl->iscan_on && wl->iscan_kickstart) return wl_wakeup_iscan(wl_to_iscan(wl)); + ndev = cfgdev_to_wlc_ndev(cfgdev, wl); + mutex_lock(&wl->usr_sync); wl_clr_drv_status(wl, SCANNING, ndev); err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &channel_inform, @@ -7235,6 +7795,7 @@ scan_done_out: mutex_unlock(&wl->usr_sync); return err; } + static s32 wl_frame_get_mgmt(u16 fc, const struct ether_addr *da, const struct ether_addr *sa, const struct ether_addr *bssid, @@ -7280,34 +7841,39 @@ wl_frame_get_mgmt(u16 fc, const struct ether_addr *da, void -wl_stop_wait_next_action_frame(struct wl_priv *wl, struct net_device *ndev) +wl_stop_wait_next_action_frame(struct wl_priv *wl) { - if (wl_get_drv_status_all(wl, SENDING_ACT_FRM) && - (wl_get_p2p_status(wl, ACTION_TX_COMPLETED) || - wl_get_p2p_status(wl, ACTION_TX_NOACK))) { + if (wl_get_drv_status_all(wl, SENDING_ACT_FRM)) { + if (!(wl_get_p2p_status(wl, ACTION_TX_COMPLETED) || + wl_get_p2p_status(wl, ACTION_TX_NOACK))) + wl_set_p2p_status(wl, ACTION_TX_COMPLETED); + WL_DBG(("*** Wake UP ** abort actframe iovar\n")); /* if channel is not zero, "actfame" uses off channel scan. * So abort scan for off channel completion. */ if (wl->af_sent_channel) - /* wl_cfg80211_scan_abort(wl, ndev); */ - wl_notify_escan_complete(wl, - (ndev == wl->p2p_net) ? wl_to_prmry_ndev(wl) : ndev, true, true); + wl_cfg80211_scan_abort(wl); } #ifdef WL_CFG80211_SYNC_GON else if (wl_get_drv_status_all(wl, WAITING_NEXT_ACT_FRM_LISTEN)) { WL_DBG(("*** Wake UP ** abort listen for next af frame\n")); /* So abort scan to cancel listen */ - wl_notify_escan_complete(wl, - (ndev == wl->p2p_net) ? wl_to_prmry_ndev(wl) : ndev, true, true); + wl_cfg80211_scan_abort(wl); } #endif /* WL_CFG80211_SYNC_GON */ } +int wl_cfg80211_get_ioctl_version(void) +{ + return ioctl_version; +} + static s32 -wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev, +wl_notify_rx_mgmt_frame(struct wl_priv *wl, bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data) + { struct ieee80211_supported_band *band; struct wiphy *wiphy = wl_to_wiphy(wl); @@ -7316,7 +7882,7 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev, bool isfree = false; s32 err = 0; s32 freq; - struct net_device *dev = NULL; + struct net_device *ndev = NULL; wifi_p2p_pub_act_frame_t *act_frm = NULL; wifi_p2p_action_frame_t *p2p_act_frm = NULL; wifi_p2psd_gas_pub_act_frame_t *sd_act_frm = NULL; @@ -7330,11 +7896,7 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev, memset(&bssid, 0, ETHER_ADDR_LEN); - if (wl->p2p_net == ndev) { - dev = wl_to_prmry_ndev(wl); - } else { - dev = ndev; - } + ndev = cfgdev_to_wlc_ndev(cfgdev, wl); if (channel <= CH_MAX_2G_CHANNEL) band = wiphy->bands[IEEE80211_BAND_2GHZ]; @@ -7344,17 +7906,17 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev, WL_ERR(("No valid band")); return -EINVAL; } -#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS) +#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) freq = ieee80211_channel_to_frequency(channel); (void)band->band; #else freq = ieee80211_channel_to_frequency(channel, band->band); #endif if (event == WLC_E_ACTION_FRAME_RX) { - wldev_iovar_getbuf_bsscfg(dev, "cur_etheraddr", + wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr", NULL, 0, wl->ioctl_buf, WLC_IOCTL_SMLEN, bsscfgidx, &wl->ioctl_buf_sync); - err = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false); + err = wldev_ioctl(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false); if (err < 0) WL_ERR(("WLC_GET_BSSID error %d\n", err)); memcpy(da.octet, wl->ioctl_buf, ETHER_ADDR_LEN); @@ -7378,13 +7940,6 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev, (void) p2p_act_frm; } else if (wl_cfgp2p_is_gas_action(&mgmt_frame[DOT11_MGMT_HDR_LEN], mgmt_frame_len - DOT11_MGMT_HDR_LEN)) { -#ifdef WL_SDO - if (wl_get_p2p_status(wl, DISC_IN_PROGRESS)) { - WL_ERR(("SD offload is in progress. Don't report the" - "frame via rx_mgmt path\n")); - goto exit; - } -#endif sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *) (&mgmt_frame[DOT11_MGMT_HDR_LEN]); @@ -7392,22 +7947,37 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev, if (wl->next_af_subtype == sd_act_frm->action) { WL_DBG(("We got a right next frame of SD!(%d)\n", sd_act_frm->action)); - wl_clr_drv_status(wl, WAITING_NEXT_ACT_FRM, - (ndev == wl->p2p_net) ? - wl_to_prmry_ndev(wl) : ndev); + wl_clr_drv_status(wl, WAITING_NEXT_ACT_FRM, ndev); /* Stop waiting for next AF. */ - wl_stop_wait_next_action_frame(wl, ndev); + wl_stop_wait_next_action_frame(wl); } } (void) sd_act_frm; } else { /* - * if we got normal action frame and ndev is p2p0, - * we have to change ndev from p2p0 to wlan0 + * if we got normal action frame and ndev is p2p0, + * we have to change ndev from p2p0 to wlan0 */ - if (wl->p2p_net == ndev) - ndev = wl_to_prmry_ndev(wl); +#if defined(WL_ENABLE_P2P_IF) + if (wl->p2p_net == cfgdev) + cfgdev = wl_to_prmry_ndev(wl); +#endif /* WL_ENABLE_P2P_IF */ + + if (wl->next_af_subtype != P2P_PAF_SUBTYPE_INVALID) { + u8 action = 0; + if (wl_get_public_action(&mgmt_frame[DOT11_MGMT_HDR_LEN], + mgmt_frame_len - DOT11_MGMT_HDR_LEN, &action) != BCME_OK) { + WL_DBG(("Recived action is not public action frame\n")); + } else if (wl->next_af_subtype == action) { + WL_DBG(("Recived action is the waiting action(%d)\n", + action)); + wl_clr_drv_status(wl, WAITING_NEXT_ACT_FRM, ndev); + + /* Stop waiting for next AF. */ + wl_stop_wait_next_action_frame(wl); + } + } } if (act_frm) { @@ -7416,12 +7986,14 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev, if (wl->next_af_subtype == act_frm->subtype) { WL_DBG(("We got a right next frame!(%d)\n", act_frm->subtype)); - wl_clr_drv_status(wl, WAITING_NEXT_ACT_FRM, - (ndev == wl->p2p_net) ? - wl_to_prmry_ndev(wl) : ndev); + wl_clr_drv_status(wl, WAITING_NEXT_ACT_FRM, ndev); + + if (wl->next_af_subtype == P2P_PAF_GON_CONF) { + OSL_SLEEP(20); + } /* Stop waiting for next AF. */ - wl_stop_wait_next_action_frame(wl, ndev); + wl_stop_wait_next_action_frame(wl); } } } @@ -7433,7 +8005,7 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev, */ if (act_frm && ((act_frm->subtype == P2P_PAF_GON_CONF) || (act_frm->subtype == P2P_PAF_PROVDIS_RSP))) { - wldev_iovar_setint(dev, "mpc", 1); + wldev_iovar_setint(ndev, "mpc", 1); } if (act_frm && (act_frm->subtype == P2P_PAF_GON_CONF)) { WL_DBG(("P2P: GO_NEG_PHASE status cleared \n")); @@ -7464,11 +8036,11 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev, } } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) - cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, mgmt_frame_len, GFP_ATOMIC); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || 0 + cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, mgmt_frame_len, GFP_ATOMIC); #else - cfg80211_rx_mgmt(ndev, freq, mgmt_frame, mgmt_frame_len, GFP_ATOMIC); -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) */ + cfg80211_rx_mgmt(cfgdev, freq, mgmt_frame, mgmt_frame_len, GFP_ATOMIC); +#endif WL_DBG(("mgmt_frame_len (%d) , e->datalen (%d), channel (%d), freq (%d)\n", mgmt_frame_len, ntoh32(e->datalen), channel, freq)); @@ -7488,14 +8060,15 @@ wl_notify_sched_scan_results(struct wl_priv *wl, struct net_device *ndev, const wl_event_msg_t *e, void *data) { wl_pfn_net_info_t *netinfo, *pnetinfo; - struct cfg80211_scan_request request; struct wiphy *wiphy = wl_to_wiphy(wl); int err = 0; + struct cfg80211_scan_request *request = NULL; struct cfg80211_ssid ssid[MAX_PFN_LIST_COUNT]; struct ieee80211_channel *channel = NULL; int channel_req = 0; int band = 0; struct wl_pfn_scanresults *pfn_result = (struct wl_pfn_scanresults *)data; + int n_pfn_results = pfn_result->count; WL_DBG(("Enter\n")); @@ -7503,26 +8076,32 @@ wl_notify_sched_scan_results(struct wl_priv *wl, struct net_device *ndev, WL_PNO(("PFN NET LOST event. Do Nothing \n")); return 0; } - WL_PNO((">>> PFN NET FOUND event. count:%d \n", pfn_result->count)); - if (pfn_result->count > 0) { + WL_PNO((">>> PFN NET FOUND event. count:%d \n", n_pfn_results)); + if (n_pfn_results > 0) { int i; - memset(&request, 0x00, sizeof(struct cfg80211_scan_request)); - memset(&ssid, 0x00, sizeof(ssid)); - request.wiphy = wiphy; - + if (n_pfn_results > MAX_PFN_LIST_COUNT) + n_pfn_results = MAX_PFN_LIST_COUNT; pnetinfo = (wl_pfn_net_info_t *)(data + sizeof(wl_pfn_scanresults_t) - sizeof(wl_pfn_net_info_t)); + + memset(&ssid, 0x00, sizeof(ssid)); + + request = kzalloc(sizeof(*request) + + sizeof(*request->channels) * n_pfn_results, + GFP_KERNEL); channel = (struct ieee80211_channel *)kzalloc( - (sizeof(struct ieee80211_channel) * MAX_PFN_LIST_COUNT), + (sizeof(struct ieee80211_channel) * n_pfn_results), GFP_KERNEL); - if (!channel) { + if (!request || !channel) { WL_ERR(("No memory")); err = -ENOMEM; goto out_err; } - for (i = 0; i < pfn_result->count; i++) { + request->wiphy = wiphy; + + for (i = 0; i < n_pfn_results; i++) { netinfo = &pnetinfo[i]; if (!netinfo) { WL_ERR(("Invalid netinfo ptr. index:%d", i)); @@ -7540,7 +8119,7 @@ wl_notify_sched_scan_results(struct wl_priv *wl, struct net_device *ndev, memcpy(ssid[i].ssid, netinfo->pfnsubnet.SSID, netinfo->pfnsubnet.SSID_len); ssid[i].ssid_len = netinfo->pfnsubnet.SSID_len; - request.n_ssids++; + request->n_ssids++; channel_req = netinfo->pfnsubnet.channel; band = (channel_req <= CH_MAX_2G_CHANNEL) ? NL80211_BAND_2GHZ @@ -7548,13 +8127,13 @@ wl_notify_sched_scan_results(struct wl_priv *wl, struct net_device *ndev, channel[i].center_freq = ieee80211_channel_to_frequency(channel_req, band); channel[i].band = band; channel[i].flags |= IEEE80211_CHAN_NO_HT40; - request.channels[i] = &channel[i]; - request.n_channels++; + request->channels[i] = &channel[i]; + request->n_channels++; } /* assign parsed ssid array */ - if (request.n_ssids) - request.ssids = &ssid[0]; + if (request->n_ssids) + request->ssids = &ssid[0]; if (wl_get_drv_status_all(wl, SCANNING)) { /* Abort any on-going scan */ @@ -7576,7 +8155,7 @@ wl_notify_sched_scan_results(struct wl_priv *wl, struct net_device *ndev, err = wl_do_escan(wl, wiphy, ndev, NULL); #else WL_PNO((">>> Doing targeted ESCAN on PNO event\n")); - err = wl_do_escan(wl, wiphy, ndev, &request); + err = wl_do_escan(wl, wiphy, ndev, request); #endif if (err) { wl_clr_drv_status(wl, SCANNING, ndev); @@ -7588,6 +8167,8 @@ wl_notify_sched_scan_results(struct wl_priv *wl, struct net_device *ndev, WL_ERR(("FALSE PNO Event. (pfn_count == 0) \n")); } out_err: + if (request) + kfree(request); if (channel) kfree(channel); return err; @@ -7636,16 +8217,35 @@ static void wl_init_event_handler(struct wl_priv *wl) wl->evt_handler[WLC_E_P2P_DISC_LISTEN_COMPLETE] = wl_cfgp2p_listen_complete; wl->evt_handler[WLC_E_ACTION_FRAME_COMPLETE] = wl_cfgp2p_action_tx_complete; wl->evt_handler[WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE] = wl_cfgp2p_action_tx_complete; + wl->evt_handler[WLC_E_JOIN] = wl_notify_connect_status; + wl->evt_handler[WLC_E_START] = wl_notify_connect_status; #ifdef PNO_SUPPORT wl->evt_handler[WLC_E_PFN_NET_FOUND] = wl_notify_pfn_status; #endif /* PNO_SUPPORT */ -#ifdef WL_SDO - wl->evt_handler[WLC_E_SERVICE_FOUND] = wl_svc_resp_handler; - wl->evt_handler[WLC_E_P2PO_ADD_DEVICE] = wl_notify_device_discovery; - wl->evt_handler[WLC_E_P2PO_DEL_DEVICE] = wl_notify_device_discovery; +#ifdef WLTDLS + wl->evt_handler[WLC_E_TDLS_PEER_EVENT] = wl_tdls_event_handler; +#endif /* WLTDLS */ +#ifdef BCMCCX_S69 + wl->evt_handler[WLC_E_CCX_S69_RESP_RX] = wl_ccx_s69_response; #endif } +#if defined(STATIC_WL_PRIV_STRUCT) +static void +wl_init_escan_result_buf(struct wl_priv *wl) +{ + wl->escan_info.escan_buf = dhd_os_prealloc(NULL, DHD_PREALLOC_WIPHY_ESCAN0, 0); + bzero(wl->escan_info.escan_buf, ESCAN_BUF_SIZE); +} + +static void +wl_deinit_escan_result_buf(struct wl_priv *wl) +{ + wl->escan_info.escan_buf = NULL; + +} +#endif /* STATIC_WL_PRIV_STRUCT */ + static s32 wl_init_priv_mem(struct wl_priv *wl) { WL_DBG(("Enter \n")); @@ -7707,8 +8307,7 @@ static s32 wl_init_priv_mem(struct wl_priv *wl) WL_ERR(("wl->ie alloc failed\n")); goto init_priv_mem_out; } - wl->escan_info.escan_buf = dhd_os_prealloc(NULL, DHD_PREALLOC_WIPHY_ESCAN0, 0); - bzero(wl->escan_info.escan_buf, ESCAN_BUF_SIZE); + wl_init_escan_result_buf(wl); #endif /* STATIC_WL_PRIV_STRUCT */ wl->afx_hdl = (void *)kzalloc(sizeof(*wl->afx_hdl), GFP_KERNEL); if (unlikely(!wl->afx_hdl)) { @@ -7753,7 +8352,7 @@ static void wl_deinit_priv_mem(struct wl_priv *wl) wl->conn_info = NULL; kfree(wl->ie); wl->ie = NULL; - wl->escan_info.escan_buf = NULL; + wl_deinit_escan_result_buf(wl); #endif /* STATIC_WL_PRIV_STRUCT */ if (wl->afx_hdl) { cancel_work_sync(&wl->afx_hdl->work); @@ -7778,11 +8377,7 @@ static s32 wl_create_event_handler(struct wl_priv *wl) /* Do not use DHD in cfg driver */ wl->event_tsk.thr_pid = -1; -#ifdef USE_KTHREAD_API - PROC_START2(wl_event_handler, wl, &wl->event_tsk, 0, "wl_event_handler"); -#else - PROC_START(wl_event_handler, wl, &wl->event_tsk, 0); -#endif + PROC_START(wl_event_handler, wl, &wl->event_tsk, 0, "wl_event_handler"); if (wl->event_tsk.thr_pid < 0) ret = -ENOMEM; return ret; @@ -8045,15 +8640,37 @@ wl_cfg80211_netdev_notifier_call(struct notifier_block * nb, return NOTIFY_DONE; switch (state) { case NETDEV_DOWN: - while (work_pending(&wdev->cleanup_work) && refcnt < 100) { - if (refcnt%5 == 0) - WL_ERR(("[NETDEV_DOWN] work_pending (%d th)\n", refcnt)); + { + int max_wait_timeout = 2; + int max_wait_count = 100; + unsigned long limit = jiffies + max_wait_timeout * HZ; + while (work_pending(&wdev->cleanup_work)) { + if (refcnt%5 == 0) { + WL_ERR(("[NETDEV_DOWN] wait for " + "complete of cleanup_work" + " (%d th)\n", refcnt)); + } + if (!time_before(jiffies, limit)) { + WL_ERR(("[NETDEV_DOWN] cleanup_work" + " of CFG80211 is not" + " completed in %d sec\n", + max_wait_timeout)); + break; + } + if (refcnt >= max_wait_count) { + WL_ERR(("[NETDEV_DOWN] cleanup_work" + " of CFG80211 is not" + " completed in %d loop\n", + max_wait_count)); + break; + } set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(100); set_current_state(TASK_RUNNING); refcnt++; } break; + } case NETDEV_UNREGISTER: /* after calling list_del_rcu(&wdev->list) */ @@ -8079,55 +8696,71 @@ static struct notifier_block wl_cfg80211_netdev_notifier = { .notifier_call = wl_cfg80211_netdev_notifier_call, }; +static void wl_cfg80211_scan_abort(struct wl_priv *wl) +{ + wl_scan_params_t *params = NULL; + s32 params_size = 0; + s32 err = BCME_OK; + struct net_device *dev = wl_to_prmry_ndev(wl); + if (!in_atomic()) { + /* Our scan params only need space for 1 channel and 0 ssids */ + params = wl_cfg80211_scan_alloc_params(-1, 0, ¶ms_size); + if (params == NULL) { + WL_ERR(("scan params allocation failed \n")); + err = -ENOMEM; + } else { + /* Do a scan abort to stop the driver's scan engine */ + err = wldev_ioctl(dev, WLC_SCAN, params, params_size, true); + if (err < 0) { + WL_ERR(("scan abort failed \n")); + } + kfree(params); + } + } +} static s32 wl_notify_escan_complete(struct wl_priv *wl, struct net_device *ndev, bool aborted, bool fw_abort) { - wl_scan_params_t *params = NULL; - s32 params_size = 0; s32 err = BCME_OK; unsigned long flags; struct net_device *dev; WL_DBG(("Enter \n")); + if (!ndev) { + WL_ERR(("ndev is null\n")); + err = BCME_ERROR; + return err; + } - if (wl->escan_info.ndev != ndev) - { + if (wl->escan_info.ndev != ndev) { WL_ERR(("ndev is different %p %p\n", wl->escan_info.ndev, ndev)); + err = BCME_ERROR; return err; } if (wl->scan_request) { - if (wl->scan_request->dev == wl->p2p_net) - dev = wl_to_prmry_ndev(wl); - else + dev = wl_to_prmry_ndev(wl); +#if defined(WL_ENABLE_P2P_IF) + if (wl->scan_request->dev != wl->p2p_net) dev = wl->scan_request->dev; +#endif /* WL_ENABLE_P2P_IF */ } else { WL_DBG(("wl->scan_request is NULL may be internal scan." - "doing scan_abort for ndev %p primary %p p2p_net %p", - ndev, wl_to_prmry_ndev(wl), wl->p2p_net)); + "doing scan_abort for ndev %p primary %p", + ndev, wl_to_prmry_ndev(wl))); dev = ndev; } if (fw_abort && !in_atomic()) { - /* Our scan params only need space for 1 channel and 0 ssids */ - params = wl_cfg80211_scan_alloc_params(-1, 0, ¶ms_size); - if (params == NULL) { - WL_ERR(("scan params allocation failed \n")); - err = -ENOMEM; - } else { - /* Do a scan abort to stop the driver's scan engine */ - err = wldev_ioctl(dev, WLC_SCAN, params, params_size, true); - if (err < 0) { - WL_ERR(("scan abort failed \n")); - } - } + wl_cfg80211_scan_abort(wl); } + if (timer_pending(&wl->scan_timeout)) del_timer_sync(&wl->scan_timeout); #if defined(ESCAN_RESULT_PATCH) if (likely(wl->scan_request)) { - wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf; + wl->bss_list = wl_escan_get_buf(wl, aborted); wl_inform_bss(wl); } #endif /* ESCAN_RESULT_PATCH */ @@ -8135,9 +8768,7 @@ static s32 wl_notify_escan_complete(struct wl_priv *wl, #ifdef WL_SCHED_SCAN if (wl->sched_scan_req && !wl->scan_request) { WL_PNO((">>> REPORTING SCHED SCAN RESULTS \n")); - if (aborted) - cfg80211_sched_scan_stopped(wl->sched_scan_req->wiphy); - else + if (!aborted) cfg80211_sched_scan_results(wl->sched_scan_req->wiphy); wl->sched_scan_running = FALSE; wl->sched_scan_req = NULL; @@ -8151,19 +8782,10 @@ static s32 wl_notify_escan_complete(struct wl_priv *wl, wl_clr_p2p_status(wl, SCANNING); wl_clr_drv_status(wl, SCANNING, dev); spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); -#ifdef WL_SDO - if (wl_get_p2p_status(wl, DISC_IN_PROGRESS) && !in_atomic()) { - wl_cfg80211_resume_sdo(ndev, wl); - } -#endif - if (params) - kfree(params); - return err; } -static s32 wl_escan_handler(struct wl_priv *wl, - struct net_device *ndev, +static s32 wl_escan_handler(struct wl_priv *wl, bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data) { s32 err = BCME_OK; @@ -8173,6 +8795,7 @@ static s32 wl_escan_handler(struct wl_priv *wl, wl_bss_info_t *bss = NULL; wl_scan_results_t *list; wifi_p2p_ie_t * p2p_ie; + struct net_device *ndev = NULL; u32 bi_length; u32 i; u8 *p2p_dev_addr = NULL; @@ -8180,6 +8803,8 @@ static s32 wl_escan_handler(struct wl_priv *wl, WL_DBG((" enter event type : %d, status : %d \n", ntoh32(e->event_type), ntoh32(e->status))); + ndev = cfgdev_to_wlc_ndev(cfgdev, wl); + mutex_lock(&wl->usr_sync); /* P2P SCAN is coming from primary interface */ if (wl_get_p2p_status(wl, SCANNING)) { @@ -8192,13 +8817,16 @@ static s32 wl_escan_handler(struct wl_priv *wl, if (!ndev || !wl->escan_on || (!wl_get_drv_status(wl, SCANNING, ndev) && !wl->sched_scan_running)) { - WL_ERR(("escan is not ready ndev %p wl->escan_on %d drv_status 0x%x\n", - ndev, wl->escan_on, wl_get_drv_status(wl, SCANNING, ndev))); + WL_ERR(("escan is not ready ndev %p wl->escan_on %d" + " drv_status 0x%x e_type %d e_states %d\n", + ndev, wl->escan_on, wl_get_drv_status(wl, SCANNING, ndev), + ntoh32(e->event_type), ntoh32(e->status))); goto exit; } + escan_result = (wl_escan_result_t *)data; + if (status == WLC_E_STATUS_PARTIAL) { WL_INFO(("WLC_E_STATUS_PARTIAL \n")); - escan_result = (wl_escan_result_t *) data; if (!escan_result) { WL_ERR(("Invalid escan result (NULL pointer)\n")); goto exit; @@ -8217,6 +8845,9 @@ static s32 wl_escan_handler(struct wl_priv *wl, WL_ERR(("Invalid bss_info length %d: ignoring\n", bi_length)); goto exit; } + if (wl_escan_check_sync_id(status, escan_result->sync_id, + wl->escan_info.cur_sync_id) < 0) + goto exit; if (!(wl_to_wiphy(wl)->interface_modes & BIT(NL80211_IFTYPE_ADHOC))) { if (dtoh16(bi->capability) & DOT11_CAP_IBSS) { @@ -8231,8 +8862,15 @@ static s32 wl_escan_handler(struct wl_priv *wl, wl->afx_hdl->tx_dst_addr.octet, ETHER_ADDR_LEN)) { s32 channel = wf_chspec_ctlchan( wl_chspec_driver_to_host(bi->chanspec)); - WL_DBG(("ACTION FRAME SCAN : Peer " MACDBG " found, channel : %d\n", - MAC2STRDBG(wl->afx_hdl->tx_dst_addr.octet), channel)); + + if ((channel > MAXCHANNEL) || (channel <= 0)) + channel = WL_INVALID; + else + WL_ERR(("ACTION FRAME SCAN : Peer " MACDBG " found," + " channel : %d\n", + MAC2STRDBG(wl->afx_hdl->tx_dst_addr.octet), + channel)); + wl_clr_p2p_status(wl, SCANNING); wl->afx_hdl->peer_chan = channel; complete(&wl->act_frm_scan); @@ -8240,20 +8878,12 @@ static s32 wl_escan_handler(struct wl_priv *wl, } } else { - int cur_len = 0; - list = (wl_scan_results_t *)wl->escan_info.escan_buf; -#if defined(WLP2P) && defined(WL_ENABLE_P2P_IF) - if (wl->p2p_net && wl->scan_request && - wl->scan_request->dev == wl->p2p_net) { -#else - if (p2p_is_on(wl) && p2p_scan(wl)) { -#endif -#ifdef WL_HOST_BAND_MGMT - s32 channel = 0; - s32 channel_band = 0; -#endif /* WL_HOST_BAND_MGMT */ + int cur_len = WL_SCAN_RESULTS_FIXED_SIZE; + list = wl_escan_get_buf(wl, FALSE); + if (scan_req_match(wl)) { /* p2p scan && allow only probe response */ - if (bi->flags & WL_BSS_FLAGS_FROM_BEACON) + if ((wl->p2p->search_state != WL_P2P_DISC_ST_SCAN) && + (bi->flags & WL_BSS_FLAGS_FROM_BEACON)) goto exit; if ((p2p_ie = wl_cfgp2p_find_p2pie(((u8 *) bi) + bi->ie_offset, bi->ie_length)) == NULL) { @@ -8261,20 +8891,6 @@ static s32 wl_escan_handler(struct wl_priv *wl, " response/beacon\n")); goto exit; } -#ifdef WL_HOST_BAND_MGMT - channel = CHSPEC_CHANNEL(wl_chspec_driver_to_host(bi->chanspec)); - channel_band = (channel > CH_MAX_2G_CHANNEL) ? - WLC_BAND_5G : WLC_BAND_2G; - - - if ((wl->curr_band == WLC_BAND_5G) && - (channel_band == WLC_BAND_2G)) { - /* Avoid sending the GO results in band conflict */ - if (wl_cfgp2p_retreive_p2pattrib(p2p_ie, - P2P_SEID_GROUP_ID) != NULL) - goto exit; - } -#endif /* WL_HOST_BAND_MGMT */ } for (i = 0; i < list->count; i++) { bss = bss ? (wl_bss_info_t *)((uintptr)bss + dtoh32(bss->length)) @@ -8360,24 +8976,27 @@ static s32 wl_escan_handler(struct wl_priv *wl, WL_ERR(("Buffer is too small: ignoring\n")); goto exit; } - memcpy(&(wl->escan_info.escan_buf[list->buflen]), bi, bi_length); + + memcpy(&(((char *)list)[list->buflen]), bi, bi_length); list->version = dtoh32(bi->version); list->buflen += bi_length; list->count++; + } } else if (status == WLC_E_STATUS_SUCCESS) { -#ifdef P2P_DISCOVERY_WAR - if (wl->p2p_net && wl->scan_request && - wl->scan_request->dev == wl->p2p_net && - !wl->p2p->vif_created) { +#if defined(P2P_DISCOVERY_WAR) + if (scan_req_match(wl) && !wl->p2p->vif_created) { if (wldev_iovar_setint(wl_to_prmry_ndev(wl), "mpc", 1) < 0) { WL_ERR(("mpc enabling back failed\n")); } } -#endif +#endif /* defined(P2P_DISCOVERY_WAR) */ wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE; + wl_escan_print_sync_id(status, wl->escan_info.cur_sync_id, + escan_result->sync_id); + if (wl_get_drv_status_all(wl, FINDING_COMMON_CHANNEL)) { WL_INFO(("ACTION FRAME SCAN DONE\n")); wl_clr_p2p_status(wl, SCANNING); @@ -8386,26 +9005,27 @@ static s32 wl_escan_handler(struct wl_priv *wl, complete(&wl->act_frm_scan); } else if ((likely(wl->scan_request)) || (wl->sched_scan_running)) { WL_INFO(("ESCAN COMPLETED\n")); - wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf; - if (wl->scan_request && wl->scan_request->dev != wl->p2p_net) { + wl->bss_list = wl_escan_get_buf(wl, FALSE); + if (!scan_req_match(wl)) { WL_TRACE_HW4(("SCAN COMPLETED: scanned AP count=%d\n", wl->bss_list->count)); } wl_inform_bss(wl); wl_notify_escan_complete(wl, ndev, false, false); } + wl_escan_increment_sync_id(wl, SCAN_BUF_NEXT); } else if (status == WLC_E_STATUS_ABORT) { -#ifdef P2P_DISCOVERY_WAR - if (wl->p2p_net && wl->scan_request && - wl->scan_request->dev == wl->p2p_net && - !wl->p2p->vif_created) { +#if defined(P2P_DISCOVERY_WAR) + if (scan_req_match(wl) && !wl->p2p->vif_created) { if (wldev_iovar_setint(wl_to_prmry_ndev(wl), "mpc", 1) < 0) { WL_ERR(("mpc enabling back failed\n")); } } -#endif +#endif /* defined(P2P_DISCOVERY_WAR) */ wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE; + wl_escan_print_sync_id(status, escan_result->sync_id, + wl->escan_info.cur_sync_id); if (wl_get_drv_status_all(wl, FINDING_COMMON_CHANNEL)) { WL_INFO(("ACTION FRAME SCAN DONE\n")); wl_clr_drv_status(wl, SCANNING, wl->afx_hdl->dev); @@ -8414,18 +9034,16 @@ static s32 wl_escan_handler(struct wl_priv *wl, complete(&wl->act_frm_scan); } else if ((likely(wl->scan_request)) || (wl->sched_scan_running)) { WL_INFO(("ESCAN ABORTED\n")); - wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf; - if (wl->scan_request && wl->scan_request->dev != wl->p2p_net) { + wl->bss_list = wl_escan_get_buf(wl, TRUE); + if (!scan_req_match(wl)) { WL_TRACE_HW4(("SCAN ABORTED: scanned AP count=%d\n", wl->bss_list->count)); } wl_inform_bss(wl); wl_notify_escan_complete(wl, ndev, true, false); } - } - else if (status == WLC_E_STATUS_NEWSCAN) - { - escan_result = (wl_escan_result_t *) data; + wl_escan_increment_sync_id(wl, SCAN_BUF_CNT); + } else if (status == WLC_E_STATUS_NEWSCAN) { WL_ERR(("WLC_E_STATUS_NEWSCAN : scan_request[%p]\n", wl->scan_request)); WL_ERR(("sync_id[%d], bss_count[%d]\n", escan_result->sync_id, escan_result->bss_count)); @@ -8438,6 +9056,8 @@ static s32 wl_escan_handler(struct wl_priv *wl, } else { WL_ERR(("unexpected Escan Event %d : abort\n", status)); wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE; + wl_escan_print_sync_id(status, escan_result->sync_id, + wl->escan_info.cur_sync_id); if (wl_get_drv_status_all(wl, FINDING_COMMON_CHANNEL)) { WL_INFO(("ACTION FRAME SCAN DONE\n")); wl_clr_p2p_status(wl, SCANNING); @@ -8445,8 +9065,8 @@ static s32 wl_escan_handler(struct wl_priv *wl, if (wl->afx_hdl->peer_chan == WL_INVALID) complete(&wl->act_frm_scan); } else if ((likely(wl->scan_request)) || (wl->sched_scan_running)) { - wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf; - if (wl->scan_request && wl->scan_request->dev != wl->p2p_net) { + wl->bss_list = wl_escan_get_buf(wl, TRUE); + if (!scan_req_match(wl)) { WL_TRACE_HW4(("SCAN ABORTED(UNEXPECTED): " "scanned AP count=%d\n", wl->bss_list->count)); @@ -8454,11 +9074,13 @@ static s32 wl_escan_handler(struct wl_priv *wl, wl_inform_bss(wl); wl_notify_escan_complete(wl, ndev, true, false); } + wl_escan_increment_sync_id(wl, 2); } exit: mutex_unlock(&wl->usr_sync); return err; } + static void wl_cfg80211_concurrent_roam(struct wl_priv *wl, int enable) { u32 connected_cnt = wl_get_drv_status_all(wl, CONNECTED); @@ -8501,9 +9123,9 @@ static void wl_cfg80211_concurrent_roam(struct wl_priv *wl, int enable) static void wl_cfg80211_determine_vsdb_mode(struct wl_priv *wl) { struct net_info *iter, *next; - u32 chan = 0; + u32 ctl_chan = 0; u32 chanspec = 0; - u32 prev_chan = 0; + u32 pre_ctl_chan = 0; u32 connected_cnt = wl_get_drv_status_all(wl, CONNECTED); wl->vsdb_mode = false; @@ -8512,33 +9134,34 @@ static void wl_cfg80211_determine_vsdb_mode(struct wl_priv *wl) } for_each_ndev(wl, iter, next) { chanspec = 0; - chan = 0; + ctl_chan = 0; if (wl_get_drv_status(wl, CONNECTED, iter->ndev)) { if (wldev_iovar_getint(iter->ndev, "chanspec", (s32 *)&chanspec) == BCME_OK) { - chan = CHSPEC_CHANNEL(chanspec); - if (CHSPEC_IS40(chanspec)) { - if (CHSPEC_SB_UPPER(chanspec)) - chan += CH_10MHZ_APART; - else - chan -= CH_10MHZ_APART; - } + chanspec = wl_chspec_driver_to_host(chanspec); + ctl_chan = wf_chspec_ctlchan(chanspec); wl_update_prof(wl, iter->ndev, NULL, - &chan, WL_PROF_CHAN); + &ctl_chan, WL_PROF_CHAN); + } + if (!wl->vsdb_mode) { + if (!pre_ctl_chan && ctl_chan) + pre_ctl_chan = ctl_chan; + else if (pre_ctl_chan && (pre_ctl_chan != ctl_chan)) { + wl->vsdb_mode = true; + } } - if (!prev_chan && chan) - prev_chan = chan; - else if (prev_chan && (prev_chan != chan)) - wl->vsdb_mode = true; } } + WL_ERR(("%s concurrency is enabled\n", wl->vsdb_mode ? "Multi Channel" : "Same Channel")); return; } + static s32 wl_notifier_change_state(struct wl_priv *wl, struct net_info *_net_info, enum wl_status state, bool set) { s32 pm = PM_FAST; s32 err = BCME_OK; + u32 mode; u32 chan = 0; struct net_info *iter, *next; struct net_device *primary_dev = wl_to_prmry_ndev(wl); @@ -8547,49 +9170,78 @@ static s32 wl_notifier_change_state(struct wl_priv *wl, struct net_info *_net_in if (state != WL_STATUS_CONNECTED) return 0; - + mode = wl_get_mode_by_netdev(wl, _net_info->ndev); if (set) { wl_cfg80211_concurrent_roam(wl, 1); - if (wl_get_mode_by_netdev(wl, _net_info->ndev) == WL_MODE_AP) { - pm = PM_OFF; - WL_DBG(("%s:AP power save %s\n", _net_info->ndev->name, - pm ? "enabled" : "disabled")); - if ((err = wldev_ioctl(_net_info->ndev, WLC_SET_PM, - &pm, sizeof(pm), true)) != 0) { - if (err == -ENODEV) - WL_DBG(("%s:net_device is not ready\n", - _net_info->ndev->name)); - else - WL_ERR(("%s:error (%d)\n", _net_info->ndev->name, err)); - } + if (mode == WL_MODE_AP) { + if (wl_add_remove_eventmsg(primary_dev, WLC_E_P2P_PROBREQ_MSG, false)) WL_ERR((" failed to unset WLC_E_P2P_PROPREQ_MSG\n")); - return 0; } wl_cfg80211_determine_vsdb_mode(wl); - pm = PM_OFF; - for_each_ndev(wl, iter, next) { - if ((!wl->vsdb_mode) && (iter->ndev != _net_info->ndev)) { - /* Do not touch the other interfaces power save - * if we are not in vsdb mode - */ - continue; + if (wl->vsdb_mode || _net_info->pm_block) { + /* Delete pm_enable_work */ + wl_add_remove_pm_enable_work(wl, FALSE, WL_HANDLER_MAINTAIN); + /* save PM_FAST in _net_info to restore this + * if _net_info->pm_block is false + */ + if (!_net_info->pm_block && (mode == WL_MODE_BSS)) { + _net_info->pm = PM_FAST; + _net_info->pm_restore = true; } - /* Save the current power mode */ - iter->pm_restore = true; - err = wldev_ioctl(iter->ndev, WLC_GET_PM, &iter->pm, - sizeof(iter->pm), false); - WL_DBG(("%s:power save %s\n", iter->ndev->name, - iter->pm ? "enabled" : "disabled")); - if ((err = wldev_ioctl(iter->ndev, WLC_SET_PM, &pm, - sizeof(pm), true)) != 0) { - if (err == -ENODEV) - WL_DBG(("%s:netdev not ready\n", iter->ndev->name)); - else - WL_ERR(("%s:error (%d)\n", iter->ndev->name, err)); - iter->ndev->ieee80211_ptr->ps = pm ? true: false; + pm = PM_OFF; + for_each_ndev(wl, iter, next) { + if (iter->pm_restore) + continue; + /* Save the current power mode */ + err = wldev_ioctl(iter->ndev, WLC_GET_PM, &iter->pm, + sizeof(iter->pm), false); + WL_DBG(("%s:power save %s\n", iter->ndev->name, + iter->pm ? "enabled" : "disabled")); + if (!err && iter->pm) { + iter->pm_restore = true; + } + + } + for_each_ndev(wl, iter, next) { + if ((err = wldev_ioctl(iter->ndev, WLC_SET_PM, &pm, + sizeof(pm), true)) != 0) { + if (err == -ENODEV) + WL_DBG(("%s:netdev not ready\n", iter->ndev->name)); + else + WL_ERR(("%s:error (%d)\n", iter->ndev->name, err)); + } else + iter->ndev->ieee80211_ptr->ps = false; } + } else { + /* add PM Enable timer to go to power save mode + * if supplicant control pm mode, it will be cleared or + * updated by wl_cfg80211_set_power_mgmt() if not - for static IP & HW4 P2P, + * PM will be configured when timer expired + */ + + /* + * before calling pm_enable_timer, we need to set PM -1 for all ndev + */ + pm = PM_OFF; + + for_each_ndev(wl, iter, next) { + if ((err = wldev_ioctl(iter->ndev, WLC_SET_PM, &pm, + sizeof(pm), true)) != 0) { + if (err == -ENODEV) + WL_DBG(("%s:netdev not ready\n", iter->ndev->name)); + else + WL_ERR(("%s:error (%d)\n", iter->ndev->name, err)); + } + } + + if (wl->pm_enable_work_on) { + wl_add_remove_pm_enable_work(wl, FALSE, WL_HANDLER_DEL); + } + + wl->pm_enable_work_on = true; + wl_add_remove_pm_enable_work(wl, TRUE, WL_HANDLER_NOTUSE); } } else { /* clear */ @@ -8598,7 +9250,7 @@ static s32 wl_notifier_change_state(struct wl_priv *wl, struct net_info *_net_in wl_update_prof(wl, _net_info->ndev, NULL, &chan, WL_PROF_CHAN); wl_cfg80211_determine_vsdb_mode(wl); for_each_ndev(wl, iter, next) { - if (iter->pm_restore) { + if (iter->pm_restore && iter->pm) { WL_DBG(("%s:restoring power save %s\n", iter->ndev->name, (iter->pm ? "enabled" : "disabled"))); err = wldev_ioctl(iter->ndev, @@ -8611,6 +9263,7 @@ static s32 wl_notifier_change_state(struct wl_priv *wl, struct net_info *_net_in break; } iter->pm_restore = 0; + iter->ndev->ieee80211_ptr->ps = true; } } wl_cfg80211_concurrent_roam(wl, 0); @@ -8641,6 +9294,7 @@ static s32 wl_init_scan(struct wl_priv *wl) } else if (wl->escan_on) { wl->evt_handler[WLC_E_ESCAN_RESULT] = wl_escan_handler; wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE; + wl_escan_init_sync_id(wl); } /* Init scan_timeout timer */ init_timer(&wl->scan_timeout); @@ -8706,7 +9360,7 @@ static void wl_deinit_priv(struct wl_priv *wl) unregister_netdevice_notifier(&wl_cfg80211_netdev_notifier); } -#if defined(WLP2P) && defined(WL_ENABLE_P2P_IF) +#if defined(WL_ENABLE_P2P_IF) static s32 wl_cfg80211_attach_p2p(void) { struct wl_priv *wl = wlcfg_drv_priv; @@ -8724,10 +9378,16 @@ static s32 wl_cfg80211_attach_p2p(void) static s32 wl_cfg80211_detach_p2p(void) { struct wl_priv *wl = wlcfg_drv_priv; - struct wireless_dev *wdev = wl->p2p_wdev; + struct wireless_dev *wdev; WL_DBG(("Enter \n")); - if (!wdev || !wl) { + if (!wl) { + WL_ERR(("Invalid Ptr\n")); + return -EINVAL; + } else + wdev = wl->p2p_wdev; + + if (!wdev) { WL_ERR(("Invalid Ptr\n")); return -EINVAL; } @@ -8741,7 +9401,7 @@ static s32 wl_cfg80211_detach_p2p(void) return 0; } -#endif /* defined(WLP2P) && defined(WL_ENABLE_P2P_IF) */ +#endif /* WL_ENABLE_P2P_IF */ s32 wl_cfg80211_attach_post(struct net_device *ndev) { @@ -8758,22 +9418,21 @@ s32 wl_cfg80211_attach_post(struct net_device *ndev) return -EINVAL; } if (!wl_get_drv_status(wl, READY, ndev)) { - if (wl->wdev && - wl_cfgp2p_supported(wl, ndev)) { + if (wl->wdev && wl_cfgp2p_supported(wl, ndev)) { #if !defined(WL_ENABLE_P2P_IF) - wl->wdev->wiphy->interface_modes |= + wl->wdev->wiphy->interface_modes |= (BIT(NL80211_IFTYPE_P2P_CLIENT)| BIT(NL80211_IFTYPE_P2P_GO)); -#endif +#endif /* !WL_ENABLE_P2P_IF */ if ((err = wl_cfgp2p_init_priv(wl)) != 0) goto fail; -#if defined(WLP2P) && defined(WL_ENABLE_P2P_IF) +#if defined(WL_ENABLE_P2P_IF) if (wl->p2p_net) { /* Update MAC addr for p2p0 interface here. */ memcpy(wl->p2p_net->dev_addr, ndev->dev_addr, ETH_ALEN); wl->p2p_net->dev_addr[0] |= 0x02; - WL_DBG(("%s: p2p_dev_addr="MACDBG "\n", + WL_ERR(("%s: p2p_dev_addr="MACDBG "\n", wl->p2p_net->name, MAC2STRDBG(wl->p2p_net->dev_addr))); } else { @@ -8781,11 +9440,11 @@ s32 wl_cfg80211_attach_post(struct net_device *ndev) " Couldn't update the MAC Address for p2p0 \n")); return -ENODEV; } -#endif /* defined(WLP2P) && (WL_ENABLE_P2P_IF) */ +#endif /* WL_ENABLE_P2P_IF */ wl->p2p_supported = true; } - } + } wl_set_drv_status(wl, READY, ndev); fail: return err; @@ -8811,7 +9470,7 @@ s32 wl_cfg80211_attach(struct net_device *ndev, void *data) WL_ERR(("Could not allocate wireless device\n")); return -ENOMEM; } - err = wl_setup_wiphy(wdev, dev); + err = wl_setup_wiphy(wdev, dev, data); if (unlikely(err)) { kfree(wdev); return -ENOMEM; @@ -8841,6 +9500,13 @@ s32 wl_cfg80211_attach(struct net_device *ndev, void *data) WL_ERR(("Failed to setup rfkill %d\n", err)); goto cfg80211_attach_out; } +#ifdef DEBUGFS_CFG80211 + err = wl_setup_debugfs(wl); + if (err) { + WL_ERR(("Failed to setup debugfs %d\n", err)); + goto cfg80211_attach_out; + } +#endif err = register_netdevice_notifier(&wl_cfg80211_netdev_notifier); if (err) { WL_ERR(("Failed to register notifierl %d\n", err)); @@ -8850,15 +9516,15 @@ s32 wl_cfg80211_attach(struct net_device *ndev, void *data) err = wl_cfg80211_btcoex_init(wl); if (err) goto cfg80211_attach_out; -#endif +#endif wlcfg_drv_priv = wl; -#if defined(WLP2P) && defined(WL_ENABLE_P2P_IF) +#if defined(WL_ENABLE_P2P_IF) err = wl_cfg80211_attach_p2p(); if (err) goto cfg80211_attach_out; -#endif +#endif /* WL_ENABLE_P2P_IF */ return err; @@ -8879,18 +9545,25 @@ void wl_cfg80211_detach(void *para) #if defined(COEX_DHCP) wl_cfg80211_btcoex_deinit(wl); -#endif +#endif wl_setup_rfkill(wl, FALSE); +#ifdef DEBUGFS_CFG80211 + wl_free_debugfs(wl); +#endif if (wl->p2p_supported) { if (timer_pending(&wl->p2p->listen_timer)) del_timer_sync(&wl->p2p->listen_timer); wl_cfgp2p_deinit_priv(wl); } -#if defined(WLP2P) && defined(WL_ENABLE_P2P_IF) +#if defined(WL_CFG80211_P2P_DEV_IF) + wl_cfgp2p_del_p2p_disc_if(wl->p2p_wdev); +#elif defined(WL_ENABLE_P2P_IF) wl_cfg80211_detach_p2p(); -#endif +#endif /* WL_CFG80211_P2P_DEV_IF */ + + wl_cfg80211_ibss_vsie_free(wl); wl_deinit_priv(wl); wlcfg_drv_priv = NULL; wl_cfg80211_clear_parent_dev(); @@ -8908,6 +9581,7 @@ static void wl_wakeup_event(struct wl_priv *wl) } } +#if (defined(WL_CFG80211_P2P_DEV_IF) || defined(WL_ENABLE_P2P_IF)) static int wl_is_p2p_event(struct wl_event_q *e) { switch (e->etype) { @@ -8922,8 +9596,8 @@ static int wl_is_p2p_event(struct wl_event_q *e) case WLC_E_ACTION_FRAME_COMPLETE: if (e->emsg.ifidx != 0) { - WL_TRACE(("P2P Event on Virtual I/F (ifidx:%d) \n", - e->emsg.ifidx)); + WL_TRACE(("P2P event(%d) on virtual interface(ifidx:%d)\n", + e->etype, e->emsg.ifidx)); /* We are only bothered about the P2P events received * on primary interface. For rest of them return false * so that it is sent over the interface corresponding @@ -8931,33 +9605,30 @@ static int wl_is_p2p_event(struct wl_event_q *e) */ return FALSE; } else { - WL_TRACE(("P2P Event on Primary I/F (ifidx:%d)." - " Sent it to p2p0 \n", e->emsg.ifidx)); + WL_TRACE(("P2P event(%d) on interface(ifidx:%d)\n", + e->etype, e->emsg.ifidx)); return TRUE; } break; default: - WL_TRACE(("NON-P2P Event %d on ifidx (ifidx:%d) \n", + WL_TRACE(("NON-P2P event(%d) on interface(ifidx:%d)\n", e->etype, e->emsg.ifidx)); return FALSE; } } +#endif /* BCMDONGLEHOST && (WL_CFG80211_P2P_DEV_IF || WL_ENABLE_P2P_IF) */ static s32 wl_event_handler(void *data) { - struct net_device *netdev; struct wl_priv *wl = NULL; struct wl_event_q *e; tsk_ctl_t *tsk = (tsk_ctl_t *)data; + bcm_struct_cfgdev *cfgdev = NULL; wl = (struct wl_priv *)tsk->parent; -#ifndef USE_KTHREAD_API - DAEMONIZE("dhd_cfg80211_event"); - complete(&tsk->completed); -#else + WL_ERR(("tsk Enter, tsk = 0x%08x\n", (unsigned int)tsk)); -#endif while (down_interruptible (&tsk->sema) == 0) { SMP_RD_BARRIER_DEPENDS(); @@ -8969,15 +9640,31 @@ static s32 wl_event_handler(void *data) * there is no corresponding bsscfg for P2P interface. Map it to p2p0 * interface. */ +#if defined(WL_CFG80211_P2P_DEV_IF) + if ((wl_is_p2p_event(e) == TRUE) && (wl->p2p_wdev)) { + cfgdev = wl_to_p2p_wdev(wl); + } else { + cfgdev = ndev_to_wdev(dhd_idx2net((struct dhd_pub *)(wl->pub), + e->emsg.ifidx)); + } +#elif defined(WL_ENABLE_P2P_IF) if ((wl_is_p2p_event(e) == TRUE) && (wl->p2p_net)) { - netdev = wl->p2p_net; + cfgdev = wl->p2p_net; } else { - netdev = dhd_idx2net((struct dhd_pub *)(wl->pub), e->emsg.ifidx); + cfgdev = dhd_idx2net((struct dhd_pub *)(wl->pub), + e->emsg.ifidx); + } +#endif /* WL_CFG80211_P2P_DEV_IF */ + + if (!cfgdev) { +#if defined(WL_CFG80211_P2P_DEV_IF) + cfgdev = wl_to_prmry_wdev(wl); +#elif defined(WL_ENABLE_P2P_IF) + cfgdev = wl_to_prmry_ndev(wl); +#endif /* WL_CFG80211_P2P_DEV_IF */ } - if (!netdev) - netdev = wl_to_prmry_ndev(wl); if (e->etype < WLC_E_LAST && wl->evt_handler[e->etype]) { - wl->evt_handler[e->etype] (wl, netdev, &e->emsg, e->edata); + wl->evt_handler[e->etype] (wl, cfgdev, &e->emsg, e->edata); } else { WL_DBG(("Unknown Event (%d): ignoring\n", e->etype)); } @@ -9247,6 +9934,7 @@ static int wl_construct_reginfo(struct wl_priv *wl, s32 bw_cap) bool update; bool ht40_allowed; u8 *pbuf = NULL; + bool dfs_radar_disabled = FALSE; #define LOCAL_BUF_LEN 1024 pbuf = kzalloc(LOCAL_BUF_LEN, GFP_KERNEL); @@ -9255,7 +9943,7 @@ static int wl_construct_reginfo(struct wl_priv *wl, s32 bw_cap) WL_ERR(("failed to allocate local buf\n")); return -ENOMEM; } - list = (wl_uint32_list_t *)(void *) pbuf; + list = (wl_uint32_list_t *)(void *)pbuf; list->count = htod32(WL_NUMCHANSPECS); @@ -9316,7 +10004,7 @@ static int wl_construct_reginfo(struct wl_priv *wl, s32 bw_cap) else index = *n_cnt; if (index < array_size) { -#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS) +#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) band_chan_arr[index].center_freq = ieee80211_channel_to_frequency(channel); #else @@ -9327,8 +10015,8 @@ static int wl_construct_reginfo(struct wl_priv *wl, s32 bw_cap) if (CHSPEC_IS40(c) && ht40_allowed) { /* assuming the order is HT20, HT40 Upper, - HT40 lower from chanspecs - */ + * HT40 lower from chanspecs + */ u32 ht40_flag = band_chan_arr[index].flags & IEEE80211_CHAN_NO_HT40; if (CHSPEC_SB_UPPER(c)) { if (ht40_flag == IEEE80211_CHAN_NO_HT40) @@ -9337,8 +10025,8 @@ static int wl_construct_reginfo(struct wl_priv *wl, s32 bw_cap) band_chan_arr[index].flags |= IEEE80211_CHAN_NO_HT40PLUS; } else { /* It should be one of - IEEE80211_CHAN_NO_HT40 or IEEE80211_CHAN_NO_HT40PLUS - */ + * IEEE80211_CHAN_NO_HT40 or IEEE80211_CHAN_NO_HT40PLUS + */ band_chan_arr[index].flags &= ~IEEE80211_CHAN_NO_HT40; if (ht40_flag == IEEE80211_CHAN_NO_HT40) band_chan_arr[index].flags |= @@ -9346,21 +10034,26 @@ static int wl_construct_reginfo(struct wl_priv *wl, s32 bw_cap) } } else { band_chan_arr[index].flags = IEEE80211_CHAN_NO_HT40; - if (band == IEEE80211_BAND_2GHZ) - channel |= WL_CHANSPEC_BAND_2G; - else - channel |= WL_CHANSPEC_BAND_5G; - channel |= WL_CHANSPEC_BW_20; - channel = wl_chspec_host_to_driver(channel); - err = wldev_iovar_getint(dev, "per_chan_info", &channel); - if (!err) { - if (channel & WL_CHAN_RADAR) - band_chan_arr[index].flags |= - (IEEE80211_CHAN_RADAR | - IEEE80211_CHAN_NO_IBSS); - if (channel & WL_CHAN_PASSIVE) - band_chan_arr[index].flags |= - IEEE80211_CHAN_PASSIVE_SCAN; + if (!dfs_radar_disabled) { + if (band == IEEE80211_BAND_2GHZ) + channel |= WL_CHANSPEC_BAND_2G; + else + channel |= WL_CHANSPEC_BAND_5G; + channel |= WL_CHANSPEC_BW_20; + channel = wl_chspec_host_to_driver(channel); + err = wldev_iovar_getint(dev, "per_chan_info", &channel); + if (!err) { + if (channel & WL_CHAN_RADAR) + band_chan_arr[index].flags |= + (IEEE80211_CHAN_RADAR | + IEEE80211_CHAN_NO_IBSS); + if (channel & WL_CHAN_PASSIVE) + band_chan_arr[index].flags |= + IEEE80211_CHAN_PASSIVE_SCAN; + } else if (err == BCME_UNSUPPORTED) { + dfs_radar_disabled = TRUE; + WL_ERR(("does not support per_chan_info\n")); + } } } if (!update) @@ -9403,9 +10096,6 @@ s32 wl_update_wiphybands(struct wl_priv *wl, bool notify) WL_ERR(("error read bandlist (%d)\n", err)); goto end_bands; } - - wiphy = wl_to_wiphy(wl); - err = wldev_ioctl(dev, WLC_GET_BAND, &cur_band, sizeof(s32), false); if (unlikely(err)) { @@ -9417,10 +10107,10 @@ s32 wl_update_wiphybands(struct wl_priv *wl, bool notify) if (unlikely(err)) { WL_ERR(("error reading nmode (%d)\n", err)); } else { - /* For nmodeonly check bw cap */ + /* For nmodeonly check bw cap */ err = wldev_iovar_getint(dev, "mimo_bw_cap", &bw_cap); if (unlikely(err)) { - WL_ERR(("error get mimo_bw_cap (%d)\n", err)); + WL_ERR(("error get mimo_bw_cap (%d)\n", err)); } } @@ -9431,7 +10121,7 @@ s32 wl_update_wiphybands(struct wl_priv *wl, bool notify) goto end_bands; err = 0; } - + wiphy = wl_to_wiphy(wl); nband = bandlist[0]; for (i = 1; i <= nband && i < ARRAYSIZE(bandlist); i++) { @@ -9466,13 +10156,20 @@ s32 wl_update_wiphybands(struct wl_priv *wl, bool notify) wiphy->bands[IEEE80211_BAND_2GHZ] = bands[IEEE80211_BAND_2GHZ]; wiphy->bands[IEEE80211_BAND_5GHZ] = bands[IEEE80211_BAND_5GHZ]; + /* check if any bands populated otherwise makes 2Ghz as default */ + if (wiphy->bands[IEEE80211_BAND_2GHZ] == NULL && + wiphy->bands[IEEE80211_BAND_5GHZ] == NULL) { + /* Setup 2Ghz band as default */ + wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; + } + if (notify) wiphy_apply_custom_regulatory(wiphy, &brcm_regdom); end_bands: if (rollback_lock) mutex_unlock(&wl->usr_sync); - return err; + return err; } static s32 __wl_cfg80211_up(struct wl_priv *wl) @@ -9499,22 +10196,8 @@ static s32 __wl_cfg80211_up(struct wl_priv *wl) err = dhd_monitor_init(wl->pub); err = wl_invoke_iscan(wl); -#ifdef WL_HOST_BAND_MGMT - /* By default the curr_band is initialized to BAND_AUTO */ - if (wl_cfg80211_set_band(ndev, WLC_BAND_AUTO) < 0) { - WL_ERR(("roam_band set failed\n")); - err = -1; - } -#endif /* WL_HOST_BAND_MGMT */ - -#if defined(DHCP_SCAN_SUPPRESS) - /* wlan scan_supp timer and work thread info */ - init_timer(&wl->scan_supp_timer); - wl->scan_supp_timer.data = (ulong)wl; - wl->scan_supp_timer.function = wl_cfg80211_scan_supp_timerfunc; - INIT_WORK(&wl->wlan_work, wl_cfg80211_work_handler); -#endif /* DHCP_SCAN_SUPPRESS */ + INIT_DELAYED_WORK(&wl->pm_enable_work, wl_cfg80211_work_handler); wl_set_drv_status(wl, READY, ndev); return err; } @@ -9525,21 +10208,37 @@ static s32 __wl_cfg80211_down(struct wl_priv *wl) unsigned long flags; struct net_info *iter, *next; struct net_device *ndev = wl_to_prmry_ndev(wl); +#if defined(WL_CFG80211) && defined(WL_ENABLE_P2P_IF) struct net_device *p2p_net = wl->p2p_net; - u32 bssidx = wl_cfgp2p_find_idx(wl, ndev); +#endif /* WL_CFG80211 && WL_ENABLE_P2P_IF */ + u32 bssidx = 0; +#ifdef PROP_TXSTATUS_VSDB + dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); +#endif /* PROP_TXSTATUS_VSDB */ WL_DBG(("In\n")); + /* Delete pm_enable_work */ + wl_add_remove_pm_enable_work(wl, FALSE, WL_HANDLER_DEL); -#if defined(DHCP_SCAN_SUPPRESS) - /* Force clear of scan_suppress */ - if (wl->scan_suppressed) - wl_cfg80211_scan_suppress(ndev, 0); - if (timer_pending(&wl->scan_supp_timer)) - del_timer_sync(&wl->scan_supp_timer); - cancel_work_sync(&wl->wlan_work); -#endif /* DHCP_SCAN_SUPPRESS */ - - /* If BSS is operational (e.g SoftAp), bring it down */ - if (wl_cfgp2p_bss_isup(ndev, bssidx)) { + if (wl->p2p_supported) { + wl_clr_p2p_status(wl, GO_NEG_PHASE); +#ifdef PROP_TXSTATUS_VSDB + if (wl->p2p->vif_created) { + if (dhd-> op_mode != DHD_FLAG_IBSS_MODE && + dhd->wlfc_enabled && wl->wlfc_on) { + dhd->wlfc_enabled = false; + dhd_wlfc_deinit(dhd); + if (dhd->plat_deinit) + dhd->plat_deinit((void *)dhd); + wl->wlfc_on = false; + } + } +#endif /* PROP_TXSTATUS_VSDB */ + } + + + /* If primary BSS is operational (for e.g SoftAP), bring it down */ + if (!(wl_cfgp2p_find_idx(wl, ndev, &bssidx)) && + wl_cfgp2p_bss_isup(ndev, bssidx)) { if (wl_cfgp2p_bss(wl, ndev, bssidx, 0) < 0) WL_ERR(("BSS down failed \n")); } @@ -9547,13 +10246,9 @@ static s32 __wl_cfg80211_down(struct wl_priv *wl) /* Check if cfg80211 interface is already down */ if (!wl_get_drv_status(wl, READY, ndev)) return err; /* it is even not ready */ - for_each_ndev(wl, iter, next) wl_set_drv_status(wl, SCAN_ABORTING, iter->ndev); -#ifdef WL_SDO - wl_cfg80211_sdo_deinit(wl); -#endif wl_term_iscan(wl); spin_lock_irqsave(&wl->cfgdrv_lock, flags); @@ -9575,8 +10270,10 @@ static s32 __wl_cfg80211_down(struct wl_priv *wl) } wl_to_prmry_ndev(wl)->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION; - if (p2p_net) - dev_close(p2p_net); +#if defined(WL_CFG80211) && defined(WL_ENABLE_P2P_IF) + if (p2p_net) + dev_close(p2p_net); +#endif /* WL_CFG80211 && WL_ENABLE_P2P_IF */ DNGL_FUNC(dhd_cfg80211_down, (wl)); wl_flush_eq(wl); wl_link_down(wl); @@ -9593,6 +10290,7 @@ s32 wl_cfg80211_up(void *para) s32 err = 0; int val = 1; dhd_pub_t *dhd; + (void)para; WL_DBG(("In\n")); wl = wlcfg_drv_priv; @@ -9632,6 +10330,7 @@ int wl_cfg80211_hang(struct net_device *dev, u16 reason) wl = wlcfg_drv_priv; WL_ERR(("In : chip crash eventing\n")); + wl_add_remove_pm_enable_work(wl, FALSE, WL_HANDLER_DEL); cfg80211_disconnected(dev, reason, NULL, 0, GFP_KERNEL); if (wl != NULL) { wl_link_down(wl); @@ -9733,7 +10432,7 @@ wl_update_prof(struct wl_priv *wl, struct net_device *ndev, } spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); - if (err == EOPNOTSUPP) + if (err == -EOPNOTSUPP) WL_ERR(("unsupported item (%d)\n", item)); return err; @@ -9784,6 +10483,29 @@ static __used s32 wl_add_ie(struct wl_priv *wl, u8 t, u8 l, u8 *v) return err; } +static void wl_update_hidden_ap_ie(struct wl_bss_info *bi, u8 *ie_stream, u32 *ie_size) +{ + u8 *ssidie; + ssidie = (u8 *)cfg80211_find_ie(WLAN_EID_SSID, ie_stream, *ie_size); + if (!ssidie) + return; + if (ssidie[1] != bi->SSID_len) { + if (ssidie[1]) { + WL_ERR(("%s: Wrong SSID len: %d != %d\n", + __FUNCTION__, ssidie[1], bi->SSID_len)); + return; + } + memmove(ssidie + bi->SSID_len + 2, ssidie + 2, *ie_size - (ssidie + 2 - ie_stream)); + memcpy(ssidie + 2, bi->SSID, bi->SSID_len); + *ie_size = *ie_size + bi->SSID_len; + ssidie[1] = bi->SSID_len; + return; + } + if (*(ssidie + 2) == '\0') + memcpy(ssidie + 2, bi->SSID, bi->SSID_len); + return; +} + static s32 wl_mrg_ie(struct wl_priv *wl, u8 *ie_stream, u16 ie_size) { struct wl_ie *ie = wl_to_ie(wl); @@ -9856,9 +10578,9 @@ static void wl_init_eq_lock(struct wl_priv *wl) static void wl_delay(u32 ms) { if (in_atomic() || (ms < jiffies_to_msecs(1))) { - mdelay(ms); + OSL_DELAY(ms*1000); } else { - msleep(ms); + OSL_SLEEP(ms); } } @@ -9909,7 +10631,7 @@ s32 wl_cfg80211_channel_to_freq(u32 channel) { int freq = 0; -#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS) +#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) freq = ieee80211_channel_to_frequency(channel); #else { @@ -9924,838 +10646,80 @@ s32 wl_cfg80211_channel_to_freq(u32 channel) return freq; } -#ifdef WL_SDO -#define MAX_QR_LEN NLMSG_GOODSIZE - -typedef struct wl_cfg80211_dev_info { - u16 band; - u16 freq; - s16 rssi; - u16 ie_len; - u8 bssid[ETH_ALEN]; -} wl_cfg80211_dev_info_t; +#ifdef WLTDLS static s32 -wl_notify_device_discovery(struct wl_priv *wl, struct net_device *ndev, - const wl_event_msg_t *e, void *data) -{ - int err = 0; - u32 event = ntoh32(e->event_type); - wl_cfg80211_dev_info_t info; - struct wl_bss_info *bi = NULL; - u8 *buf = NULL; - u32 buflen = 0; - u16 channel = 0; - wl_escan_result_t *escan_result; - - WL_SD(("Enter. type:%d \n", event)); - - if ((event != WLC_E_P2PO_ADD_DEVICE) && (event != WLC_E_P2PO_DEL_DEVICE)) { - WL_ERR(("Unknown Event\n")); - return -EINVAL; - } - - mutex_lock(&wl->usr_sync); - if (event == WLC_E_P2PO_DEL_DEVICE) { - WL_SD(("DEV_LOST MAC:"MACDBG" \n", MAC2STRDBG(e->addr.octet))); - err = wl_genl_send_msg(ndev, event, (u8 *)e->addr.octet, ETH_ALEN, 0, 0); - } else { - - escan_result = (wl_escan_result_t *) data; - - if (dtoh16(escan_result->bss_count) != 1) { - WL_ERR(("Invalid bss_count %d: ignoring\n", escan_result->bss_count)); - err = -EINVAL; - goto exit; - } - - bi = escan_result->bss_info; - buflen = dtoh32(bi->length); - if (unlikely(buflen > WL_BSS_INFO_MAX)) { - WL_DBG(("Beacon is larger than buffer. Discarding\n")); - err = -EINVAL; - goto exit; - } - - /* Update sub-header */ - bzero(&info, sizeof(wl_cfg80211_dev_info_t)); - channel = bi->ctl_ch ? bi->ctl_ch : - CHSPEC_CHANNEL(wl_chspec_driver_to_host(bi->chanspec)); - info.freq = wl_cfg80211_channel_to_freq(channel); - info.rssi = wl_rssi_offset(dtoh16(bi->RSSI)); - memcpy(info.bssid, &bi->BSSID, ETH_ALEN); - info.ie_len = buflen; - - WL_SD(("DEV_FOUND band:%x Freq:%d rssi:%x "MACDBG" \n", - info.band, info.freq, info.rssi, MAC2STRDBG(info.bssid))); - - buf = ((u8 *) bi) + bi->ie_offset; - err = wl_genl_send_msg(ndev, event, buf, - buflen, (u8 *)&info, sizeof(wl_cfg80211_dev_info_t)); - } -exit: - mutex_unlock(&wl->usr_sync); - return err; -} - -s32 -wl_cfg80211_sdo_init(struct wl_priv *wl) -{ - u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - - if (wl->sdo) { - WL_SD(("SDO already initialized\n")); - return 0; - } - - wl->sdo = kzalloc(sizeof(sd_offload_t), kflags); - if (!wl->sdo) { - WL_ERR(("malloc failed for SDO \n")); - return -ENOMEM; - } - - return 0; -} - -s32 -wl_cfg80211_sdo_deinit(struct wl_priv *wl) -{ - s32 bssidx; - int ret = 0; - int sdo_pause = 0; - if (!wl || !wl->p2p) { - WL_ERR(("Wl %p or wl->p2p %p is null\n", wl, wl ? wl->p2p : NULL)); - return 0; - } - - bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE); - if (!wl->sdo) { - WL_DBG(("SDO Not Initialized. Do nothing. \n")); - return 0; - } - if (wl->sdo->dd_state && - (ret = wldev_iovar_setbuf_bsscfg(wl_to_prmry_ndev(wl), - "p2po_stop", (void*)&sdo_pause, sizeof(sdo_pause), - wl->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, NULL)) < 0) { - WL_ERR(("p2po_stop Failed :%d\n", ret)); - } - kfree(wl->sdo); - wl->sdo = NULL; +wl_tdls_event_handler(struct wl_priv *wl, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data) { - WL_SD(("SDO Deinit Done \n")); - - return 0; -} - -s32 -wl_cfg80211_resume_sdo(struct net_device *dev, struct wl_priv *wl) -{ - wl_sd_listen_t sd_listen; - int ret = 0; - s32 bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE); - - WL_DBG(("Enter\n")); - - if (!wl->sdo) { - return -EINVAL; - } - - if (dev == NULL) - dev = wl_to_prmry_ndev(wl); - - /* Disable back the ESCAN events for the offload */ - wl_add_remove_eventmsg(dev, WLC_E_ESCAN_RESULT, false); - - /* Resume according to the saved state */ - if (wl->sdo->dd_state == WL_DD_STATE_SEARCH) { - if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_find", NULL, 0, - wl->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, NULL)) < 0) { - WL_ERR(("p2po_find Failed :%d\n", ret)); - } - } else if (wl->sdo->dd_state == WL_DD_STATE_LISTEN) { - sd_listen.interval = wl->sdo->sd_listen.interval; - sd_listen.period = wl->sdo->sd_listen.period; - - if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_listen", (void*)&sd_listen, - sizeof(wl_sd_listen_t), wl->ioctl_buf, WLC_IOCTL_SMLEN, - bssidx, NULL)) < 0) { - WL_ERR(("p2po_listen Failed :%d\n", ret)); - } - - } - - /* p2po_stop clears of the eventmask for GAS. Set it back */ - wl_add_remove_eventmsg(dev, WLC_E_SERVICE_FOUND, true); - wl_add_remove_eventmsg(dev, WLC_E_GAS_FRAGMENT_RX, true); - wl_add_remove_eventmsg(dev, WLC_E_GAS_COMPLETE, true); - - WL_SD(("SDO Resumed \n")); - - return ret; -} - -s32 wl_cfg80211_pause_sdo(struct net_device *dev, struct wl_priv *wl) -{ - - int ret = 0; - s32 bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE); - int sdo_pause = 1; - - WL_DBG(("Enter \n")); - - if (!wl->sdo) { - WL_ERR(("SDO not initialized \n")); - return -EINVAL; - } - - if (dev == NULL) - dev = wl_to_prmry_ndev(wl); - - if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_stop", - (void*)&sdo_pause, sizeof(sdo_pause), - wl->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &wl->ioctl_buf_sync)) < 0) { - WL_ERR(("p2po_stop Failed :%d\n", ret)); - } - - /* Enable back the ESCAN events for the SCAN */ - wl_add_remove_eventmsg(dev, WLC_E_ESCAN_RESULT, true); - - WL_SD(("SDO Paused \n")); - - return ret; -} - -static s32 -wl_svc_resp_handler(struct wl_priv *wl, struct net_device *ndev, - const wl_event_msg_t *e, void *data) -{ - u32 event = ntoh32(e->event_type); - struct net_device *dev = NULL; - u8 *dst_mac = (u8 *)e->addr.octet; - int ret = 0; - wl_event_sd_t *gas = NULL; - int status = ntoh32(e->status); - sdo_event_t sdo_hdr; - u32 data_len = ntoh32(e->datalen); - u8 *data_ptr = NULL; - u32 tot_len = 0; - - - WL_SD(("Enter event_type:%d status:%d\n", event, status)); - - if (!wl->sdo) { - WL_ERR(("SDO Not initialized \n")); - return -EINVAL; - } - - if (!(wl->sdo->sd_state & WL_SD_SEARCH_SVC)) { - /* We are not searching for any service. Drop - * any bogus Event - */ - WL_ERR(("Bogus SDO Event. Do nothing.. \n")); - return -1; - } - - mutex_lock(&wl->usr_sync); - - if (ndev == wl_to_prmry_ndev(wl)) - dev = wl->p2p_net; - else - dev = ndev; - - if (event == WLC_E_SERVICE_FOUND) { - - if ((status != WLC_E_STATUS_SUCCESS) && (status != WLC_E_STATUS_PARTIAL)) { - WL_ERR(("WLC_E_SERVICE_FOUND: unknown status \n")); - goto exit; - } - - gas = (wl_event_sd_t *)data; - if (!gas) { - ret = -EINVAL; - goto exit; - } - - bzero(&sdo_hdr, sizeof(sdo_event_t)); - sdo_hdr.freq = wl_cfg80211_channel_to_freq(gas->channel); - sdo_hdr.count = gas->count; - memcpy(sdo_hdr.addr, dst_mac, ETH_ALEN); - data_ptr = (char *)gas->tlv; - tot_len = data_len - (sizeof(wl_event_sd_t) - sizeof(wl_sd_tlv_t)); - - WL_SD(("WLC_E_SERVICE_FOUND "MACDBG" data_len:%d tlv_count:%d \n", - MAC2STRDBG(dst_mac), data_len, sdo_hdr.count)); - - if (tot_len > NLMSG_DEFAULT_SIZE) { - WL_ERR(("size(%u) > %lu not supported \n", tot_len, NLMSG_DEFAULT_SIZE)); - ret = -ENOMEM; - goto exit; - } - - if (wl_genl_send_msg(dev, event, data_ptr, - tot_len, (u8 *)&sdo_hdr, sizeof(sdo_event_t)) < 0) - WL_ERR(("Couldn't send up the NETLINK Event \n")); - else - WL_SD(("GAS event sent up \n")); - } else { - WL_ERR(("Unsupported Event: %d \n", event)); - } - -exit: - mutex_unlock(&wl->usr_sync); - return ret; -} - -s32 wl_cfg80211_DsdOffloadParseProto(char* proto_str, u8* proto) -{ - s32 len = -1; - int i = 0; - - for (i = 0; i < MAX_SDO_PROTO; i++) { - if (strncmp(proto_str, wl_sdo_protos[i].str, strlen(wl_sdo_protos[i].str)) == 0) { - WL_SD(("Matching proto (%d) found \n", wl_sdo_protos[i].val)); - *proto = wl_sdo_protos[i].val; - len = strlen(wl_sdo_protos[i].str); - break; - } - } - return len; -} - -/* - * register to search for a UPnP service - * ./DRIVER P2P_SD_REQ upnp 0x10urn:schemas-upnporg:device:InternetGatewayDevice:1 - * - * Enable discovery - * ./wl p2po_find -*/ -#define UPNP_QUERY_VER_OFFSET 3 -s32 wl_sd_handle_sd_req( - struct net_device *dev, - u8 * buf, - int len) -{ - struct wl_priv *wl = wlcfg_drv_priv; - s32 bssidx = wl_cfgp2p_find_idx(wl, dev); - wl_sd_qr_t *sdreq; - u8 proto = 0; - s32 ret = 0; - u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - u32 tot_len = len + sizeof(wl_sd_qr_t); - u16 version = 0; - - /* Check for the least arg length expected */ - if (!buf || (len < strlen("all"))) { - WL_ERR(("Wrong Arg\n")); - return -EINVAL; - } - - if (tot_len > WLC_IOCTL_MAXLEN) { - WL_ERR(("Length > %lu not supported \n", MAX_QR_LEN)); - return -EINVAL; - } - - sdreq = kzalloc(tot_len, kflags); - if (!sdreq) { - WL_ERR(("malloc failed\n")); - return -ENOMEM; - } - - WL_SD(("%s Len: %d\n", buf, len)); - if ((ret = wl_cfg80211_DsdOffloadParseProto(buf, &proto)) < 0) { - WL_ERR(("Unknown proto \n")); - goto exit; - } - - sdreq->protocol = proto; - buf += ret; - buf++; /* skip the space */ - sdreq->transaction_id = simple_strtoul(buf, NULL, 16); - WL_SD(("transaction_id:%d\n", sdreq->transaction_id)); - buf += sizeof(sdreq->transaction_id); + struct net_device *ndev = NULL; + u32 reason = ntoh32(e->reason); + s8 *msg = NULL; - if (*buf == '\0') { - WL_SD(("No Query present. Proto:%d \n", proto)); - sdreq->query_len = 0; - } else { - buf++; /* skip the space */ - /* UPNP version needs to put as binary val */ - if (sdreq->protocol == SVC_RPOTYPE_UPNP) { - /* Extract UPNP version */ - version = simple_strtoul(buf, NULL, 16); - buf = buf + UPNP_QUERY_VER_OFFSET; - buf[0] = version; - WL_SD(("Upnp version: 0x%x \n", version)); - } - - len = strlen(buf); - WL_SD(("Len after stripping proto: %d Query: %s\n", len, buf)); - /* copy the query part */ - memcpy(sdreq->qrbuf, buf, len); - sdreq->query_len = len; - } - - /* Enable discovery */ - if ((ret = wl_cfgp2p_enable_discovery(wl, dev, NULL, 0)) < 0) { - WL_ERR(("cfgp2p_enable discovery failed")); - goto exit; - } + ndev = cfgdev_to_wlc_ndev(cfgdev, wl); - if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_sd_req_resp", (void*)sdreq, - tot_len, wl->ioctl_buf, WLC_IOCTL_MAXLEN, - bssidx, &wl->ioctl_buf_sync)) < 0) { - WL_ERR(("Find SVC Failed \n")); - goto exit; + switch (reason) { + case WLC_E_TDLS_PEER_DISCOVERED : + msg = " TDLS PEER DISCOVERD "; + break; + case WLC_E_TDLS_PEER_CONNECTED : + msg = " TDLS PEER CONNECTED "; + break; + case WLC_E_TDLS_PEER_DISCONNECTED : + msg = "TDLS PEER DISCONNECTED "; + break; } - - wl->sdo->sd_state |= WL_SD_SEARCH_SVC; - -exit: - kfree(sdreq); - return ret; -} - -s32 wl_sd_handle_sd_cancel_req( - struct net_device *dev, - u8 *buf) -{ - struct wl_priv *wl = wlcfg_drv_priv; - s32 bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE); - - if (wldev_iovar_setbuf_bsscfg(dev, "p2po_sd_cancel", NULL, - 0, wl->ioctl_buf, WLC_IOCTL_SMLEN, - bssidx, &wl->ioctl_buf_sync) < 0) { - WL_ERR(("Cancel SD Failed \n")); - return -EINVAL; + if (msg) { + WL_ERR(("%s: " MACDBG " on %s ndev\n", msg, MAC2STRDBG((u8*)(&e->addr)), + (wl_to_prmry_ndev(wl) == ndev) ? "primary" : "secondary")); } - - wl->sdo->sd_state &= ~WL_SD_SEARCH_SVC; - return 0; -} - -/* - * register a UPnP service to be discovered - * ./wl P2P_SD_SVC_ADD upnp 0x10urn:schemas-upnporg:device:InternetGatewayDevice:1 0x10uu - * id:6859dede-8574-59ab-9332-123456789012::urn:schemas-upnporg:device:InternetGate - * wayDevice:1 -*/ -s32 wl_sd_handle_sd_add_svc( - struct net_device *dev, - u8 * buf, - int len) -{ - struct wl_priv *wl = wlcfg_drv_priv; - s32 bssidx = wl_cfgp2p_find_idx(wl, dev); - wl_sd_qr_t *sdreq; - u8 proto = 0; - u16 version = 0; - s32 ret = 0; - u8 *resp = NULL; - u8 *query = NULL; - u32 tot_len = len + sizeof(wl_sd_qr_t); - u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - - if (!buf || !len) - return -EINVAL; - - WL_SD(("%s Len: %d\n", buf, len)); - if (tot_len > WLC_IOCTL_MAXLEN) { - WL_ERR(("Query-Resp length > %d not supported \n", WLC_IOCTL_MAXLEN)); - return -ENOMEM; - } - - sdreq = kzalloc(tot_len, kflags); - if (!sdreq) { - WL_ERR(("malloc failed\n")); - return -ENOMEM; - } - - if ((ret = wl_cfg80211_DsdOffloadParseProto(buf, &proto)) < 0) { - WL_ERR(("Unknown Proto \n")); - goto exit; - } - - sdreq->protocol = proto; - buf += ret; - - if (*buf == '\0') { - WL_ERR(("No Query Resp pair present \n")); - ret = -EINVAL; - goto exit; - } - - buf++; /* Skip the space */ - len = strlen(buf); - query = strsep((char **)&buf, " "); - if (!query || !buf) { - WL_ERR(("No Query RESP Present\n")); - ret = -EINVAL; - goto exit; - } - resp = buf; - - if (sdreq->protocol == SVC_RPOTYPE_UPNP) { - /* Extract UPNP version */ - version = simple_strtoul(query, NULL, 16); - query = query + UPNP_QUERY_VER_OFFSET; - resp = resp + UPNP_QUERY_VER_OFFSET; - query[0] = version; - resp[0] = version; - WL_SD(("Upnp version: 0x%x \n", version)); - } - - sdreq->query_len = strlen(query); - sdreq->response_len = strlen(buf); - WL_SD(("query:%s len:%u \n", query, sdreq->query_len)); - WL_SD(("resp:%s len:%u \n", buf, sdreq->response_len)); - - memcpy(sdreq->qrbuf, query, sdreq->query_len); - memcpy((sdreq->qrbuf + sdreq->query_len), resp, sdreq->response_len); - - /* Enable discovery */ - if ((ret = wl_cfgp2p_enable_discovery(wl, dev, NULL, 0)) < 0) { - WL_ERR(("cfgp2p_enable discovery failed")); - goto exit; - } - - if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_addsvc", (void*)sdreq, - tot_len, wl->ioctl_buf, WLC_IOCTL_MAXLEN, - bssidx, &wl->ioctl_buf_sync)) < 0) { - WL_ERR(("FW Failed in doing p2po_addsvc. RET:%d \n", ret)); - goto exit; - } - wl->sdo->sd_state |= WL_SD_ADV_SVC; - -exit: - kfree(sdreq); - return ret; } +#endif /* WLTDLS */ -s32 wl_sd_handle_sd_del_svc( - struct net_device *dev, - u8 * buf, - int len) +#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || 0 +static s32 +wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, + u8 *peer, enum nl80211_tdls_operation oper) { - struct wl_priv *wl = wlcfg_drv_priv; - s32 bssidx = wl_cfgp2p_find_idx(wl, dev); - wl_sd_qr_t *sdreq; - u8 proto = 0; s32 ret = 0; - u32 tot_len = len + sizeof(wl_sd_qr_t); - u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - u16 version = 0; - sdreq = (wl_sd_qr_t *)kzalloc(tot_len, kflags); - if (!sdreq) { - WL_ERR(("malloc failed\n")); - ret = -ENOMEM; - goto exit; - } - - /* Check for the least arg length expected */ - if (buf && len >= strlen("all")) { - WL_DBG(("%s Len: %d\n", buf, len)); - if ((ret = wl_cfg80211_DsdOffloadParseProto(buf, &proto)) < 0) { - WL_ERR(("Unknown Proto \n")); - goto exit; - } - sdreq->protocol = proto; - buf += ret; - - if (*buf == ' ') { - /* Query present */ - buf++; /* Skip the space */ - /* UPNP version needs to put as binary val */ - if (sdreq->protocol == SVC_RPOTYPE_UPNP) { - /* Extract UPNP version */ - version = simple_strtoul(buf, NULL, 16); - buf = buf + UPNP_QUERY_VER_OFFSET; - buf[0] = version; - WL_SD(("Upnp version: 0x%x \n", version)); - } - memcpy(sdreq->qrbuf, buf, strlen(buf)); - sdreq->query_len = strlen(buf); - WL_SD(("Query to be deleted:%s len:%d\n", buf, sdreq->query_len)); - } - } else { - /* ALL */ - proto = 0; - } - - sdreq->protocol = proto; - WL_SD(("Proto: %d \n", proto)); - - if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_delsvc", (void*)sdreq, - tot_len, wl->ioctl_buf, WLC_IOCTL_MAXLEN, - bssidx, &wl->ioctl_buf_sync)) < 0) { - WL_ERR(("FW Failed in doing sd_delsvc. ret=%d \n", ret)); - goto exit; - } - - wl->sdo->sd_state &= ~WL_SD_ADV_SVC; - -exit: - if (sdreq) - kfree(sdreq); - - return ret; -} - -s32 wl_sd_handle_sd_stop_discovery( - struct net_device *dev, - u8 * buf, - int len) -{ +#ifdef WLTDLS struct wl_priv *wl = wlcfg_drv_priv; - s32 bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE); - int ret = 0; - int sdo_pause = 0; - - if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_stop", (void*)&sdo_pause, - sizeof(sdo_pause), wl->ioctl_buf, WLC_IOCTL_SMLEN, - bssidx, &wl->ioctl_buf_sync)) < 0) { - WL_ERR(("p2po_stop Failed :%d\n", ret)); - return -1; - } - - if (wldev_iovar_setint(dev, "mpc", 1) < 0) { - /* Setting of MPC failed */ - WL_ERR(("mpc enabling back failed\n")); - return -1; - } - - /* clear the states */ - wl->sdo->dd_state = WL_DD_STATE_IDLE; - wl_clr_p2p_status(wl, DISC_IN_PROGRESS); - - bzero(&wl->sdo->sd_listen, sizeof(wl_sd_listen_t)); - - /* Remove ESCAN from waking up the host if ofind/olisten is enabled */ - wl_add_remove_eventmsg(dev, WLC_E_ESCAN_RESULT, true); - - return ret; -} - -s32 wl_sd_handle_sd_find( - struct net_device *dev, - u8 * buf, - int len) -{ - struct wl_priv *wl = wlcfg_drv_priv; - s32 bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE); - int ret = 0; - s32 disc_bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE); - vndr_ie_setbuf_t *ie_setbuf; - vndr_ie_t *vndrie; - vndr_ie_buf_t *vndriebuf; - u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - int tot_len = 0; - uint channel = 0; - - u8 p2pie_buf[] = { - 0x09, 0x02, 0x02, 0x00, 0x27, 0x0c, 0x06, 0x05, 0x00, - 0x55, 0x53, 0x04, 0x51, 0x0b, 0x11, 0x05, 0x00, 0x55, - 0x53, 0x04, 0x51, 0x0b - }; - - /* Enable discovery */ - if ((ret = wl_cfgp2p_enable_discovery(wl, dev, NULL, 0)) < 0) { - WL_ERR(("cfgp2p_enable discovery failed")); - return -1; - } - - if (buf && strncmp(buf, "chan=", strlen("chan=")) == 0) { - buf += strlen("chan="); - channel = simple_strtol(buf, NULL, 10); - WL_SD(("listen_chan to be set:%d\n", channel)); - if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_listen_channel", (void*)&channel, - sizeof(channel), wl->ioctl_buf, WLC_IOCTL_SMLEN, - bssidx, &wl->ioctl_buf_sync)) < 0) { - WL_ERR(("p2po_listen_channel Failed :%d\n", ret)); - return -1; - } - } - - tot_len = sizeof(vndr_ie_setbuf_t) + sizeof(p2pie_buf); - ie_setbuf = (vndr_ie_setbuf_t *) kzalloc(tot_len, kflags); - if (!ie_setbuf) { - WL_ERR(("IE memory alloc failed\n")); - return -ENOMEM; - } - - /* Apply the p2p_ie for p2po_find */ - strcpy(ie_setbuf->cmd, "add"); - - vndriebuf = &ie_setbuf->vndr_ie_buffer; - vndriebuf->iecount = htod32(1); - vndriebuf->vndr_ie_list[0].pktflag = htod32(16); - - vndrie = &vndriebuf->vndr_ie_list[0].vndr_ie_data; - - vndrie->id = (uchar) DOT11_MNG_PROPR_ID; - vndrie->len = sizeof(p2pie_buf); - memcpy(vndrie->oui, WFA_OUI, WFA_OUI_LEN); - memcpy(vndrie->data, p2pie_buf, sizeof(p2pie_buf)); - - /* Remove ESCAN from waking up the host if SDO is enabled */ - wl_add_remove_eventmsg(dev, WLC_E_ESCAN_RESULT, false); - - if (wldev_iovar_setbuf_bsscfg(dev, "ie", (void*)ie_setbuf, - tot_len, wl->ioctl_buf, WLC_IOCTL_SMLEN, - disc_bssidx, &wl->ioctl_buf_sync) < 0) { - WL_ERR(("p2p add_ie failed \n")); - ret = -EINVAL; - goto exit; - } else - WL_SD(("p2p add_ie applied successfully len:%d \n", tot_len)); - - if (wldev_iovar_setint(dev, "mpc", 0) < 0) { - /* Setting of MPC failed */ - WL_ERR(("mpc disabling faild\n")); - ret = -1; - goto exit; + tdls_iovar_t info; + dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); + memset(&info, 0, sizeof(tdls_iovar_t)); + if (peer) + memcpy(&info.ea, peer, ETHER_ADDR_LEN); + switch (oper) { + case NL80211_TDLS_DISCOVERY_REQ: + if (!dhd->tdls_enable) + ret = dhd_tdls_enable_disable(dhd, 1); + if (ret < 0) + return ret; + info.mode = TDLS_MANUAL_EP_DISCOVERY; + break; + case NL80211_TDLS_SETUP: + info.mode = TDLS_MANUAL_EP_CREATE; + break; + case NL80211_TDLS_TEARDOWN: + info.mode = TDLS_MANUAL_EP_DELETE; + break; + default: + WL_ERR(("Unsupported operation : %d\n", oper)); + goto out; } - - if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_find", NULL, 0, - wl->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &wl->ioctl_buf_sync)) < 0) { - WL_ERR(("p2po_find Failed :%d\n", ret)); - ret = -1; - goto exit; + ret = wldev_iovar_setbuf(dev, "tdls_endpoint", &info, sizeof(info), + wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync); + if (ret) { + WL_ERR(("tdls_endpoint error %d\n", ret)); } - - /* set the states */ - wl->sdo->dd_state = WL_DD_STATE_SEARCH; - wl_set_p2p_status(wl, DISC_IN_PROGRESS); - -exit: - if (ie_setbuf) - kfree(ie_setbuf); - - /* Incase of failure enable back the ESCAN event */ - if (ret) - wl_add_remove_eventmsg(dev, WLC_E_ESCAN_RESULT, true); - +out: +#endif /* WLTDLS */ return ret; } +#endif -s32 wl_sd_handle_sd_listen( - struct net_device *dev, - u8 *buf, - int len) -{ - struct wl_priv *wl = wlcfg_drv_priv; - s32 bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE); - wl_sd_listen_t sd_listen; - int ret = 0; - u8 * ptr = NULL; - uint channel = 0; - - /* Just in case if it is not enabled */ - if ((ret = wl_cfgp2p_enable_discovery(wl, dev, NULL, 0)) < 0) { - WL_ERR(("cfgp2p_enable discovery failed")); - return -1; - } - - if (wldev_iovar_setint(dev, "mpc", 0) < 0) { - /* Setting of MPC failed */ - WL_ERR(("mpc disabling faild\n")); - return -1; - } - - bzero(&sd_listen, sizeof(wl_sd_listen_t)); - - if (len) { - ptr = strsep((char **)&buf, " "); - if (ptr == NULL) { - /* period and duration given wrongly */ - WL_ERR(("Arguments in wrong format \n")); - return -EINVAL; - } - else if (strncmp(ptr, "chan=", strlen("chan=")) == 0) { - sd_listen.interval = 65535; - sd_listen.period = 65535; - ptr += strlen("chan="); - channel = simple_strtol(ptr, NULL, 10); - } - else { - sd_listen.period = simple_strtol(ptr, NULL, 10); - ptr = strsep((char **)&buf, " "); - sd_listen.interval = simple_strtol(ptr, NULL, 10); - if (buf && strncmp(buf, "chan=", strlen("chan=")) == 0) { - buf += strlen("chan="); - channel = simple_strtol(buf, NULL, 10); - } - } - WL_SD(("listen_period:%d, listen_interval:%d and listen_channel:%d\n", - sd_listen.period, sd_listen.interval, channel)); - } - if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_listen_channel", (void*)&channel, - sizeof(channel), wl->ioctl_buf, WLC_IOCTL_SMLEN, - bssidx, &wl->ioctl_buf_sync)) < 0) { - WL_ERR(("p2po_listen_channel Failed :%d\n", ret)); - return -1; - } - - WL_SD(("p2po_listen period:%d interval:%d \n", - sd_listen.period, sd_listen.interval)); - if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_listen", (void*)&sd_listen, - sizeof(wl_sd_listen_t), wl->ioctl_buf, WLC_IOCTL_SMLEN, - bssidx, &wl->ioctl_buf_sync)) < 0) { - WL_ERR(("p2po_listen Failed :%d\n", ret)); - return -1; - } - - /* Remove ESCAN from waking up the host if ofind/olisten is enabled */ - wl_add_remove_eventmsg(dev, WLC_E_ESCAN_RESULT, false); - - /* Store the extended listen values for use in sdo_resume */ - wl->sdo->sd_listen.interval = sd_listen.interval; - wl->sdo->sd_listen.period = sd_listen.period; - - /* set the states */ - wl->sdo->dd_state = WL_DD_STATE_LISTEN; - wl_set_p2p_status(wl, DISC_IN_PROGRESS); - - return 0; -} - -s32 wl_cfg80211_sd_offload(struct net_device *dev, char *cmd, char* buf, int len) -{ - int ret = 0; - struct wl_priv *wl = wlcfg_drv_priv; - - WL_SD(("Entry cmd:%s arg_len:%d \n", cmd, len)); - - if (!wl->sdo) { - WL_SD(("Initializing SDO \n")); - if ((ret = wl_cfg80211_sdo_init(wl)) < 0) - goto exit; - } - - if (strncmp(cmd, "P2P_SD_REQ", strlen("P2P_SD_REQ")) == 0) { - ret = wl_sd_handle_sd_req(dev, buf, len); - } else if (strncmp(cmd, "P2P_SD_CANCEL_REQ", strlen("P2P_SD_CANCEL_REQ")) == 0) { - ret = wl_sd_handle_sd_cancel_req(dev, buf); - } else if (strncmp(cmd, "P2P_SD_SVC_ADD", strlen("P2P_SD_SVC_ADD")) == 0) { - ret = wl_sd_handle_sd_add_svc(dev, buf, len); - } else if (strncmp(cmd, "P2P_SD_SVC_DEL", strlen("P2P_SD_SVC_DEL")) == 0) { - ret = wl_sd_handle_sd_del_svc(dev, buf, len); - } else if (strncmp(cmd, "P2P_SD_FIND", strlen("P2P_SD_FIND")) == 0) { - ret = wl_sd_handle_sd_find(dev, buf, len); - } else if (strncmp(cmd, "P2P_SD_LISTEN", strlen("P2P_SD_LISTEN")) == 0) { - ret = wl_sd_handle_sd_listen(dev, buf, len); - } else if (strncmp(cmd, "P2P_SD_STOP", strlen("P2P_STOP")) == 0) { - ret = wl_sd_handle_sd_stop_discovery(dev, buf, len); - } else { - WL_ERR(("Request for Unsupported CMD:%s \n", buf)); - ret = -EINVAL; - } - -exit: - return ret; -} -#endif /* WL_SDO */ s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *net, char *buf, int len, enum wl_management_type type) { @@ -10767,14 +10731,16 @@ s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *net, char *buf, int len, s32 pktflag = 0; wl = wlcfg_drv_priv; - if (wl_get_drv_status(wl, AP_CREATING, net) || - wl_get_drv_status(wl, AP_CREATED, net)) { + if (wl_get_drv_status(wl, AP_CREATING, net)) { + /* Vendor IEs should be set to FW + * after SoftAP interface is brought up + */ + goto exit; + } else if (wl_get_drv_status(wl, AP_CREATED, net)) { ndev = net; bssidx = 0; } else if (wl->p2p) { - if (net == wl->p2p_net) { - net = wl_to_prmry_ndev(wl); - } + net = ndev_to_wlc_ndev(net, wl); if (!wl->p2p->on) { get_primary_mac(wl, &primary_mac); wl_cfgp2p_generate_bss_mac(&primary_mac, &wl->p2p->dev_addr, @@ -10989,7 +10955,7 @@ wl_cfg80211_get_best_channel(struct net_device *ndev, void *buf, int buflen, retry = CHAN_SEL_RETRY_COUNT; while (retry--) { - bcm_mdelay(CHAN_SEL_IOCTL_DELAY); + OSL_SLEEP(CHAN_SEL_IOCTL_DELAY); ret = wldev_ioctl(ndev, WLC_GET_CHANNEL_SEL, &chosen, sizeof(chosen), false); @@ -11191,6 +11157,128 @@ err_out: return err; } +#ifdef DEBUGFS_CFG80211 +/** +* Format : echo "SCAN:1 DBG:1" > /sys/kernel/debug/dhd/debug_level +* to turn on SCAN and DBG log. +* To turn off SCAN partially, echo "SCAN:0" > /sys/kernel/debug/dhd/debug_level +* To see current setting of debug level, +* cat /sys/kernel/debug/dhd/debug_level +*/ +static ssize_t +wl_debuglevel_write(struct file *file, const char __user *userbuf, + size_t count, loff_t *ppos) +{ + char tbuf[S_SUBLOGLEVEL * ARRAYSIZE(sublogname_map)], sublog[S_SUBLOGLEVEL]; + char *params, *token, *colon; + uint i, tokens, log_on = 0; + memset(tbuf, 0, sizeof(tbuf)); + memset(sublog, 0, sizeof(sublog)); + if (copy_from_user(&tbuf, userbuf, min_t(size_t, sizeof(tbuf), count))) + return -EFAULT; + + params = &tbuf[0]; + colon = strchr(params, '\n'); + if (colon != NULL) + *colon = '\0'; + while ((token = strsep(¶ms, " ")) != NULL) { + memset(sublog, 0, sizeof(sublog)); + if (token == NULL || !*token) + break; + if (*token == '\0') + continue; + colon = strchr(token, ':'); + if (colon != NULL) { + *colon = ' '; + } + tokens = sscanf(token, "%s %u", sublog, &log_on); + if (colon != NULL) + *colon = ':'; + + if (tokens == 2) { + for (i = 0; i < ARRAYSIZE(sublogname_map); i++) { + if (!strncmp(sublog, sublogname_map[i].sublogname, + strlen(sublogname_map[i].sublogname))) { + if (log_on) + wl_dbg_level |= + (sublogname_map[i].log_level); + else + wl_dbg_level &= + ~(sublogname_map[i].log_level); + } + } + } else + WL_ERR(("%s: can't parse '%s' as a " + "SUBMODULE:LEVEL (%d tokens)\n", + tbuf, token, tokens)); + + + } + return count; +} + +static ssize_t +wl_debuglevel_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + char *param; + char tbuf[S_SUBLOGLEVEL * ARRAYSIZE(sublogname_map)]; + uint i; + memset(tbuf, 0, sizeof(tbuf)); + param = &tbuf[0]; + for (i = 0; i < ARRAYSIZE(sublogname_map); i++) { + param += snprintf(param, sizeof(tbuf) - 1, "%s:%d ", + sublogname_map[i].sublogname, + (wl_dbg_level & sublogname_map[i].log_level) ? 1 : 0); + } + *param = '\n'; + return simple_read_from_buffer(user_buf, count, ppos, tbuf, strlen(&tbuf[0])); + +} +static const struct file_operations fops_debuglevel = { + .open = NULL, + .write = wl_debuglevel_write, + .read = wl_debuglevel_read, + .owner = THIS_MODULE, + .llseek = NULL, +}; + +static s32 wl_setup_debugfs(struct wl_priv *wl) +{ + s32 err = 0; + struct dentry *_dentry; + if (!wl) + return -EINVAL; + wl->debugfs = debugfs_create_dir(KBUILD_MODNAME, NULL); + if (!wl->debugfs || IS_ERR(wl->debugfs)) { + if (wl->debugfs == ERR_PTR(-ENODEV)) + WL_ERR(("Debugfs is not enabled on this kernel\n")); + else + WL_ERR(("Can not create debugfs directory\n")); + wl->debugfs = NULL; + goto exit; + + } + _dentry = debugfs_create_file("debug_level", S_IRUSR | S_IWUSR, + wl->debugfs, wl, &fops_debuglevel); + if (!_dentry || IS_ERR(_dentry)) { + WL_ERR(("failed to create debug_level debug file\n")); + wl_free_debugfs(wl); + } +exit: + return err; +} +static s32 wl_free_debugfs(struct wl_priv *wl) +{ + if (!wl) + return -EINVAL; + if (wl->debugfs) + debugfs_remove_recursive(wl->debugfs); + wl->debugfs = NULL; + return 0; +} +#endif /* DEBUGFS_CFG80211 */ + struct device *wl_cfg80211_get_parent_dev(void) { return cfg80211_parent_dev; @@ -11206,12 +11294,25 @@ static void wl_cfg80211_clear_parent_dev(void) cfg80211_parent_dev = NULL; } -static void get_primary_mac(struct wl_priv *wl, struct ether_addr *mac) +void get_primary_mac(struct wl_priv *wl, struct ether_addr *mac) { wldev_iovar_getbuf_bsscfg(wl_to_prmry_ndev(wl), "cur_etheraddr", NULL, 0, wl->ioctl_buf, WLC_IOCTL_SMLEN, 0, &wl->ioctl_buf_sync); memcpy(mac->octet, wl->ioctl_buf, ETHER_ADDR_LEN); } +static bool check_dev_role_integrity(struct wl_priv *wl, u32 dev_role) +{ + dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); + if (((dev_role == NL80211_IFTYPE_AP) && + !(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) || + ((dev_role == NL80211_IFTYPE_P2P_GO) && + !(dhd->op_mode & DHD_FLAG_P2P_GO_MODE))) + { + WL_ERR(("device role select failed\n")); + return false; + } + return true; +} int wl_cfg80211_do_driver_init(struct net_device *net) { @@ -11237,7 +11338,7 @@ void wl_cfg80211_enable_trace(bool set, u32 level) 2, 0)) static s32 wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, - struct net_device *dev, u64 cookie) + bcm_struct_cfgdev *cfgdev, u64 cookie) { /* CFG80211 checks for tx_cancel_wait callback when ATTR_DURATION * is passed with CMD_FRAME. This callback is supposed to cancel @@ -11249,192 +11350,79 @@ wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, } #endif /* WL_SUPPORT_BACKPORTED_PATCHES || KERNEL >= 3.2.0 */ -#ifdef WL11U -bcm_tlv_t * -wl_cfg80211_find_interworking_ie(u8 *parse, u32 len) -{ - bcm_tlv_t *ie; - while ((ie = bcm_parse_tlvs(parse, (u32)len, DOT11_MNG_INTERWORKING_ID))) { - return (bcm_tlv_t *)ie; - } - return NULL; -} -static s32 -wl_cfg80211_add_iw_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssidx, s32 pktflag, - uint8 ie_id, uint8 *data, uint8 data_len) +static void wl_cfg80211_work_handler(struct work_struct * work) { + struct wl_priv *wl = NULL; + struct net_info *iter, *next; s32 err = BCME_OK; - s32 buf_len; - s32 iecount; - ie_setbuf_t *ie_setbuf; - - if (ie_id != DOT11_MNG_INTERWORKING_ID) - return BCME_UNSUPPORTED; - - /* Validate the pktflag parameter */ - if ((pktflag & ~(VNDR_IE_BEACON_FLAG | VNDR_IE_PRBRSP_FLAG | - VNDR_IE_ASSOCRSP_FLAG | VNDR_IE_AUTHRSP_FLAG | - VNDR_IE_PRBREQ_FLAG | VNDR_IE_ASSOCREQ_FLAG| - VNDR_IE_CUSTOM_FLAG))) { - WL_ERR(("cfg80211 Add IE: Invalid packet flag 0x%x\n", pktflag)); - return -1; - } - - /* use VNDR_IE_CUSTOM_FLAG flags for none vendor IE . currently fixed value */ - pktflag = htod32(pktflag); - - buf_len = sizeof(ie_setbuf_t) + data_len - 1; - ie_setbuf = (ie_setbuf_t *) kzalloc(buf_len, GFP_KERNEL); - - if (!ie_setbuf) { - WL_ERR(("Error allocating buffer for IE\n")); - return -ENOMEM; - } - - if (wl->iw_ie_len == data_len && !memcmp(wl->iw_ie, data, data_len)) { - WL_ERR(("Previous IW IE is equals to current IE\n")); - err = BCME_OK; - goto exit; - } - - strncpy(ie_setbuf->cmd, "add", VNDR_IE_CMD_LEN - 1); - ie_setbuf->cmd[VNDR_IE_CMD_LEN - 1] = '\0'; - - /* Buffer contains only 1 IE */ - iecount = htod32(1); - memcpy((void *)&ie_setbuf->ie_buffer.iecount, &iecount, sizeof(int)); - memcpy((void *)&ie_setbuf->ie_buffer.ie_list[0].pktflag, &pktflag, sizeof(uint32)); - - /* Now, add the IE to the buffer */ - ie_setbuf->ie_buffer.ie_list[0].ie_data.id = ie_id; - - /* if already set with previous values, delete it first */ - if (wl->iw_ie_len != 0) { - WL_DBG(("Different IW_IE was already set. clear first\n")); - - ie_setbuf->ie_buffer.ie_list[0].ie_data.len = 0; - - err = wldev_iovar_setbuf_bsscfg(ndev, "ie", ie_setbuf, buf_len, - wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync); - - if (err != BCME_OK) - goto exit; - } - - ie_setbuf->ie_buffer.ie_list[0].ie_data.len = data_len; - memcpy((uchar *)&ie_setbuf->ie_buffer.ie_list[0].ie_data.data[0], data, data_len); - - err = wldev_iovar_setbuf_bsscfg(ndev, "ie", ie_setbuf, buf_len, - wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync); - - if (err == BCME_OK) { - memcpy(wl->iw_ie, data, data_len); - wl->iw_ie_len = data_len; - wl->wl11u = TRUE; - - err = wldev_iovar_setint_bsscfg(ndev, "grat_arp", 1, bssidx); - } - -exit: - if (ie_setbuf) - kfree(ie_setbuf); - return err; -} -#endif /* WL11U */ - -#ifdef WL_HOST_BAND_MGMT -s32 -wl_cfg80211_set_band(struct net_device *ndev, int band) -{ - struct wl_priv *wl = wlcfg_drv_priv; - int ret = 0; - char ioctl_buf[50]; - - if ((band < WLC_BAND_AUTO) || (band > WLC_BAND_2G)) { - WL_ERR(("Invalid band\n")); - return -EINVAL; - } + s32 pm = PM_FAST; - if ((ret = wldev_iovar_setbuf(ndev, "roam_band", &band, - sizeof(int), ioctl_buf, sizeof(ioctl_buf), NULL)) < 0) { - WL_ERR(("seting roam_band failed code=%d\n", ret)); - return ret; + wl = container_of(work, struct wl_priv, pm_enable_work.work); + WL_DBG(("Enter \n")); + if (wl->pm_enable_work_on) { + wl->pm_enable_work_on = false; + for_each_ndev(wl, iter, next) { + if (!wl_get_drv_status(wl, CONNECTED, iter->ndev) || + (wl_get_mode_by_netdev(wl, iter->ndev) != WL_MODE_BSS)) + continue; + if (iter->ndev) { + if ((err = wldev_ioctl(iter->ndev, WLC_SET_PM, + &pm, sizeof(pm), true)) != 0) { + if (err == -ENODEV) + WL_DBG(("%s:netdev not ready\n", iter->ndev->name)); + else + WL_ERR(("%s:error (%d)\n", iter->ndev->name, err)); + } else + iter->ndev->ieee80211_ptr->ps = true; + } + } } - - WL_DBG(("Setting band to %d\n", band)); - wl->curr_band = band; - - return 0; } -#endif /* WL_HOST_BAND_MGMT */ -#if defined(DHCP_SCAN_SUPPRESS) -static void wl_cfg80211_scan_supp_timerfunc(ulong data) +u8 +wl_get_action_category(void *frame, u32 frame_len) { - struct wl_priv *wl = (struct wl_priv *)data; - - WL_DBG(("Enter \n")); - schedule_work(&wl->wlan_work); + u8 category; + u8 *ptr = (u8 *)frame; + if (frame == NULL) + return DOT11_ACTION_CAT_ERR_MASK; + if (frame_len < DOT11_ACTION_HDR_LEN) + return DOT11_ACTION_CAT_ERR_MASK; + category = ptr[DOT11_ACTION_CAT_OFF]; + WL_INFO(("Action Category: %d\n", category)); + return category; } -static void wl_cfg80211_work_handler(struct work_struct *work) +int +wl_get_public_action(void *frame, u32 frame_len, u8 *ret_action) { - struct wl_priv *wl = wlcfg_drv_priv; - - wl = container_of(work, struct wl_priv, wlan_work); - - if (!wl) { - WL_ERR(("wl_priv ptr NULL\n")); - return; - } - - if (wl->scan_suppressed) { - /* There is pending scan_suppress. Clean it */ - WL_ERR(("Clean up from timer after %d msec\n", WL_SCAN_SUPPRESS_TIMEOUT)); - wl_cfg80211_scan_suppress(wl_to_prmry_ndev(wl), 0); - } + u8 *ptr = (u8 *)frame; + if (frame == NULL || ret_action == NULL) + return BCME_ERROR; + if (frame_len < DOT11_ACTION_HDR_LEN) + return BCME_ERROR; + if (DOT11_ACTION_CAT_PUBLIC != wl_get_action_category(frame, frame_len)) + return BCME_ERROR; + *ret_action = ptr[DOT11_ACTION_ACT_OFF]; + WL_INFO(("Public Action : %d\n", *ret_action)); + return BCME_OK; } - -int wl_cfg80211_scan_suppress(struct net_device *dev, int suppress) +#ifdef BCMCCX_S69 +static s32 +wl_ccx_s69_response(struct wl_priv *wl, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data) { - struct wl_priv *wl = wlcfg_drv_priv; - int ret = 0; - - if (!dev || !wl || ((suppress != 0) && (suppress != 1))) - return -EINVAL; - - if (suppress == wl->scan_suppressed) { - WL_DBG(("No change in scan_suppress state. Ignoring cmd..\n")); - return 0; - } - - if (timer_pending(&wl->scan_supp_timer)) - del_timer_sync(&wl->scan_supp_timer); - - if ((ret = wldev_ioctl(dev, WLC_SET_SCANSUPPRESS, - &suppress, sizeof(int), true)) < 0) { - WL_ERR(("Scan suppress setting failed ret:%d \n", ret)); - } else { - WL_DBG(("Scan suppress %s \n", suppress ? "Enabled" : "Disabled")); - wl->scan_suppressed = suppress; - } + struct net_device *ndev = NULL; + u32 event = ntoh32(e->event_type); + u32 datalen = ntoh32(e->datalen); + s32 err; - /* If scan_suppress is set, Start a timer to monitor it (just incase) */ - if (wl->scan_suppressed) { - if (ret) { - WL_ERR(("Retry scan_suppress reset at a later time \n")); - mod_timer(&wl->scan_supp_timer, - jiffies + msecs_to_jiffies(WL_SCAN_SUPPRESS_RETRY)); - } else { - WL_DBG(("Start wlan_timer to clear of scan_suppress \n")); - mod_timer(&wl->scan_supp_timer, - jiffies + msecs_to_jiffies(WL_SCAN_SUPPRESS_TIMEOUT)); - } - } + ndev = cfgdev_to_wlc_ndev(cfgdev, wl); + err = wl_genl_send_msg(ndev, event, data, (u16)datalen, 0, 0); - return ret; + return err; } -#endif /* DHCP_SCAN_SUPPRESS */ +#endif /* BCMCCX_S69 */ diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.h b/drivers/net/wireless/bcmdhd/wl_cfg80211.h index b18c1c1adc76..4ea4b8273d36 100644..100755 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.h +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.h @@ -1,7 +1,7 @@ /* * Linux cfg80211 driver * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -21,7 +21,7 @@ * 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: wl_cfg80211.h 382747 2013-02-04 07:09:23Z $ + * $Id: wl_cfg80211.h 431563 2013-10-24 01:50:16Z $ */ #ifndef _wl_cfg80211_h_ @@ -138,7 +138,7 @@ do { \ #define WL_SCAN_IE_LEN_MAX 2048 #define WL_BSS_INFO_MAX 2048 #define WL_ASSOC_INFO_MAX 512 -#define WL_IOCTL_LEN_MAX 1024 +#define WL_IOCTL_LEN_MAX 2048 #define WL_EXTRA_BUF_MAX 2048 #define WL_ISCAN_BUF_MAX 2048 #define WL_ISCAN_TIMER_INTERVAL_MS 3000 @@ -146,7 +146,7 @@ do { \ #define WL_AP_MAX 256 #define WL_FILE_NAME_MAX 256 #define WL_DWELL_TIME 200 -#define WL_MED_DWELL_TIME 400 +#define WL_MED_DWELL_TIME 400 #define WL_MIN_DWELL_TIME 100 #define WL_LONG_DWELL_TIME 1000 #define IFACE_MAX_CNT 2 @@ -156,19 +156,24 @@ do { \ #define WL_SCAN_JOIN_PASSIVE_DWELL_TIME_MS 400 #define WL_AF_TX_MAX_RETRY 5 -#define WL_SCAN_TIMER_INTERVAL_MS 8000 /* Scan timeout */ +#define WL_AF_SEARCH_TIME_MAX 450 +#define WL_AF_TX_EXTRA_TIME_MAX 200 + +#define WL_SCAN_TIMER_INTERVAL_MS 10000 /* Scan timeout */ #define WL_CHANNEL_SYNC_RETRY 5 #define WL_INVALID -1 /* Bring down SCB Timeout to 20secs from 60secs default */ #ifndef WL_SCB_TIMEOUT -#define WL_SCB_TIMEOUT 20 +#define WL_SCB_TIMEOUT 20 #endif /* SCAN_SUPPRESS timer values in ms */ #define WL_SCAN_SUPPRESS_TIMEOUT 31000 /* default Framwork DHCP timeout is 30 sec */ #define WL_SCAN_SUPPRESS_RETRY 3000 +#define WL_PM_ENABLE_TIMEOUT 10000 + /* driver status */ enum wl_status { WL_STATUS_READY = 0, @@ -251,6 +256,14 @@ enum wl_management_type { WL_PROBE_RESP = 0x2, WL_ASSOC_RESP = 0x4 }; + +enum wl_handler_del_type { + WL_HANDLER_NOTUSE, + WL_HANDLER_DEL, + WL_HANDLER_MAINTAIN, + WL_HANDLER_PEND +}; + /* beacon / probe_response */ struct beacon_proberesp { __le64 timestamp; @@ -269,8 +282,8 @@ struct wl_conf { struct ieee80211_channel channel; }; -typedef s32(*EVENT_HANDLER) (struct wl_priv *wl, - struct net_device *ndev, const wl_event_msg_t *e, void *data); +typedef s32(*EVENT_HANDLER) (struct wl_priv *wl, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data); /* bss inform structure for cfg80211 interface */ struct wl_cfg80211_bss_info { @@ -400,7 +413,7 @@ struct escan_info { #if defined(STATIC_WL_PRIV_STRUCT) #ifndef CONFIG_DHD_USE_STATIC_BUF #error STATIC_WL_PRIV_STRUCT should be used with CONFIG_DHD_USE_STATIC_BUF -#endif +#endif /* CONFIG_DHD_USE_STATIC_BUF */ u8 *escan_buf; #else u8 escan_buf[ESCAN_BUF_SIZE]; @@ -466,55 +479,6 @@ struct parsed_ies { u32 wpa2_ie_len; }; -#ifdef WL_SDO -/* Service discovery */ -typedef struct { - uint8 transaction_id; /* Transaction ID */ - uint8 protocol; /* Service protocol type */ - uint16 query_len; /* Length of query */ - uint16 response_len; /* Length of response */ - uint8 qrbuf[1]; -} wl_sd_qr_t; - -typedef struct { - uint16 period; /* extended listen period */ - uint16 interval; /* extended listen interval */ -} wl_sd_listen_t; - -#define WL_SD_STATE_IDLE 0x0000 -#define WL_SD_SEARCH_SVC 0x0001 -#define WL_SD_ADV_SVC 0x0002 - -enum wl_dd_state { - WL_DD_STATE_IDLE, - WL_DD_STATE_SEARCH, - WL_DD_STATE_LISTEN -}; - -#define MAX_SDO_PROTO_STR_LEN 20 -typedef struct wl_sdo_proto { - char str[MAX_SDO_PROTO_STR_LEN]; - u32 val; -} wl_sdo_proto_t; - -typedef struct sd_offload { - u32 sd_state; - enum wl_dd_state dd_state; - wl_sd_listen_t sd_listen; -} sd_offload_t; - -typedef struct sdo_event { - u8 addr[ETH_ALEN]; - uint16 freq; /* channel Freq */ - uint8 count; /* Tlv count */ - uint16 update_ind; -} sdo_event_t; -#endif /* WL_SDO */ - -#ifdef WL11U -/* Max length of Interworking element */ -#define IW_IES_MAX_BUF_LEN 9 -#endif #define MAX_EVENT_BUF_NUM 16 typedef struct wl_eventmsg_buf { @@ -530,6 +494,7 @@ struct wl_priv { struct wireless_dev *wdev; /* representing wl cfg80211 device */ struct wireless_dev *p2p_wdev; /* representing wl cfg80211 device for P2P */ + struct net_device *p2p_net; /* reference to p2p0 interface */ struct wl_conf *conf; @@ -562,7 +527,9 @@ struct wl_priv { #else struct wl_connect_info conn_info; #endif - +#ifdef DEBUGFS_CFG80211 + struct dentry *debugfs; +#endif /* DEBUGFS_CFG80211 */ struct wl_pmk_list *pmk_list; /* wpa2 pmk list */ tsk_ctl_t event_tsk; /* task of main event handler thread */ void *pub; @@ -589,7 +556,7 @@ struct wl_priv { bool wlfc_on; bool vsdb_mode; bool roamoff_on_concurrent; - u8 *ioctl_buf; /* ioctl buffer */ + u8 *ioctl_buf; /* ioctl buffer */ struct mutex ioctl_buf_sync; u8 *escan_ioctl_buf; u8 *extra_buf; /* maily to grab assoc information */ @@ -613,25 +580,19 @@ struct wl_priv { struct net_info *_net_info, enum wl_status state, bool set); unsigned long interrested_state; wlc_ssid_t hostapd_ssid; -#ifdef WL_SDO - sd_offload_t *sdo; -#endif -#ifdef WL11U - bool wl11u; - u8 iw_ie[IW_IES_MAX_BUF_LEN]; - u32 iw_ie_len; -#endif /* WL11U */ bool sched_scan_running; /* scheduled scan req status */ #ifdef WL_SCHED_SCAN struct cfg80211_sched_scan_request *sched_scan_req; /* scheduled scan req */ #endif /* WL_SCHED_SCAN */ -#ifdef WL_HOST_BAND_MGMT - u8 curr_band; -#endif /* WL_HOST_BAND_MGMT */ bool scan_suppressed; struct timer_list scan_supp_timer; struct work_struct wlan_work; struct mutex event_sync; /* maily for up/down synchronization */ + bool pm_enable_work_on; + struct delayed_work pm_enable_work; + vndr_ie_setbuf_t *ibss_vsie; /* keep the VSIE for IBSS */ + int ibss_vsie_len; + }; @@ -726,8 +687,8 @@ wl_set_status_all(struct wl_priv *wl, s32 status, u32 op) return; /* change all status is not allowed */ default: return; /* unknown operation */ - } } + } } static inline void wl_set_status_by_netdev(struct wl_priv *wl, s32 status, @@ -822,7 +783,47 @@ wl_get_netinfo_by_netdev(struct wl_priv *wl, struct net_device *ndev) } #define wl_to_wiphy(w) (w->wdev->wiphy) #define wl_to_prmry_ndev(w) (w->wdev->netdev) +#define wl_to_prmry_wdev(w) (w->wdev) +#define wl_to_p2p_wdev(w) (w->p2p_wdev) #define ndev_to_wl(n) (wdev_to_wl(n->ieee80211_ptr)) +#define ndev_to_wdev(ndev) (ndev->ieee80211_ptr) +#define wdev_to_ndev(wdev) (wdev->netdev) + +#if defined(WL_ENABLE_P2P_IF) +#define ndev_to_wlc_ndev(ndev, wl) ((ndev == wl->p2p_net) ? \ + wl_to_prmry_ndev(wl) : ndev) +#else +#define ndev_to_wlc_ndev(ndev, wl) (ndev) +#endif /* WL_ENABLE_P2P_IF */ + +#if defined(WL_CFG80211_P2P_DEV_IF) +#define wdev_to_wlc_ndev(wdev, wl) \ + ((wdev->iftype == NL80211_IFTYPE_P2P_DEVICE) ? \ + wl_to_prmry_ndev(wl) : wdev_to_ndev(wdev)) +#define cfgdev_to_wlc_ndev(cfgdev, wl) wdev_to_wlc_ndev(cfgdev, wl) +#elif defined(WL_ENABLE_P2P_IF) +#define cfgdev_to_wlc_ndev(cfgdev, wl) ndev_to_wlc_ndev(cfgdev, wl) +#else +#define cfgdev_to_wlc_ndev(cfgdev, wl) (cfgdev) +#endif /* WL_CFG80211_P2P_DEV_IF */ + +#if defined(WL_CFG80211_P2P_DEV_IF) +#define ndev_to_cfgdev(ndev) ndev_to_wdev(ndev) +#else +#define ndev_to_cfgdev(ndev) (ndev) +#endif /* WL_CFG80211_P2P_DEV_IF */ + +#if defined(WL_CFG80211_P2P_DEV_IF) +#define scan_req_match(wl) (((wl) && (wl->scan_request) && \ + (wl->scan_request->wdev == wl->p2p_wdev)) ? true : false) +#elif defined(WL_ENABLE_P2P_IF) +#define scan_req_match(wl) (((wl) && (wl->scan_request) && \ + (wl->scan_request->dev == wl->p2p_net)) ? true : false) +#else +#define scan_req_match(wl) (((wl) && p2p_is_on(wl) && p2p_scan(wl)) ? \ + true : false) +#endif /* WL_CFG80211_P2P_DEV_IF */ + #define wl_to_sr(w) (w->scan_req_int) #if defined(STATIC_WL_PRIV_STRUCT) #define wl_to_ie(w) (w->ie) @@ -842,7 +843,7 @@ wl_get_netinfo_by_netdev(struct wl_priv *wl, struct net_device *ndev) (wl_set_status_by_netdev(wl, WL_STATUS_ ## stat, ndev, 1)) #define wl_clr_drv_status(wl, stat, ndev) \ (wl_set_status_by_netdev(wl, WL_STATUS_ ## stat, ndev, 2)) -#define wl_clr_drv_status_all(wl, stat) \ +#define wl_clr_drv_status_all(wl, stat) \ (wl_set_status_all(wl, WL_STATUS_ ## stat, 2)) #define wl_chg_drv_status(wl, stat, ndev) \ (wl_set_status_by_netdev(wl, WL_STATUS_ ## stat, ndev, 4)) @@ -887,13 +888,6 @@ extern s32 wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len); extern s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *net, char *buf, int len, enum wl_management_type type); extern s32 wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len); -#ifdef WL_SDO -extern s32 wl_cfg80211_sdo_init(struct wl_priv *wl); -extern s32 wl_cfg80211_sdo_deinit(struct wl_priv *wl); -extern s32 wl_cfg80211_sd_offload(struct net_device *net, char *cmd, char* buf, int len); -extern s32 wl_cfg80211_pause_sdo(struct net_device *dev, struct wl_priv *wl); -extern s32 wl_cfg80211_resume_sdo(struct net_device *dev, struct wl_priv *wl); -#endif #ifdef WL_SUPPORT_AUTO_CHANNEL #define CHANSPEC_BUF_SIZE 1024 #define CHAN_SEL_IOCTL_DELAY 300 @@ -915,13 +909,24 @@ extern s32 wl_update_wiphybands(struct wl_priv *wl, bool notify); extern s32 wl_cfg80211_if_is_group_owner(void); extern chanspec_t wl_ch_host_to_driver(u16 channel); extern s32 wl_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add); -extern void wl_stop_wait_next_action_frame(struct wl_priv *wl, struct net_device *ndev); -extern s32 wl_cfg80211_set_band(struct net_device *ndev, int band); +extern void wl_stop_wait_next_action_frame(struct wl_priv *wl); extern int wl_cfg80211_update_power_mode(struct net_device *dev); -#if defined(DHCP_SCAN_SUPPRESS) -extern int wl_cfg80211_scan_suppress(struct net_device *dev, int suppress); -#endif /* OEM_ANDROID */ extern void wl_cfg80211_add_to_eventbuffer(wl_eventmsg_buf_t *ev, u16 event, bool set); extern s32 wl_cfg80211_apply_eventbuffer(struct net_device *ndev, struct wl_priv *wl, wl_eventmsg_buf_t *ev); +extern void get_primary_mac(struct wl_priv *wl, struct ether_addr *mac); +#define SCAN_BUF_CNT 2 +#define SCAN_BUF_NEXT 1 +#define wl_escan_set_sync_id(a, b) ((a) = htod16(0x1234)) +#define wl_escan_get_buf(a, b) ((wl_scan_results_t *) (a)->escan_info.escan_buf) +#define wl_escan_check_sync_id(a, b, c) 0 +#define wl_escan_print_sync_id(a, b, c) +#define wl_escan_increment_sync_id(a, b) +#define wl_escan_init_sync_id(a) +extern void wl_cfg80211_ibss_vsie_set_buffer(vndr_ie_setbuf_t *ibss_vsie, int ibss_vsie_len); +extern s32 wl_cfg80211_ibss_vsie_delete(struct net_device *dev); + +/* Action frame specific functions */ +extern u8 wl_get_action_category(void *frame, u32 frame_len); +extern int wl_get_public_action(void *frame, u32 frame_len, u8 *ret_action); #endif /* _wl_cfg80211_h_ */ diff --git a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c index 2023ede36109..bc5caf1dfbbb 100644..100755 --- a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c +++ b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c @@ -1,14 +1,14 @@ /* * Linux cfgp2p driver * - * Copyright (C) 1999-2012, Broadcom Corporation - * + * Copyright (C) 1999-2013, Broadcom Corporation + * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2 (the "GPL"), * available at http://www.broadcom.com/licenses/GPLv2.php, with the * following added to such license: - * + * * As a special exception, the copyright holders of this software give you * permission to link this software with independent modules, and to copy and * distribute the resulting executable under terms of your choice, provided that @@ -16,12 +16,12 @@ * 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: wl_cfgp2p.c 386294 2013-02-20 05:43:37Z $ + * $Id: wl_cfgp2p.c 432088 2013-10-25 15:02:04Z $ * */ #include <typedefs.h> @@ -53,22 +53,24 @@ static bool wl_cfgp2p_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u8 type); static u32 -wl_cfgp2p_vndr_ie(struct wl_priv *wl, u8 *iebuf, s32 bssidx, s32 pktflag, +wl_cfgp2p_vndr_ie(struct wl_priv *wl, u8 *iebuf, s32 pktflag, s8 *oui, s32 ie_id, s8 *data, s32 datalen, const s8* add_del_cmd); +static s32 wl_cfgp2p_cancel_listen(struct wl_priv *wl, struct net_device *ndev, + struct wireless_dev *wdev, bool notify); +#if defined(WL_ENABLE_P2P_IF) static int wl_cfgp2p_start_xmit(struct sk_buff *skb, struct net_device *ndev); static int wl_cfgp2p_do_ioctl(struct net_device *net, struct ifreq *ifr, int cmd); static int wl_cfgp2p_if_open(struct net_device *net); static int wl_cfgp2p_if_stop(struct net_device *net); -static s32 wl_cfgp2p_cancel_listen(struct wl_priv *wl, struct net_device *ndev, - bool notify); static const struct net_device_ops wl_cfgp2p_if_ops = { - .ndo_open = wl_cfgp2p_if_open, - .ndo_stop = wl_cfgp2p_if_stop, - .ndo_do_ioctl = wl_cfgp2p_do_ioctl, - .ndo_start_xmit = wl_cfgp2p_start_xmit, + .ndo_open = wl_cfgp2p_if_open, + .ndo_stop = wl_cfgp2p_if_stop, + .ndo_do_ioctl = wl_cfgp2p_do_ioctl, + .ndo_start_xmit = wl_cfgp2p_start_xmit, }; +#endif /* WL_ENABLE_P2P_IF */ bool wl_cfgp2p_is_pub_action(void *frame, u32 frame_len) { @@ -109,12 +111,6 @@ bool wl_cfgp2p_is_p2p_action(void *frame, u32 frame_len) return false; } -/* -* Currently Action frame just pass to P2P interface regardless real dst. -* but GAS Action can be used for Hotspot2.0 as well -* Need to distingush that it's for P2P or HS20 -*/ -#ifdef WL11U #define GAS_RESP_LEN 2 #define DOUBLE_TLV_BODY_OFF 4 #define GAS_RESP_OFFSET 4 @@ -146,7 +142,6 @@ bool wl_cfgp2p_find_gas_subtype(u8 subtype, u8* data, u32 len) return false; } -#endif /* WL11U */ bool wl_cfgp2p_is_gas_action(void *frame, u32 frame_len) { @@ -157,27 +152,11 @@ bool wl_cfgp2p_is_gas_action(void *frame, u32 frame_len) return false; sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *)frame; - if (frame_len < sizeof(wifi_p2psd_gas_pub_act_frame_t) - 1) + if (frame_len < (sizeof(wifi_p2psd_gas_pub_act_frame_t) - 1)) return false; if (sd_act_frm->category != P2PSD_ACTION_CATEGORY) return false; -#ifdef WL11U - if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_IRESP) - return wl_cfgp2p_find_gas_subtype(P2PSD_GAS_OUI_SUBTYPE, - (u8 *)sd_act_frm->query_data + GAS_RESP_OFFSET, - frame_len); - - else if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_CRESP) - return wl_cfgp2p_find_gas_subtype(P2PSD_GAS_OUI_SUBTYPE, - (u8 *)sd_act_frm->query_data + GAS_CRESP_OFFSET, - frame_len); - else if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_IREQ || - sd_act_frm->action == P2PSD_ACTION_ID_GAS_CREQ) - return true; - else - return false; -#else if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_IREQ || sd_act_frm->action == P2PSD_ACTION_ID_GAS_IRESP || sd_act_frm->action == P2PSD_ACTION_ID_GAS_CREQ || @@ -185,7 +164,6 @@ bool wl_cfgp2p_is_gas_action(void *frame, u32 frame_len) return true; else return false; -#endif /* WLC11U */ } void wl_cfgp2p_print_actframe(bool tx, void *frame, u32 frame_len, u32 channel) { @@ -360,7 +338,11 @@ wl_cfgp2p_set_firm_p2p(struct wl_priv *wl) s32 ret = BCME_OK; s32 val = 0; /* Do we have to check whether APSTA is enabled or not ? */ - wldev_iovar_getint(ndev, "apsta", &val); + ret = wldev_iovar_getint(ndev, "apsta", &val); + if (ret < 0) { + CFGP2P_ERR(("get apsta error %d\n", ret)); + return ret; + } if (val == 0) { val = 1; ret = wldev_ioctl(ndev, WLC_DOWN, &val, sizeof(s32), true); @@ -428,7 +410,7 @@ wl_cfgp2p_ifadd(struct wl_priv *wl, struct ether_addr *mac, u8 if_type, /* Disable a P2P BSS. * Parameters: - * @mac : MAC address of the BSS to create + * @mac : MAC address of the BSS to disable * Returns 0 if success. */ s32 @@ -449,7 +431,7 @@ wl_cfgp2p_ifdisable(struct wl_priv *wl, struct ether_addr *mac) /* Delete a P2P BSS. * Parameters: - * @mac : MAC address of the BSS to create + * @mac : MAC address of the BSS to delete * Returns 0 if success. */ s32 @@ -566,18 +548,18 @@ wl_cfgp2p_set_p2p_mode(struct wl_priv *wl, u8 mode, u32 channel, u16 listen_ms, struct net_device *dev; CFGP2P_DBG(("enter\n")); - if (unlikely(bssidx == WL_INVALID || bssidx >= P2PAPI_BSSCFG_MAX)) { + if (unlikely(bssidx == WL_INVALID)) { CFGP2P_ERR((" %d index out of range\n", bssidx)); return -1; } - dev = wl_to_p2p_bss_ndev(wl, bssidx); + dev = wl_cfgp2p_find_ndev(wl, bssidx); if (unlikely(dev == NULL)) { CFGP2P_ERR(("bssidx %d is not assigned\n", bssidx)); return BCME_NOTFOUND; } -#ifdef P2P_DISCOVERY_WAR +#if defined(P2P_DISCOVERY_WAR) if (mode == WL_P2P_DISC_ST_LISTEN || mode == WL_P2P_DISC_ST_SEARCH) { if (!wl->p2p->vif_created) { if (wldev_iovar_setint(wl_to_prmry_ndev(wl), "mpc", 0) < 0) { @@ -585,7 +567,7 @@ wl_cfgp2p_set_p2p_mode(struct wl_priv *wl, u8 mode, u32 channel, u16 listen_ms, } } } -#endif +#endif /* defined(P2P_DISCOVERY_WAR) */ /* Put the WL driver into P2P Listen Mode to respond to P2P probe reqs */ discovery_mode.state = mode; @@ -705,8 +687,14 @@ wl_cfgp2p_enable_discovery(struct wl_priv *wl, struct net_device *dev, const u8 *ie, u32 ie_len) { s32 ret = BCME_OK; - s32 bssidx = (wl_to_prmry_ndev(wl) == dev) ? - wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) : wl_cfgp2p_find_idx(wl, dev); + s32 bssidx; + + if (wl_to_prmry_ndev(wl) == dev) { + bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE); + } else if (wl_cfgp2p_find_idx(wl, dev, &bssidx) != BCME_OK) { + WL_ERR(("Find p2p index from dev(%p) failed\n", dev)); + return BCME_ERROR; + } if (wl_get_p2p_status(wl, DISCOVERY_ON)) { CFGP2P_INFO((" DISCOVERY is already initialized, we have nothing to do\n")); goto set_ie; @@ -782,7 +770,8 @@ exit: s32 wl_cfgp2p_escan(struct wl_priv *wl, struct net_device *dev, u16 active, u32 num_chans, u16 *channels, - s32 search_state, u16 action, u32 bssidx, struct ether_addr *tx_dst_addr) + s32 search_state, u16 action, u32 bssidx, struct ether_addr *tx_dst_addr, + p2p_scan_purpose_t p2p_scan_purpose) { s32 ret = BCME_OK; s32 memsize; @@ -809,7 +798,7 @@ wl_cfgp2p_escan(struct wl_priv *wl, struct net_device *dev, u16 active, memsize = sizeof(wl_p2p_scan_t) + eparams_size; memblk = scanparambuf; if (memsize > sizeof(scanparambuf)) { - CFGP2P_ERR((" scanpar buf too small (%u > %u)\n", + CFGP2P_ERR((" scanpar buf too small (%u > %zu)\n", memsize, sizeof(scanparambuf))); return -1; } @@ -821,8 +810,9 @@ wl_cfgp2p_escan(struct wl_priv *wl, struct net_device *dev, u16 active, * because dongle use P2P WILDCARD internally by default */ wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SEARCH, 0, 0, bssidx); - ssid.SSID_len = htod32(0); - + /* use null ssid */ + ssid.SSID_len = 0; + memset(&ssid.SSID, 0, sizeof(ssid.SSID)); } else if (search_state == WL_P2P_DISC_ST_SCAN) { /* SCAN STATE 802.11 SCAN * WFD Supplicant has p2p_find command with (type=progressive, type= full) @@ -830,12 +820,12 @@ wl_cfgp2p_escan(struct wl_priv *wl, struct net_device *dev, u16 active, * we have to set ssid to P2P WILDCARD because * we just do broadcast scan unless setting SSID */ - strncpy(ssid.SSID, WL_P2P_WILDCARD_SSID, sizeof(ssid.SSID) - 1); - ssid.SSID[sizeof(ssid.SSID) - 1] = 0; - ssid.SSID_len = htod32(WL_P2P_WILDCARD_SSID_LEN); wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0, bssidx); - } - else { + /* use wild card ssid */ + ssid.SSID_len = WL_P2P_WILDCARD_SSID_LEN; + memset(&ssid.SSID, 0, sizeof(ssid.SSID)); + memcpy(&ssid.SSID, WL_P2P_WILDCARD_SSID, WL_P2P_WILDCARD_SSID_LEN); + } else { CFGP2P_ERR((" invalid search state %d\n", search_state)); return -1; } @@ -862,26 +852,32 @@ wl_cfgp2p_escan(struct wl_priv *wl, struct net_device *dev, u16 active, eparams->params.home_time = htod32(P2PAPI_SCAN_HOME_TIME_MS); - /* SOCIAL_CHAN_CNT + 1 takes care of the Progressive scan supported by - * the supplicant - */ - if ((num_chans == SOCIAL_CHAN_CNT) || (num_chans == SOCIAL_CHAN_CNT + 1)) - eparams->params.active_time = htod32(P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS); - else if (num_chans == AF_PEER_SEARCH_CNT) - eparams->params.active_time = htod32(P2PAPI_SCAN_AF_SEARCH_DWELL_TIME_MS); - else if (wl_get_drv_status_all(wl, CONNECTED)) - eparams->params.active_time = -1; - else - eparams->params.active_time = htod32(P2PAPI_SCAN_DWELL_TIME_MS); - eparams->params.nprobes = htod32((eparams->params.active_time / - P2PAPI_SCAN_NPROBS_TIME_MS)); + switch (p2p_scan_purpose) { + case P2P_SCAN_SOCIAL_CHANNEL: + eparams->params.active_time = htod32(P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS); + break; + case P2P_SCAN_AFX_PEER_NORMAL: + case P2P_SCAN_AFX_PEER_REDUCED: + eparams->params.active_time = htod32(P2PAPI_SCAN_AF_SEARCH_DWELL_TIME_MS); + break; + case P2P_SCAN_CONNECT_TRY: + eparams->params.active_time = htod32(WL_SCAN_CONNECT_DWELL_TIME_MS); + break; + default : + if (wl_get_drv_status_all(wl, CONNECTED)) + eparams->params.active_time = -1; + else + eparams->params.active_time = htod32(P2PAPI_SCAN_DWELL_TIME_MS); + break; + } - /* Override scan params to find a peer for a connection */ - if (num_chans == 1) { - eparams->params.active_time = htod32(WL_SCAN_CONNECT_DWELL_TIME_MS); + if (p2p_scan_purpose == P2P_SCAN_CONNECT_TRY) eparams->params.nprobes = htod32(eparams->params.active_time / WL_SCAN_JOIN_PROBE_INTERVAL_MS); - } + else + eparams->params.nprobes = htod32((eparams->params.active_time / + P2PAPI_SCAN_NPROBS_TIME_MS)); + if (eparams->params.nprobes <= 0) eparams->params.nprobes = 1; @@ -896,7 +892,7 @@ wl_cfgp2p_escan(struct wl_priv *wl, struct net_device *dev, u16 active, } eparams->version = htod32(ESCAN_REQ_VERSION); eparams->action = htod16(action); - eparams->sync_id = htod16(0x1234); + wl_escan_set_sync_id(eparams->sync_id, wl); CFGP2P_INFO(("SCAN CHANNELS : ")); for (i = 0; i < num_chans; i++) { @@ -927,11 +923,12 @@ wl_cfgp2p_act_frm_search(struct wl_priv *wl, struct net_device *ndev, s32 ret = 0; u32 chan_cnt = 0; u16 *default_chan_list = NULL; + p2p_scan_purpose_t p2p_scan_purpose = P2P_SCAN_AFX_PEER_NORMAL; if (!p2p_is_on(wl) || ndev == NULL || bssidx == WL_INVALID) return -BCME_ERROR; - CFGP2P_ERR((" Enter\n")); - if (bssidx == P2PAPI_BSSCFG_PRIMARY) - bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE); + CFGP2P_DBG((" Enter\n")); + if (bssidx == wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_PRIMARY)) + bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE); if (channel) chan_cnt = AF_PEER_SEARCH_CNT; else @@ -953,9 +950,10 @@ wl_cfgp2p_act_frm_search(struct wl_priv *wl, struct net_device *ndev, default_chan_list[1] = SOCIAL_CHAN_2; default_chan_list[2] = SOCIAL_CHAN_3; } + ret = wl_cfgp2p_escan(wl, ndev, true, chan_cnt, default_chan_list, WL_P2P_DISC_ST_SEARCH, - WL_SCAN_ACTION_START, bssidx, tx_dst_addr); + WL_SCAN_ACTION_START, bssidx, NULL, p2p_scan_purpose); kfree(default_chan_list); exit: return ret; @@ -971,7 +969,9 @@ exit: #define wl_cfgp2p_is_p2p_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \ (const uint8 *)WFA_OUI, WFA_OUI_LEN, WFA_OUI_TYPE_P2P) /* Check whether the given IE looks like WFA WFDisplay IE. */ +#ifndef WFA_OUI_TYPE_WFD #define WFA_OUI_TYPE_WFD 0x0a /* WiFi Display OUI TYPE */ +#endif #define wl_cfgp2p_is_wfd_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \ (const uint8 *)WFA_OUI, WFA_OUI_LEN, WFA_OUI_TYPE_WFD) @@ -1060,45 +1060,50 @@ wl_cfgp2p_set_management_ie(struct wl_priv *wl, struct net_device *ndev, s32 bss struct parsed_vndr_ies new_vndr_ies; s32 i; u8 *ptr; + s32 type = -1; s32 remained_buf_len; - #define IE_TYPE(type, bsstype) (wl_to_p2p_bss_saved_ie(wl, bsstype).p2p_ ## type ## _ie) #define IE_TYPE_LEN(type, bsstype) (wl_to_p2p_bss_saved_ie(wl, bsstype).p2p_ ## type ## _ie_len) memset(g_mgmt_ie_buf, 0, sizeof(g_mgmt_ie_buf)); curr_ie_buf = g_mgmt_ie_buf; CFGP2P_DBG((" bssidx %d, pktflag : 0x%02X\n", bssidx, pktflag)); if (wl->p2p != NULL) { + if (wl_cfgp2p_find_type(wl, bssidx, &type)) { + CFGP2P_ERR(("cannot find type from bssidx : %d\n", bssidx)); + return BCME_ERROR; + } + switch (pktflag) { case VNDR_IE_PRBREQ_FLAG : - mgmt_ie_buf = IE_TYPE(probe_req, bssidx); - mgmt_ie_len = &IE_TYPE_LEN(probe_req, bssidx); - mgmt_ie_buf_len = sizeof(IE_TYPE(probe_req, bssidx)); + mgmt_ie_buf = IE_TYPE(probe_req, type); + mgmt_ie_len = &IE_TYPE_LEN(probe_req, type); + mgmt_ie_buf_len = sizeof(IE_TYPE(probe_req, type)); break; case VNDR_IE_PRBRSP_FLAG : - mgmt_ie_buf = IE_TYPE(probe_res, bssidx); - mgmt_ie_len = &IE_TYPE_LEN(probe_res, bssidx); - mgmt_ie_buf_len = sizeof(IE_TYPE(probe_res, bssidx)); + mgmt_ie_buf = IE_TYPE(probe_res, type); + mgmt_ie_len = &IE_TYPE_LEN(probe_res, type); + mgmt_ie_buf_len = sizeof(IE_TYPE(probe_res, type)); break; case VNDR_IE_ASSOCREQ_FLAG : - mgmt_ie_buf = IE_TYPE(assoc_req, bssidx); - mgmt_ie_len = &IE_TYPE_LEN(assoc_req, bssidx); - mgmt_ie_buf_len = sizeof(IE_TYPE(assoc_req, bssidx)); + mgmt_ie_buf = IE_TYPE(assoc_req, type); + mgmt_ie_len = &IE_TYPE_LEN(assoc_req, type); + mgmt_ie_buf_len = sizeof(IE_TYPE(assoc_req, type)); break; case VNDR_IE_ASSOCRSP_FLAG : - mgmt_ie_buf = IE_TYPE(assoc_res, bssidx); - mgmt_ie_len = &IE_TYPE_LEN(assoc_res, bssidx); - mgmt_ie_buf_len = sizeof(IE_TYPE(assoc_res, bssidx)); + mgmt_ie_buf = IE_TYPE(assoc_res, type); + mgmt_ie_len = &IE_TYPE_LEN(assoc_res, type); + mgmt_ie_buf_len = sizeof(IE_TYPE(assoc_res, type)); break; case VNDR_IE_BEACON_FLAG : - mgmt_ie_buf = IE_TYPE(beacon, bssidx); - mgmt_ie_len = &IE_TYPE_LEN(beacon, bssidx); - mgmt_ie_buf_len = sizeof(IE_TYPE(beacon, bssidx)); + mgmt_ie_buf = IE_TYPE(beacon, type); + mgmt_ie_len = &IE_TYPE_LEN(beacon, type); + mgmt_ie_buf_len = sizeof(IE_TYPE(beacon, type)); break; default: mgmt_ie_buf = NULL; mgmt_ie_len = NULL; CFGP2P_ERR(("not suitable type\n")); - return -1; + return BCME_ERROR; } } else if (wl_get_mode_by_netdev(wl, ndev) == WL_MODE_AP) { switch (pktflag) { @@ -1116,7 +1121,7 @@ wl_cfgp2p_set_management_ie(struct wl_priv *wl, struct net_device *ndev, s32 bss mgmt_ie_buf = NULL; mgmt_ie_len = NULL; CFGP2P_ERR(("not suitable type\n")); - return -1; + return BCME_ERROR; } bssidx = 0; } else if (wl_get_mode_by_netdev(wl, ndev) == WL_MODE_BSS) { @@ -1135,12 +1140,12 @@ wl_cfgp2p_set_management_ie(struct wl_priv *wl, struct net_device *ndev, s32 bss mgmt_ie_buf = NULL; mgmt_ie_len = NULL; CFGP2P_ERR(("not suitable type\n")); - return -1; + return BCME_ERROR; } bssidx = 0; } else { CFGP2P_ERR(("not suitable type\n")); - return -1; + return BCME_ERROR; } if (vndr_ie_len > mgmt_ie_buf_len) { @@ -1186,7 +1191,7 @@ wl_cfgp2p_set_management_ie(struct wl_priv *wl, struct net_device *ndev, s32 bss vndrie_info->vndrie.oui[2])); del_add_ie_buf_len = wl_cfgp2p_vndr_ie(wl, curr_ie_buf, - bssidx, pktflag, vndrie_info->vndrie.oui, + pktflag, vndrie_info->vndrie.oui, vndrie_info->vndrie.id, vndrie_info->ie_ptr + VNDR_IE_FIXED_LEN, vndrie_info->ie_len - VNDR_IE_FIXED_LEN, @@ -1216,7 +1221,7 @@ wl_cfgp2p_set_management_ie(struct wl_priv *wl, struct net_device *ndev, s32 bss vndrie_info->vndrie.oui[2])); del_add_ie_buf_len = wl_cfgp2p_vndr_ie(wl, curr_ie_buf, - bssidx, pktflag, vndrie_info->vndrie.oui, + pktflag, vndrie_info->vndrie.oui, vndrie_info->vndrie.id, vndrie_info->ie_ptr + VNDR_IE_FIXED_LEN, vndrie_info->ie_len - VNDR_IE_FIXED_LEN, @@ -1271,6 +1276,7 @@ wl_cfgp2p_clear_management_ie(struct wl_priv *wl, s32 bssidx) s32 vndrie_flag[] = {VNDR_IE_BEACON_FLAG, VNDR_IE_PRBRSP_FLAG, VNDR_IE_ASSOCRSP_FLAG, VNDR_IE_PRBREQ_FLAG, VNDR_IE_ASSOCREQ_FLAG}; s32 index = -1; + s32 type = -1; struct net_device *ndev = wl_cfgp2p_find_ndev(wl, bssidx); #define INIT_IE(IE_TYPE, BSS_TYPE) \ do { \ @@ -1283,15 +1289,20 @@ wl_cfgp2p_clear_management_ie(struct wl_priv *wl, s32 bssidx) CFGP2P_ERR(("invalid %s\n", (bssidx < 0) ? "bssidx" : "ndev")); return BCME_BADARG; } + + if (wl_cfgp2p_find_type(wl, bssidx, &type)) { + CFGP2P_ERR(("invalid argument\n")); + return BCME_BADARG; + } for (index = 0; index < ARRAYSIZE(vndrie_flag); index++) { /* clean up vndr ies in dongle */ wl_cfgp2p_set_management_ie(wl, ndev, bssidx, vndrie_flag[index], NULL, 0); } - INIT_IE(probe_req, bssidx); - INIT_IE(probe_res, bssidx); - INIT_IE(assoc_req, bssidx); - INIT_IE(assoc_res, bssidx); - INIT_IE(beacon, bssidx); + INIT_IE(probe_req, type); + INIT_IE(probe_res, type); + INIT_IE(assoc_req, type); + INIT_IE(assoc_res, type); + INIT_IE(beacon, type); return BCME_OK; } @@ -1373,7 +1384,7 @@ wl_cfgp2p_find_wfdie(u8 *parse, u32 len) return NULL; } static u32 -wl_cfgp2p_vndr_ie(struct wl_priv *wl, u8 *iebuf, s32 bssidx, s32 pktflag, +wl_cfgp2p_vndr_ie(struct wl_priv *wl, u8 *iebuf, s32 pktflag, s8 *oui, s32 ie_id, s8 *data, s32 datalen, const s8* add_del_cmd) { vndr_ie_setbuf_t hdr; /* aligned temporary vndr_ie buffer header */ @@ -1430,31 +1441,31 @@ wl_cfgp2p_vndr_ie(struct wl_priv *wl, u8 *iebuf, s32 bssidx, s32 pktflag, * Parameters: * @wl : wl_private data * @ndev : net device to search bssidx - * Returns bssidx for ndev + * @bssidx : output arg to store bssidx of the bsscfg of firmware. + * Returns error */ s32 -wl_cfgp2p_find_idx(struct wl_priv *wl, struct net_device *ndev) +wl_cfgp2p_find_idx(struct wl_priv *wl, struct net_device *ndev, s32 *bssidx) { u32 i; - s32 index = -1; - - if (ndev == NULL) { - CFGP2P_ERR((" ndev is NULL\n")); - goto exit; + if (ndev == NULL || bssidx == NULL) { + CFGP2P_ERR((" argument is invalid\n")); + return BCME_BADARG; } if (!wl->p2p_supported) { - return P2PAPI_BSSCFG_PRIMARY; + *bssidx = P2PAPI_BSSCFG_PRIMARY; + return BCME_OK; } + /* we cannot find the bssidx of DISCOVERY BSS + * because the ndev is same with ndev of PRIMARY BSS. + */ for (i = 0; i < P2PAPI_BSSCFG_MAX; i++) { if (ndev == wl_to_p2p_bss_ndev(wl, i)) { - index = wl_to_p2p_bss_bssidx(wl, i); - break; + *bssidx = wl_to_p2p_bss_bssidx(wl, i); + return BCME_OK; } } - if (index == -1) - return P2PAPI_BSSCFG_PRIMARY; -exit: - return index; + return BCME_BADARG; } struct net_device * wl_cfgp2p_find_ndev(struct wl_priv *wl, s32 bssidx) @@ -1476,32 +1487,60 @@ wl_cfgp2p_find_ndev(struct wl_priv *wl, s32 bssidx) exit: return ndev; } +/* + * Search the driver array idx based on bssidx argument + * Parameters: + * @wl : wl_private data + * @bssidx : bssidx which indicate bsscfg->idx of firmware. + * @type : output arg to store array idx of p2p->bss. + * Returns error + */ + +s32 +wl_cfgp2p_find_type(struct wl_priv *wl, s32 bssidx, s32 *type) +{ + u32 i; + if (bssidx < 0 || type == NULL) { + CFGP2P_ERR((" argument is invalid\n")); + goto exit; + } + + for (i = 0; i < P2PAPI_BSSCFG_MAX; i++) { + if (bssidx == wl_to_p2p_bss_bssidx(wl, i)) { + *type = i; + return BCME_OK; + } + } + +exit: + return BCME_BADARG; +} /* * Callback function for WLC_E_P2P_DISC_LISTEN_COMPLETE */ s32 -wl_cfgp2p_listen_complete(struct wl_priv *wl, struct net_device *ndev, - const wl_event_msg_t *e, void *data) +wl_cfgp2p_listen_complete(struct wl_priv *wl, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data) { s32 ret = BCME_OK; - struct net_device *netdev; + struct net_device *ndev = NULL; + if (!wl || !wl->p2p) return BCME_ERROR; - if (wl->p2p_net == ndev) { - netdev = wl_to_prmry_ndev(wl); - } else { - netdev = ndev; - } + CFGP2P_DBG((" Enter\n")); -#ifdef P2P_DISCOVERY_WAR + ndev = cfgdev_to_wlc_ndev(cfgdev, wl); + +#if defined(P2P_DISCOVERY_WAR) if (!wl->p2p->vif_created) { - if (wldev_iovar_setint(netdev, "mpc", 1) < 0) { + if (wldev_iovar_setint(ndev, "mpc", 1) < 0) { WL_ERR(("mpc enabling back failed\n")); } } -#endif +#endif /* defined(P2P_DISCOVERY_WAR) */ + if (wl_get_p2p_status(wl, LISTEN_EXPIRED) == 0) { wl_set_p2p_status(wl, LISTEN_EXPIRED); if (timer_pending(&wl->p2p->listen_timer)) { @@ -1515,12 +1554,12 @@ wl_cfgp2p_listen_complete(struct wl_priv *wl, struct net_device *ndev, } #ifdef WL_CFG80211_SYNC_GON else if (wl_get_drv_status_all(wl, WAITING_NEXT_ACT_FRM_LISTEN)) { - wl_clr_drv_status(wl, WAITING_NEXT_ACT_FRM_LISTEN, netdev); + wl_clr_drv_status(wl, WAITING_NEXT_ACT_FRM_LISTEN, ndev); WL_DBG(("Listen DONE and wake up wait_next_af !!(%d)\n", jiffies_to_msecs(jiffies - wl->af_tx_sent_jiffies))); if (wl_get_drv_status_all(wl, WAITING_NEXT_ACT_FRM)) - wl_clr_drv_status(wl, WAITING_NEXT_ACT_FRM, netdev); + wl_clr_drv_status(wl, WAITING_NEXT_ACT_FRM, ndev); complete(&wl->wait_next_af); } @@ -1533,13 +1572,18 @@ wl_cfgp2p_listen_complete(struct wl_priv *wl, struct net_device *ndev, wl_get_drv_status_all(wl, FAKE_REMAINING_ON_CHANNEL)) { #endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ WL_DBG(("Listen DONE for ramain on channel expired\n")); - wl_clr_drv_status(wl, REMAINING_ON_CHANNEL, netdev); + wl_clr_drv_status(wl, REMAINING_ON_CHANNEL, ndev); #ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST - wl_clr_drv_status(wl, FAKE_REMAINING_ON_CHANNEL, netdev); + wl_clr_drv_status(wl, FAKE_REMAINING_ON_CHANNEL, ndev); #endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ if (ndev && (ndev->ieee80211_ptr != NULL)) { - cfg80211_remain_on_channel_expired(ndev, wl->last_roc_id, +#if defined(WL_CFG80211_P2P_DEV_IF) + cfg80211_remain_on_channel_expired(cfgdev, wl->last_roc_id, + &wl->remain_on_chan, GFP_KERNEL); +#else + cfg80211_remain_on_channel_expired(cfgdev, wl->last_roc_id, &wl->remain_on_chan, wl->remain_on_chan_type, GFP_KERNEL); +#endif /* WL_CFG80211_P2P_DEV_IF */ } } if (wl_add_remove_eventmsg(wl_to_prmry_ndev(wl), @@ -1566,15 +1610,20 @@ wl_cfgp2p_listen_expired(unsigned long data) CFGP2P_DBG((" Enter\n")); bzero(&msg, sizeof(wl_event_msg_t)); msg.event_type = hton32(WLC_E_P2P_DISC_LISTEN_COMPLETE); +#if defined(WL_ENABLE_P2P_IF) wl_cfg80211_event(wl->p2p_net ? wl->p2p_net : wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE), &msg, NULL); +#else + wl_cfg80211_event(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE), &msg, + NULL); +#endif /* WL_ENABLE_P2P_IF */ } /* * Routine for cancelling the P2P LISTEN */ static s32 wl_cfgp2p_cancel_listen(struct wl_priv *wl, struct net_device *ndev, - bool notify) + struct wireless_dev *wdev, bool notify) { WL_DBG(("Enter \n")); /* Irrespective of whether timer is running or not, reset @@ -1584,9 +1633,13 @@ wl_cfgp2p_cancel_listen(struct wl_priv *wl, struct net_device *ndev, del_timer_sync(&wl->p2p->listen_timer); if (notify) if (ndev && ndev->ieee80211_ptr) { +#if defined(WL_CFG80211_P2P_DEV_IF) + cfg80211_remain_on_channel_expired(wdev, wl->last_roc_id, + &wl->remain_on_chan, GFP_KERNEL); +#else cfg80211_remain_on_channel_expired(ndev, wl->last_roc_id, - &wl->remain_on_chan, wl->remain_on_chan_type, - GFP_KERNEL); + &wl->remain_on_chan, wl->remain_on_chan_type, GFP_KERNEL); +#endif /* WL_CFG80211_P2P_DEV_IF */ } } return 0; @@ -1690,31 +1743,35 @@ wl_cfgp2p_discover_enable_search(struct wl_priv *wl, u8 enable) * Callback function for WLC_E_ACTION_FRAME_COMPLETE, WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE */ s32 -wl_cfgp2p_action_tx_complete(struct wl_priv *wl, struct net_device *ndev, +wl_cfgp2p_action_tx_complete(struct wl_priv *wl, bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data) { s32 ret = BCME_OK; u32 event_type = ntoh32(e->event_type); u32 status = ntoh32(e->status); CFGP2P_DBG((" Enter\n")); - if (event_type == WLC_E_ACTION_FRAME_COMPLETE) { + if (wl_get_drv_status_all(wl, SENDING_ACT_FRM)) { + if (event_type == WLC_E_ACTION_FRAME_COMPLETE) { - CFGP2P_INFO((" WLC_E_ACTION_FRAME_COMPLETE is received : %d\n", status)); - if (status == WLC_E_STATUS_SUCCESS) { - wl_set_p2p_status(wl, ACTION_TX_COMPLETED); - CFGP2P_DBG(("WLC_E_ACTION_FRAME_COMPLETE : ACK\n")); - } - else { - wl_set_p2p_status(wl, ACTION_TX_NOACK); - CFGP2P_INFO(("WLC_E_ACTION_FRAME_COMPLETE : NO ACK\n")); - wl_stop_wait_next_action_frame(wl, ndev); - } - } else { - CFGP2P_INFO((" WLC_E_ACTION_FRAME_OFFCHAN_COMPLETE is received," - "status : %d\n", status)); + CFGP2P_INFO((" WLC_E_ACTION_FRAME_COMPLETE is received : %d\n", status)); + if (status == WLC_E_STATUS_SUCCESS) { + wl_set_p2p_status(wl, ACTION_TX_COMPLETED); + CFGP2P_DBG(("WLC_E_ACTION_FRAME_COMPLETE : ACK\n")); + } + else { + if (!wl_get_p2p_status(wl, ACTION_TX_COMPLETED)) { + wl_set_p2p_status(wl, ACTION_TX_NOACK); + CFGP2P_INFO(("WLC_E_ACTION_FRAME_COMPLETE : NO ACK\n")); + wl_stop_wait_next_action_frame(wl); + } + } + } else { + CFGP2P_INFO((" WLC_E_ACTION_FRAME_OFFCHAN_COMPLETE is received," + "status : %d\n", status)); - if (wl_get_drv_status_all(wl, SENDING_ACT_FRM)) - complete(&wl->send_af_done); + if (wl_get_drv_status_all(wl, SENDING_ACT_FRM)) + complete(&wl->send_af_done); + } } return ret; } @@ -1731,6 +1788,7 @@ wl_cfgp2p_tx_action_frame(struct wl_priv *wl, struct net_device *dev, wl_af_params_t *af_params, s32 bssidx) { s32 ret = BCME_OK; + s32 evt_ret = BCME_OK; s32 timeout = 0; wl_eventmsg_buf_t buf; @@ -1745,10 +1803,9 @@ wl_cfgp2p_tx_action_frame(struct wl_priv *wl, struct net_device *dev, bzero(&buf, sizeof(wl_eventmsg_buf_t)); wl_cfg80211_add_to_eventbuffer(&buf, WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE, true); wl_cfg80211_add_to_eventbuffer(&buf, WLC_E_ACTION_FRAME_COMPLETE, true); - if ((ret = wl_cfg80211_apply_eventbuffer(wl_to_prmry_ndev(wl), wl, &buf)) < 0) - return ret; + if ((evt_ret = wl_cfg80211_apply_eventbuffer(wl_to_prmry_ndev(wl), wl, &buf)) < 0) + return evt_ret; -#define MAX_WAIT_TIME 2000 if (bssidx == P2PAPI_BSSCFG_PRIMARY) bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE); @@ -1765,9 +1822,10 @@ wl_cfgp2p_tx_action_frame(struct wl_priv *wl, struct net_device *dev, goto exit; } - timeout = wait_for_completion_timeout(&wl->send_af_done, msecs_to_jiffies(MAX_WAIT_TIME)); + timeout = wait_for_completion_timeout(&wl->send_af_done, + msecs_to_jiffies(af_params->dwell_time + WL_AF_TX_EXTRA_TIME_MAX)); - if (timeout > 0 && wl_get_p2p_status(wl, ACTION_TX_COMPLETED)) { + if (timeout >= 0 && wl_get_p2p_status(wl, ACTION_TX_COMPLETED)) { CFGP2P_INFO(("tx action frame operation is completed\n")); ret = BCME_OK; } else { @@ -1784,10 +1842,11 @@ exit: bzero(&buf, sizeof(wl_eventmsg_buf_t)); wl_cfg80211_add_to_eventbuffer(&buf, WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE, false); wl_cfg80211_add_to_eventbuffer(&buf, WLC_E_ACTION_FRAME_COMPLETE, false); - if ((ret = wl_cfg80211_apply_eventbuffer(wl_to_prmry_ndev(wl), wl, &buf)) < 0) + if ((evt_ret = wl_cfg80211_apply_eventbuffer(wl_to_prmry_ndev(wl), wl, &buf)) < 0) { WL_ERR(("TX frame events revert back failed \n")); + return evt_ret; + } -#undef MAX_WAIT_TIME return ret; } @@ -1947,14 +2006,27 @@ wl_cfgp2p_supported(struct wl_priv *wl, struct net_device *ndev) s32 wl_cfgp2p_down(struct wl_priv *wl) { + struct net_device *ndev = NULL; + struct wireless_dev *wdev = NULL; s32 i = 0, index = -1; - wl_cfgp2p_cancel_listen(wl, - wl->p2p_net ? wl->p2p_net : wl_to_prmry_ndev(wl), TRUE); + +#if defined(WL_CFG80211_P2P_DEV_IF) + ndev = wl_to_prmry_ndev(wl); + wdev = wl_to_p2p_wdev(wl); +#elif defined(WL_ENABLE_P2P_IF) + ndev = wl->p2p_net ? wl->p2p_net : wl_to_prmry_ndev(wl); + wdev = ndev_to_wdev(ndev); +#endif /* WL_CFG80211_P2P_DEV_IF */ + + wl_cfgp2p_cancel_listen(wl, ndev, wdev, TRUE); for (i = 0; i < P2PAPI_BSSCFG_MAX; i++) { index = wl_to_p2p_bss_bssidx(wl, i); if (index != WL_INVALID) wl_cfgp2p_clear_management_ie(wl, index); } +#if defined(WL_CFG80211_P2P_DEV_IF) + wl_cfgp2p_del_p2p_disc_if(wdev); +#endif /* WL_CFG80211_P2P_DEV_IF */ wl_cfgp2p_deinit_priv(wl); return 0; } @@ -2228,12 +2300,12 @@ wl_cfgp2p_retreive_p2p_dev_addr(wl_bss_info_t *bi, u32 bi_length) /* In probe responses, DEVICE INFO attribute will be present */ if (!(ptr = wl_cfgp2p_find_attrib_in_all_p2p_Ies(((u8 *) bi) + bi->ie_offset, - bi->ie_length, P2P_SEID_DEV_INFO))) { + bi->ie_length, P2P_SEID_DEV_INFO))) { /* If DEVICE_INFO is not found, this might be a beacon frame. * check for DEVICE_ID in the beacon frame. */ ptr = wl_cfgp2p_find_attrib_in_all_p2p_Ies(((u8 *) bi) + bi->ie_offset, - bi->ie_length, P2P_SEID_DEV_ID); + bi->ie_length, P2P_SEID_DEV_ID); } if (!ptr) @@ -2255,6 +2327,7 @@ struct ethtool_ops cfgp2p_ethtool_ops = { }; #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */ +#if defined(WL_ENABLE_P2P_IF) s32 wl_cfgp2p_register_ndev(struct wl_priv *wl) { @@ -2353,6 +2426,7 @@ wl_cfgp2p_unregister_ndev(struct wl_priv *wl) } static int wl_cfgp2p_start_xmit(struct sk_buff *skb, struct net_device *ndev) { + if (skb) { CFGP2P_DBG(("(%s) is not used for data operations.Droping the packet.\n", @@ -2394,6 +2468,7 @@ static int wl_cfgp2p_if_open(struct net_device *net) if (!wdev || !wl || !wl->p2p) return -EINVAL; WL_TRACE(("Enter\n")); +#if !defined(WL_IFACE_COMB_NUM_CHANNELS) /* If suppose F/W download (ifconfig wlan0 up) hasn't been done by now, * do it here. This will make sure that in concurrent mode, supplicant * is not dependent on a particular order of interface initialization. @@ -2402,6 +2477,7 @@ static int wl_cfgp2p_if_open(struct net_device *net) */ wdev->wiphy->interface_modes |= (BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO)); +#endif /* !WL_IFACE_COMB_NUM_CHANNELS */ wl_cfg80211_do_driver_init(net); return 0; @@ -2430,9 +2506,11 @@ static int wl_cfgp2p_if_stop(struct net_device *net) spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); if (clear_flag) wl_clr_drv_status(wl, SCANNING, net); +#if !defined(WL_IFACE_COMB_NUM_CHANNELS) wdev->wiphy->interface_modes = (wdev->wiphy->interface_modes) & (~(BIT(NL80211_IFTYPE_P2P_CLIENT)| BIT(NL80211_IFTYPE_P2P_GO))); +#endif /* !WL_IFACE_COMB_NUM_CHANNELS */ return 0; } @@ -2440,3 +2518,143 @@ bool wl_cfgp2p_is_ifops(const struct net_device_ops *if_ops) { return (if_ops == &wl_cfgp2p_if_ops); } +#endif /* WL_ENABLE_P2P_IF */ + +#if defined(WL_CFG80211_P2P_DEV_IF) +struct wireless_dev * +wl_cfgp2p_add_p2p_disc_if(void) +{ + extern struct wl_priv *wlcfg_drv_priv; + struct wl_priv *wl = wlcfg_drv_priv; + struct wireless_dev *wdev = NULL; + struct ether_addr primary_mac; + + if (!wl) + return NULL; + + WL_TRACE(("Enter\n")); + + if (wl->p2p_wdev) { + CFGP2P_ERR(("p2p_wdev defined already.\n")); + return NULL; + } + + wdev = kzalloc(sizeof(*wdev), GFP_KERNEL); + if (unlikely(!wdev)) { + WL_ERR(("Could not allocate wireless device\n")); + return NULL; + } + + memset(&primary_mac, 0, sizeof(primary_mac)); + get_primary_mac(wl, &primary_mac); + wl_cfgp2p_generate_bss_mac(&primary_mac, + &wl->p2p->dev_addr, &wl->p2p->int_addr); + + wdev->wiphy = wl->wdev->wiphy; + wdev->iftype = NL80211_IFTYPE_P2P_DEVICE; + memcpy(wdev->address, &wl->p2p->dev_addr, ETHER_ADDR_LEN); + + /* store p2p wdev ptr for further reference. */ + wl->p2p_wdev = wdev; + + CFGP2P_ERR(("P2P interface registered\n")); + + return wdev; +} + +int +wl_cfgp2p_start_p2p_device(struct wiphy *wiphy, struct wireless_dev *wdev) +{ + int ret = 0; + extern struct wl_priv *wlcfg_drv_priv; + struct wl_priv *wl = wlcfg_drv_priv; + + if (!wl) + return -EINVAL; + + WL_TRACE(("Enter\n")); + + ret = wl_cfgp2p_set_firm_p2p(wl); + if (unlikely(ret < 0)) { + CFGP2P_ERR(("Set P2P in firmware failed, ret=%d\n", ret)); + goto exit; + } + + ret = wl_cfgp2p_enable_discovery(wl, wl_to_prmry_ndev(wl), NULL, 0); + if (unlikely(ret < 0)) { + CFGP2P_ERR(("P2P enable discovery failed, ret=%d\n", ret)); + goto exit; + } + + p2p_on(wl) = true; + + CFGP2P_DBG(("P2P interface started\n")); + +exit: + return ret; +} + +void +wl_cfgp2p_stop_p2p_device(struct wiphy *wiphy, struct wireless_dev *wdev) +{ + int ret = 0; + int clear_flag = 0; + unsigned long flags = 0; + struct net_device *ndev = NULL; + extern struct wl_priv *wlcfg_drv_priv; + struct wl_priv *wl = wlcfg_drv_priv; + + if (!wl || !wdev) + return; + + WL_TRACE(("Enter\n")); + + ndev = wdev_to_wlc_ndev(wdev, wl); + + spin_lock_irqsave(&wl->cfgdrv_lock, flags); + if (wl->scan_request && wl->scan_request->wdev == wdev) { + cfg80211_scan_done(wl->scan_request, true); + wl->scan_request = NULL; + clear_flag = 1; + } + spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); + + if (clear_flag) + wl_clr_drv_status(wl, SCANNING, ndev); + + ret = wl_cfgp2p_disable_discovery(wl); + if (unlikely(ret < 0)) { + CFGP2P_ERR(("P2P disable discovery failed, ret=%d\n", ret)); + goto exit; + } + + p2p_on(wl) = false; + + CFGP2P_DBG(("P2P interface stopped\n")); + +exit: + return; +} + +int +wl_cfgp2p_del_p2p_disc_if(struct wireless_dev *wdev) +{ + extern struct wl_priv *wlcfg_drv_priv; + struct wl_priv *wl = wlcfg_drv_priv; + + if (!wdev) + return -EINVAL; + + WL_TRACE(("Enter\n")); + + cfg80211_unregister_wdev(wdev); + + kfree(wdev); + + wl->p2p_wdev = NULL; + + CFGP2P_ERR(("P2P interface unregistered\n")); + + return 0; +} +#endif /* WL_CFG80211_P2P_DEV_IF */ diff --git a/drivers/net/wireless/bcmdhd/wl_cfgp2p.h b/drivers/net/wireless/bcmdhd/wl_cfgp2p.h index 73c5da748d63..3645a668047c 100644..100755 --- a/drivers/net/wireless/bcmdhd/wl_cfgp2p.h +++ b/drivers/net/wireless/bcmdhd/wl_cfgp2p.h @@ -1,7 +1,7 @@ /* * Linux cfgp2p driver * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -21,7 +21,7 @@ * 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: wl_cfgp2p.h 386594 2013-02-21 07:02:10Z $ + * $Id: wl_cfgp2p.h 415640 2013-07-31 02:43:28Z $ */ #ifndef _wl_cfgp2p_h_ #define _wl_cfgp2p_h_ @@ -43,6 +43,17 @@ typedef enum { P2PAPI_BSSCFG_MAX } p2p_bsscfg_type_t; +typedef enum { + P2P_SCAN_PURPOSE_MIN, + P2P_SCAN_SOCIAL_CHANNEL, /* scan for social channel */ + P2P_SCAN_AFX_PEER_NORMAL, /* scan for action frame search */ + P2P_SCAN_AFX_PEER_REDUCED, /* scan for action frame search with short time */ + P2P_SCAN_DURING_CONNECTED, /* scan during connected status */ + P2P_SCAN_CONNECT_TRY, /* scan for connecting */ + P2P_SCAN_NORMAL, /* scan during not-connected status */ + P2P_SCAN_PURPOSE_MAX +} p2p_scan_purpose_t; + /* vendor ies max buffer length for probe response or beacon */ #define VNDR_IES_MAX_BUF_LEN 1400 /* normal vendor ies buffer length */ @@ -72,12 +83,13 @@ struct p2p_bss { struct p2p_info { bool on; /* p2p on/off switch */ bool scan; + int16 search_state; bool vif_created; s8 vir_ifname[IFNAMSIZ]; unsigned long status; struct ether_addr dev_addr; struct ether_addr int_addr; - struct p2p_bss bss_idx[P2PAPI_BSSCFG_MAX]; + struct p2p_bss bss[P2PAPI_BSSCFG_MAX]; struct timer_list listen_timer; wl_p2p_sched_t noa; wl_p2p_ops_t ops; @@ -115,11 +127,11 @@ enum wl_cfgp2p_status { }; -#define wl_to_p2p_bss_ndev(wl, type) ((wl)->p2p->bss_idx[type].dev) -#define wl_to_p2p_bss_bssidx(wl, type) ((wl)->p2p->bss_idx[type].bssidx) -#define wl_to_p2p_bss_saved_ie(wl, type) ((wl)->p2p->bss_idx[type].saved_ie) -#define wl_to_p2p_bss_private(wl, type) ((wl)->p2p->bss_idx[type].private_data) -#define wl_to_p2p_bss(wl, type) ((wl)->p2p->bss_idx[type]) +#define wl_to_p2p_bss_ndev(wl, type) ((wl)->p2p->bss[type].dev) +#define wl_to_p2p_bss_bssidx(wl, type) ((wl)->p2p->bss[type].bssidx) +#define wl_to_p2p_bss_saved_ie(wl, type) ((wl)->p2p->bss[type].saved_ie) +#define wl_to_p2p_bss_private(wl, type) ((wl)->p2p->bss[type].private_data) +#define wl_to_p2p_bss(wl, type) ((wl)->p2p->bss[type]) #define wl_get_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0 : test_bit(WLP2P_STATUS_ ## stat, \ &(wl)->p2p->status)) #define wl_set_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0 : set_bit(WLP2P_STATUS_ ## stat, \ @@ -175,6 +187,27 @@ enum wl_cfgp2p_status { timer->data = (unsigned long) wl; \ add_timer(timer); \ } while (0); + +#if !defined(WL_CFG80211_P2P_DEV_IF) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) +#define WL_CFG80211_P2P_DEV_IF +#endif /* !WL_CFG80211_P2P_DEV_IF && (LINUX_VERSION >= VERSION(3, 8, 0)) */ + +#if defined(WL_ENABLE_P2P_IF) && (defined(WL_CFG80211_P2P_DEV_IF) || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0))) +#error Disable 'WL_ENABLE_P2P_IF', if 'WL_CFG80211_P2P_DEV_IF' is enabled \ + or kernel version is 3.8.0 or above +#endif /* WL_ENABLE_P2P_IF && (WL_CFG80211_P2P_DEV_IF || (LINUX_VERSION >= VERSION(3, 8, 0))) */ + +#if !defined(WLP2P) && (defined(WL_ENABLE_P2P_IF) || defined(WL_CFG80211_P2P_DEV_IF)) +#error WLP2P not defined +#endif /* !WLP2P && (WL_ENABLE_P2P_IF || WL_CFG80211_P2P_DEV_IF) */ + +#if defined(WL_CFG80211_P2P_DEV_IF) +#define bcm_struct_cfgdev struct wireless_dev +#else +#define bcm_struct_cfgdev struct net_device +#endif /* WL_CFG80211_P2P_DEV_IF */ + extern void wl_cfgp2p_listen_expired(unsigned long data); extern bool @@ -183,6 +216,8 @@ extern bool wl_cfgp2p_is_p2p_action(void *frame, u32 frame_len); extern bool wl_cfgp2p_is_gas_action(void *frame, u32 frame_len); +extern bool +wl_cfgp2p_find_gas_subtype(u8 subtype, u8* data, u32 len); extern void wl_cfgp2p_print_actframe(bool tx, void *frame, u32 frame_len, u32 channel); extern s32 @@ -216,7 +251,8 @@ wl_cfgp2p_disable_discovery(struct wl_priv *wl); extern s32 wl_cfgp2p_escan(struct wl_priv *wl, struct net_device *dev, u16 active, u32 num_chans, u16 *channels, - s32 search_state, u16 action, u32 bssidx, struct ether_addr *tx_dst_addr); + s32 search_state, u16 action, u32 bssidx, struct ether_addr *tx_dst_addr, + p2p_scan_purpose_t p2p_scan_purpose); extern s32 wl_cfgp2p_act_frm_search(struct wl_priv *wl, struct net_device *ndev, @@ -240,14 +276,16 @@ extern s32 wl_cfgp2p_clear_management_ie(struct wl_priv *wl, s32 bssidx); extern s32 -wl_cfgp2p_find_idx(struct wl_priv *wl, struct net_device *ndev); +wl_cfgp2p_find_idx(struct wl_priv *wl, struct net_device *ndev, s32 *index); extern struct net_device * wl_cfgp2p_find_ndev(struct wl_priv *wl, s32 bssidx); +extern s32 +wl_cfgp2p_find_type(struct wl_priv *wl, s32 bssidx, s32 *type); extern s32 -wl_cfgp2p_listen_complete(struct wl_priv *wl, struct net_device *ndev, - const wl_event_msg_t *e, void *data); +wl_cfgp2p_listen_complete(struct wl_priv *wl, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data); extern s32 wl_cfgp2p_discover_listen(struct wl_priv *wl, s32 channel, u32 duration_ms); @@ -255,8 +293,9 @@ extern s32 wl_cfgp2p_discover_enable_search(struct wl_priv *wl, u8 enable); extern s32 -wl_cfgp2p_action_tx_complete(struct wl_priv *wl, struct net_device *ndev, - const wl_event_msg_t *e, void *data); +wl_cfgp2p_action_tx_complete(struct wl_priv *wl, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data); + extern s32 wl_cfgp2p_tx_action_frame(struct wl_priv *wl, struct net_device *dev, wl_af_params_t *af_params, s32 bssidx); @@ -307,6 +346,20 @@ wl_cfgp2p_unregister_ndev(struct wl_priv *wl); extern bool wl_cfgp2p_is_ifops(const struct net_device_ops *if_ops); +#if defined(WL_CFG80211_P2P_DEV_IF) +extern struct wireless_dev * +wl_cfgp2p_add_p2p_disc_if(void); + +extern int +wl_cfgp2p_start_p2p_device(struct wiphy *wiphy, struct wireless_dev *wdev); + +extern void +wl_cfgp2p_stop_p2p_device(struct wiphy *wiphy, struct wireless_dev *wdev); + +extern int +wl_cfgp2p_del_p2p_disc_if(struct wireless_dev *wdev); +#endif /* WL_CFG80211_P2P_DEV_IF */ + /* WiFi Direct */ #define SOCIAL_CHAN_1 1 #define SOCIAL_CHAN_2 6 diff --git a/drivers/net/wireless/bcmdhd/wl_dbg.h b/drivers/net/wireless/bcmdhd/wl_dbg.h index 68e40537d682..05963b111e4d 100644..100755 --- a/drivers/net/wireless/bcmdhd/wl_dbg.h +++ b/drivers/net/wireless/bcmdhd/wl_dbg.h @@ -2,7 +2,7 @@ * Minimal debug/trace/assert driver definitions for * Broadcom 802.11 Networking Adapter. * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -22,7 +22,7 @@ * 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: wl_dbg.h 326635 2012-04-10 03:15:29Z $ + * $Id: wl_dbg.h 376019 2012-12-21 01:00:06Z $ */ diff --git a/drivers/net/wireless/bcmdhd/wl_iw.c b/drivers/net/wireless/bcmdhd/wl_iw.c index 04f907fab345..fdc4d6a86895 100644..100755 --- a/drivers/net/wireless/bcmdhd/wl_iw.c +++ b/drivers/net/wireless/bcmdhd/wl_iw.c @@ -1,7 +1,7 @@ /* * Linux Wireless Extensions support * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -21,7 +21,7 @@ * 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: wl_iw.c 352251 2012-08-22 06:08:38Z $ + * $Id: wl_iw.c 396420 2013-04-12 06:55:45Z $ */ #if defined(USE_IW) @@ -38,7 +38,6 @@ #include <linux/if_arp.h> #include <asm/uaccess.h> - typedef const struct si_pub si_t; #include <wlioctl.h> @@ -47,6 +46,31 @@ typedef const struct si_pub si_t; #include <wl_iw.h> +/* Broadcom extensions to WEXT, linux upstream has obsoleted WEXT */ +#ifndef IW_AUTH_KEY_MGMT_FT_802_1X +#define IW_AUTH_KEY_MGMT_FT_802_1X 0x04 +#endif + +#ifndef IW_AUTH_KEY_MGMT_FT_PSK +#define IW_AUTH_KEY_MGMT_FT_PSK 0x08 +#endif + +#ifndef IW_ENC_CAPA_FW_ROAM_ENABLE +#define IW_ENC_CAPA_FW_ROAM_ENABLE 0x00000020 +#endif + + +/* FC9: wireless.h 2.6.25-14.fc9.i686 is missing these, even though WIRELESS_EXT is set to latest + * version 22. + */ +#ifndef IW_ENCODE_ALG_PMK +#define IW_ENCODE_ALG_PMK 4 +#endif +#ifndef IW_ENC_CAPA_4WAY_HANDSHAKE +#define IW_ENC_CAPA_4WAY_HANDSHAKE 0x00000010 +#endif +/* End FC9. */ + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) #include <linux/rtnetlink.h> #endif @@ -79,7 +103,10 @@ extern int dhd_wait_pend8021x(struct net_device *dev); #endif /* WIRELESS_EXT < 19 */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) +#define DAEMONIZE(a) +#elif ((LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)) && \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))) #define DAEMONIZE(a) daemonize(a); \ allow_signal(SIGKILL); \ allow_signal(SIGTERM); @@ -404,6 +431,9 @@ wl_iw_set_pm( error = dev_wlc_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm)); return error; } + +#if WIRELESS_EXT > 17 +#endif /* WIRELESS_EXT > 17 */ #endif /* WIRELESS_EXT > 12 */ int @@ -654,6 +684,7 @@ wl_iw_get_range( {14, 29, 43, 58, 87, 116, 130, 144}, {27, 54, 81, 108, 162, 216, 243, 270}, {30, 60, 90, 120, 180, 240, 270, 300}}; + int fbt_cap = 0; WL_TRACE(("%s: SIOCGIWRANGE\n", dev->name)); @@ -709,15 +740,18 @@ wl_iw_get_range( range->num_bitrates = rateset.count; for (i = 0; i < rateset.count && i < IW_MAX_BITRATES; i++) range->bitrate[i] = (rateset.rates[i] & 0x7f) * 500000; /* convert to bps */ - dev_wlc_intvar_get(dev, "nmode", &nmode); + if ((error = dev_wlc_intvar_get(dev, "nmode", &nmode))) + return error; if ((error = dev_wlc_ioctl(dev, WLC_GET_PHYTYPE, &phytype, sizeof(phytype)))) return error; - if (nmode == 1 && ((phytype == WLC_PHY_TYPE_SSN) || (phytype == WLC_PHY_TYPE_LCN) || (phytype == WLC_PHY_TYPE_LCN40))) { - dev_wlc_intvar_get(dev, "mimo_bw_cap", &bw_cap); - dev_wlc_intvar_get(dev, "sgi_tx", &sgi_tx); - dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(channel_info_t)); + if ((error = dev_wlc_intvar_get(dev, "mimo_bw_cap", &bw_cap))) + return error; + if ((error = dev_wlc_intvar_get(dev, "sgi_tx", &sgi_tx))) + return error; + if ((error = dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(channel_info_t)))) + return error; ci.hw_channel = dtoh32(ci.hw_channel); if (bw_cap == 0 || @@ -735,6 +769,7 @@ wl_iw_get_range( nrate_list2copy = 3; } range->num_bitrates += 8; + ASSERT(range->num_bitrates < IW_MAX_BITRATES); for (k = 0; i < range->num_bitrates; k++, i++) { /* convert to bps */ range->bitrate[i] = (nrate_list[nrate_list2copy][k]) * 500000; @@ -805,10 +840,19 @@ wl_iw_get_range( range->enc_capa |= IW_ENC_CAPA_CIPHER_TKIP; range->enc_capa |= IW_ENC_CAPA_CIPHER_CCMP; range->enc_capa |= IW_ENC_CAPA_WPA2; -#if (defined(BCMSUP_PSK) && defined(WLFBT)) - /* Tell the host (e.g. wpa_supplicant) to let us do the handshake */ - range->enc_capa |= IW_ENC_CAPA_4WAY_HANDSHAKE; -#endif /* (defined (BCMSUP_PSK) && defined(WLFBT)) */ + + /* Determine driver FBT capability. */ + if (dev_wlc_intvar_get(dev, "fbt_cap", &fbt_cap) == 0) { + if (fbt_cap == WLC_FBT_CAP_DRV_4WAY_AND_REASSOC) { + /* Tell the host (e.g. wpa_supplicant) to let driver do the handshake */ + range->enc_capa |= IW_ENC_CAPA_4WAY_HANDSHAKE; + } + } + +#ifdef BCMFW_ROAM_ENABLE_WEXT + /* Advertise firmware roam capability to the external supplicant */ + range->enc_capa |= IW_ENC_CAPA_FW_ROAM_ENABLE; +#endif /* BCMFW_ROAM_ENABLE_WEXT */ /* Event capability (kernel) */ IW_EVENT_CAPA_SET_KERNEL(range->event_capa); @@ -1294,14 +1338,12 @@ wl_iw_handle_scanresults_ies(char **event_p, char *end, } ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t); -#if defined(WLFBT) if ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_MDIE_ID))) { iwe.cmd = IWEVGENIE; iwe.u.data.length = ie->len + 2; event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)ie); } ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t); -#endif /* WLFBT */ while ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_WPA_ID))) { /* look for WPS IE */ @@ -2305,7 +2347,6 @@ wl_iw_set_encodeext( return error; } } -#if (defined(BCMSUP_PSK) && defined(WLFBT)) /* This case is used to allow an external 802.1x supplicant * to pass the PMK to the in-driver supplicant for use in * the 4-way handshake. @@ -2331,7 +2372,6 @@ wl_iw_set_encodeext( if (error) return error; } -#endif /* (defined (BCMSUP_PSK) && defined(WLFBT)) */ else { if (iwe->key_len > sizeof(key.data)) @@ -2533,7 +2573,8 @@ wl_iw_set_wpaauth( break; case IW_AUTH_CIPHER_PAIRWISE: - case IW_AUTH_CIPHER_GROUP: + case IW_AUTH_CIPHER_GROUP: { + int fbt_cap = 0; if (paramid == IW_AUTH_CIPHER_PAIRWISE) { iw->pwsec = paramval; @@ -2570,33 +2611,44 @@ wl_iw_set_wpaauth( if ((error = dev_wlc_intvar_set(dev, "wsec", val))) return error; -#ifdef WLFBT - if ((paramid == IW_AUTH_CIPHER_PAIRWISE) && (val | AES_ENABLED)) { - if ((error = dev_wlc_intvar_set(dev, "sup_wpa", 1))) - return error; - } - else if (val == 0) { - if ((error = dev_wlc_intvar_set(dev, "sup_wpa", 0))) - return error; + + /* Ensure in-dongle supplicant is turned on when FBT wants to do the 4-way + * handshake. + */ + if (dev_wlc_intvar_get(dev, "fbt_cap", &fbt_cap) == 0) { + if (fbt_cap == WLC_FBT_CAP_DRV_4WAY_AND_REASSOC) { + if ((paramid == IW_AUTH_CIPHER_PAIRWISE) && (val & AES_ENABLED)) { + if ((error = dev_wlc_intvar_set(dev, "sup_wpa", 1))) + return error; + } + else if (val == 0) { + if ((error = dev_wlc_intvar_set(dev, "sup_wpa", 0))) + return error; + } + } } -#endif /* WLFBT */ break; + } case IW_AUTH_KEY_MGMT: if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val))) return error; if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) { - if (paramval & IW_AUTH_KEY_MGMT_PSK) + if (paramval & (IW_AUTH_KEY_MGMT_FT_PSK | IW_AUTH_KEY_MGMT_PSK)) val = WPA_AUTH_PSK; else val = WPA_AUTH_UNSPECIFIED; + if (paramval & (IW_AUTH_KEY_MGMT_FT_802_1X | IW_AUTH_KEY_MGMT_FT_PSK)) + val |= WPA2_AUTH_FT; } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) { - if (paramval & IW_AUTH_KEY_MGMT_PSK) + if (paramval & (IW_AUTH_KEY_MGMT_FT_PSK | IW_AUTH_KEY_MGMT_PSK)) val = WPA2_AUTH_PSK; else val = WPA2_AUTH_UNSPECIFIED; + if (paramval & (IW_AUTH_KEY_MGMT_FT_802_1X | IW_AUTH_KEY_MGMT_FT_PSK)) + val |= WPA2_AUTH_FT; } WL_TRACE(("%s: %d: setting wpa_auth to %d\n", __FUNCTION__, __LINE__, val)); if ((error = dev_wlc_intvar_set(dev, "wpa_auth", val))) @@ -2861,13 +2913,19 @@ static const iw_handler wl_iw_handler[] = enum { WL_IW_SET_LEDDC = SIOCIWFIRSTPRIV, WL_IW_SET_VLANMODE, - WL_IW_SET_PM + WL_IW_SET_PM, +#if WIRELESS_EXT > 17 +#endif /* WIRELESS_EXT > 17 */ + WL_IW_SET_LAST }; static iw_handler wl_iw_priv_handler[] = { wl_iw_set_leddc, wl_iw_set_vlanmode, - wl_iw_set_pm + wl_iw_set_pm, +#if WIRELESS_EXT > 17 +#endif /* WIRELESS_EXT > 17 */ + NULL }; static struct iw_priv_args wl_iw_priv_args[] = { @@ -2888,7 +2946,10 @@ static struct iw_priv_args wl_iw_priv_args[] = { IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_pm" - } + }, +#if WIRELESS_EXT > 17 +#endif /* WIRELESS_EXT > 17 */ + { 0, 0, 0, { 0 } } }; const struct iw_handler_def wl_iw_handler_def = @@ -3497,7 +3558,7 @@ static void wl_iw_send_scan_complete(iscan_info_t *iscan) memset(&wrqu, 0, sizeof(wrqu)); - /* wext expects to get no data for SIOCGIWSCAN Event */ + /* wext expects to get no data for SIOCGIWSCAN Event */ wireless_send_event(iscan->dev, SIOCGIWSCAN, &wrqu, NULL); } diff --git a/drivers/net/wireless/bcmdhd/wl_iw.h b/drivers/net/wireless/bcmdhd/wl_iw.h index c675a56c5085..df59a65c1620 100644..100755 --- a/drivers/net/wireless/bcmdhd/wl_iw.h +++ b/drivers/net/wireless/bcmdhd/wl_iw.h @@ -1,7 +1,7 @@ /* * Linux Wireless Extensions support * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd/wl_linux_mon.c b/drivers/net/wireless/bcmdhd/wl_linux_mon.c index af2586326c20..117b0abe76de 100644..100755 --- a/drivers/net/wireless/bcmdhd/wl_linux_mon.c +++ b/drivers/net/wireless/bcmdhd/wl_linux_mon.c @@ -1,7 +1,7 @@ /* * Broadcom Dongle Host Driver (DHD), Linux monitor network interface * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2013, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/wireless/bcmdhd/wldev_common.c b/drivers/net/wireless/bcmdhd/wldev_common.c index eebca8d0d9a3..9c678d944720 100644..100755 --- a/drivers/net/wireless/bcmdhd/wldev_common.c +++ b/drivers/net/wireless/bcmdhd/wldev_common.c @@ -1,14 +1,14 @@ /* * Common function shared by Linux WEXT, cfg80211 and p2p drivers * - * Copyright (C) 1999-2012, Broadcom Corporation - * + * Copyright (C) 1999-2013, Broadcom Corporation + * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2 (the "GPL"), * available at http://www.broadcom.com/licenses/GPLv2.php, with the * following added to such license: - * + * * As a special exception, the copyright holders of this software give you * permission to link this software with independent modules, and to copy and * distribute the resulting executable under terms of your choice, provided that @@ -16,7 +16,7 @@ * 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. @@ -109,6 +109,7 @@ s32 wldev_iovar_setbuf( ret = wldev_ioctl(dev, WLC_SET_VAR, buf, iovar_len, TRUE); else ret = BCME_BUFTOOSHORT; + if (buf_sync) mutex_unlock(buf_sync); return ret; @@ -334,6 +335,56 @@ int wldev_set_band( return error; } + +int wldev_set_country( + struct net_device *dev, char *country_code, bool notify, bool user_enforced) +{ + int error = -1; + wl_country_t cspec = {{0}, 0, {0}}; + scb_val_t scbval; + char smbuf[WLC_IOCTL_SMLEN]; + + if (!country_code) + return error; + + bzero(&scbval, sizeof(scb_val_t)); + error = wldev_iovar_getbuf(dev, "country", NULL, 0, &cspec, sizeof(cspec), NULL); + if (error < 0) { + WLDEV_ERROR(("%s: get country failed = %d\n", __FUNCTION__, error)); + return error; + } + + if ((error < 0) || + (strncmp(country_code, cspec.ccode, WLC_CNTRY_BUF_SZ) != 0)) { + + if (user_enforced) { + bzero(&scbval, sizeof(scb_val_t)); + error = wldev_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t), true); + if (error < 0) { + WLDEV_ERROR(("%s: set country failed due to Disassoc error %d\n", + __FUNCTION__, error)); + return error; + } + } + + cspec.rev = -1; + memcpy(cspec.country_abbrev, country_code, WLC_CNTRY_BUF_SZ); + memcpy(cspec.ccode, country_code, WLC_CNTRY_BUF_SZ); + get_customized_country_code((char *)&cspec.country_abbrev, &cspec); + error = wldev_iovar_setbuf(dev, "country", &cspec, sizeof(cspec), + smbuf, sizeof(smbuf), NULL); + if (error < 0) { + WLDEV_ERROR(("%s: set country for %s as %s rev %d failed\n", + __FUNCTION__, country_code, cspec.ccode, cspec.rev)); + return error; + } + dhd_bus_country_set(dev, &cspec, notify); + WLDEV_ERROR(("%s: set country for %s as %s rev %d\n", + __FUNCTION__, country_code, cspec.ccode, cspec.rev)); + } + return 0; +} + /* tuning performance for miracast */ int wldev_miracast_tuning( struct net_device *dev, char *command, int total_len) @@ -359,7 +410,7 @@ set_mode: if (mode == 0) { /* Normal mode: restore everything to default */ - ampdu_mpdu = -1; + ampdu_mpdu = -1; /* FW default */ #if defined(ROAM_ENABLE) roam_off = 0; /* roam enable */ #elif defined(DISABLE_BUILTIN_ROAM) @@ -372,7 +423,7 @@ set_mode: } else if (mode == 1) { /* Miracast source mode */ - ampdu_mpdu = 8; + ampdu_mpdu = 8; /* for tx latency */ #if defined(ROAM_ENABLE) || defined(DISABLE_BUILTIN_ROAM) roam_off = 1; /* roam disable */ #endif @@ -383,7 +434,7 @@ set_mode: } else if (mode == 2) { /* Miracast sink/PC Gaming mode */ - ampdu_mpdu = 8; + ampdu_mpdu = 8; /* FW default */ #if defined(ROAM_ENABLE) || defined(DISABLE_BUILTIN_ROAM) roam_off = 1; /* roam disable */ #endif @@ -630,51 +681,56 @@ done: } -int wldev_set_country( - struct net_device *dev, char *country_code, bool notify, bool user_enforced) + +int wldev_get_rx_rate_stats( + struct net_device *dev, char *command, int total_len) { - int error = -1; - wl_country_t cspec = {{0}, 0, {0}}; - scb_val_t scbval; + wl_scb_rx_rate_stats_t *rstats; + struct ether_addr ea; char smbuf[WLC_IOCTL_SMLEN]; + char eabuf[18] = {0, }; + int bytes_written = 0; + int error; - if (!country_code) - return error; + memcpy(eabuf, command+strlen("RXRATESTATS")+1, 17); - bzero(&scbval, sizeof(scb_val_t)); - error = wldev_iovar_getbuf(dev, "country", NULL, 0, &cspec, sizeof(cspec), NULL); - if (error < 0) { - WLDEV_ERROR(("%s: get country failed = %d\n", __FUNCTION__, error)); - return error; + if (!bcm_ether_atoe(eabuf, &ea)) { + WLDEV_ERROR(("Invalid MAC Address\n")); + return -1; } - if ((error < 0) || - (strncmp(country_code, cspec.ccode, WLC_CNTRY_BUF_SZ) != 0)) { + error = wldev_iovar_getbuf(dev, "rx_rate_stats", + &ea, ETHER_ADDR_LEN, smbuf, sizeof(smbuf), NULL); + if (error < 0) { + WLDEV_ERROR(("get rx_rate_stats failed = %d\n", error)); + return -1; + } - if (user_enforced) { - bzero(&scbval, sizeof(scb_val_t)); - error = wldev_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t), true); - if (error < 0) { - WLDEV_ERROR(("%s: set country failed due to Disassoc error %d\n", - __FUNCTION__, error)); - return error; - } - } + rstats = (wl_scb_rx_rate_stats_t *)smbuf; + bytes_written = sprintf(command, "1/%d/%d,", + dtoh32(rstats->rx1mbps[0]), dtoh32(rstats->rx1mbps[1])); + bytes_written += sprintf(command+bytes_written, "2/%d/%d,", + dtoh32(rstats->rx2mbps[0]), dtoh32(rstats->rx2mbps[1])); + bytes_written += sprintf(command+bytes_written, "5.5/%d/%d,", + dtoh32(rstats->rx5mbps5[0]), dtoh32(rstats->rx5mbps5[1])); + bytes_written += sprintf(command+bytes_written, "6/%d/%d,", + dtoh32(rstats->rx6mbps[0]), dtoh32(rstats->rx6mbps[1])); + bytes_written += sprintf(command+bytes_written, "9/%d/%d,", + dtoh32(rstats->rx9mbps[0]), dtoh32(rstats->rx9mbps[1])); + bytes_written += sprintf(command+bytes_written, "11/%d/%d,", + dtoh32(rstats->rx11mbps[0]), dtoh32(rstats->rx11mbps[1])); + bytes_written += sprintf(command+bytes_written, "12/%d/%d,", + dtoh32(rstats->rx12mbps[0]), dtoh32(rstats->rx12mbps[1])); + bytes_written += sprintf(command+bytes_written, "18/%d/%d,", + dtoh32(rstats->rx18mbps[0]), dtoh32(rstats->rx18mbps[1])); + bytes_written += sprintf(command+bytes_written, "24/%d/%d,", + dtoh32(rstats->rx24mbps[0]), dtoh32(rstats->rx24mbps[1])); + bytes_written += sprintf(command+bytes_written, "36/%d/%d,", + dtoh32(rstats->rx36mbps[0]), dtoh32(rstats->rx36mbps[1])); + bytes_written += sprintf(command+bytes_written, "48/%d/%d,", + dtoh32(rstats->rx48mbps[0]), dtoh32(rstats->rx48mbps[1])); + bytes_written += sprintf(command+bytes_written, "54/%d/%d", + dtoh32(rstats->rx54mbps[0]), dtoh32(rstats->rx54mbps[1])); - cspec.rev = -1; - memcpy(cspec.country_abbrev, country_code, WLC_CNTRY_BUF_SZ); - memcpy(cspec.ccode, country_code, WLC_CNTRY_BUF_SZ); - get_customized_country_code((char *)&cspec.country_abbrev, &cspec); - error = wldev_iovar_setbuf(dev, "country", &cspec, sizeof(cspec), - smbuf, sizeof(smbuf), NULL); - if (error < 0) { - WLDEV_ERROR(("%s: set country for %s as %s rev %d failed\n", - __FUNCTION__, country_code, cspec.ccode, cspec.rev)); - return error; - } - dhd_bus_country_set(dev, &cspec, notify); - WLDEV_ERROR(("%s: set country for %s as %s rev %d\n", - __FUNCTION__, country_code, cspec.ccode, cspec.rev)); - } - return 0; + return bytes_written; } diff --git a/drivers/net/wireless/bcmdhd/wldev_common.h b/drivers/net/wireless/bcmdhd/wldev_common.h index e70faac7ad27..a23209e32f46 100644..100755 --- a/drivers/net/wireless/bcmdhd/wldev_common.h +++ b/drivers/net/wireless/bcmdhd/wldev_common.h @@ -1,14 +1,14 @@ /* * Common function shared by Linux WEXT, cfg80211 and p2p drivers * - * Copyright (C) 1999-2012, Broadcom Corporation - * + * Copyright (C) 1999-2013, Broadcom Corporation + * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2 (the "GPL"), * available at http://www.broadcom.com/licenses/GPLv2.php, with the * following added to such license: - * + * * As a special exception, the copyright holders of this software give you * permission to link this software with independent modules, and to copy and * distribute the resulting executable under terms of your choice, provided that @@ -16,7 +16,7 @@ * 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. @@ -110,6 +110,8 @@ int wldev_get_band(struct net_device *dev, uint *pband); int wldev_set_band(struct net_device *dev, uint band); int wldev_miracast_tuning(struct net_device *dev, char *command, int total_len); +int wldev_get_assoc_resp_ie(struct net_device *dev, char *command, int total_len); +int wldev_get_rx_rate_stats(struct net_device *dev, char *command, int total_len); int wldev_get_assoc_resp_ie(struct net_device *dev, char *command, int total_len); |