net: wireless: bcmdhd: add bcmdhd 1.201.31 driver
Nagarjuna Kristam [Thu, 17 Jul 2014 07:13:47 +0000 (12:13 +0530)]
Bug 1454889
Bug 200022910

Change-Id: Id697f3118515ef70a1cb0747b8d1691a88df8083
Signed-off-by: Nagarjuna Kristam <nkristam@nvidia.com>
Reviewed-on: http://git-master/r/450639
Reviewed-by: Manikanta Maddireddy <mmaddireddy@nvidia.com>
Tested-by: Manikanta Maddireddy <mmaddireddy@nvidia.com>
Reviewed-by: Mohan Thadikamalla <mohant@nvidia.com>
GVS: Gerrit_Virtual_Submit
Reviewed-by: Laxman Dewangan <ldewangan@nvidia.com>

155 files changed:
drivers/net/wireless/bcmdhd/Kconfig
drivers/net/wireless/bcmdhd/Makefile
drivers/net/wireless/bcmdhd/aiutils.c [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/bcmevent.c [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/bcmsdh.c [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/bcmsdh_linux.c [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/bcmsdspi_linux.c [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/bcmspibrcm.c [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/bcmutils.c [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/bcmwifi_channels.c [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/bcmwifi_channels.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/bcmwifi_rates.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/circularbuf.c [deleted file]
drivers/net/wireless/bcmdhd/dhd.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/dhd_bta.c [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/dhd_bta.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/dhd_bus.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/dhd_cdc.c [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/dhd_cfg80211.c [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/dhd_cfg80211.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/dhd_cfg_vendor.c [new file with mode: 0644]
drivers/net/wireless/bcmdhd/dhd_common.c [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/dhd_custom_gpio.c [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/dhd_dbg.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/dhd_flowring.c [new file with mode: 0644]
drivers/net/wireless/bcmdhd/dhd_flowring.h [new file with mode: 0644]
drivers/net/wireless/bcmdhd/dhd_ip.c [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/dhd_ip.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/dhd_linux.c [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/dhd_linux.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/dhd_linux_platdev.c [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/dhd_linux_sched.c [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/dhd_linux_wq.c [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/dhd_linux_wq.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/dhd_msgbuf.c [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/dhd_pcie.c [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/dhd_pcie.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/dhd_pcie_linux.c [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/dhd_pno.c [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/dhd_pno.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/dhd_proto.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/dhd_qmon.c [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/dhd_qmon.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/dhd_sdio.c [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/dhd_wlfc.c [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/dhd_wlfc.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/dngl_stats.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/dngl_wlhdr.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/hnd_pktpool.c [new file with mode: 0644]
drivers/net/wireless/bcmdhd/hnd_pktq.c [new file with mode: 0644]
drivers/net/wireless/bcmdhd/hndpmu.c [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/Makefile [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/aidmp.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/bcm_cfg.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/bcm_mpool_pub.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/bcmcdc.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/bcmdefs.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/bcmdevs.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/bcmendian.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/bcmmsgbuf.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/bcmnvram.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/bcmpcie.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/bcmpcispi.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/bcmperf.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/bcmsdbus.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/bcmsdh.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/bcmsdpcm.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/bcmsdspi.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/bcmsdstd.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/bcmspi.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/bcmspibrcm.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/bcmsrom_fmt.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/bcmsrom_tbl.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/bcmutils.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/brcm_nl80211.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/circularbuf.h [deleted file]
drivers/net/wireless/bcmdhd/include/dbus.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/devctrl_if/wlioctl_defs.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/dhdioctl.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/epivers.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/hnd_armtrap.h [moved from drivers/net/wireless/bcmdhd/include/hndrte_armtrap.h with 93% similarity, mode: 0644]
drivers/net/wireless/bcmdhd/include/hnd_cons.h [moved from drivers/net/wireless/bcmdhd/include/hndrte_cons.h with 86% similarity, mode: 0644]
drivers/net/wireless/bcmdhd/include/hnd_pktpool.h [new file with mode: 0644]
drivers/net/wireless/bcmdhd/include/hnd_pktq.h [new file with mode: 0644]
drivers/net/wireless/bcmdhd/include/hndpmu.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/hndsoc.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/linux_osl.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/linuxver.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/miniopt.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/msgtrace.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/osl.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/osl_decl.h [new file with mode: 0644]
drivers/net/wireless/bcmdhd/include/packed_section_end.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/packed_section_start.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/pcicfg.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/pcie_core.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/proto/802.11.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/proto/802.11_bta.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/proto/802.11e.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/proto/802.1d.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/proto/802.3.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/proto/bcmdhcp.h [new file with mode: 0644]
drivers/net/wireless/bcmdhd/include/proto/bcmeth.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/proto/bcmevent.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/proto/bcmip.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/proto/bcmipv6.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/proto/bcmtcp.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/proto/bcmudp.h [new file with mode: 0644]
drivers/net/wireless/bcmdhd/include/proto/bt_amp_hci.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/proto/eapol.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/proto/ethernet.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/proto/p2p.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/proto/sdspi.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/proto/vlan.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/proto/wpa.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/proto/wps.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/sbchipc.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/sbconfig.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/sbhnddma.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/sbpcmcia.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/sbsdio.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/sbsdpcmdev.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/sbsocram.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/sdio.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/sdioh.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/sdiovar.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/siutils.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/spid.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/trxhdr.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/typedefs.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/wlfc_proto.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/include/wlioctl.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/linux_osl.c [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/pcie_core.c [new file with mode: 0644]
drivers/net/wireless/bcmdhd/sbutils.c [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/siutils.c [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/siutils_priv.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/uamp_api.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/wl_android.c [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/wl_android.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/wl_cfg80211.c
drivers/net/wireless/bcmdhd/wl_cfg80211.h
drivers/net/wireless/bcmdhd/wl_cfg_btcoex.c [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/wl_cfgp2p.c [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/wl_cfgp2p.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/wl_cfgvendor.h [new file with mode: 0644]
drivers/net/wireless/bcmdhd/wl_dbg.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/wl_iw.c [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/wl_iw.h [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/wl_linux_mon.c [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/wldev_common.c [changed mode: 0755->0644]
drivers/net/wireless/bcmdhd/wldev_common.h [changed mode: 0755->0644]

index 1870948..508b97b 100644 (file)
@@ -16,20 +16,32 @@ config BCMDHD_PCIE
        bool "PCIe bus interface support"
        depends on BCMDHD && PCI && !BCMDHD_SDIO
 
+config BCM43241
+       bool "Broadcom 43241 wireless card support"
+       depends on BCMDHD
+       default y
+
 config BCM4354
        bool "Broadcom 4354 wireless cards PRC support"
-       depends on BCMDHD
+       depends on BCMDHD && !BCM43241
        ---help---
          This module adds support for wireless adapters based on
          Broadcom 4354 chipset.
 
 config BCM4339
        bool "Broadcom 4339 wireless cards PRC support"
-       depends on BCMDHD
+       depends on BCMDHD && !BCM43241 && !BCM4354
        ---help---
          This module adds support for wireless adapters based on
          Broadcom 4339 chipset.
 
+config BCMDHD_INSMOD_NO_FW_LOAD
+       bool "Enable delayed firmware load"
+       depends on BCMDHD
+       default n
+       ---help---
+       Enable delayes firmware
+
 config BCMDHD_FW_PATH
        depends on BCMDHD
        string "Firmware path"
index 98afe0f..ec58043 100644 (file)
@@ -9,8 +9,8 @@ DHDCFLAGS += -Wall -Wstrict-prototypes -Dlinux -DLINUX -DBCMDRIVER            \
        -DWIFI_ACT_FRAME -DARP_OFFLOAD_SUPPORT                                \
        -DKEEP_ALIVE -DCSCAN -DPKT_FILTER_SUPPORT                             \
        -DEMBEDDED_PLATFORM -DPNO_SUPPORT                                     \
-       -DDHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT -DGET_CUSTOM_MAC_ENABLE   \
-       -DCUSTOMER_HW2 -DENABLE_INSMOD_NO_FW_LOAD -DQMONITOR -DTOE
+       -DDHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT                           \
+       -DCUSTOMER_HW2
 
 #################
 # Common feature
@@ -94,24 +94,24 @@ DHDCFLAGS += -DWL_ENABLE_P2P_IF
 ##########################
 DRIVER_TYPE ?= $(CONFIG_BCMDHD)
 
-DHDCFLAGS += -DBCM4339_CHIP -DBCM43241_CHIP -DBCM4354_CHIP
-DHDCFLAGS += -DPROP_TXSTATUS_VSDB
-DHDCFLAGS += -DCUSTOM_DPC_PRIO_SETTING=99
-DHDCFLAGS += -DRXFRAME_THREAD
-DHDCFLAGS += -DDHDTCPACK_SUPPRESS
-
 #########################
-# BCM43241Chip dependent feature
+# Chip dependent feature
 #########################
-DHDCFLAGS += -DMIMO_ANT_SETTING
-DHDCFLAGS += -DCUSTOM_SDIO_F2_BLKSIZE=128
-DHDCFLAGS += -DAMPDU_HOSTREORDER
-DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=32
-ifeq ($(DRIVER_TYPE),m)
-  DHDCFLAGS += -fno-pic
+ifneq ($(CONFIG_BCM43241),)
+  DHDCFLAGS += -DBCM43241_CHIP -DHW_OOB
+  DHDCFLAGS += -DCUSTOM_SDIO_F2_BLKSIZE=256
+ DHDCFLAGS += -DAMPDU_HOSTREORDER
+ DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=32
+ DHDCFLAGS += -DPROP_TXSTATUS_VSDB
+ DHDCFLAGS += -DCUSTOM_DPC_PRIO_SETTING=99
+ DHDCFLAGS += -DRXFRAME_THREAD
+ DHDCFLAGS += -DDHDTCPACK_SUPPRESS
+ DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0
 endif
 
 ifneq ($(CONFIG_BCM4354),)
+  DHDCFLAGS += -DBCM4354_CHIP -DHW_OOB
+
 # tput enhancement
   DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1
   DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128
@@ -123,6 +123,7 @@ ifneq ($(CONFIG_BCM4354),)
   DHDCFLAGS += -DREPEAT_READFRAME
   DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64
   DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0
+# DHDCFLAGS += -DPROP_TXSTATUS_VSDB
   DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=40
   DHDCFLAGS += -DMAX_HDR_READ=128
   DHDCFLAGS += -DDHD_FIRSTREAD=128
@@ -135,6 +136,8 @@ ifneq ($(CONFIG_BCM4354),)
 endif
 
 ifneq ($(CONFIG_BCM4339),)
+  DHDCFLAGS += -DBCM4339_CHIP -DHW_OOB
+
   # tput enhancement
   DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1
   DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128
@@ -145,6 +148,7 @@ ifneq ($(CONFIG_BCM4339),)
   DHDCFLAGS += -DRXFRAME_THREAD
   DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64
   DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0
+# DHDCFLAGS += -DPROP_TXSTATUS_VSDB
   DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=32
 
   # New Features
@@ -154,15 +158,10 @@ ifneq ($(CONFIG_BCM4339),)
 endif
 
 ifneq ($(CONFIG_BCMDHD_SDIO),)
-  DHDCFLAGS += -DBDC -DDHD_BCMEVENTS -DMMC_SDIO_ABORT
+  DHDCFLAGS += -DBDC -DOOB_INTR_ONLY -DDHD_BCMEVENTS -DMMC_SDIO_ABORT
   DHDCFLAGS += -DBCMSDIO -DBCMLXSDMMC -DUSE_SDIOFIFO_IOVAR
   DHDCFLAGS += -DPROP_TXSTATUS
-endif
-
-ifeq ($(CONFIG_BCMDHD_HW_OOB),y)
- DHDCFLAGS += -DHW_OOB -DOOB_INTR_ONLY
-else
- DHDCFLAGS += -DSDIO_ISR_THREAD
+  DHDCFLAGS += -DQMONITOR
 endif
 
 ifneq ($(CONFIG_BCMDHD_PCIE),)
@@ -171,25 +170,43 @@ endif
 
 #EXTRA_LDFLAGS += --strip-debug
 
+ifeq ($(CONFIG_BCMDHD_INSMOD_NO_FW_LOAD),y)
+  DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD
+endif
+
 EXTRA_CFLAGS += $(DHDCFLAGS) -DDHD_DEBUG
 EXTRA_CFLAGS += -DSRCBASE=\"$(src)\"
 EXTRA_CFLAGS += -I$(src)/include/ -I$(src)/
-KBUILD_CFLAGS += -I$(LINUXDIR)/include -I$(shell pwd) -Idrivers/net/wireless/bcmdhd -Idrivers/net/wireless/bcmdhd/include
+KBUILD_CFLAGS += -I$(LINUXDIR)/include -I$(shell pwd)
 
 DHDOFILES := dhd_pno.o dhd_common.o dhd_ip.o dhd_custom_gpio.o \
        dhd_linux.o dhd_linux_sched.o dhd_cfg80211.o dhd_linux_wq.o aiutils.o bcmevent.o \
        bcmutils.o bcmwifi_channels.o hndpmu.o linux_osl.o sbutils.o siutils.o \
        wl_android.o wl_cfg80211.o wl_cfgp2p.o wl_cfg_btcoex.o wldev_common.o wl_linux_mon.o  \
-       dhd_linux_platdev.o dhd_pno.o dhd_linux_wq.o wl_cfg_btcoex.o dhd_qmon.o
+       dhd_linux_platdev.o dhd_pno.o dhd_linux_wq.o wl_cfg_btcoex.o \
+       hnd_pktq.o hnd_pktpool.o
 
 ifneq ($(CONFIG_BCMDHD_SDIO),)
   DHDOFILES += bcmsdh.o bcmsdh_linux.o bcmsdh_sdmmc.o bcmsdh_sdmmc_linux.o
-  DHDOFILES += dhd_cdc.o dhd_wlfc.o dhd_sdio.o
+  DHDOFILES += dhd_cdc.o dhd_wlfc.o dhd_sdio.o dhd_qmon.o
 endif
 
 ifneq ($(CONFIG_BCMDHD_PCIE),)
-  DHDOFILES += dhd_pcie.o dhd_pcie_linux.o dhd_msgbuf.o circularbuf.o
+  DHDOFILES += dhd_pcie.o dhd_pcie_linux.o dhd_msgbuf.o dhd_flowring.o
+  DHDOFILES += pcie_core.o
 endif
 
 bcmdhd-objs := $(DHDOFILES)
 obj-$(DRIVER_TYPE)   += bcmdhd.o
+
+all:
+       @echo "$(MAKE) --no-print-directory -C $(KDIR) SUBDIRS=$(CURDIR) modules"
+       @$(MAKE) --no-print-directory -C $(KDIR) SUBDIRS=$(CURDIR) modules
+
+clean:
+       rm -rf *.o *.ko *.mod.c *~ .*.cmd *.o.cmd .*.o.cmd \
+       Module.symvers modules.order .tmp_versions modules.builtin
+
+install:
+       @$(MAKE) --no-print-directory -C $(KDIR) \
+               SUBDIRS=$(CURDIR) modules_install
old mode 100755 (executable)
new mode 100644 (file)
index 611f9a7..9095894
@@ -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 432226 2013-10-26 04:34:36Z $
+ * $Id: aiutils.c 467150 2014-04-02 17:30:43Z $
  */
 #include <bcm_cfg.h>
 #include <typedefs.h>
@@ -39,6 +39,7 @@
 #define BCM47162_DMP() (0)
 #define BCM5357_DMP() (0)
 #define BCM4707_DMP() (0)
+#define PMU_DMP() (0)
 #define remap_coreid(sih, coreid)      (coreid)
 #define remap_corerev(sih, corerev)    (corerev)
 
@@ -211,7 +212,8 @@ ai_scan(si_t *sih, void *regs, uint devid)
                                        sii->oob_router = addrl;
                                }
                        }
-                       if (cid != GMAC_COMMON_4706_CORE_ID && cid != NS_CCB_CORE_ID)
+                       if (cid != GMAC_COMMON_4706_CORE_ID && cid != NS_CCB_CORE_ID &&
+                               cid != PMU_CORE_ID && cid != GCI_CORE_ID)
                                continue;
                }
 
@@ -339,6 +341,9 @@ error:
        return;
 }
 
+#define AI_SETCOREIDX_MAPSIZE(coreid) \
+       (((coreid) == NS_CCB_CORE_ID) ? 15 * SI_CORE_SIZE : SI_CORE_SIZE)
+
 /* This function changes the logical "focus" to the indicated core.
  * Return the current core's virtual address.
  */
@@ -366,7 +371,8 @@ ai_setcoreidx(si_t *sih, uint coreidx)
        case SI_BUS:
                /* map new one */
                if (!cores_info->regs[coreidx]) {
-                       cores_info->regs[coreidx] = REG_MAP(addr, SI_CORE_SIZE);
+                       cores_info->regs[coreidx] = REG_MAP(addr,
+                               AI_SETCOREIDX_MAPSIZE(cores_info->coreid[coreidx]));
                        ASSERT(GOODREGS(cores_info->regs[coreidx]));
                }
                sii->curmap = regs = cores_info->regs[coreidx];
@@ -564,7 +570,17 @@ ai_flag(si_t *sih)
                        __FUNCTION__));
                return sii->curidx;
        }
+
+#ifdef REROUTE_OOBINT
+       if (PMU_DMP()) {
+               SI_ERROR(("%s: Attempting to read PMU DMP registers\n",
+                       __FUNCTION__));
+               return PMU_OOB_BIT;
+       }
+#endif /* REROUTE_OOBINT */
+
        ai = sii->curwrap;
+       ASSERT(ai != NULL);
 
        return (R_REG(sii->osh, &ai->oobselouta30) & 0x1f);
 }
@@ -588,6 +604,14 @@ ai_flag_alt(si_t *sih)
                        __FUNCTION__));
                return sii->curidx;
        }
+#ifdef REROUTE_OOBINT
+       if (PMU_DMP()) {
+               SI_ERROR(("%s: Attempting to read PMU DMP registers\n",
+                       __FUNCTION__));
+               return PMU_OOB_BIT;
+       }
+#endif /* REROUTE_OOBINT */
+
        ai = sii->curwrap;
 
        return ((R_REG(sii->osh, &ai->oobselouta30) >> AI_OOBSEL_1_SHIFT) & AI_OOBSEL_MASK);
@@ -922,6 +946,11 @@ ai_core_cflags_wo(si_t *sih, uint32 mask, uint32 val)
                        __FUNCTION__));
                return;
        }
+       if (PMU_DMP()) {
+               SI_ERROR(("%s: Accessing PMU DMP register (ioctrl)\n",
+                       __FUNCTION__));
+               return;
+       }
 
        ASSERT(GOODREGS(sii->curwrap));
        ai = sii->curwrap;
@@ -957,6 +986,11 @@ ai_core_cflags(si_t *sih, uint32 mask, uint32 val)
                return 0;
        }
 
+       if (PMU_DMP()) {
+               SI_ERROR(("%s: Accessing PMU DMP register (ioctrl)\n",
+                       __FUNCTION__));
+               return 0;
+       }
        ASSERT(GOODREGS(sii->curwrap));
        ai = sii->curwrap;
 
@@ -992,6 +1026,11 @@ ai_core_sflags(si_t *sih, uint32 mask, uint32 val)
                        __FUNCTION__));
                return 0;
        }
+       if (PMU_DMP()) {
+               SI_ERROR(("%s: Accessing PMU DMP register (ioctrl)\n",
+                       __FUNCTION__));
+               return 0;
+       }
 
        ASSERT(GOODREGS(sii->curwrap));
        ai = sii->curwrap;
@@ -1006,3 +1045,71 @@ ai_core_sflags(si_t *sih, uint32 mask, uint32 val)
 
        return R_REG(sii->osh, &ai->iostatus);
 }
+
+#if defined(BCMDBG_PHYDUMP)
+/* print interesting aidmp registers */
+void
+ai_dumpregs(si_t *sih, struct bcmstrbuf *b)
+{
+       si_info_t *sii = SI_INFO(sih);
+       si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info;
+       osl_t *osh;
+       aidmp_t *ai;
+       uint i;
+
+       osh = sii->osh;
+
+       for (i = 0; i < sii->numcores; i++) {
+               si_setcoreidx(&sii->pub, i);
+               ai = sii->curwrap;
+
+               bcm_bprintf(b, "core 0x%x: \n", cores_info->coreid[i]);
+               if (BCM47162_DMP()) {
+                       bcm_bprintf(b, "Skipping mips74k in 47162a0\n");
+                       continue;
+               }
+               if (BCM5357_DMP()) {
+                       bcm_bprintf(b, "Skipping usb20h in 5357\n");
+                       continue;
+               }
+               if (BCM4707_DMP()) {
+                       bcm_bprintf(b, "Skipping chipcommonb in 4707\n");
+                       continue;
+               }
+
+               if (PMU_DMP()) {
+                       bcm_bprintf(b, "Skipping pmu core\n");
+                       continue;
+               }
+
+               bcm_bprintf(b, "ioctrlset 0x%x ioctrlclear 0x%x ioctrl 0x%x iostatus 0x%x"
+                           "ioctrlwidth 0x%x iostatuswidth 0x%x\n"
+                           "resetctrl 0x%x resetstatus 0x%x resetreadid 0x%x resetwriteid 0x%x\n"
+                           "errlogctrl 0x%x errlogdone 0x%x errlogstatus 0x%x"
+                           "errlogaddrlo 0x%x errlogaddrhi 0x%x\n"
+                           "errlogid 0x%x errloguser 0x%x errlogflags 0x%x\n"
+                           "intstatus 0x%x config 0x%x itcr 0x%x\n",
+                           R_REG(osh, &ai->ioctrlset),
+                           R_REG(osh, &ai->ioctrlclear),
+                           R_REG(osh, &ai->ioctrl),
+                           R_REG(osh, &ai->iostatus),
+                           R_REG(osh, &ai->ioctrlwidth),
+                           R_REG(osh, &ai->iostatuswidth),
+                           R_REG(osh, &ai->resetctrl),
+                           R_REG(osh, &ai->resetstatus),
+                           R_REG(osh, &ai->resetreadid),
+                           R_REG(osh, &ai->resetwriteid),
+                           R_REG(osh, &ai->errlogctrl),
+                           R_REG(osh, &ai->errlogdone),
+                           R_REG(osh, &ai->errlogstatus),
+                           R_REG(osh, &ai->errlogaddrlo),
+                           R_REG(osh, &ai->errlogaddrhi),
+                           R_REG(osh, &ai->errlogid),
+                           R_REG(osh, &ai->errloguser),
+                           R_REG(osh, &ai->errlogflags),
+                           R_REG(osh, &ai->intstatus),
+                           R_REG(osh, &ai->config),
+                           R_REG(osh, &ai->itcr));
+       }
+}
+#endif 
old mode 100755 (executable)
new mode 100644 (file)
index 93beccb..d3780d5
@@ -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 440870 2013-12-04 05:23:45Z $
+ * $Id: bcmevent.c 487838 2014-06-27 05:51:44Z $
  */
 
 #include <typedefs.h>
 #include <proto/bcmeth.h>
 #include <proto/bcmevent.h>
 
+
+/* Table of event name strings for UIs and debugging dumps */
+typedef struct {
+       uint event;
+       const char *name;
+} bcmevent_name_str_t;
+
 /* Use the actual name for event tracing */
 #define BCMEVENT_NAME(_event) {(_event), #_event}
 
-const bcmevent_name_t bcmevent_names[] = {
+static const bcmevent_name_str_t bcmevent_names[] = {
        BCMEVENT_NAME(WLC_E_SET_SSID),
        BCMEVENT_NAME(WLC_E_JOIN),
        BCMEVENT_NAME(WLC_E_START),
@@ -119,7 +126,6 @@ const bcmevent_name_t bcmevent_names[] = {
 #endif
        BCMEVENT_NAME(WLC_E_ASSOC_REQ_IE),
        BCMEVENT_NAME(WLC_E_ASSOC_RESP_IE),
-       BCMEVENT_NAME(WLC_E_ACTION_FRAME_RX_NDIS),
        BCMEVENT_NAME(WLC_E_BEACON_FRAME_RX),
 #ifdef WLTDLS
        BCMEVENT_NAME(WLC_E_TDLS_PEER_EVENT),
@@ -145,6 +151,36 @@ const bcmevent_name_t bcmevent_names[] = {
        BCMEVENT_NAME(WLC_E_BCMC_CREDIT_SUPPORT),
 #endif
        BCMEVENT_NAME(WLC_E_TXFAIL_THRESH),
+#ifdef WLBSSLOAD_REPORT
+       BCMEVENT_NAME(WLC_E_BSS_LOAD),
+#endif
+#if defined(BT_WIFI_HANDOVER) || defined(WL_TBOW)
+       BCMEVENT_NAME(WLC_E_BT_WIFI_HANDOVER_REQ),
+#endif
+       BCMEVENT_NAME(WLC_E_RMC_EVENT),
 };
 
-const int bcmevent_names_size = ARRAYSIZE(bcmevent_names);
+
+const char *bcmevent_get_name(uint event_type)
+{
+       /* note:  first coded this as a static const but some
+        * ROMs already have something called event_name so
+        * changed it so we don't have a variable for the
+        * 'unknown string
+        */
+       const char *event_name = NULL;
+
+       uint idx;
+       for (idx = 0; idx < (uint)ARRAYSIZE(bcmevent_names); idx++) {
+
+               if (bcmevent_names[idx].event == event_type) {
+                       event_name = bcmevent_names[idx].name;
+                       break;
+               }
+       }
+
+       /* if we find an event name in the array, return it.
+        * otherwise return unknown string.
+        */
+       return ((event_name) ? event_name : "Unknown Event");
+}
old mode 100755 (executable)
new mode 100644 (file)
index f77de60..5ee526b
@@ -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 455573 2014-02-14 17:49:31Z $
+ * $Id: bcmsdh.c 450676 2014-01-22 22:45:13Z $
  */
 
 /**
old mode 100755 (executable)
new mode 100644 (file)
index a2888df..5b2d8b4
@@ -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 455573 2014-02-14 17:49:31Z $
+ * $Id: bcmsdh_linux.c 461444 2014-03-12 02:55:28Z $
  */
 
 /**
@@ -44,6 +44,9 @@ extern void dhdsdio_isr(void * args);
 #include <bcmutils.h>
 #include <dngl_stats.h>
 #include <dhd.h>
+#if defined(CONFIG_ARCH_ODIN)
+#include <linux/platform_data/gpio-odin.h>
+#endif /* defined(CONFIG_ARCH_ODIN) */
 #include <dhd_linux.h>
 
 /* driver info, initialized when bcmsdh_register is called */
@@ -338,8 +341,13 @@ int bcmsdh_oob_intr_register(bcmsdh_info_t *bcmsdh, bcmsdh_cb_fn_t oob_irq_handl
                (int)bcmsdh_osinfo->oob_irq_num, (int)bcmsdh_osinfo->oob_irq_flags));
        bcmsdh_osinfo->oob_irq_handler = oob_irq_handler;
        bcmsdh_osinfo->oob_irq_handler_context = oob_irq_handler_context;
+#if defined(CONFIG_ARCH_ODIN)
+       err = odin_gpio_sms_request_irq(bcmsdh_osinfo->oob_irq_num, wlan_oob_irq,
+               bcmsdh_osinfo->oob_irq_flags, "bcmsdh_sdmmc", bcmsdh);
+#else
        err = request_irq(bcmsdh_osinfo->oob_irq_num, wlan_oob_irq,
                bcmsdh_osinfo->oob_irq_flags, "bcmsdh_sdmmc", bcmsdh);
+#endif /* defined(CONFIG_ARCH_ODIN) */
        if (err) {
                SDLX_MSG(("%s: request_irq failed with %d\n", __FUNCTION__, err));
                return err;
old mode 100755 (executable)
new mode 100644 (file)
index 390ad0b..d668d88
@@ -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 457662 2014-02-24 15:07:28Z $
+ * $Id: bcmsdh_sdmmc.c 459285 2014-03-03 02:54:39Z $
  */
 #include <typedefs.h>
 
@@ -1331,7 +1331,7 @@ sdioh_start(sdioh_info_t *sd, 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(sd->func[0]->card->host))) {
+               if ((ret = sdio_reset_comm(sd->func[0]->card))) {
                        sd_err(("%s Failed, error = %d\n", __FUNCTION__, ret));
                        return ret;
                }
@@ -1418,8 +1418,6 @@ sdioh_stop(sdioh_info_t *sd)
 #endif
                bcmsdh_oob_intr_set(sd->bcmsdh, FALSE);
 #endif /* !defined(OOB_INTR_ONLY) */
-               if (mmc_power_save_host((sd->func[0])->card->host))
-                       sd_err(("%s card power save fail\n", __FUNCTION__));
        }
        else
                sd_err(("%s Failed\n", __FUNCTION__));
old mode 100755 (executable)
new mode 100644 (file)
index e8c1958..a93f983
@@ -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 434724 2013-11-07 05:38:43Z $
+ * $Id: bcmsdh_sdmmc_linux.c 434777 2013-11-07 09:30:27Z $
  */
 
 #include <typedefs.h>
@@ -40,9 +40,6 @@
 #include <dhd_linux.h>
 #include <bcmsdh_sdmmc.h>
 #include <dhd_dbg.h>
-#if defined(CONFIG_WIFI_CONTROL_FUNC)
-#include <linux/wlan_plat.h>
-#endif
 
 #if !defined(SDIO_VENDOR_ID_BROADCOM)
 #define SDIO_VENDOR_ID_BROADCOM                0x02d0
@@ -106,30 +103,12 @@ static int sdioh_probe(struct sdio_func *func)
        wifi_adapter_info_t *adapter;
        osl_t *osh = NULL;
        sdioh_info_t *sdioh = NULL;
-#if defined(CONFIG_WIFI_CONTROL_FUNC)
-       struct wifi_platform_data *plat_data;
-#endif
 
        sd_err(("bus num (host idx)=%d, slot num (rca)=%d\n", host_idx, rca));
        adapter = dhd_wifi_platform_get_adapter(SDIO_BUS, host_idx, rca);
-       if (adapter  != NULL) {
+       if (adapter  != NULL)
                sd_err(("found adapter info '%s'\n", adapter->name));
-#if defined(CONFIG_WIFI_CONTROL_FUNC)
-               if (adapter->wifi_plat_data) {
-                       plat_data = adapter->wifi_plat_data;
-                       /* sdio card detection is completed,
-                        * so stop card detection here */
-                       if (plat_data->set_carddetect) {
-                               sd_debug(("stopping card detection\n"));
-                               plat_data->set_carddetect(0);
-                       }
-                       else
-                               sd_err(("set_carddetect is not registered\n"));
-               }
-               else
-                       sd_err(("platform data is NULL\n"));
-#endif
-       } else
+       else
                sd_err(("can't find adapter info for this chip\n"));
 
 #ifdef WL_CFG80211
@@ -197,11 +176,8 @@ static int bcmsdh_sdmmc_probe(struct sdio_func *func,
        sd_info(("Function#: 0x%04x\n", func->num));
 
        /* 4318 doesn't have function 2 */
-       if ((func->num == 2) || (func->num == 1 && func->device == 0x4)) {
+       if ((func->num == 2) || (func->num == 1 && func->device == 0x4))
                ret = sdioh_probe(func);
-               if (mmc_power_save_host(func->card->host))
-                       sd_err(("%s: card power save fail", __FUNCTION__));
-       }
 
        return ret;
 }
@@ -225,11 +201,17 @@ static void bcmsdh_sdmmc_remove(struct sdio_func *func)
 
 /* devices we support, null terminated */
 static const struct sdio_device_id bcmsdh_sdmmc_ids[] = {
-       {       .class  = SDIO_CLASS_NONE,
-               .vendor = SDIO_VENDOR_ID_BROADCOM,
-               .device = SDIO_ANY_ID
-       },
-       { /* end: all zeroes */                         },
+       { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_DEFAULT) },
+       { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4325_SDGWB) },
+       { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4325) },
+       { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4329) },
+       { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4319) },
+       { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4330) },
+       { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4334) },
+       { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4324) },
+       { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_43239) },
+       { SDIO_DEVICE_CLASS(SDIO_CLASS_NONE)            },
+       { /* end: all zeroes */                         },
 };
 
 MODULE_DEVICE_TABLE(sdio, bcmsdh_sdmmc_ids);
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
index dee05aa..78257d0
@@ -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 457888 2014-02-25 03:34:39Z $
+ * $Id: bcmutils.c 488316 2014-06-30 15:22:21Z $
  */
 
 #include <bcm_cfg.h>
@@ -65,6 +65,7 @@ void *_bcmutils_dummy_fn = NULL;
 
 
 
+
 #ifdef BCMDRIVER
 
 
@@ -256,489 +257,6 @@ pktoffset(osl_t *osh, void *p,  uint offset)
        return p;
 }
 
-/*
- * osl multiple-precedence packet queue
- * hi_prec is always >= the number of the highest non-empty precedence
- */
-void * BCMFASTPATH
-pktq_penq(struct pktq *pq, int prec, void *p)
-{
-       struct pktq_prec *q;
-
-       ASSERT(prec >= 0 && prec < pq->num_prec);
-       ASSERT(PKTLINK(p) == NULL);         /* queueing chains not allowed */
-
-       ASSERT(!pktq_full(pq));
-       ASSERT(!pktq_pfull(pq, prec));
-
-       q = &pq->q[prec];
-
-       if (q->head)
-               PKTSETLINK(q->tail, p);
-       else
-               q->head = p;
-
-       q->tail = p;
-       q->len++;
-
-       pq->len++;
-
-       if (pq->hi_prec < prec)
-               pq->hi_prec = (uint8)prec;
-
-       return p;
-}
-
-void * BCMFASTPATH
-pktq_penq_head(struct pktq *pq, int prec, void *p)
-{
-       struct pktq_prec *q;
-
-       ASSERT(prec >= 0 && prec < pq->num_prec);
-       ASSERT(PKTLINK(p) == NULL);         /* queueing chains not allowed */
-
-       ASSERT(!pktq_full(pq));
-       ASSERT(!pktq_pfull(pq, prec));
-
-       q = &pq->q[prec];
-
-       if (q->head == NULL)
-               q->tail = p;
-
-       PKTSETLINK(p, q->head);
-       q->head = p;
-       q->len++;
-
-       pq->len++;
-
-       if (pq->hi_prec < prec)
-               pq->hi_prec = (uint8)prec;
-
-       return p;
-}
-
-void * BCMFASTPATH
-pktq_pdeq(struct pktq *pq, int prec)
-{
-       struct pktq_prec *q;
-       void *p;
-
-       ASSERT(prec >= 0 && prec < pq->num_prec);
-
-       q = &pq->q[prec];
-
-       if ((p = q->head) == NULL)
-               return NULL;
-
-       if ((q->head = PKTLINK(p)) == NULL)
-               q->tail = NULL;
-
-       q->len--;
-
-       pq->len--;
-
-       PKTSETLINK(p, NULL);
-
-       return p;
-}
-
-void * BCMFASTPATH
-pktq_pdeq_prev(struct pktq *pq, int prec, void *prev_p)
-{
-       struct pktq_prec *q;
-       void *p;
-
-       ASSERT(prec >= 0 && prec < pq->num_prec);
-
-       q = &pq->q[prec];
-
-       if (prev_p == NULL)
-               return NULL;
-
-       if ((p = PKTLINK(prev_p)) == NULL)
-               return NULL;
-
-       q->len--;
-
-       pq->len--;
-
-       PKTSETLINK(prev_p, PKTLINK(p));
-       PKTSETLINK(p, NULL);
-
-       return 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));
-               if (q->tail == p) {
-                       q->tail = prev;
-               }
-       }
-
-       q->len--;
-
-       pq->len--;
-
-       PKTSETLINK(p, NULL);
-
-       return p;
-}
-
-void * BCMFASTPATH
-pktq_pdeq_tail(struct pktq *pq, int prec)
-{
-       struct pktq_prec *q;
-       void *p, *prev;
-
-       ASSERT(prec >= 0 && prec < pq->num_prec);
-
-       q = &pq->q[prec];
-
-       if ((p = q->head) == NULL)
-               return NULL;
-
-       for (prev = NULL; p != q->tail; p = PKTLINK(p))
-               prev = p;
-
-       if (prev)
-               PKTSETLINK(prev, NULL);
-       else
-               q->head = NULL;
-
-       q->tail = prev;
-       q->len--;
-
-       pq->len--;
-
-       return p;
-}
-
-void
-pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir, ifpkt_cb_t fn, int arg)
-{
-       struct pktq_prec *q;
-       void *p, *prev = NULL;
-
-       q = &pq->q[prec];
-       p = q->head;
-       while (p) {
-               if (fn == NULL || (*fn)(p, arg)) {
-                       bool head = (p == q->head);
-                       if (head)
-                               q->head = PKTLINK(p);
-                       else
-                               PKTSETLINK(prev, PKTLINK(p));
-                       PKTSETLINK(p, NULL);
-                       PKTFREE(osh, p, dir);
-                       q->len--;
-                       pq->len--;
-                       p = (head ? q->head : PKTLINK(prev));
-               } else {
-                       prev = p;
-                       p = PKTLINK(p);
-               }
-       }
-
-       if (q->head == NULL) {
-               ASSERT(q->len == 0);
-               q->tail = NULL;
-       }
-}
-
-bool BCMFASTPATH
-pktq_pdel(struct pktq *pq, void *pktbuf, int prec)
-{
-       struct pktq_prec *q;
-       void *p;
-
-       ASSERT(prec >= 0 && prec < pq->num_prec);
-
-       if (!pktbuf)
-               return FALSE;
-
-       q = &pq->q[prec];
-
-       if (q->head == pktbuf) {
-               if ((q->head = PKTLINK(pktbuf)) == NULL)
-                       q->tail = NULL;
-       } else {
-               for (p = q->head; p && PKTLINK(p) != pktbuf; p = PKTLINK(p))
-                       ;
-               if (p == NULL)
-                       return FALSE;
-
-               PKTSETLINK(p, PKTLINK(pktbuf));
-               if (q->tail == pktbuf)
-                       q->tail = p;
-       }
-
-       q->len--;
-       pq->len--;
-       PKTSETLINK(pktbuf, NULL);
-       return TRUE;
-}
-
-void
-pktq_init(struct pktq *pq, int num_prec, int max_len)
-{
-       int prec;
-
-       ASSERT(num_prec > 0 && num_prec <= PKTQ_MAX_PREC);
-
-       /* pq is variable size; only zero out what's requested */
-       bzero(pq, OFFSETOF(struct pktq, q) + (sizeof(struct pktq_prec) * num_prec));
-
-       pq->num_prec = (uint16)num_prec;
-
-       pq->max = (uint16)max_len;
-
-       for (prec = 0; prec < num_prec; prec++)
-               pq->q[prec].max = pq->max;
-}
-
-void
-pktq_set_max_plen(struct pktq *pq, int prec, int max_len)
-{
-       ASSERT(prec >= 0 && prec < pq->num_prec);
-
-       if (prec < pq->num_prec)
-               pq->q[prec].max = (uint16)max_len;
-}
-
-void * BCMFASTPATH
-pktq_deq(struct pktq *pq, int *prec_out)
-{
-       struct pktq_prec *q;
-       void *p;
-       int prec;
-
-       if (pq->len == 0)
-               return NULL;
-
-       while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
-               pq->hi_prec--;
-
-       q = &pq->q[prec];
-
-       if ((p = q->head) == NULL)
-               return NULL;
-
-       if ((q->head = PKTLINK(p)) == NULL)
-               q->tail = NULL;
-
-       q->len--;
-
-       pq->len--;
-
-       if (prec_out)
-               *prec_out = prec;
-
-       PKTSETLINK(p, NULL);
-
-       return p;
-}
-
-void * BCMFASTPATH
-pktq_deq_tail(struct pktq *pq, int *prec_out)
-{
-       struct pktq_prec *q;
-       void *p, *prev;
-       int prec;
-
-       if (pq->len == 0)
-               return NULL;
-
-       for (prec = 0; prec < pq->hi_prec; prec++)
-               if (pq->q[prec].head)
-                       break;
-
-       q = &pq->q[prec];
-
-       if ((p = q->head) == NULL)
-               return NULL;
-
-       for (prev = NULL; p != q->tail; p = PKTLINK(p))
-               prev = p;
-
-       if (prev)
-               PKTSETLINK(prev, NULL);
-       else
-               q->head = NULL;
-
-       q->tail = prev;
-       q->len--;
-
-       pq->len--;
-
-       if (prec_out)
-               *prec_out = prec;
-
-       PKTSETLINK(p, NULL);
-
-       return p;
-}
-
-void *
-pktq_peek(struct pktq *pq, int *prec_out)
-{
-       int prec;
-
-       if (pq->len == 0)
-               return NULL;
-
-       while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
-               pq->hi_prec--;
-
-       if (prec_out)
-               *prec_out = prec;
-
-       return (pq->q[prec].head);
-}
-
-void *
-pktq_peek_tail(struct pktq *pq, int *prec_out)
-{
-       int prec;
-
-       if (pq->len == 0)
-               return NULL;
-
-       for (prec = 0; prec < pq->hi_prec; prec++)
-               if (pq->q[prec].head)
-                       break;
-
-       if (prec_out)
-               *prec_out = prec;
-
-       return (pq->q[prec].tail);
-}
-
-void
-pktq_flush(osl_t *osh, struct pktq *pq, bool dir, ifpkt_cb_t fn, int arg)
-{
-       int prec;
-
-       /* Optimize flush, if pktq len = 0, just return.
-        * pktq len of 0 means pktq's prec q's are all empty.
-        */
-       if (pq->len == 0) {
-               return;
-       }
-
-       for (prec = 0; prec < pq->num_prec; prec++)
-               pktq_pflush(osh, pq, prec, dir, fn, arg);
-       if (fn == NULL)
-               ASSERT(pq->len == 0);
-}
-
-/* Return sum of lengths of a specific set of precedences */
-int
-pktq_mlen(struct pktq *pq, uint prec_bmp)
-{
-       int prec, len;
-
-       len = 0;
-
-       for (prec = 0; prec <= pq->hi_prec; prec++)
-               if (prec_bmp & (1 << prec))
-                       len += pq->q[prec].len;
-
-       return len;
-}
-
-/* Priority peek from a specific set of precedences */
-void * BCMFASTPATH
-pktq_mpeek(struct pktq *pq, uint prec_bmp, int *prec_out)
-{
-       struct pktq_prec *q;
-       void *p;
-       int prec;
-
-       if (pq->len == 0)
-       {
-               return NULL;
-       }
-       while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
-               pq->hi_prec--;
-
-       while ((prec_bmp & (1 << prec)) == 0 || pq->q[prec].head == NULL)
-               if (prec-- == 0)
-                       return NULL;
-
-       q = &pq->q[prec];
-
-       if ((p = q->head) == NULL)
-               return NULL;
-
-       if (prec_out)
-               *prec_out = prec;
-
-       return p;
-}
-/* Priority dequeue from a specific set of precedences */
-void * BCMFASTPATH
-pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out)
-{
-       struct pktq_prec *q;
-       void *p;
-       int prec;
-
-       if (pq->len == 0)
-               return NULL;
-
-       while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
-               pq->hi_prec--;
-
-       while ((pq->q[prec].head == NULL) || ((prec_bmp & (1 << prec)) == 0))
-               if (prec-- == 0)
-                       return NULL;
-
-       q = &pq->q[prec];
-
-       if ((p = q->head) == NULL)
-               return NULL;
-
-       if ((q->head = PKTLINK(p)) == NULL)
-               q->tail = NULL;
-
-       q->len--;
-
-       if (prec_out)
-               *prec_out = prec;
-
-       pq->len--;
-
-       PKTSETLINK(p, NULL);
-
-       return p;
-}
-
 #endif /* BCMDRIVER */
 
 #if !defined(BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS)
@@ -849,8 +367,8 @@ bcmstrstr(const char *haystack, const char *needle)
        if ((haystack == NULL) || (needle == NULL))
                return DISCARD_QUAL(haystack, char);
 
-       nlen = strlen(needle);
-       len = strlen(haystack) - nlen + 1;
+       nlen = (int)strlen(needle);
+       len = (int)strlen(haystack) - nlen + 1;
 
        for (i = 0; i < len; i++)
                if (memcmp(needle, &haystack[i], nlen) == 0)
@@ -859,6 +377,16 @@ bcmstrstr(const char *haystack, const char *needle)
 }
 
 char *
+bcmstrnstr(const char *s, uint s_len, const char *substr, uint substr_len)
+{
+       for (; s_len >= substr_len; s++, s_len--)
+               if (strncmp(s, substr, substr_len) == 0)
+                       return DISCARD_QUAL(s, char);
+
+       return NULL;
+}
+
+char *
 bcmstrcat(char *dest, const char *src)
 {
        char *p;
@@ -1242,7 +770,8 @@ pktsetprio(void *pkt, bool update_vtag)
                vlan_tag = ntoh16(evh->vlan_tag);
                vlan_prio = (int) (vlan_tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK;
 
-               if (evh->ether_type == hton16(ETHER_TYPE_IP)) {
+               if ((evh->ether_type == hton16(ETHER_TYPE_IP)) ||
+                       (evh->ether_type == hton16(ETHER_TYPE_IPV6))) {
                        uint8 *ip_body = pktdata + sizeof(struct ethervlan_header);
                        uint8 tos_tc = IP_TOS46(ip_body);
                        dscp_prio = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
@@ -1269,7 +798,8 @@ pktsetprio(void *pkt, bool update_vtag)
                        evh->vlan_tag = hton16(vlan_tag);
                        rc |= PKTPRIO_UPD;
                }
-       } else if (eh->ether_type == hton16(ETHER_TYPE_IP)) {
+       } else if ((eh->ether_type == hton16(ETHER_TYPE_IP)) ||
+               (eh->ether_type == hton16(ETHER_TYPE_IPV6))) {
                uint8 *ip_body = pktdata + sizeof(struct ether_header);
                uint8 tos_tc = IP_TOS46(ip_body);
                uint8 dscp = tos_tc >> IPV4_TOS_DSCP_SHIFT;
@@ -1303,6 +833,43 @@ pktsetprio(void *pkt, bool update_vtag)
        return (rc | priority);
 }
 
+/* Returns TRUE and DSCP if IP header found, FALSE otherwise.
+ */
+bool BCMFASTPATH
+pktgetdscp(uint8 *pktdata, uint pktlen, uint8 *dscp)
+{
+       struct ether_header *eh;
+       struct ethervlan_header *evh;
+       uint8 *ip_body;
+       bool rc = FALSE;
+
+       /* minimum length is ether header and IP header */
+       if (pktlen < sizeof(struct ether_header) + IPV4_MIN_HEADER_LEN)
+               return FALSE;
+
+       eh = (struct ether_header *) pktdata;
+
+       if (eh->ether_type == HTON16(ETHER_TYPE_IP)) {
+               ip_body = pktdata + sizeof(struct ether_header);
+               *dscp = IP_DSCP46(ip_body);
+               rc = TRUE;
+       }
+       else if (eh->ether_type == HTON16(ETHER_TYPE_8021Q)) {
+               evh = (struct ethervlan_header *)eh;
+
+               /* minimum length is ethervlan header and IP header */
+               if (pktlen >= sizeof(struct ethervlan_header) + IPV4_MIN_HEADER_LEN &&
+                       evh->ether_type == HTON16(ETHER_TYPE_IP)) {
+                       ip_body = pktdata + sizeof(struct ethervlan_header);
+                       *dscp = IP_DSCP46(ip_body);
+                       rc = TRUE;
+               }
+       }
+
+       return rc;
+}
+
+/* The 0.5KB string table is not removed by compiler even though it's unused */
 
 static char bcm_undeferrstr[32];
 static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE;
@@ -1327,6 +894,7 @@ bcmerrorstr(int bcmerror)
 
 
 /* iovar table lookup */
+/* could mandate sorted tables and do a binary search */
 const bcm_iovar_t*
 bcm_iovar_lookup(const bcm_iovar_t *table, const char *name)
 {
@@ -1831,6 +1399,22 @@ bcm_parse_tlvs(void *buf, int buflen, uint key)
 /*
  * Traverse a string of 1-byte tag/1-byte length/variable-length value
  * triples, returning a pointer to the substring whose first element
+ * matches tag
+ * return NULL if not found or length field < min_varlen
+ */
+bcm_tlv_t *
+bcm_parse_tlvs_min_bodylen(void *buf, int buflen, uint key, int min_bodylen)
+{
+       bcm_tlv_t * ret = bcm_parse_tlvs(buf, buflen, key);
+       if (ret == NULL || ret->len < min_bodylen) {
+               return NULL;
+       }
+       return ret;
+}
+
+/*
+ * Traverse a string of 1-byte tag/1-byte length/variable-length value
+ * triples, returning a pointer to the substring whose first element
  * matches tag.  Stop parsing when we see an element whose ID is greater
  * than the target key.
  */
@@ -1943,6 +1527,7 @@ bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char* buf, int len)
 
        return (int)(p - buf);
 }
+#endif 
 
 /* print bytes formatted as hex to a string. return the resulting string length */
 int
@@ -1958,7 +1543,6 @@ bcm_format_hex(char *str, const void *bytes, int len)
        }
        return (int)(p - str);
 }
-#endif 
 
 /* pretty hex print a contiguous buffer */
 void
@@ -2059,7 +1643,7 @@ printbig(char *buf)
        uint len, max_len;
        char c;
 
-       len = strlen(buf);
+       len = (uint)strlen(buf);
 
        max_len = BUFSIZE_TODUMP_ATONCE;
 
@@ -2110,7 +1694,7 @@ bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen)
 {
        uint len;
 
-       len = strlen(name) + 1;
+       len = (uint)strlen(name) + 1;
 
        if ((len + datalen) > buflen)
                return 0;
@@ -2532,6 +2116,35 @@ isclr(const void *array, uint bit)
 #endif /* setbit */
 
 void
+set_bitrange(void *array, uint start, uint end, uint maxbit)
+{
+       uint startbyte = start/NBBY;
+       uint endbyte = end/NBBY;
+       uint i, startbytelastbit, endbytestartbit;
+
+       if (end >= start) {
+               if (endbyte - startbyte > 1)
+               {
+                       startbytelastbit = (startbyte+1)*NBBY - 1;
+                       endbytestartbit = endbyte*NBBY;
+                       for (i = startbyte+1; i < endbyte; i++)
+                               ((uint8 *)array)[i] = 0xFF;
+                       for (i = start; i <= startbytelastbit; i++)
+                               setbit(array, i);
+                       for (i = endbytestartbit; i <= end; i++)
+                               setbit(array, i);
+               } else {
+                       for (i = start; i <= end; i++)
+                               setbit(array, i);
+               }
+       }
+       else {
+               set_bitrange(array, start, maxbit, maxbit);
+               set_bitrange(array, 0, end, maxbit);
+       }
+}
+
+void
 bcm_bitprint32(const uint32 u32)
 {
        int i;
@@ -2542,6 +2155,27 @@ bcm_bitprint32(const uint32 u32)
        printf("\n");
 }
 
+/* calculate checksum for ip header, tcp / udp header / data */
+uint16
+bcm_ip_cksum(uint8 *buf, uint32 len, uint32 sum)
+{
+       while (len > 1) {
+               sum += (buf[0] << 8) | buf[1];
+               buf += 2;
+               len -= 2;
+       }
+
+       if (len > 0) {
+               sum += (*buf) << 8;
+       }
+
+       while (sum >> 16) {
+               sum = (sum & 0xffff) + (sum >> 16);
+       }
+
+       return ((uint16)~sum);
+}
+
 #ifdef BCMDRIVER
 /*
  * Hierarchical Multiword bitmap based small id allocator.
@@ -2709,7 +2343,7 @@ bcm_mwbmap_fini(osl_t * osh, struct bcm_mwbmap * mwbmap_hdl)
 }
 
 /* Allocate a unique small index using a multiword bitmap index allocator.    */
-uint32
+uint32 BCMFASTPATH
 bcm_mwbmap_alloc(struct bcm_mwbmap * mwbmap_hdl)
 {
        bcm_mwbmap_t * mwbmap_p;
@@ -2845,7 +2479,7 @@ bcm_mwbmap_force(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix)
 }
 
 /* Free a previously allocated index back into the multiword bitmap allocator */
-void
+void BCMFASTPATH
 bcm_mwbmap_free(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix)
 {
        bcm_mwbmap_t * mwbmap_p;
@@ -2998,10 +2632,226 @@ bcm_mwbmap_audit(struct bcm_mwbmap * mwbmap_hdl)
                }
        }
 
-       ASSERT(free_cnt == mwbmap_p->ifree);
+       ASSERT((int)free_cnt == mwbmap_p->ifree);
 }
 /* END : Multiword bitmap based 64bit to Unique 32bit Id allocator. */
 
+/* Simple 16bit Id allocator using a stack implementation. */
+typedef struct id16_map {
+       uint16  total;     /* total number of ids managed by allocator */
+       uint16  start;     /* start value of 16bit ids to be managed */
+       uint32  failures;  /* count of failures */
+       void    *dbg;      /* debug placeholder */
+       int     stack_idx; /* index into stack of available ids */
+       uint16  stack[0];  /* stack of 16 bit ids */
+} id16_map_t;
+
+#define ID16_MAP_SZ(items)      (sizeof(id16_map_t) + \
+                                    (sizeof(uint16) * (items)))
+
+#if defined(BCM_DBG)
+
+/* Uncomment BCM_DBG_ID16 to debug double free */
+/* #define BCM_DBG_ID16 */
+
+typedef struct id16_map_dbg {
+       uint16  total;
+       bool    avail[0];
+} id16_map_dbg_t;
+#define ID16_MAP_DBG_SZ(items)  (sizeof(id16_map_dbg_t) + \
+                                    (sizeof(bool) * (items)))
+#define ID16_MAP_MSG(x)         print x
+#else
+#define ID16_MAP_MSG(x)
+#endif /* BCM_DBG */
+
+void * /* Construct an id16 allocator: [start_val16 .. start_val16+total_ids) */
+id16_map_init(osl_t *osh, uint16 total_ids, uint16 start_val16)
+{
+       uint16 idx, val16;
+       id16_map_t * id16_map;
+
+       ASSERT(total_ids > 0);
+       ASSERT((start_val16 + total_ids) < ID16_INVALID);
+
+       id16_map = (id16_map_t *) MALLOC(osh, ID16_MAP_SZ(total_ids));
+       if (id16_map == NULL) {
+               return NULL;
+       }
+
+       id16_map->total = total_ids;
+       id16_map->start = start_val16;
+       id16_map->failures = 0;
+       id16_map->dbg = NULL;
+
+       /* Populate stack with 16bit id values, commencing with start_val16 */
+       id16_map->stack_idx = 0;
+       val16 = start_val16;
+
+       for (idx = 0; idx < total_ids; idx++, val16++) {
+               id16_map->stack_idx = idx;
+               id16_map->stack[id16_map->stack_idx] = val16;
+       }
+
+#if defined(BCM_DBG) && defined(BCM_DBG_ID16)
+       id16_map->dbg = MALLOC(osh, ID16_MAP_DBG_SZ(total_ids));
+
+       if (id16_map->dbg) {
+               id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg;
+
+               id16_map_dbg->total = total_ids;
+               for (idx = 0; idx < total_ids; idx++) {
+                       id16_map_dbg->avail[idx] = TRUE;
+               }
+       }
+#endif /* BCM_DBG && BCM_DBG_ID16 */
+
+       return (void *)id16_map;
+}
+
+void * /* Destruct an id16 allocator instance */
+id16_map_fini(osl_t *osh, void * id16_map_hndl)
+{
+       uint16 total_ids;
+       id16_map_t * id16_map;
+
+       if (id16_map_hndl == NULL)
+               return NULL;
+
+       id16_map = (id16_map_t *)id16_map_hndl;
+
+       total_ids = id16_map->total;
+       ASSERT(total_ids > 0);
+
+#if defined(BCM_DBG) && defined(BCM_DBG_ID16)
+       if (id16_map->dbg) {
+               MFREE(osh, id16_map->dbg, ID16_MAP_DBG_SZ(total_ids));
+               id16_map->dbg = NULL;
+       }
+#endif /* BCM_DBG && BCM_DBG_ID16 */
+
+       id16_map->total = 0;
+       MFREE(osh, id16_map, ID16_MAP_SZ(total_ids));
+
+       return NULL;
+}
+
+uint16 BCMFASTPATH /* Allocate a unique 16bit id */
+id16_map_alloc(void * id16_map_hndl)
+{
+       uint16 val16;
+       id16_map_t * id16_map;
+
+       ASSERT(id16_map_hndl != NULL);
+
+       id16_map = (id16_map_t *)id16_map_hndl;
+
+       ASSERT(id16_map->total > 0);
+
+       if (id16_map->stack_idx < 0) {
+               id16_map->failures++;
+               return ID16_INVALID;
+       }
+
+       val16 = id16_map->stack[id16_map->stack_idx];
+       id16_map->stack_idx--;
+
+#if defined(BCM_DBG) && defined(BCM_DBG_ID16)
+
+       ASSERT(val16 < (id16_map->start + id16_map->total));
+
+       if (id16_map->dbg) { /* Validate val16 */
+               id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg;
+
+               ASSERT(id16_map_dbg->avail[val16 - id16_map->start] == TRUE);
+               id16_map_dbg->avail[val16 - id16_map->start] = FALSE;
+       }
+#endif /* BCM_DBG && BCM_DBG_ID16 */
+
+       return val16;
+}
+
+
+void BCMFASTPATH /* Free a 16bit id value into the id16 allocator */
+id16_map_free(void * id16_map_hndl, uint16 val16)
+{
+       id16_map_t * id16_map;
+
+       ASSERT(id16_map_hndl != NULL);
+
+       id16_map = (id16_map_t *)id16_map_hndl;
+
+#if defined(BCM_DBG) && defined(BCM_DBG_ID16)
+
+       ASSERT(val16 < (id16_map->start + id16_map->total));
+
+       if (id16_map->dbg) { /* Validate val16 */
+               id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg;
+
+               ASSERT(id16_map_dbg->avail[val16 - id16_map->start] == FALSE);
+               id16_map_dbg->avail[val16 - id16_map->start] = TRUE;
+       }
+#endif /* BCM_DBG && BCM_DBG_ID16 */
+
+       id16_map->stack_idx++;
+       id16_map->stack[id16_map->stack_idx] = val16;
+}
+
+uint32 /* Returns number of failures to allocate an unique id16 */
+id16_map_failures(void * id16_map_hndl)
+{
+       ASSERT(id16_map_hndl != NULL);
+       return ((id16_map_t *)id16_map_hndl)->failures;
+}
+
+bool
+id16_map_audit(void * id16_map_hndl)
+{
+       int idx;
+       int insane = 0;
+       id16_map_t * id16_map;
+
+       ASSERT(id16_map_hndl != NULL);
+
+       id16_map = (id16_map_t *)id16_map_hndl;
+
+       ASSERT((id16_map->stack_idx > 0) && (id16_map->stack_idx < id16_map->total));
+       for (idx = 0; idx <= id16_map->stack_idx; idx++) {
+               ASSERT(id16_map->stack[idx] >= id16_map->start);
+               ASSERT(id16_map->stack[idx] < (id16_map->start + id16_map->total));
+
+#if defined(BCM_DBG) && defined(BCM_DBG_ID16)
+               if (id16_map->dbg) {
+                       uint16 val16 = id16_map->stack[idx];
+                       if (((id16_map_dbg_t *)(id16_map->dbg))->avail[val16] != TRUE) {
+                               insane |= 1;
+                               ID16_MAP_MSG(("id16_map<%p>: stack_idx %u invalid val16 %u\n",
+                                             id16_map_hndl, idx, val16));
+                       }
+               }
+#endif /* BCM_DBG && BCM_DBG_ID16 */
+       }
+
+#if defined(BCM_DBG) && defined(BCM_DBG_ID16)
+       if (id16_map->dbg) {
+               uint16 avail = 0; /* Audit available ids counts */
+               for (idx = 0; idx < id16_map_dbg->total; idx++) {
+                       if (((id16_map_dbg_t *)(id16_map->dbg))->avail[idx16] == TRUE)
+                               avail++;
+               }
+               if (avail && (avail != (id16_map->stack_idx + 1))) {
+                       insane |= 1;
+                       ID16_MAP_MSG(("id16_map<%p>: avail %u stack_idx %u\n",
+                                     id16_map_hndl, avail, id16_map->stack_idx));
+               }
+       }
+#endif /* BCM_DBG && BCM_DBG_ID16 */
+
+       return (!!insane);
+}
+/* END: Simple id16 allocator */
+
+
 #endif /* BCMDRIVER */
 
 /* calculate a >> b; and returns only lower 32 bits */
@@ -3080,3 +2930,84 @@ void counter_printlog(counter_tbl_t *ctr_tbl)
 #define counter_printlog(a) do {} while (0)
 #endif /* OSL_SYSUPTIME_SUPPORT == TRUE */
 #endif /* DEBUG_COUNTER */
+
+#ifdef BCMDRIVER
+void
+dll_pool_detach(void * osh, dll_pool_t * pool, uint16 elems_max, uint16 elem_size)
+{
+       uint32 mem_size;
+       mem_size = sizeof(dll_pool_t) + (elems_max * elem_size);
+       if (pool)
+               MFREE(osh, pool, mem_size);
+}
+dll_pool_t *
+dll_pool_init(void * osh, uint16 elems_max, uint16 elem_size)
+{
+       uint32 mem_size, i;
+       dll_pool_t * dll_pool_p;
+       dll_t * elem_p;
+
+       ASSERT(elem_size > sizeof(dll_t));
+
+       mem_size = sizeof(dll_pool_t) + (elems_max * elem_size);
+
+       if ((dll_pool_p = (dll_pool_t *)MALLOC(osh, mem_size)) == NULL) {
+               printf("dll_pool_init: elems_max<%u> elem_size<%u> malloc failure\n",
+                       elems_max, elem_size);
+               ASSERT(0);
+               return dll_pool_p;
+       }
+
+       bzero(dll_pool_p, mem_size);
+
+       dll_init(&dll_pool_p->free_list);
+       dll_pool_p->elems_max = elems_max;
+       dll_pool_p->elem_size = elem_size;
+
+       elem_p = dll_pool_p->elements;
+       for (i = 0; i < elems_max; i++) {
+               dll_append(&dll_pool_p->free_list, elem_p);
+               elem_p = (dll_t *)((uintptr)elem_p + elem_size);
+       }
+
+       dll_pool_p->free_count = elems_max;
+
+       return dll_pool_p;
+}
+
+
+void *
+dll_pool_alloc(dll_pool_t * dll_pool_p)
+{
+       dll_t * elem_p;
+
+       if (dll_pool_p->free_count == 0) {
+               ASSERT(dll_empty(&dll_pool_p->free_list));
+               return NULL;
+       }
+
+       elem_p = dll_head_p(&dll_pool_p->free_list);
+       dll_delete(elem_p);
+       dll_pool_p->free_count -= 1;
+
+       return (void *)elem_p;
+}
+
+void
+dll_pool_free(dll_pool_t * dll_pool_p, void * elem_p)
+{
+       dll_t * node_p = (dll_t *)elem_p;
+       dll_prepend(&dll_pool_p->free_list, node_p);
+       dll_pool_p->free_count += 1;
+}
+
+
+void
+dll_pool_free_tail(dll_pool_t * dll_pool_p, void * elem_p)
+{
+       dll_t * node_p = (dll_t *)elem_p;
+       dll_append(&dll_pool_p->free_list, node_p);
+       dll_pool_p->free_count += 1;
+}
+
+#endif /* BCMDRIVER */
old mode 100755 (executable)
new mode 100644 (file)
index f092699..8b80ce9
@@ -232,6 +232,18 @@ channel_80mhz_to_id(uint ch)
        return -1;
 }
 
+/* wrapper function for wf_chspec_ntoa. In case of an error it puts
+ * the original chanspec in the output buffer, prepended with "invalid".
+ * Can be directly used in print routines as it takes care of null
+ */
+char *
+wf_chspec_ntoa_ex(chanspec_t chspec, char *buf)
+{
+       if (wf_chspec_ntoa(chspec, buf) == NULL)
+               snprintf(buf, CHANSPEC_STR_LEN, "invalid 0x%04x", chspec);
+       return buf;
+}
+
 /* given a chanspec and a string buffer, format the chanspec as a
  * string, and return the original pointer a.
  * Min buffer length must be CHANSPEC_STR_LEN.
@@ -524,32 +536,25 @@ done_read:
                int ch1_id = 0, ch2_id = 0;
                int sb;
 
+               /* look up the channel ID for the specified channel numbers */
                ch1_id = channel_80mhz_to_id(ch1);
                ch2_id = channel_80mhz_to_id(ch2);
 
                /* validate channels */
-               if (ch1 >= ch2 || ch1_id < 0 || ch2_id < 0)
+               if (ch1_id < 0 || ch2_id < 0)
                        return 0;
 
-               /* combined channel in chspec */
-               chspec_ch = (((uint16)ch1_id << WL_CHANSPEC_CHAN1_SHIFT) |
-                       ((uint16)ch2_id << WL_CHANSPEC_CHAN2_SHIFT));
+               /* combine 2 channel IDs in channel field of chspec */
+               chspec_ch = (((uint)ch1_id << WL_CHANSPEC_CHAN1_SHIFT) |
+                            ((uint)ch2_id << WL_CHANSPEC_CHAN2_SHIFT));
 
-               /* figure out ctl sideband */
+               /* figure out primary 20 MHz sideband */
 
-               /* does the primary channel fit with the 1st 80MHz channel ? */
+               /* is the primary channel contained in the 1st 80MHz channel? */
                sb = channel_to_sb(ch1, ctl_ch, bw);
                if (sb < 0) {
-                       /* no, so does the primary channel fit with the 2nd 80MHz channel ? */
-                       sb = channel_to_sb(ch2, ctl_ch, bw);
-                       if (sb < 0) {
-                               /* no match for ctl_ch to either 80MHz center channel */
-                               return 0;
-                       }
-                       /* sb index is 0-3 for the low 80MHz channel, and 4-7 for
-                        * the high 80MHz channel. Add 4 to to shift to high set.
-                        */
-                       sb += 4;
+                       /* no match for primary channel 'ctl_ch' in segment0 80MHz channel */
+                       return 0;
                }
 
                chspec_sb = sb << WL_CHANSPEC_CTL_SB_SHIFT;
@@ -586,15 +591,12 @@ wf_chspec_malformed(chanspec_t chanspec)
                if (chspec_bw == WL_CHANSPEC_BW_8080) {
                        uint ch1_id, ch2_id;
 
-                       /* channel number in 80+80 must be in range */
+                       /* channel IDs in 80+80 must be in range */
                        ch1_id = CHSPEC_CHAN1(chanspec);
                        ch2_id = CHSPEC_CHAN2(chanspec);
                        if (ch1_id >= WF_NUM_5G_80M_CHANS || ch2_id >= WF_NUM_5G_80M_CHANS)
                                return TRUE;
 
-                       /* ch2 must be above ch1 for the chanspec */
-                       if (ch2_id <= ch1_id)
-                               return TRUE;
                } else if (chspec_bw == WL_CHANSPEC_BW_20 || chspec_bw == WL_CHANSPEC_BW_40 ||
                           chspec_bw == WL_CHANSPEC_BW_80 || chspec_bw == WL_CHANSPEC_BW_160) {
 
@@ -617,11 +619,14 @@ wf_chspec_malformed(chanspec_t chanspec)
        } else if (chspec_bw == WL_CHANSPEC_BW_40) {
                if (CHSPEC_CTL_SB(chanspec) > WL_CHANSPEC_CTL_SB_LLU)
                        return TRUE;
-       } else if (chspec_bw == WL_CHANSPEC_BW_80) {
+       } else if (chspec_bw == WL_CHANSPEC_BW_80 ||
+                  chspec_bw == WL_CHANSPEC_BW_8080) {
                if (CHSPEC_CTL_SB(chanspec) > WL_CHANSPEC_CTL_SB_LUU)
                        return TRUE;
        }
-
+       else if (chspec_bw == WL_CHANSPEC_BW_160) {
+               ASSERT(CHSPEC_CTL_SB(chanspec) <= WL_CHANSPEC_CTL_SB_UUU);
+       }
        return FALSE;
 }
 
@@ -654,10 +659,9 @@ wf_chspec_valid(chanspec_t chanspec)
                        ch1 = wf_5g_80m_chans[CHSPEC_CHAN1(chanspec)];
                        ch2 = wf_5g_80m_chans[CHSPEC_CHAN2(chanspec)];
 
-                       /* the two channels must be separated by more than 80MHz by VHT req,
-                        * and ch2 above ch1 for the chanspec
-                        */
-                       if (ch2 > ch1 + CH_80MHZ_APART)
+                       /* the two channels must be separated by more than 80MHz by VHT req */
+                       if ((ch2 > ch1 + CH_80MHZ_APART) ||
+                           (ch1 > ch2 + CH_80MHZ_APART))
                                return TRUE;
                } else {
                        const uint8 *center_ch;
@@ -740,18 +744,15 @@ wf_chspec_ctlchan(chanspec_t chspec)
                sb = CHSPEC_CTL_SB(chspec) >> WL_CHANSPEC_CTL_SB_SHIFT;
 
                if (CHSPEC_IS8080(chspec)) {
-                       bw_mhz = 80;
+                       /* For an 80+80 MHz channel, the sideband 'sb' field is an 80 MHz sideband
+                        * (LL, LU, UL, LU) for the 80 MHz frequency segment 0.
+                        */
+                       uint chan_id = CHSPEC_CHAN1(chspec);
 
-                       if (sb < 4) {
-                               center_chan = CHSPEC_CHAN1(chspec);
-                       }
-                       else {
-                               center_chan = CHSPEC_CHAN2(chspec);
-                               sb -= 4;
-                       }
+                       bw_mhz = 80;
 
                        /* convert from channel index to channel number */
-                       center_chan = wf_5g_80m_chans[center_chan];
+                       center_chan = wf_5g_80m_chans[chan_id];
                }
                else {
                        bw_mhz = bw_chspec_to_mhz(chspec);
@@ -762,6 +763,13 @@ wf_chspec_ctlchan(chanspec_t chspec)
        }
 }
 
+/* given a chanspec, return the bandwidth string */
+char *
+wf_chspec_to_bw_str(chanspec_t chspec)
+{
+       return (char *)wf_chspec_bw_str[(CHSPEC_BW(chspec) >> WL_CHANSPEC_BW_SHIFT)];
+}
+
 /*
  * This function returns the chanspec of the control channel of a given chanspec
  */
@@ -847,22 +855,25 @@ extern chanspec_t wf_chspec_primary40_chspec(chanspec_t chspec)
 
        ASSERT(!wf_chspec_malformed(chspec));
 
+       /* if the chanspec is > 80MHz, use the helper routine to find the primary 80 MHz channel */
+       if (CHSPEC_IS8080(chspec) || CHSPEC_IS160(chspec)) {
+               chspec = wf_chspec_primary80_chspec(chspec);
+       }
+
+       /* determine primary 40 MHz sub-channel of an 80 MHz chanspec */
        if (CHSPEC_IS80(chspec)) {
                center_chan = CHSPEC_CHANNEL(chspec);
                sb = CHSPEC_CTL_SB(chspec);
 
-               if (sb == WL_CHANSPEC_CTL_SB_UL) {
-                       /* Primary 40MHz is on upper side */
-                       sb = WL_CHANSPEC_CTL_SB_L;
-                       center_chan += CH_20MHZ_APART;
-               } else if (sb == WL_CHANSPEC_CTL_SB_UU) {
-                       /* Primary 40MHz is on upper side */
-                       sb = WL_CHANSPEC_CTL_SB_U;
-                       center_chan += CH_20MHZ_APART;
-               } else {
+               if (sb < WL_CHANSPEC_CTL_SB_UL) {
                        /* Primary 40MHz is on lower side */
-                       /* sideband bits are the same for LL/LU and L/U */
                        center_chan -= CH_20MHZ_APART;
+                       /* sideband bits are the same for LL/LU and L/U */
+               } else {
+                       /* Primary 40MHz is on upper side */
+                       center_chan += CH_20MHZ_APART;
+                       /* sideband bits need to be adjusted by UL offset */
+                       sb -= WL_CHANSPEC_CTL_SB_UL;
                }
 
                /* Create primary 40MHz chanspec */
@@ -962,52 +973,101 @@ wf_channel2mhz(uint ch, uint start_factor)
        return freq;
 }
 
+static const uint16 sidebands[] = {
+       WL_CHANSPEC_CTL_SB_LLL, WL_CHANSPEC_CTL_SB_LLU,
+       WL_CHANSPEC_CTL_SB_LUL, WL_CHANSPEC_CTL_SB_LUU,
+       WL_CHANSPEC_CTL_SB_ULL, WL_CHANSPEC_CTL_SB_ULU,
+       WL_CHANSPEC_CTL_SB_UUL, WL_CHANSPEC_CTL_SB_UUU
+};
+
 /*
- * Returns the 80+80 chanspec corresponding to the following input parameters
+ * Returns the chanspec 80Mhz channel corresponding to the following input
+ * parameters
  *
- *    primary_20mhz - Primary 20 Mhz channel
- *    chan1 - channel number of first 80 Mhz band
- *    chan2 - channel number of second 80 Mhz band
+ *     primary_channel - primary 20Mhz channel
+ *     center_channel   - center frequecny of the 80Mhz channel
  *
- *  parameters chan1 and chan2  are channel numbers in {42, 58, 106, 122, 138, 155}
+ * The center_channel can be one of {42, 58, 106, 122, 138, 155}
  *
- *  returns INVCHANSPEC in case of error
+ * returns INVCHANSPEC in case of error
  */
+chanspec_t
+wf_chspec_80(uint8 center_channel, uint8 primary_channel)
+{
 
+       chanspec_t chanspec = INVCHANSPEC;
+       chanspec_t chanspec_cur;
+       uint i;
+
+       for (i = 0; i < WF_NUM_SIDEBANDS_80MHZ; i++) {
+               chanspec_cur = CH80MHZ_CHSPEC(center_channel, sidebands[i]);
+               if (primary_channel == wf_chspec_ctlchan(chanspec_cur)) {
+                       chanspec = chanspec_cur;
+                       break;
+               }
+       }
+       /* If the loop ended early, we are good, otherwise we did not
+       * find a 80MHz chanspec with the given center_channel that had a primary channel
+       *matching the given primary_channel.
+       */
+       return chanspec;
+}
+
+/*
+ * Returns the 80+80 chanspec corresponding to the following input parameters
+ *
+ *    primary_20mhz - Primary 20 MHz channel
+ *    chan0 - center channel number of one frequency segment
+ *    chan1 - center channel number of the other frequency segment
+ *
+ * Parameters chan0 and chan1 are channel numbers in {42, 58, 106, 122, 138, 155}.
+ * The primary channel must be contained in one of the 80MHz channels. This routine
+ * will determine which frequency segment is the primary 80 MHz segment.
+ *
+ * Returns INVCHANSPEC in case of error.
+ *
+ * Refer to IEEE802.11ac section 22.3.14 "Channelization".
+ */
 chanspec_t
-wf_chspec_get8080_chspec(uint8 primary_20mhz, uint8 chan1, uint8 chan2)
+wf_chspec_get8080_chspec(uint8 primary_20mhz, uint8 chan0, uint8 chan1)
 {
        int sb = 0;
        uint16 chanspec = 0;
-       int chan1_id = 0, chan2_id = 0;
+       int chan0_id = 0, chan1_id = 0;
+       int seg0, seg1;
+
+       chan0_id = channel_80mhz_to_id(chan0);
+       chan1_id = channel_80mhz_to_id(chan1);
+
+       /* make sure the channel numbers were valid */
+       if (chan0_id == -1 || chan1_id == -1)
+               return INVCHANSPEC;
 
        /* does the primary channel fit with the 1st 80MHz channel ? */
-       sb = channel_to_sb(chan1, primary_20mhz, 80);
-       if (sb < 0) {
+       sb = channel_to_sb(chan0, primary_20mhz, 80);
+       if (sb >= 0) {
+               /* yes, so chan0 is frequency segment 0, and chan1 is seg 1 */
+               seg0 = chan0_id;
+               seg1 = chan1_id;
+       } else {
                /* no, so does the primary channel fit with the 2nd 80MHz channel ? */
-               sb = channel_to_sb(chan2, primary_20mhz, 80);
+               sb = channel_to_sb(chan1, primary_20mhz, 80);
                if (sb < 0) {
                        /* no match for ctl_ch to either 80MHz center channel */
                        return INVCHANSPEC;
                }
-               /* sb index is 0-3 for the low 80MHz channel, and 4-7 for
-                * the high 80MHz channel. Add 4 to to shift to high set.
-                */
-               sb += 4;
+               /* swapped, so chan1 is frequency segment 0, and chan0 is seg 1 */
+               seg0 = chan1_id;
+               seg1 = chan0_id;
        }
-       chan1_id = channel_80mhz_to_id(chan1);
-       chan2_id = channel_80mhz_to_id(chan2);
-       if (chan1_id == -1 || chan2_id == -1)
-               return INVCHANSPEC;
 
-       chanspec = (chan1_id << WL_CHANSPEC_CHAN1_SHIFT)|
-               (chan2_id << WL_CHANSPEC_CHAN2_SHIFT)|
-               (sb << WL_CHANSPEC_CTL_SB_SHIFT)|
-               (WL_CHANSPEC_BW_8080)|
-               (WL_CHANSPEC_BAND_5G);
+       chanspec = ((seg0 << WL_CHANSPEC_CHAN1_SHIFT) |
+                   (seg1 << WL_CHANSPEC_CHAN2_SHIFT) |
+                   (sb << WL_CHANSPEC_CTL_SB_SHIFT) |
+                   WL_CHANSPEC_BW_8080 |
+                   WL_CHANSPEC_BAND_5G);
 
        return chanspec;
-
 }
 
 /*
@@ -1033,46 +1093,29 @@ wf_chspec_get80Mhz_ch(uint8 chan_80Mhz_id)
 uint8
 wf_chspec_primary80_channel(chanspec_t chanspec)
 {
-       uint8 chan1 = 0, chan2 = 0, primary_20mhz = 0, primary80_chan = 0;
-       int sb = 0;
-
-       primary_20mhz = wf_chspec_ctlchan(chanspec);
+       uint8 primary80_chan;
 
        if (CHSPEC_IS80(chanspec))      {
                primary80_chan = CHSPEC_CHANNEL(chanspec);
        }
        else if (CHSPEC_IS8080(chanspec)) {
-               chan1 = wf_chspec_get80Mhz_ch(CHSPEC_CHAN1(chanspec));
-               chan2 = wf_chspec_get80Mhz_ch(CHSPEC_CHAN2(chanspec));
-
-               /* does the primary channel fit with the 1st 80MHz channel ? */
-               sb = channel_to_sb(chan1, primary_20mhz, 80);
-               if (sb < 0) {
-                       /* no, so does the primary channel fit with the 2nd 80MHz channel ? */
-                       sb = channel_to_sb(chan2, primary_20mhz, 80);
-                       if (!(sb < 0)) {
-                               primary80_chan = chan2;
-                       }
-               }
-               else {
-                       primary80_chan = chan1;
-               }
+               /* Channel ID 1 corresponds to frequency segment 0, the primary 80 MHz segment */
+               primary80_chan = wf_chspec_get80Mhz_ch(CHSPEC_CHAN1(chanspec));
        }
        else if (CHSPEC_IS160(chanspec)) {
-               chan1 = CHSPEC_CHANNEL(chanspec);
-               sb = channel_to_sb(chan1, primary_20mhz, 160);
-               if (!(sb < 0)) {
-                   /* based on the sb value  primary 80 channel can be retrieved
-                        * if sb is in range 0 to 3 the lower band is the 80Mhz primary band
-                        */
-                       if (sb < 4) {
-                               primary80_chan = chan1 - CH_40MHZ_APART;
-                       }
-                       /* if sb is in range 4 to 7 the lower band is the 80Mhz primary band */
-                       else
-                       {
-                               primary80_chan = chan1 + CH_40MHZ_APART;
-                       }
+               uint8 center_chan = CHSPEC_CHANNEL(chanspec);
+               uint sb = CHSPEC_CTL_SB(chanspec) >> WL_CHANSPEC_CTL_SB_SHIFT;
+
+               /* based on the sb value primary 80 channel can be retrieved
+                * if sb is in range 0 to 3 the lower band is the 80Mhz primary band
+                */
+               if (sb < 4) {
+                       primary80_chan = center_chan - CH_40MHZ_APART;
+               }
+               /* if sb is in range 4 to 7 the upper band is the 80Mhz primary band */
+               else
+               {
+                       primary80_chan = center_chan + CH_40MHZ_APART;
                }
        }
        else {
@@ -1087,55 +1130,35 @@ wf_chspec_primary80_channel(chanspec_t chanspec)
  *
  *    chanspec - Input chanspec for which the 80MHz secondary channel has to be retrieved
  *
- *  returns -1 in case the provided channel is 20/40 Mhz chanspec
+ *  returns -1 in case the provided channel is 20/40/80 Mhz chanspec
  */
 uint8
 wf_chspec_secondary80_channel(chanspec_t chanspec)
 {
-       uint8 chan1 = 0, chan2 = 0, primary_20mhz = 0, secondary80_chan = 0;
-       int sb = 0;
+       uint8 secondary80_chan;
 
-       primary_20mhz = wf_chspec_ctlchan(chanspec);
-       if (CHSPEC_IS80(chanspec)) {
-               secondary80_chan = -1;
+       if (CHSPEC_IS8080(chanspec)) {
+               secondary80_chan = wf_chspec_get80Mhz_ch(CHSPEC_CHAN2(chanspec));
        }
-       else if (CHSPEC_IS8080(chanspec)) {
-               chan1 = wf_chspec_get80Mhz_ch(CHSPEC_CHAN1(chanspec));
-               chan2 = wf_chspec_get80Mhz_ch(CHSPEC_CHAN2(chanspec));
+       else if (CHSPEC_IS160(chanspec)) {
+               uint8 center_chan = CHSPEC_CHANNEL(chanspec);
+               uint sb = CHSPEC_CTL_SB(chanspec) >> WL_CHANSPEC_CTL_SB_SHIFT;
 
-               /* does the primary channel fit with the 1st 80MHz channel ? */
-               sb = channel_to_sb(chan1, primary_20mhz, 80);
-               if (sb < 0) {
-                       /* no, so does the primary channel fit with the 2nd 80MHz channel ? */
-                       sb = channel_to_sb(chan2, primary_20mhz, 80);
-                       if (!(sb < 0)) {
-                               secondary80_chan = chan1;
-                       }
-               }
-               else {
-                       secondary80_chan = chan2;
+               /* based on the sb value  secondary 80 channel can be retrieved
+                * if sb is in range 0 to 3 upper band is the secondary 80Mhz band
+                */
+               if (sb < 4) {
+                       secondary80_chan = center_chan + CH_40MHZ_APART;
                }
-       }
-       else if (CHSPEC_IS160(chanspec)) {
-               chan1 = CHSPEC_CHANNEL(chanspec);
-               sb = channel_to_sb(chan1, primary_20mhz, 160);
-               if (!(sb < 0)) {
-                   /* based on the sb value  secondary 80 channel can be retrieved
-                         *if sb is in range 0 to 3 upper band is the secondary 80Mhz  band
-                         */
-                       if (sb < 4) {
-                               secondary80_chan = chan1 + CH_40MHZ_APART;
-                       }
-                       /* if sb is in range 4 to 7 the lower band is the secondary 80Mhz band */
-                       else
-                       {
-                               secondary80_chan = chan1 - CH_40MHZ_APART;
-                       }
+               /* if sb is in range 4 to 7 the lower band is the secondary 80Mhz band */
+               else
+               {
+                       secondary80_chan = center_chan - CH_40MHZ_APART;
                }
        }
        else {
-               /* for 20 and 40 Mhz */
-               secondary80_chan  = -1;
+               /* for 20, 40, and 80 Mhz */
+               secondary80_chan = -1;
        }
        return secondary80_chan;
 }
@@ -1145,55 +1168,62 @@ wf_chspec_secondary80_channel(chanspec_t chanspec)
  *
  *    chanspec - Input chanspec for which the primary 80Mhz chanspec has to be retreived
  *
- *  returns INVCHANSPEC in case the provided channel is 20/40 Mhz chanspec
+ *  returns the input chanspec in case the provided chanspec is an 80 MHz chanspec
+ *  returns INVCHANSPEC in case the provided channel is 20/40 MHz chanspec
  */
 chanspec_t
 wf_chspec_primary80_chspec(chanspec_t chspec)
 {
        chanspec_t chspec80;
-       uint center_chan, chan1 = 0, chan2 = 0;
+       uint center_chan;
        uint sb;
 
        ASSERT(!wf_chspec_malformed(chspec));
-       if (CHSPEC_IS8080(chspec)) {
-               chan1 = wf_chspec_get80Mhz_ch(CHSPEC_CHAN1(chspec));
-               chan2 = wf_chspec_get80Mhz_ch(CHSPEC_CHAN2(chspec));
+       if (CHSPEC_IS80(chspec)) {
+               chspec80 = chspec;
+       }
+       else if (CHSPEC_IS8080(chspec)) {
+
+               /* Channel ID 1 corresponds to frequency segment 0, the primary 80 MHz segment */
+               center_chan = wf_chspec_get80Mhz_ch(CHSPEC_CHAN1(chspec));
 
                sb = CHSPEC_CTL_SB(chspec);
 
-               if (sb < 4) {
-                       /* Primary 80MHz is on lower side */
-                       center_chan = chan1;
-               }
-               else
-               {
-                       /* Primary 80MHz is on upper side */
-                       center_chan = chan2;
-                       sb -= 4;
-               }
                /* Create primary 80MHz chanspec */
-               chspec80 = (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_80 |sb | center_chan);
+               chspec80 = (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_80 | sb | center_chan);
        }
        else if (CHSPEC_IS160(chspec)) {
                center_chan = CHSPEC_CHANNEL(chspec);
                sb = CHSPEC_CTL_SB(chspec);
 
-               if (sb < 4) {
-                       /* Primary 80MHz is on upper side */
+               if (sb < WL_CHANSPEC_CTL_SB_ULL) {
+                       /* Primary 80MHz is on lower side */
                        center_chan -= CH_40MHZ_APART;
                }
-               else
-               {
-                       /* Primary 80MHz is on lower side */
+               else {
+                       /* Primary 80MHz is on upper side */
                        center_chan += CH_40MHZ_APART;
-                       sb -= 4;
+                       sb -= WL_CHANSPEC_CTL_SB_ULL;
                }
                /* Create primary 80MHz chanspec */
                chspec80 = (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_80 | sb | center_chan);
        }
-       else
-       {
+       else {
                chspec80 = INVCHANSPEC;
        }
+
        return chspec80;
 }
+
+#ifdef WL11AC_80P80
+uint8
+wf_chspec_channel(chanspec_t chspec)
+{
+       if (CHSPEC_IS8080(chspec)) {
+               return wf_chspec_primary80_channel(chspec);
+       }
+       else {
+               return ((uint8)((chspec) & WL_CHANSPEC_CHAN_MASK));
+       }
+}
+#endif /* WL11AC_80P80 */
old mode 100755 (executable)
new mode 100644 (file)
index f642555..7152e35
@@ -43,10 +43,15 @@ typedef uint16 chanspec_t;
 #define CH_10MHZ_APART                 2
 #define CH_5MHZ_APART                  1       /* 2G band channels are 5 Mhz apart */
 #define CH_MAX_2G_CHANNEL              14      /* Max channel in 2G band */
-#define        MAXCHANNEL              224     /* max # supported channels. The max channel no is 216,
+#define MAXCHANNEL             224     /* max # supported channels. The max channel no is above,
                                         * this is that + 1 rounded up to a multiple of NBBY (8).
                                         * DO NOT MAKE it > 255: channels are uint8's all over
                                         */
+#define MAXCHANNEL_NUM (MAXCHANNEL - 1)        /* max channel number */
+
+/* make sure channel num is within valid range */
+#define CH_NUM_VALID_RANGE(ch_num) ((ch_num) > 0 && (ch_num) <= MAXCHANNEL_NUM)
+
 #define CHSPEC_CTLOVLP(sp1, sp2, sep)  (ABS(wf_chspec_ctlchan(sp1) - wf_chspec_ctlchan(sp2)) < \
                                  (sep))
 
@@ -131,7 +136,11 @@ typedef uint16 chanspec_t;
                                         WL_CHANSPEC_BW_160 | WL_CHANSPEC_BAND_5G)
 
 /* simple MACROs to get different fields of chanspec */
+#ifdef WL11AC_80P80
+#define CHSPEC_CHANNEL(chspec) wf_chspec_channel(chspec)
+#else
 #define CHSPEC_CHANNEL(chspec) ((uint8)((chspec) & WL_CHANSPEC_CHAN_MASK))
+#endif
 #define CHSPEC_CHAN1(chspec)   ((chspec) & WL_CHANSPEC_CHAN1_MASK) >> WL_CHANSPEC_CHAN1_SHIFT
 #define CHSPEC_CHAN2(chspec)   ((chspec) & WL_CHANSPEC_CHAN2_MASK) >> WL_CHANSPEC_CHAN2_SHIFT
 #define CHSPEC_BAND(chspec)            ((chspec) & WL_CHANSPEC_BAND_MASK)
@@ -294,12 +303,34 @@ typedef uint16 chanspec_t;
 #define WLC_2G_25MHZ_OFFSET            5       /* 2.4GHz band channel offset */
 
 /**
+ *  No of sub-band vlaue of the specified Mhz chanspec
+ */
+#define WF_NUM_SIDEBANDS_40MHZ   2
+#define WF_NUM_SIDEBANDS_80MHZ   4
+#define WF_NUM_SIDEBANDS_8080MHZ 4
+#define WF_NUM_SIDEBANDS_160MHZ  8
+
+/**
+ * Convert chanspec to ascii string
+ *
+ * @param      chspec          chanspec format
+ * @param      buf             ascii string of chanspec
+ *
+ * @return     pointer to buf with room for at least CHANSPEC_STR_LEN bytes
+ *             Original chanspec in case of error
+ *
+ * @see                CHANSPEC_STR_LEN
+ */
+extern char * wf_chspec_ntoa_ex(chanspec_t chspec, char *buf);
+
+/**
  * Convert chanspec to ascii string
  *
  * @param      chspec          chanspec format
  * @param      buf             ascii string of chanspec
  *
  * @return     pointer to buf with room for at least CHANSPEC_STR_LEN bytes
+ *             NULL in case of error
  *
  * @see                CHANSPEC_STR_LEN
  */
@@ -350,6 +381,17 @@ extern bool wf_chspec_valid(chanspec_t chanspec);
 extern uint8 wf_chspec_ctlchan(chanspec_t chspec);
 
 /**
+ * Return the bandwidth string.
+ *
+ * This function returns the bandwidth string for the passed chanspec.
+ *
+ * @param      chspec    input chanspec
+ *
+ * @return Returns the bandwidth string
+ */
+extern char * wf_chspec_to_bw_str(chanspec_t chspec);
+
+/**
  * Return the primary (control) chanspec.
  *
  * This function returns the chanspec of the primary 20MHz channel. For 20MHz
@@ -429,6 +471,19 @@ extern int wf_mhz2channel(uint freq, uint start_factor);
 extern int wf_channel2mhz(uint channel, uint start_factor);
 
 /**
+ * Returns the chanspec 80Mhz channel corresponding to the following input
+ * parameters
+ *
+ *     primary_channel - primary 20Mhz channel
+ *     center_channel   - center frequecny of the 80Mhz channel
+ *
+ * The center_channel can be one of {42, 58, 106, 122, 138, 155}
+ *
+ * returns INVCHANSPEC in case of error
+ */
+extern chanspec_t wf_chspec_80(uint8 center_channel, uint8 primary_channel);
+
+/**
  * Convert ctl chan and bw to chanspec
  *
  * @param      ctl_ch          channel
@@ -443,19 +498,22 @@ extern uint wf_channel2freq(uint channel);
 extern uint wf_freq2channel(uint freq);
 
 /*
- * Returns the 80+80 chanspec corresponding to the following input parameters
+ * Returns the 80+80 MHz chanspec corresponding to the following input parameters
  *
- *    primary_20mhz - Primary 20 Mhz channel
- *    chan1 - channel number of first 80 Mhz band
- *    chan2 - channel number of second 80 Mhz band
+ *    primary_20mhz - Primary 20 MHz channel
+ *    chan0_80MHz - center channel number of one frequency segment
+ *    chan1_80MHz - center channel number of the other frequency segment
  *
- *  parameters chan1 and chan2  are channel numbers in {42, 58, 106, 122, 138, 155}
+ * Parameters chan0_80MHz and chan1_80MHz are channel numbers in {42, 58, 106, 122, 138, 155}.
+ * The primary channel must be contained in one of the 80MHz channels. This routine
+ * will determine which frequency segment is the primary 80 MHz segment.
  *
- *  returns INVCHANSPEC in case of error
+ * Returns INVCHANSPEC in case of error.
+ *
+ * Refer to IEEE802.11ac section 22.3.14 "Channelization".
  */
-
 extern chanspec_t wf_chspec_get8080_chspec(uint8 primary_20mhz,
-uint8 chan1_80Mhz, uint8 chan2_80Mhz);
+       uint8 chan0_80Mhz, uint8 chan1_80Mhz);
 
 /*
  * Returns the primary 80 Mhz channel for the provided chanspec
@@ -480,5 +538,11 @@ extern uint8 wf_chspec_secondary80_channel(chanspec_t chanspec);
  */
 extern chanspec_t wf_chspec_primary80_chspec(chanspec_t chspec);
 
-
+#ifdef WL11AC_80P80
+/*
+ * This function returns the centre chanel for the given chanspec.
+ * In case of 80+80 chanspec it returns the primary 80 Mhz centre channel
+ */
+extern uint8 wf_chspec_channel(chanspec_t chspec);
+#endif
 #endif /* _bcmwifi_channels_h_ */
old mode 100755 (executable)
new mode 100644 (file)
index 38d339b..f8983a1
@@ -34,9 +34,16 @@ extern "C" {
 
 #define WL_RATESET_SZ_DSSS             4
 #define WL_RATESET_SZ_OFDM             8
-#define WL_RATESET_SZ_HT_MCS   8
 #define WL_RATESET_SZ_VHT_MCS  10
 
+#if defined(WLPROPRIETARY_11N_RATES)
+#define WL_RATESET_SZ_HT_MCS   WL_RATESET_SZ_VHT_MCS
+#else
+#define WL_RATESET_SZ_HT_MCS   8
+#endif
+
+#define WL_RATESET_SZ_HT_IOCTL 8       /* MAC histogram, compatibility with wl utility */
+
 #define WL_TX_CHAINS_MAX       3
 
 #define WL_RATE_DISABLED               (-128) /* Power value corresponding to unsupported rate */
@@ -46,14 +53,19 @@ typedef enum wl_tx_bw {
        WL_TX_BW_20,
        WL_TX_BW_40,
        WL_TX_BW_80,
-       WL_TX_BW_160,
        WL_TX_BW_20IN40,
        WL_TX_BW_20IN80,
        WL_TX_BW_40IN80,
+       WL_TX_BW_160,
        WL_TX_BW_20IN160,
        WL_TX_BW_40IN160,
        WL_TX_BW_80IN160,
-       WL_TX_BW_ALL
+       WL_TX_BW_ALL,
+       WL_TX_BW_8080,
+       WL_TX_BW_8080CHAN2,
+       WL_TX_BW_20IN8080,
+       WL_TX_BW_40IN8080,
+       WL_TX_BW_80IN8080
 } wl_tx_bw_t;
 
 
diff --git a/drivers/net/wireless/bcmdhd/circularbuf.c b/drivers/net/wireless/bcmdhd/circularbuf.c
deleted file mode 100755 (executable)
index 6f89f73..0000000
+++ /dev/null
@@ -1,326 +0,0 @@
-/*
- * Initialization and support routines for self-booting compressed image.
- *
- * Copyright (C) 1999-2014, 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: circularbuf.c 452261 2014-01-29 19:30:23Z $
- */
-
-#include <circularbuf.h>
-#include <bcmmsgbuf.h>
-#include <osl.h>
-
-#define CIRCULARBUF_READ_SPACE_AT_END(x)               \
-                       ((x->w_ptr >= x->rp_ptr) ? (x->w_ptr - x->rp_ptr) : (x->e_ptr - x->rp_ptr))
-
-#define CIRCULARBUF_READ_SPACE_AVAIL(x)                \
-                       (((CIRCULARBUF_READ_SPACE_AT_END(x) == 0) && (x->w_ptr < x->rp_ptr)) ? \
-                               x->w_ptr : CIRCULARBUF_READ_SPACE_AT_END(x))
-
-int cbuf_msg_level = CBUF_ERROR_VAL | CBUF_TRACE_VAL | CBUF_INFORM_VAL;
-
-/* #define CBUF_DEBUG */
-#ifdef CBUF_DEBUG
-#define CBUF_DEBUG_CHECK(x)    x
-#else
-#define CBUF_DEBUG_CHECK(x)
-#endif /* CBUF_DEBUG */
-
-/*
- * -----------------------------------------------------------------------------
- * Function   : circularbuf_init
- * Description:
- *
- *
- * Input Args :
- *
- *
- * Return Values :
- *
- * -----------------------------------------------------------------------------
- */
-void
-circularbuf_init(circularbuf_t *handle, void *buf_base_addr, uint16 total_buf_len)
-{
-       handle->buf_addr = buf_base_addr;
-
-       handle->depth = handle->e_ptr = HTOL32(total_buf_len);
-
-       /* Initialize Read and Write pointers */
-       handle->w_ptr = handle->r_ptr = handle->wp_ptr = handle->rp_ptr = HTOL32(0);
-       handle->mb_ring_bell = NULL;
-       handle->mb_ctx = NULL;
-
-       return;
-}
-
-void
-circularbuf_register_cb(circularbuf_t *handle, mb_ring_t mb_ring_func, void *ctx)
-{
-       handle->mb_ring_bell = mb_ring_func;
-       handle->mb_ctx = ctx;
-}
-
-#ifdef CBUF_DEBUG
-static void
-circularbuf_check_sanity(circularbuf_t *handle)
-{
-       if ((handle->e_ptr > handle->depth) ||
-           (handle->r_ptr > handle->e_ptr) ||
-               (handle->rp_ptr > handle->e_ptr) ||
-               (handle->w_ptr > handle->e_ptr))
-       {
-               printf("%s:%d: Pointers are corrupted.\n", __FUNCTION__, __LINE__);
-               circularbuf_debug_print(handle);
-               ASSERT(0);
-       }
-       return;
-}
-#endif /* CBUF_DEBUG */
-
-/*
- * -----------------------------------------------------------------------------
- * Function   : circularbuf_reserve_for_write
- *
- * Description:
- * This function reserves N bytes for write in the circular buffer. The circularbuf
- * implementation will only reserve space in the ciruclar buffer and return
- * the pointer to the address where the new data can be written.
- * The actual write implementation (bcopy/dma) is outside the scope of
- * circularbuf implementation.
- *
- * Input Args :
- *             size - No. of bytes to reserve for write
- *
- * Return Values :
- *             void * : Pointer to the reserved location. This is the address
- *                       that will be used for write (dma/bcopy)
- *
- * -----------------------------------------------------------------------------
- */
-void * BCMFASTPATH
-circularbuf_reserve_for_write(circularbuf_t *handle, uint16 size)
-{
-       int16 avail_space;
-       void *ret_ptr = NULL;
-
-       CBUF_DEBUG_CHECK(circularbuf_check_sanity(handle));
-       ASSERT(size < handle->depth);
-
-       if (handle->wp_ptr >= handle->r_ptr)
-               avail_space = handle->depth - handle->wp_ptr;
-       else
-               avail_space = handle->r_ptr - handle->wp_ptr;
-
-       ASSERT(avail_space <= handle->depth);
-       if (avail_space > size)
-       {
-               /* Great. We have enough space. */
-               ret_ptr = CIRCULARBUF_START(handle) + handle->wp_ptr;
-
-               /*
-                * We need to update the wp_ptr for the next guy to write.
-                *
-                * Please Note : We are not updating the write pointer here. This can be
-                * done only after write is complete (In case of DMA, we can only schedule
-                * the DMA. Actual completion will be known only on DMA complete interrupt).
-                */
-               handle->wp_ptr += size;
-               return ret_ptr;
-       }
-
-       /*
-        * If there is no available space, we should check if there is some space left
-        * in the beginning of the circular buffer.  Wrap-around case, where there is
-        * not enough space in the end of the circular buffer. But, there might be
-        * room in the beginning of the buffer.
-        */
-       if (handle->wp_ptr >= handle->r_ptr)
-       {
-               avail_space = handle->r_ptr;
-               if (avail_space > size)
-               {
-                       /* OK. There is room in the beginning. Let's go ahead and use that.
-                        * But, before that, we have left a hole at the end of the circular
-                        * buffer as that was not sufficient to accomodate the requested
-                        * size. Let's make sure this is updated in the circularbuf structure
-                        * so that consumer does not use the hole.
-                        */
-                       handle->e_ptr  = handle->wp_ptr;
-                       handle->wp_ptr = size;
-
-                       return CIRCULARBUF_START(handle);
-               }
-       }
-
-       /* We have tried enough to accomodate the new packet. There is no room for now. */
-       return NULL;
-}
-
-/*
- * -----------------------------------------------------------------------------
- * Function   : circularbuf_write_complete
- *
- * Description:
- * This function has to be called by the producer end of circularbuf to indicate to
- * the circularbuf layer that data has been written and the write pointer can be
- * updated. In the process, if there was a doorbell callback registered, that
- * function would also be invoked.
- *
- * Input Args :
- *             dest_addr         : Address where the data was written. This would be the
- *                                         same address that was reserved earlier.
- *             bytes_written : Length of data written
- *
- * -----------------------------------------------------------------------------
- */
-void BCMFASTPATH
-circularbuf_write_complete(circularbuf_t *handle, uint16 bytes_written)
-{
-       CBUF_DEBUG_CHECK(circularbuf_check_sanity(handle));
-
-       /* Update the write pointer */
-       if ((handle->w_ptr + bytes_written) >= handle->depth) {
-               OSL_CACHE_FLUSH((void *) CIRCULARBUF_START(handle), bytes_written);
-               handle->w_ptr = bytes_written;
-       } else {
-               OSL_CACHE_FLUSH((void *) (CIRCULARBUF_START(handle) + handle->w_ptr),
-                       bytes_written);
-               handle->w_ptr += bytes_written;
-       }
-
-       /* And ring the door bell (mail box interrupt) to indicate to the peer that
-        * message is available for consumption.
-        */
-       if (handle->mb_ring_bell)
-               handle->mb_ring_bell(handle->mb_ctx);
-}
-
-/*
- * -----------------------------------------------------------------------------
- * Function   : circularbuf_get_read_ptr
- *
- * Description:
- * This function will be called by the consumer of circularbuf for reading data from
- * the circular buffer. This will typically be invoked when the consumer gets a
- * doorbell interrupt.
- * Please note that the function only returns the pointer (and length) from
- * where the data can be read. Actual read implementation is upto the
- * consumer. It could be a bcopy or dma.
- *
- * Input Args :
- *             void *                  : Address from where the data can be read.
- *             available_len   : Length of data available for read.
- *
- * -----------------------------------------------------------------------------
- */
-void * BCMFASTPATH
-circularbuf_get_read_ptr(circularbuf_t *handle, uint16 *available_len)
-{
-       uint8 *ret_addr;
-
-       CBUF_DEBUG_CHECK(circularbuf_check_sanity(handle));
-
-       /* First check if there is any data available in the circular buffer */
-       *available_len = CIRCULARBUF_READ_SPACE_AVAIL(handle);
-       if (*available_len == 0)
-               return NULL;
-
-       /*
-        * Although there might be data in the circular buffer for read, in
-        * cases of write wrap-around and read still in the end of the circular
-        * buffer, we might have to wrap around the read pending pointer also.
-        */
-       if (CIRCULARBUF_READ_SPACE_AT_END(handle) == 0)
-               handle->rp_ptr = 0;
-
-       ret_addr = CIRCULARBUF_START(handle) + handle->rp_ptr;
-
-       /*
-        * Please note that we do not update the read pointer here. Only
-        * read pending pointer is updated, so that next reader knows where
-        * to read data from.
-        * read pointer can only be updated when the read is complete.
-        */
-       handle->rp_ptr = (uint16)(ret_addr - CIRCULARBUF_START(handle) + *available_len);
-
-       ASSERT(*available_len <= handle->depth);
-
-       OSL_CACHE_INV((void *) ret_addr, *available_len);
-
-       return ret_addr;
-}
-
-/*
- * -----------------------------------------------------------------------------
- * Function   : circularbuf_read_complete
- * Description:
- * This function has to be called by the consumer end of circularbuf to indicate
- * that data has been consumed and the read pointer can be updated.
- *
- * Input Args :
- *             bytes_read : No. of bytes consumed by the consumer. This has to match
- *                                      the length returned by circularbuf_get_read_ptr
- *
- * Return Values :
- *             CIRCULARBUF_SUCCESS             : Otherwise
- *
- * -----------------------------------------------------------------------------
- */
-circularbuf_ret_t BCMFASTPATH
-circularbuf_read_complete(circularbuf_t *handle, uint16 bytes_read)
-{
-       CBUF_DEBUG_CHECK(circularbuf_check_sanity(handle));
-       ASSERT(bytes_read < handle->depth);
-
-       /* Update the read pointer */
-       if ((handle->r_ptr + bytes_read) >= handle->depth)
-               handle->r_ptr = bytes_read;
-       else
-               handle->r_ptr += bytes_read;
-
-       return CIRCULARBUF_SUCCESS;
-}
-/*
- * -----------------------------------------------------------------------------
- * Function    : circularbuf_revert_rp_ptr
- *
- * Description:
- * The rp_ptr update during circularbuf_get_read_ptr() is done to reflect the amount of data
- * that is sent out to be read by the consumer. But the consumer may not always read the
- * entire data. In such a case, the rp_ptr needs to be reverted back by 'left' bytes, where
- * 'left' is the no. of bytes left unread.
- *
- * Input args:
- *     bytes : The no. of bytes left unread by the consumer
- *
- * -----------------------------------------------------------------------------
- */
-circularbuf_ret_t
-circularbuf_revert_rp_ptr(circularbuf_t *handle, uint16 bytes)
-{
-       CBUF_DEBUG_CHECK(circularbuf_check_sanity(handle));
-       ASSERT(bytes < handle->depth);
-
-       handle->rp_ptr -= bytes;
-
-       return CIRCULARBUF_SUCCESS;
-}
old mode 100755 (executable)
new mode 100644 (file)
index 735a106..677f905
@@ -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.h 457888 2014-02-25 03:34:39Z $
+ * $Id: dhd.h 490628 2014-07-11 07:13:31Z $
  */
 
 /****************
@@ -53,12 +53,21 @@ struct task_struct;
 struct sched_param;
 int setScheduler(struct task_struct *p, int policy, struct sched_param *param);
 int get_scheduler_policy(struct task_struct *p);
+#define MAX_EVENT      16
 
 #define ALL_INTERFACES 0xff
 
 #include <wlioctl.h>
 #include <wlfc_proto.h>
 
+#if defined(BCMWDF)
+#include <wdf.h>
+#include <WdfMiniport.h>
+#endif /* (BCMWDF)  */
+
+#if defined(WL11U)
+#define MFP /* Applying interaction with MFP by spec HS2.0 REL2 */
+#endif /* WL11U */
 
 #if defined(KEEP_ALIVE)
 /* Default KEEP_ALIVE Period is 55 sec to prevent AP from sending Keep Alive probe frame */
@@ -75,10 +84,16 @@ struct dhd_ioctl;
 enum dhd_bus_state {
        DHD_BUS_DOWN,           /* Not ready for frame transfers */
        DHD_BUS_LOAD,           /* Download access only (CPU reset) */
-       DHD_BUS_DATA            /* Ready for frame transfers */
+       DHD_BUS_DATA,           /* Ready for frame transfers */
+       DHD_BUS_SUSPEND,        /* Bus has been suspended */
 };
 
 
+/* For supporting multiple interfaces */
+#define DHD_MAX_IFS    16
+#define DHD_DEL_IF     -0xE
+#define DHD_BAD_IF     -0xF
+
 enum dhd_op_flags {
 /* Firmware requested operation mode */
        DHD_FLAG_STA_MODE                               = (1 << (0)), /* STA only */
@@ -103,8 +118,8 @@ enum dhd_op_flags {
 #define MAX_CNTL_RX_TIMEOUT 1
 #endif /* MAX_CNTL_RX_TIMEOUT */
 
-#define DHD_SCAN_ASSOC_ACTIVE_TIME     35 /* ms: Embedded default Active setting from DHD */
-#define DHD_SCAN_UNASSOC_ACTIVE_TIME 65 /* ms: Embedded def. Unassoc Active setting from DHD */
+#define DHD_SCAN_ASSOC_ACTIVE_TIME     40 /* ms: Embedded default Active setting from DHD */
+#define DHD_SCAN_UNASSOC_ACTIVE_TIME 80 /* ms: Embedded def. Unassoc Active setting from DHD */
 #define DHD_SCAN_PASSIVE_TIME          130 /* ms: Embedded default Passive setting from DHD */
 
 #ifndef POWERUP_MAX_RETRY
@@ -158,17 +173,44 @@ typedef struct reorder_info {
 } reorder_info_t;
 
 #ifdef DHDTCPACK_SUPPRESS
-#define TCPACK_SUP_OFF         0       /* TCPACK suppress off */
-/* Replace TCPACK in txq when new coming one has higher ACK number. */
-#define TCPACK_SUP_REPLACE     1
-/* TCPACK_SUP_REPLACE + delayed TCPACK TX unless ACK to PSH DATA.
- * This will give benefits to Half-Duplex bus interface(e.g. SDIO) that
- * 1. we are able to read TCP DATA packets first from the bus
- * 2. TCPACKs that do not need to hurry delivered remains longer in TXQ so can be suppressed.
- */
-#define TCPACK_SUP_DELAYTX     2
+
+enum {
+       /* TCPACK suppress off */
+       TCPACK_SUP_OFF,
+       /* Replace TCPACK in txq when new coming one has higher ACK number. */
+       TCPACK_SUP_REPLACE,
+       /* TCPACK_SUP_REPLACE + delayed TCPACK TX unless ACK to PSH DATA.
+        * This will give benefits to Half-Duplex bus interface(e.g. SDIO) that
+        * 1. we are able to read TCP DATA packets first from the bus
+        * 2. TCPACKs that don't need to hurry delivered remains longer in TXQ so can be suppressed.
+        */
+       TCPACK_SUP_DELAYTX,
+       TCPACK_SUP_LAST_MODE
+};
 #endif /* DHDTCPACK_SUPPRESS */
 
+
+/* DMA'ing r/w indices for rings supported */
+#ifdef BCM_INDX_TCM /* FW gets r/w indices in TCM */
+#define DMA_INDX_ENAB(dma_indxsup)     0
+#elif defined BCM_INDX_DMA  /* FW gets r/w indices from Host memory */
+#define DMA_INDX_ENAB(dma_indxsup)     1
+#else  /* r/w indices in TCM or host memory based on FW/Host agreement */
+#define DMA_INDX_ENAB(dma_indxsup)     dma_indxsup
+#endif /* BCM_INDX_TCM */
+
+#if defined(WLTDLS) && defined(PCIE_FULL_DONGLE)
+struct tdls_peer_node {
+       uint8 addr[ETHER_ADDR_LEN];
+       struct tdls_peer_node *next;
+};
+typedef struct tdls_peer_node tdls_peer_node_t;
+typedef struct {
+       tdls_peer_node_t *node;
+       uint8 tdls_peer_count;
+} tdls_peer_tbl_t;
+#endif /* defined(WLTDLS) && defined(PCIE_FULL_DONGLE) */
+
 /* Common structure for module and instance linkage */
 typedef struct dhd_pub {
        /* Linkage ponters */
@@ -200,6 +242,7 @@ typedef struct dhd_pub {
 
        /* Additional stats for the bus level */
        ulong tx_packets;       /* Data packets sent to dongle */
+       ulong tx_dropped;       /* Data packets dropped in dhd */
        ulong tx_multicast;     /* Multicast data packets sent to dongle */
        ulong tx_errors;        /* Errors in sending data to dongle */
        ulong tx_ctlpkts;       /* Control packets sent to dongle */
@@ -278,6 +321,8 @@ typedef struct dhd_pub {
        bool    proptxstatus_module_ignore;
        bool    proptxstatus_credit_ignore;
        bool    proptxstatus_txstatus_ignore;
+
+       bool    wlfc_rxpkt_chk;
        /*
         * implement below functions in each platform if needed.
         */
@@ -323,8 +368,47 @@ typedef struct dhd_pub {
        struct task_struct * current_rxf;
        int chan_isvht80;
 #endif /* CUSTOM_SET_CPUCORE */
+
+
+       void    *sta_pool;          /* pre-allocated pool of sta objects */
+       void    *staid_allocator;   /* allocator of sta indexes */
+
+       void    *flowid_allocator;  /* unique flowid allocator */
+       void    *flow_ring_table;   /* flow ring table, include prot and bus info */
+       void    *if_flow_lkup;      /* per interface flowid lkup hash table */
+       uint32  num_flow_rings;
+       uint8  flow_prio_map[NUMPRIO];
+       uint8   flow_prio_map_type;
+       char enable_log[MAX_EVENT];
+       bool dma_d2h_ring_upd_support;
+       bool dma_h2d_ring_upd_support;
+#ifdef DHD_WMF
+       bool wmf_ucast_igmp;
+#ifdef DHD_IGMP_UCQUERY
+       bool wmf_ucast_igmp_query;
+#endif
+#ifdef DHD_UCAST_UPNP
+       bool wmf_ucast_upnp;
+#endif
+#endif /* DHD_WMF */
+#ifdef DHD_UNICAST_DHCP
+       bool dhcp_unicast;
+#endif /* DHD_UNICAST_DHCP */
+#ifdef DHD_L2_FILTER
+       bool block_ping;
+#endif
+#if defined(WLTDLS) && defined(PCIE_FULL_DONGLE)
+       tdls_peer_tbl_t peer_tbl;
+#endif /* defined(WLTDLS) && defined(PCIE_FULL_DONGLE) */
 } dhd_pub_t;
 
+#if defined(BCMWDF)
+typedef struct {
+       dhd_pub_t *dhd_pub;
+} dhd_workitem_context_t;
+
+WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(dhd_workitem_context_t, dhd_get_dhd_workitem_context)
+#endif /* (BCMWDF)  */
 
        #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP)
 
@@ -387,8 +471,6 @@ typedef struct dhd_pub {
 
 #define DHD_IF_VIF     0x01    /* Virtual IF (Hidden from user) */
 
-unsigned long dhd_os_spin_lock(dhd_pub_t *pub);
-void dhd_os_spin_unlock(dhd_pub_t *pub, unsigned long flags);
 #ifdef PNO_SUPPORT
 int dhd_pno_clean(dhd_pub_t *dhd);
 #endif /* PNO_SUPPORT */
@@ -404,6 +486,8 @@ extern int dhd_os_wake_lock_ctrl_timeout_enable(dhd_pub_t *pub, int val);
 extern int dhd_os_wake_lock_ctrl_timeout_cancel(dhd_pub_t *pub);
 extern int dhd_os_wd_wake_lock(dhd_pub_t *pub);
 extern int dhd_os_wd_wake_unlock(dhd_pub_t *pub);
+extern int dhd_os_wake_lock_waive(dhd_pub_t *pub);
+extern int dhd_os_wake_lock_restore(dhd_pub_t *pub);
 
 inline static void MUTEX_LOCK_SOFTAP_SET_INIT(dhd_pub_t * dhdp)
 {
@@ -428,8 +512,6 @@ inline static void MUTEX_UNLOCK_SOFTAP_SET(dhd_pub_t * dhdp)
 
 #define DHD_OS_WAKE_LOCK(pub)                  dhd_os_wake_lock(pub)
 #define DHD_OS_WAKE_UNLOCK(pub)                dhd_os_wake_unlock(pub)
-#define DHD_OS_WD_WAKE_LOCK(pub)               dhd_os_wd_wake_lock(pub)
-#define DHD_OS_WD_WAKE_UNLOCK(pub)             dhd_os_wd_wake_unlock(pub)
 #define DHD_OS_WAKE_LOCK_TIMEOUT(pub)          dhd_os_wake_lock_timeout(pub)
 #define DHD_OS_WAKE_LOCK_RX_TIMEOUT_ENABLE(pub, val) \
        dhd_os_wake_lock_rx_timeout_enable(pub, val)
@@ -437,6 +519,11 @@ inline static void MUTEX_UNLOCK_SOFTAP_SET(dhd_pub_t * dhdp)
        dhd_os_wake_lock_ctrl_timeout_enable(pub, val)
 #define DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_CANCEL(pub) \
        dhd_os_wake_lock_ctrl_timeout_cancel(pub)
+#define DHD_OS_WAKE_LOCK_WAIVE(pub)             dhd_os_wake_lock_waive(pub)
+#define DHD_OS_WAKE_LOCK_RESTORE(pub)           dhd_os_wake_lock_restore(pub)
+
+#define DHD_OS_WD_WAKE_LOCK(pub)               dhd_os_wd_wake_lock(pub)
+#define DHD_OS_WD_WAKE_UNLOCK(pub)             dhd_os_wd_wake_unlock(pub)
 #define DHD_PACKET_TIMEOUT_MS  500
 #define DHD_EVENT_TIMEOUT_MS   1500
 
@@ -545,7 +632,7 @@ extern int dhd_os_send_hang_message(dhd_pub_t *dhdp);
 extern void dhd_set_version_info(dhd_pub_t *pub, char *fw);
 extern bool dhd_os_check_if_up(dhd_pub_t *pub);
 extern int dhd_os_check_wakelock(dhd_pub_t *pub);
-
+extern int dhd_get_instance(dhd_pub_t *pub);
 #ifdef CUSTOM_SET_CPUCORE
 extern void dhd_set_cpucore(dhd_pub_t *dhd, int set);
 #endif /* CUSTOM_SET_CPUCORE */
@@ -575,9 +662,6 @@ extern bool dhd_support_sta_mode(dhd_pub_t *dhd);
 extern int write_to_file(dhd_pub_t *dhd, uint8 *buf, int size);
 #endif /* DHD_DEBUG */
 
-extern void dhd_os_sdtxlock(dhd_pub_t * pub);
-extern void dhd_os_sdtxunlock(dhd_pub_t * pub);
-
 typedef struct {
        uint32 limit;           /* Expiration time (usec) */
        uint32 increment;       /* Current expiration increment (usec) */
@@ -585,15 +669,24 @@ typedef struct {
        uint32 tick;            /* O/S tick time (usec) */
 } dhd_timeout_t;
 
+#ifdef SHOW_LOGTRACE
+typedef struct {
+       int  num_fmts;
+       char **fmts;
+       char *raw_fmts;
+} dhd_event_log_t;
+#endif /* SHOW_LOGTRACE */
+
 extern void dhd_timeout_start(dhd_timeout_t *tmo, uint usec);
 extern int dhd_timeout_expired(dhd_timeout_t *tmo);
 
 extern int dhd_ifname2idx(struct dhd_info *dhd, char *name);
+extern int dhd_ifidx2hostidx(struct dhd_info *dhd, int ifidx);
 extern int dhd_net2idx(struct dhd_info *dhd, struct net_device *net);
 extern struct net_device * dhd_idx2net(void *pub, int ifidx);
 extern int net_os_send_hang_message(struct net_device *dev);
 extern int wl_host_event(dhd_pub_t *dhd_pub, int *idx, void *pktdata,
-                         wl_event_msg_t *, void **data_ptr);
+                         wl_event_msg_t *, void **data_ptr,  void *);
 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);
@@ -632,16 +725,33 @@ extern int dhd_bus_resume(dhd_pub_t *dhdpub, int stage);
 extern int dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint size);
 extern void dhd_print_buf(void *pbuf, int len, int bytes_per_line);
 extern bool dhd_is_associated(dhd_pub_t *dhd, void *bss_buf, int *retval);
-#if defined(BCMSDIO)
+#if defined(BCMSDIO) || defined(BCMPCIE)
 extern uint dhd_bus_chip_id(dhd_pub_t *dhdp);
 extern uint dhd_bus_chiprev_id(dhd_pub_t *dhdp);
 extern uint dhd_bus_chippkg_id(dhd_pub_t *dhdp);
-#endif /* defined(BCMSDIO) */
+#endif /* defined(BCMSDIO) || defined(BCMPCIE) */
 
 #if defined(KEEP_ALIVE)
 extern int dhd_keep_alive_onoff(dhd_pub_t *dhd);
 #endif /* KEEP_ALIVE */
 
+/* OS spin lock API */
+extern void *dhd_os_spin_lock_init(osl_t *osh);
+extern void dhd_os_spin_lock_deinit(osl_t *osh, void *lock);
+extern unsigned long dhd_os_spin_lock(void *lock);
+void dhd_os_spin_unlock(void *lock, unsigned long flags);
+
+/*
+ * Manage sta objects in an interface. Interface is identified by an ifindex and
+ * sta(s) within an interfaces are managed using a MacAddress of the sta.
+ */
+struct dhd_sta;
+extern struct dhd_sta *dhd_findadd_sta(void *pub, int ifidx, void *ea);
+extern void dhd_del_sta(void *pub, int ifidx, void *ea);
+extern int dhd_get_ap_isolate(dhd_pub_t *dhdp, uint32 idx);
+extern int dhd_set_ap_isolate(dhd_pub_t *dhdp, uint32 idx, int val);
+extern int dhd_bssidx2idx(dhd_pub_t *dhdp, uint32 bssidx);
+
 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 {
@@ -770,6 +880,11 @@ extern uint dhd_force_tx_queueing;
 #define WIFI_TURNON_DELAY              DEFAULT_WIFI_TURNON_DELAY
 #endif /* WIFI_TURNON_DELAY */
 
+#define DEFAULT_DHD_WATCHDOG_INTERVAL_MS       10 /* msec */
+#ifndef CUSTOM_DHD_WATCHDOG_MS
+#define CUSTOM_DHD_WATCHDOG_MS                 DEFAULT_DHD_WATCHDOG_INTERVAL_MS
+#endif /* DEFAULT_DHD_WATCHDOG_INTERVAL_MS */
+
 #ifdef WLTDLS
 #ifndef CUSTOM_TDLS_IDLE_MODE_SETTING
 #define CUSTOM_TDLS_IDLE_MODE_SETTING  60000 /* 60sec to tear down TDLS of not active */
@@ -810,11 +925,6 @@ extern char fw_path2[MOD_PARAM_PATHLEN];
 extern uint dhd_download_fw_on_driverload;
 
 
-/* For supporting multiple interfaces */
-#define DHD_MAX_IFS    16
-#define DHD_DEL_IF     -0xe
-#define DHD_BAD_IF     -0xf
-
 extern void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar);
 extern void dhd_wait_event_wakeup(dhd_pub_t*dhd);
 
@@ -837,7 +947,10 @@ void dhd_arp_offload_add_ip(dhd_pub_t *dhd, uint32 ipaddr, int idx);
 #endif /* ARP_OFFLOAD_SUPPORT */
 #ifdef WLTDLS
 int dhd_tdls_enable(struct net_device *dev, bool tdls_on, bool auto_on, struct ether_addr *mac);
-#endif
+#ifdef PCIE_FULL_DONGLE
+void dhd_tdls_update_peer_info(struct net_device *dev, bool connect_disconnect, uint8 *addr);
+#endif /* PCIE_FULL_DONGLE */
+#endif /* WLTDLS */
 /* 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);
@@ -855,11 +968,14 @@ extern bool dhd_prec_drop_pkts(dhd_pub_t *dhdp, struct pktq *pq, int prec, f_dro
 #ifdef PROP_TXSTATUS
 int dhd_os_wlfc_block(dhd_pub_t *pub);
 int dhd_os_wlfc_unblock(dhd_pub_t *pub);
+extern const uint8 prio2fifo[];
 #endif /* PROP_TXSTATUS */
 
 uint8* dhd_os_prealloc(dhd_pub_t *dhdpub, int section, uint size, bool kmalloc_if_fail);
 void dhd_os_prefree(dhd_pub_t *dhdpub, void *addr, uint size);
 
+int dhd_process_cid_mac(dhd_pub_t *dhdp, bool prepost);
+
 #if defined(CONFIG_DHD_USE_STATIC_BUF)
 #define DHD_OS_PREALLOC(dhdpub, section, size) dhd_os_prealloc(dhdpub, section, size, FALSE)
 #define DHD_OS_PREFREE(dhdpub, addr, size) dhd_os_prefree(dhdpub, addr, size)
@@ -869,4 +985,36 @@ void dhd_os_prefree(dhd_pub_t *dhdpub, void *addr, uint size);
 #endif /* defined(CONFIG_DHD_USE_STATIC_BUF) */
 
 
+#define dhd_add_flowid(pub, ifidx, ac_prio, ea, flowid)  do {} while (0)
+#define dhd_del_flowid(pub, ifidx, flowid)               do {} while (0)
+
+extern unsigned long dhd_os_general_spin_lock(dhd_pub_t *pub);
+extern void dhd_os_general_spin_unlock(dhd_pub_t *pub, unsigned long flags);
+
+/** Miscellaenous DHD Spin Locks */
+
+/* Disable router 3GMAC bypass path perimeter lock */
+#define DHD_PERIM_LOCK(dhdp)              do {} while (0)
+#define DHD_PERIM_UNLOCK(dhdp)            do {} while (0)
+
+/* Enable DHD general spin lock/unlock */
+#define DHD_GENERAL_LOCK(dhdp, flags) \
+       (flags) = dhd_os_general_spin_lock(dhdp)
+#define DHD_GENERAL_UNLOCK(dhdp, flags) \
+       dhd_os_general_spin_unlock((dhdp), (flags))
+
+/* Enable DHD flowring queue spin lock/unlock */
+#define DHD_QUEUE_LOCK(lock, flags)       (flags) = dhd_os_spin_lock(lock)
+#define DHD_QUEUE_UNLOCK(lock, flags)     dhd_os_spin_unlock((lock), (flags))
+
+
+
+typedef struct wl_io_pport {
+       dhd_pub_t *dhd_pub;
+       uint ifidx;
+} wl_io_pport_t;
+
+extern void *dhd_pub_wlinfo(dhd_pub_t *dhd_pub);
+
+
 #endif /* _dhd_h_ */
old mode 100755 (executable)
new mode 100644 (file)
index 46ee3d4..d82d6d2
@@ -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_bta.c 434656 2013-11-07 01:11:33Z $
+ * $Id: dhd_bta.c 434434 2013-11-06 07:16:02Z $
  */
 #error "WLBTAMP is not defined"
 
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
index f22ac6a..ac725b8
@@ -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 457888 2014-02-25 03:34:39Z $
+ * $Id: dhd_bus.h 489654 2014-07-07 17:16:07Z $
  */
 
 #ifndef _dhd_bus_h_
@@ -110,7 +110,11 @@ extern void *dhd_bus_pub(struct dhd_bus *bus);
 extern void *dhd_bus_txq(struct dhd_bus *bus);
 extern void *dhd_bus_sih(struct dhd_bus *bus);
 extern uint dhd_bus_hdrlen(struct dhd_bus *bus);
+#ifdef BCMSDIO
 extern void dhd_bus_set_dotxinrx(struct dhd_bus *bus, bool val);
+#else
+#define dhd_bus_set_dotxinrx(a, b) do {} while (0)
+#endif
 
 #define DHD_SET_BUS_STATE_DOWN(_bus)  do { \
        (_bus)->dhd->busstate = DHD_BUS_DOWN; \
@@ -126,33 +130,59 @@ extern int dhd_bus_get_ids(struct dhd_bus *bus, uint32 *bus_type, uint32 *bus_nu
 #ifdef BCMPCIE
 enum {
        DNGL_TO_HOST_BUF_IOCT,
-       DNGL_TO_HOST_BUF_ADDR,
-       HOST_TO_DNGL_BUF_ADDR,
-       HOST_TO_DNGL_WPTR,
-       HOST_TO_DNGL_RPTR,
-       DNGL_TO_HOST_WPTR,
-       DNGL_TO_HOST_RPTR,
+       DNGL_TO_HOST_DMA_SCRATCH_BUFFER,
+       DNGL_TO_HOST_DMA_SCRATCH_BUFFER_LEN,
+       HOST_TO_DNGL_DMA_WRITEINDX_BUFFER,
+       HOST_TO_DNGL_DMA_READINDX_BUFFER,
+       DNGL_TO_HOST_DMA_WRITEINDX_BUFFER,
+       DNGL_TO_HOST_DMA_READINDX_BUFFER,
        TOTAL_LFRAG_PACKET_CNT,
-       HOST_TO_DNGL_CTRLBUF_ADDR,
-       DNGL_TO_HOST_CTRLBUF_ADDR,
-       HTOD_CTRL_RPTR,
-       HTOD_CTRL_WPTR,
-       DTOH_CTRL_RPTR,
-       DTOH_CTRL_WPTR,
        HTOD_MB_DATA,
        DTOH_MB_DATA,
+       RING_BUF_ADDR,
+       H2D_DMA_WRITEINDX,
+       H2D_DMA_READINDX,
+       D2H_DMA_WRITEINDX,
+       D2H_DMA_READINDX,
+       RING_READ_PTR,
+       RING_WRITE_PTR,
+       RING_LEN_ITEMS,
+       RING_MAX_ITEM,
        MAX_HOST_RXBUFS
 };
 typedef void (*dhd_mb_ring_t) (struct dhd_bus *, uint32);
-extern void dhd_bus_cmn_writeshared(struct dhd_bus *bus, void * data, uint32 len, uint8 type);
+extern void dhd_bus_cmn_writeshared(struct dhd_bus *bus, void * data, uint32 len, uint8 type,
+       uint16 ringid);
 extern void dhd_bus_ringbell(struct dhd_bus *bus, uint32 value);
-extern void dhd_bus_cmn_readshared(struct dhd_bus *bus, void* data, uint8 type);
+extern void dhd_bus_cmn_readshared(struct dhd_bus *bus, void* data, uint8 type, uint16 ringid);
 extern uint32 dhd_bus_get_sharedflags(struct dhd_bus *bus);
 extern void dhd_bus_rx_frame(struct dhd_bus *bus, void* pkt, int ifidx, uint pkt_count);
 extern void dhd_bus_start_queue(struct dhd_bus *bus);
 extern void dhd_bus_stop_queue(struct dhd_bus *bus);
-extern void dhd_bus_update_retlen(struct dhd_bus *bus, uint32 retlen, uint32 cmd_id, uint32 status,
-       uint32 inline_data);
+extern void dhd_bus_update_retlen(struct dhd_bus *bus, uint32 retlen, uint32 cmd_id, uint16 status,
+       uint32 resp_len);
 extern dhd_mb_ring_t dhd_bus_get_mbintr_fn(struct dhd_bus *bus);
+extern void dhd_bus_write_flow_ring_states(struct dhd_bus *bus,
+       void * data, uint16 flowid);
+extern void dhd_bus_read_flow_ring_states(struct dhd_bus *bus,
+       void * data, uint8 flowid);
+extern int dhd_bus_flow_ring_create_request(struct dhd_bus *bus, void *flow_ring_node);
+extern void dhd_bus_clean_flow_ring(struct dhd_bus *bus, uint16 flowid);
+extern void dhd_bus_flow_ring_create_response(struct dhd_bus *bus, uint16 flow_id, int32 status);
+extern int dhd_bus_flow_ring_delete_request(struct dhd_bus *bus, void *flow_ring_node);
+extern void dhd_bus_flow_ring_delete_response(struct dhd_bus *bus, uint16 flowid, uint32 status);
+extern int dhd_bus_flow_ring_flush_request(struct dhd_bus *bus, void *flow_ring_node);
+extern void dhd_bus_flow_ring_flush_response(struct dhd_bus *bus, uint16 flowid, uint32 status);
+extern uint8 dhd_bus_is_txmode_push(struct dhd_bus *bus);
+extern uint32 dhd_bus_max_h2d_queues(struct dhd_bus *bus, uint8 *txpush);
+extern int dhd_bus_schedule_queue(struct dhd_bus *bus, uint16 flow_id, bool txs);
+extern int dhdpcie_bus_clock_start(struct dhd_bus *bus);
+extern int dhdpcie_bus_clock_stop(struct dhd_bus *bus);
+extern int dhdpcie_bus_enable_device(struct dhd_bus *bus);
+extern int dhdpcie_bus_disable_device(struct dhd_bus *bus);
+extern bool dhdpcie_bus_dongle_attach(struct dhd_bus *bus);
+extern int dhd_bus_release_dongle(struct dhd_bus *bus);
+
+
 #endif /* BCMPCIE */
 #endif /* _dhd_bus_h_ */
old mode 100755 (executable)
new mode 100644 (file)
index ad7ab42..4a69389
@@ -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_cdc.c 449353 2014-01-16 21:34:16Z $
+ * $Id: dhd_cdc.c 472193 2014-04-23 06:27:38Z $
  *
  * 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
@@ -379,6 +379,17 @@ dhd_prot_hdrpush(dhd_pub_t *dhd, int ifidx, void *PKTBUF)
 }
 #undef PKTBUF  /* Only defined in the above routine */
 
+uint
+dhd_prot_hdrlen(dhd_pub_t *dhd, void *PKTBUF)
+{
+       uint hdrlen = 0;
+#ifdef BDC
+       /* Length of BDC(+WLFC) headers pushed */
+       hdrlen = BDC_HEADER_LEN + (((struct bdc_header *)PKTBUF)->dataOffset * 4);
+#endif
+       return hdrlen;
+}
+
 int
 dhd_prot_hdrpull(dhd_pub_t *dhd, int *ifidx, void *pktbuf, uchar *reorder_buf_info,
        uint *reorder_info_len)
@@ -498,7 +509,8 @@ dhd_prot_detach(dhd_pub_t *dhd)
 void
 dhd_prot_dstats(dhd_pub_t *dhd)
 {
-/* No stats from dongle added yet, copy bus stats */
+       /*  copy bus stats */
+
        dhd->dstats.tx_packets = dhd->tx_packets;
        dhd->dstats.tx_errors = dhd->tx_errors;
        dhd->dstats.rx_packets = dhd->rx_packets;
@@ -509,7 +521,7 @@ dhd_prot_dstats(dhd_pub_t *dhd)
 }
 
 int
-dhd_prot_init(dhd_pub_t *dhd)
+dhd_sync_with_dongle(dhd_pub_t *dhd)
 {
        int ret = 0;
        wlc_rev_info_t revinfo;
@@ -523,8 +535,13 @@ dhd_prot_init(dhd_pub_t *dhd)
                goto done;
 
 
+       dhd_process_cid_mac(dhd, TRUE);
+
        ret = dhd_preinit_ioctls(dhd);
 
+       if (!ret)
+               dhd_process_cid_mac(dhd, FALSE);
+
        /* Always assumes wl for now */
        dhd->iswl = TRUE;
 
@@ -532,6 +549,11 @@ done:
        return ret;
 }
 
+int dhd_prot_init(dhd_pub_t *dhd)
+{
+       return TRUE;
+}
+
 void
 dhd_prot_stop(dhd_pub_t *dhd)
 {
old mode 100755 (executable)
new mode 100644 (file)
index 987912f..51665ca
@@ -30,7 +30,6 @@
 #include <bcmutils.h>
 #include <wldev_common.h>
 #include <wl_cfg80211.h>
-#include <brcm_nl80211.h>
 #include <dhd_cfg80211.h>
 
 #ifdef PKT_FILTER_SUPPORT
@@ -52,9 +51,11 @@ static int dhd_dongle_up = FALSE;
 #include <dhd.h>
 #include <dhdioctl.h>
 #include <wlioctl.h>
+#include <brcm_nl80211.h>
 #include <dhd_cfg80211.h>
 
-static s32 wl_dongle_up(struct net_device *ndev, u32 up);
+static s32 wl_dongle_up(struct net_device *ndev);
+static s32 wl_dongle_down(struct net_device *ndev);
 
 /**
  * Function implementations
@@ -74,6 +75,17 @@ s32 dhd_cfg80211_deinit(struct bcm_cfg80211 *cfg)
 
 s32 dhd_cfg80211_down(struct bcm_cfg80211 *cfg)
 {
+       struct net_device *ndev;
+       s32 err = 0;
+
+       WL_TRACE(("In\n"));
+       if (!dhd_dongle_up) {
+               WL_ERR(("Dongle is already down\n"));
+               return err;
+       }
+
+       ndev = bcmcfg_to_prmry_ndev(cfg);
+       wl_dongle_down(ndev);
        dhd_dongle_up = FALSE;
        return 0;
 }
@@ -127,9 +139,34 @@ int wl_cfg80211_remove_if(struct bcm_cfg80211 *cfg, int ifidx, struct net_device
        return dhd_remove_if(cfg->pub, ifidx, FALSE);
 }
 
-static s32 wl_dongle_up(struct net_device *ndev, u32 up)
+struct net_device * dhd_cfg80211_netdev_free(struct net_device *ndev)
+{
+       if (ndev) {
+               if (ndev->ieee80211_ptr) {
+                       kfree(ndev->ieee80211_ptr);
+                       ndev->ieee80211_ptr = NULL;
+               }
+               free_netdev(ndev);
+               return NULL;
+       }
+
+       return ndev;
+}
+
+void dhd_netdev_free(struct net_device *ndev)
+{
+#ifdef WL_CFG80211
+       ndev = dhd_cfg80211_netdev_free(ndev);
+#endif
+       if (ndev)
+               free_netdev(ndev);
+}
+
+static s32
+wl_dongle_up(struct net_device *ndev)
 {
        s32 err = 0;
+       u32 up = 0;
 
        err = wldev_ioctl(ndev, WLC_UP, &up, sizeof(up), true);
        if (unlikely(err)) {
@@ -138,6 +175,20 @@ static s32 wl_dongle_up(struct net_device *ndev, u32 up)
        return err;
 }
 
+static s32
+wl_dongle_down(struct net_device *ndev)
+{
+       s32 err = 0;
+       u32 down = 0;
+
+       err = wldev_ioctl(ndev, WLC_DOWN, &down, sizeof(down), true);
+       if (unlikely(err)) {
+               WL_ERR(("WLC_DOWN error (%d)\n", err));
+       }
+       return err;
+}
+
+
 s32 dhd_config_dongle(struct bcm_cfg80211 *cfg)
 {
 #ifndef DHD_SDALIGN
@@ -154,7 +205,7 @@ s32 dhd_config_dongle(struct bcm_cfg80211 *cfg)
 
        ndev = bcmcfg_to_prmry_ndev(cfg);
 
-       err = wl_dongle_up(ndev, 0);
+       err = wl_dongle_up(ndev);
        if (unlikely(err)) {
                WL_ERR(("wl_dongle_up failed\n"));
                goto default_conf_out;
@@ -166,96 +217,3 @@ default_conf_out:
        return err;
 
 }
-
-#ifdef CONFIG_NL80211_TESTMODE
-int dhd_cfg80211_testmode_cmd(struct wiphy *wiphy, void *data, int len)
-{
-       struct sk_buff *reply;
-       struct bcm_cfg80211 *cfg;
-       dhd_pub_t *dhd;
-       struct bcm_nlmsg_hdr *nlioc = data;
-       dhd_ioctl_t ioc = { 0 };
-       int err = 0;
-       void *buf = NULL, *cur;
-       u16 buflen;
-       u16 maxmsglen = PAGE_SIZE - 0x100;
-       bool newbuf = false;
-
-       WL_TRACE(("entry: cmd = %d\n", nlioc->cmd));
-       cfg = wiphy_priv(wiphy);
-       dhd = cfg->pub;
-
-       DHD_OS_WAKE_LOCK(dhd);
-
-       /* send to dongle only if we are not waiting for reload already */
-       if (dhd->hang_was_sent) {
-               WL_ERR(("HANG was sent up earlier\n"));
-               DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(dhd, DHD_EVENT_TIMEOUT_MS);
-               DHD_OS_WAKE_UNLOCK(dhd);
-               return OSL_ERROR(BCME_DONGLE_DOWN);
-       }
-
-       len -= sizeof(struct bcm_nlmsg_hdr);
-
-       if (nlioc->len > 0) {
-               if (nlioc->len <= len) {
-                       buf = (void *)nlioc + nlioc->offset;
-                       *(char *)(buf + nlioc->len) = '\0';
-               } else {
-                       if (nlioc->len > DHD_IOCTL_MAXLEN)
-                               nlioc->len = DHD_IOCTL_MAXLEN;
-                       buf = vzalloc(nlioc->len);
-                       if (!buf)
-                               return -ENOMEM;
-                       newbuf = true;
-                       memcpy(buf, (void *)nlioc + nlioc->offset, len);
-                       *(char *)(buf + len) = '\0';
-               }
-       }
-
-       ioc.cmd = nlioc->cmd;
-       ioc.len = nlioc->len;
-       ioc.set = nlioc->set;
-       ioc.driver = nlioc->magic;
-       err = dhd_ioctl_process(dhd, 0, &ioc, buf);
-       if (err) {
-               WL_TRACE(("dhd_ioctl_process return err %d\n", err));
-               err = OSL_ERROR(err);
-               goto done;
-       }
-
-       cur = buf;
-       while (nlioc->len > 0) {
-               buflen = nlioc->len > maxmsglen ? maxmsglen : nlioc->len;
-               nlioc->len -= buflen;
-               reply = cfg80211_testmode_alloc_reply_skb(wiphy, buflen+4);
-               if (!reply) {
-                       WL_ERR(("Failed to allocate reply msg\n"));
-                       err = -ENOMEM;
-                       break;
-               }
-
-               if (nla_put(reply, BCM_NLATTR_DATA, buflen, cur) ||
-                       nla_put_u16(reply, BCM_NLATTR_LEN, buflen)) {
-                       kfree_skb(reply);
-                       err = -ENOBUFS;
-                       break;
-               }
-
-               do {
-                       err = cfg80211_testmode_reply(reply);
-               } while (err == -EAGAIN);
-               if (err) {
-                       WL_ERR(("testmode reply failed:%d\n", err));
-                       break;
-               }
-               cur += buflen;
-       }
-
-done:
-       if (newbuf)
-               vfree(buf);
-       DHD_OS_WAKE_UNLOCK(dhd);
-       return err;
-}
-#endif /* CONFIG_NL80211_TESTMODE */
old mode 100755 (executable)
new mode 100644 (file)
index 905b306..4d425f0
 #include <wl_cfg80211.h>
 #include <wl_cfgp2p.h>
 
+#ifndef WL_ERR
+#define WL_ERR CFG80211_ERR
+#endif
+#ifndef WL_TRACE
+#define WL_TRACE CFG80211_TRACE
+#endif
+
 s32 dhd_cfg80211_init(struct bcm_cfg80211 *cfg);
 s32 dhd_cfg80211_deinit(struct bcm_cfg80211 *cfg);
 s32 dhd_cfg80211_down(struct bcm_cfg80211 *cfg);
@@ -38,13 +45,4 @@ s32 dhd_cfg80211_set_p2p_info(struct bcm_cfg80211 *cfg, int val);
 s32 dhd_cfg80211_clean_p2p_info(struct bcm_cfg80211 *cfg);
 s32 dhd_config_dongle(struct bcm_cfg80211 *cfg);
 
-#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
-
 #endif /* __DHD_CFG80211__ */
diff --git a/drivers/net/wireless/bcmdhd/dhd_cfg_vendor.c b/drivers/net/wireless/bcmdhd/dhd_cfg_vendor.c
new file mode 100644 (file)
index 0000000..190e830
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * Linux cfg80211 vendor command/event handlers of DHD
+ *
+ * Copyright (C) 1999-2014, 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_cfg_vendor.c 487126 2014-06-24 23:06:12Z $
+ */
+
+#include <linuxver.h>
+#include <net/cfg80211.h>
+#include <net/netlink.h>
+
+#include <bcmutils.h>
+#include <wl_cfg80211.h>
+#include <wl_cfgvendor.h>
+#include <dngl_stats.h>
+#include <dhd.h>
+#include <dhdioctl.h>
+#include <brcm_nl80211.h>
+
+#ifdef VENDOR_EXT_SUPPORT
+static int dhd_cfgvendor_priv_string_handler(struct wiphy *wiphy,
+       struct wireless_dev *wdev, const void  *data, int len)
+{
+       const struct bcm_nlmsg_hdr *nlioc = data;
+       struct net_device *ndev = NULL;
+       struct bcm_cfg80211 *cfg;
+       struct sk_buff *reply;
+       void *buf = NULL, *cur;
+       dhd_pub_t *dhd;
+       dhd_ioctl_t ioc = { 0 };
+       int ret = 0, ret_len, payload, msglen;
+       int maxmsglen = PAGE_SIZE - 0x100;
+       int8 index;
+
+       WL_TRACE(("entry: cmd = %d\n", nlioc->cmd));
+       DHD_ERROR(("entry: cmd = %d\n", nlioc->cmd));
+
+       cfg = wiphy_priv(wiphy);
+       dhd = cfg->pub;
+
+       DHD_OS_WAKE_LOCK(dhd);
+
+       /* send to dongle only if we are not waiting for reload already */
+       if (dhd->hang_was_sent) {
+               WL_ERR(("HANG was sent up earlier\n"));
+               DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(dhd, DHD_EVENT_TIMEOUT_MS);
+               DHD_OS_WAKE_UNLOCK(dhd);
+               return OSL_ERROR(BCME_DONGLE_DOWN);
+       }
+
+       len -= sizeof(struct bcm_nlmsg_hdr);
+       ret_len = nlioc->len;
+       if (ret_len > 0 || len > 0) {
+               if (len > DHD_IOCTL_MAXLEN) {
+                       WL_ERR(("oversize input buffer %d\n", len));
+                       len = DHD_IOCTL_MAXLEN;
+               }
+               if (ret_len > DHD_IOCTL_MAXLEN) {
+                       WL_ERR(("oversize return buffer %d\n", ret_len));
+                       ret_len = DHD_IOCTL_MAXLEN;
+               }
+               payload = max(ret_len, len) + 1;
+               buf = vzalloc(payload);
+               if (!buf) {
+                       DHD_OS_WAKE_UNLOCK(dhd);
+                       return -ENOMEM;
+               }
+               memcpy(buf, (void *)nlioc + nlioc->offset, len);
+               *(char *)(buf + len) = '\0';
+       }
+
+       ndev = wdev_to_wlc_ndev(wdev, cfg);
+       index = dhd_net2idx(dhd->info, ndev);
+       if (index == DHD_BAD_IF) {
+               WL_ERR(("Bad ifidx from wdev:%p\n", wdev));
+               ret = BCME_ERROR;
+               goto done;
+       }
+
+       ioc.cmd = nlioc->cmd;
+       ioc.len = nlioc->len;
+       ioc.set = nlioc->set;
+       ioc.driver = nlioc->magic;
+       ret = dhd_ioctl_process(dhd, index, &ioc, buf);
+       if (ret) {
+               WL_TRACE(("dhd_ioctl_process return err %d\n", ret));
+               ret = OSL_ERROR(ret);
+               goto done;
+       }
+
+       cur = buf;
+       while (ret_len > 0) {
+               msglen = nlioc->len > maxmsglen ? maxmsglen : ret_len;
+               ret_len -= msglen;
+               payload = msglen + sizeof(msglen);
+               reply = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, payload);
+               if (!reply) {
+                       WL_ERR(("Failed to allocate reply msg\n"));
+                       ret = -ENOMEM;
+                       break;
+               }
+
+               if (nla_put(reply, BCM_NLATTR_DATA, msglen, cur) ||
+                       nla_put_u16(reply, BCM_NLATTR_LEN, msglen)) {
+                       kfree_skb(reply);
+                       ret = -ENOBUFS;
+                       break;
+               }
+
+               ret = cfg80211_vendor_cmd_reply(reply);
+               if (ret) {
+                       WL_ERR(("testmode reply failed:%d\n", ret));
+                       break;
+               }
+               cur += msglen;
+       }
+
+done:
+       vfree(buf);
+       DHD_OS_WAKE_UNLOCK(dhd);
+       return ret;
+}
+
+const struct wiphy_vendor_command dhd_cfgvendor_cmds [] = {
+       {
+               {
+                       .vendor_id = OUI_BRCM,
+                       .subcmd = BRCM_VENDOR_SCMD_PRIV_STR
+               },
+               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+               .doit = dhd_cfgvendor_priv_string_handler
+       },
+};
+
+int cfgvendor_attach(struct wiphy *wiphy)
+{
+       wiphy->vendor_commands  = dhd_cfgvendor_cmds;
+       wiphy->n_vendor_commands = ARRAY_SIZE(dhd_cfgvendor_cmds);
+
+       return 0;
+}
+
+int cfgvendor_detach(struct wiphy *wiphy)
+{
+       wiphy->vendor_commands  = NULL;
+       wiphy->n_vendor_commands = 0;
+
+       return 0;
+}
+#endif /* VENDOR_EXT_SUPPORT */
old mode 100755 (executable)
new mode 100644 (file)
index 21ce01d..9d4b5f3
@@ -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_common.c 457888 2014-02-25 03:34:39Z $
+ * $Id: dhd_common.c 490628 2014-07-11 07:13:31Z $
  */
 #include <typedefs.h>
 #include <osl.h>
 #include <wlioctl.h>
 #include <dhd.h>
 #include <dhd_ip.h>
-
 #include <proto/bcmevent.h>
 
+#ifdef SHOW_LOGTRACE
+#include <event_log.h>
+#endif /* SHOW_LOGTRACE */
+
+#ifdef BCMPCIE
+#include <dhd_flowring.h>
+#endif
+
 #include <dhd_bus.h>
 #include <dhd_proto.h>
 #include <dhd_dbg.h>
 #ifdef PNO_SUPPORT
 #include <dhd_pno.h>
 #endif
-#ifdef SET_RANDOM_MAC_SOFTAP
-#include <linux/random.h>
-#include <linux/jiffies.h>
-#endif
 
 #define htod32(i) (i)
 #define htod16(i) (i)
 #include <dhd_wlfc.h>
 #endif
 
+#ifdef DHD_WMF
+#include <dhd_linux.h>
+#include <dhd_wmf_linux.h>
+#endif /* DHD_WMF */
+
+
 #ifdef WLMEDIA_HTSF
 extern void htsf_update(struct dhd_info *dhd, void *data);
 #endif
@@ -83,7 +92,9 @@ uint32 dhd_conn_event;
 uint32 dhd_conn_status;
 uint32 dhd_conn_reason;
 
-extern int disable_proptx;
+#if defined(SHOW_EVENTS) && defined(SHOW_LOGTRACE)
+static int check_event_log_sequence_number(uint32 seq_no);
+#endif /* defined(SHOW_EVENTS) && defined(SHOW_LOGTRACE) */
 extern int dhd_iscan_request(void * dhdp, uint16 action);
 extern void dhd_ind_scan_confirm(void *h, bool status);
 extern int dhd_iscan_in_progress(void *h);
@@ -113,6 +124,8 @@ const char dhd_version[] = "\nDongle Host Driver, version " EPI_VERSION_STR "\nC
 
 void dhd_set_timer(void *bus, uint wdtick);
 
+
+
 /* IOVar table */
 enum {
        IOV_VERSION = 1,
@@ -142,6 +155,7 @@ enum {
        IOV_PROPTXSTATUS_MODULE_IGNORE,
        IOV_PROPTXSTATUS_CREDIT_IGNORE,
        IOV_PROPTXSTATUS_TXSTATUS_IGNORE,
+       IOV_PROPTXSTATUS_RXPKT_CHK,
 #endif /* PROP_TXSTATUS */
        IOV_BUS_TYPE,
 #ifdef WLMEDIA_HTSF
@@ -152,6 +166,24 @@ enum {
 #ifdef DHDTCPACK_SUPPRESS
        IOV_TCPACK_SUPPRESS,
 #endif /* DHDTCPACK_SUPPRESS */
+#ifdef DHD_WMF
+       IOV_WMF_BSS_ENAB,
+       IOV_WMF_UCAST_IGMP,
+       IOV_WMF_MCAST_DATA_SENDUP,
+#ifdef WL_IGMP_UCQUERY
+       IOV_WMF_UCAST_IGMP_QUERY,
+#endif /* WL_IGMP_UCQUERY */
+#ifdef DHD_UCAST_UPNP
+       IOV_WMF_UCAST_UPNP,
+#endif /* DHD_UCAST_UPNP */
+#endif /* DHD_WMF */
+       IOV_AP_ISOLATE,
+#ifdef DHD_UNICAST_DHCP
+       IOV_DHCP_UNICAST,
+#endif /* DHD_UNICAST_DHCP */
+#ifdef DHD_L2_FILTER
+       IOV_BLOCK_PING,
+#endif
        IOV_LAST
 };
 
@@ -188,6 +220,7 @@ const bcm_iovar_t dhd_iovars[] = {
        {"pmodule_ignore", IOV_PROPTXSTATUS_MODULE_IGNORE, 0, IOVT_BOOL, 0 },
        {"pcredit_ignore", IOV_PROPTXSTATUS_CREDIT_IGNORE, 0, IOVT_BOOL, 0 },
        {"ptxstatus_ignore", IOV_PROPTXSTATUS_TXSTATUS_IGNORE, 0, IOVT_BOOL, 0 },
+       {"rxpkt_chk", IOV_PROPTXSTATUS_RXPKT_CHK, 0, IOVT_BOOL, 0 },
 #endif /* PROP_TXSTATUS */
        {"bustype", IOV_BUS_TYPE, 0, IOVT_UINT32, 0},
 #ifdef WLMEDIA_HTSF
@@ -199,6 +232,24 @@ const bcm_iovar_t dhd_iovars[] = {
 #ifdef DHDTCPACK_SUPPRESS
        {"tcpack_suppress",     IOV_TCPACK_SUPPRESS,    0,      IOVT_UINT8,     0 },
 #endif /* DHDTCPACK_SUPPRESS */
+#ifdef DHD_WMF
+       {"wmf_bss_enable", IOV_WMF_BSS_ENAB,    0,      IOVT_BOOL,      0 },
+       {"wmf_ucast_igmp", IOV_WMF_UCAST_IGMP,  0,      IOVT_BOOL,      0 },
+       {"wmf_mcast_data_sendup", IOV_WMF_MCAST_DATA_SENDUP,    0,      IOVT_BOOL,      0 },
+#ifdef WL_IGMP_UCQUERY
+       {"wmf_ucast_igmp_query", IOV_WMF_UCAST_IGMP_QUERY, (0), IOVT_BOOL, 0 },
+#endif /* WL_IGMP_UCQUERY */
+#ifdef DHD_UCAST_UPNP
+       {"wmf_ucast_upnp", IOV_WMF_UCAST_UPNP, (0), IOVT_BOOL, 0 },
+#endif /* DHD_UCAST_UPNP */
+#endif /* DHD_WMF */
+#ifdef DHD_UNICAST_DHCP
+       {"dhcp_unicast", IOV_DHCP_UNICAST, (0), IOVT_BOOL, 0 },
+#endif /* DHD_UNICAST_DHCP */
+       {"ap_isolate", IOV_AP_ISOLATE, (0), IOVT_BOOL, 0},
+#ifdef DHD_L2_FILTER
+       {"block_ping", IOV_BLOCK_PING, (0), IOVT_BOOL, 0},
+#endif
        {NULL, 0, 0, 0, 0 }
 };
 
@@ -239,8 +290,8 @@ dhd_dump(dhd_pub_t *dhdp, char *buf, int buflen)
        bcm_bprintf(strbuf, "multicast %lu\n", dhdp->dstats.multicast);
 
        bcm_bprintf(strbuf, "bus stats:\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_packets %lu  tx_dropped %lu tx_multicast %lu tx_errors %lu\n",
+                   dhdp->tx_packets, dhdp->tx_dropped, dhdp->tx_multicast, dhdp->tx_errors);
        bcm_bprintf(strbuf, "tx_ctlpkts %lu tx_ctlerrs %lu\n",
                    dhdp->tx_ctlpkts, dhdp->tx_ctlerrs);
        bcm_bprintf(strbuf, "rx_packets %lu rx_multicast %lu rx_errors %lu \n",
@@ -258,11 +309,12 @@ dhd_dump(dhd_pub_t *dhdp, char *buf, int buflen)
        /* Add any bus info */
        dhd_bus_dump(dhdp, strbuf);
 
+
        return (!strbuf->size ? BCME_BUFTOOSHORT : 0);
 }
 
 int
-dhd_wl_ioctl_cmd(dhd_pub_t *dhd_pub, int cmd, void *arg, int len, uint8 set, int ifindex)
+dhd_wl_ioctl_cmd(dhd_pub_t *dhd_pub, int cmd, void *arg, int len, uint8 set, int ifidx)
 {
        wl_ioctl_t ioc;
 
@@ -271,22 +323,35 @@ dhd_wl_ioctl_cmd(dhd_pub_t *dhd_pub, int cmd, void *arg, int len, uint8 set, int
        ioc.len = len;
        ioc.set = set;
 
-       return dhd_wl_ioctl(dhd_pub, ifindex, &ioc, arg, len);
+       return dhd_wl_ioctl(dhd_pub, ifidx, &ioc, arg, len);
 }
 
-
 int
-dhd_wl_ioctl(dhd_pub_t *dhd_pub, int ifindex, wl_ioctl_t *ioc, void *buf, int len)
+dhd_wl_ioctl(dhd_pub_t *dhd_pub, int ifidx, wl_ioctl_t *ioc, void *buf, int len)
 {
-       int ret = 0;
+       int ret = BCME_ERROR;
 
        if (dhd_os_proto_block(dhd_pub))
        {
+#if defined(WL_WLC_SHIM)
+               wl_info_t *wl = dhd_pub_wlinfo(dhd_pub);
+
+               wl_io_pport_t io_pport;
+               io_pport.dhd_pub = dhd_pub;
+               io_pport.ifidx = ifidx;
+
+               ret = wl_shim_ioctl(wl->shim, ioc, &io_pport);
+               if (ret != BCME_OK) {
+                       DHD_ERROR(("%s: wl_shim_ioctl(%d) ERR %d\n", __FUNCTION__, ioc->cmd, ret));
+               }
+#else
+               ret = dhd_prot_ioctl(dhd_pub, ifidx, ioc, buf, len);
+#endif /* defined(WL_WLC_SHIM) */
 
-               ret = dhd_prot_ioctl(dhd_pub, ifindex, ioc, buf, len);
-               if ((ret) && (dhd_pub->up))
+               if (ret && dhd_pub->up) {
                        /* Send hang event only if dhd_open() was success */
-                       dhd_os_check_hang(dhd_pub, ifindex, ret);
+                       dhd_os_check_hang(dhd_pub, ifidx, ret);
+               }
 
                if (ret == -ETIMEDOUT && !dhd_pub->up) {
                        DHD_ERROR(("%s: 'resumed on timeout' error is "
@@ -297,12 +362,58 @@ dhd_wl_ioctl(dhd_pub_t *dhd_pub, int ifindex, wl_ioctl_t *ioc, void *buf, int le
 
                dhd_os_proto_unblock(dhd_pub);
 
-
        }
 
        return ret;
 }
 
+uint wl_get_port_num(wl_io_pport_t *io_pport)
+{
+       return 0;
+}
+
+/* Get bssidx from iovar params
+ * Input:   dhd_pub - pointer to dhd_pub_t
+ *         params  - IOVAR params
+ * Output:  idx            - BSS index
+ *         val     - ponter to the IOVAR arguments
+ */
+static int
+dhd_iovar_parse_bssidx(dhd_pub_t *dhd_pub, char *params, int *idx, char **val)
+{
+       char *prefix = "bsscfg:";
+       uint32  bssidx;
+
+       if (!(strncmp(params, prefix, strlen(prefix)))) {
+               /* per bss setting should be prefixed with 'bsscfg:' */
+               char *p = (char *)params + strlen(prefix);
+
+               /* Skip Name */
+               while (*p != '\0')
+                       p++;
+               /* consider null */
+               p = p + 1;
+               bcopy(p, &bssidx, sizeof(uint32));
+               /* Get corresponding dhd index */
+               bssidx = dhd_bssidx2idx(dhd_pub, bssidx);
+
+               if (bssidx >= DHD_MAX_IFS) {
+                       DHD_ERROR(("%s Wrong bssidx provided\n", __FUNCTION__));
+                       return BCME_ERROR;
+               }
+
+               /* skip bss idx */
+               p += sizeof(uint32);
+               *val = p;
+               *idx = bssidx;
+       } else {
+               DHD_ERROR(("%s: bad parameter for per bss iovar\n", __FUNCTION__));
+               return BCME_ERROR;
+       }
+
+       return BCME_OK;
+}
+
 static int
 dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const char *name,
             void *params, int plen, void *arg, int len, int val_size)
@@ -389,6 +500,7 @@ dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const ch
                dhd_pub->tx_errors = dhd_pub->rx_errors = 0;
                dhd_pub->tx_ctlpkts = dhd_pub->rx_ctlpkts = 0;
                dhd_pub->tx_ctlerrs = dhd_pub->rx_ctlerrs = 0;
+               dhd_pub->tx_dropped = 0;
                dhd_pub->rx_dropped = 0;
                dhd_pub->rx_readahead_cnt = 0;
                dhd_pub->tx_realloc = 0;
@@ -433,7 +545,6 @@ dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const ch
                if (bcmerror != BCME_OK)
                        goto exit;
 
-               disable_proptx = int_val ? FALSE : TRUE;
                /* wlfc is already set as desired */
                if (wlfc_enab == (int_val == 0 ? FALSE : TRUE))
                        goto exit;
@@ -506,6 +617,18 @@ dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const ch
        case IOV_SVAL(IOV_PROPTXSTATUS_TXSTATUS_IGNORE):
                dhd_wlfc_set_txstatus_ignore(dhd_pub, int_val);
                break;
+
+       case IOV_GVAL(IOV_PROPTXSTATUS_RXPKT_CHK):
+               bcmerror = dhd_wlfc_get_rxpkt_chk(dhd_pub, &int_val);
+               if (bcmerror != BCME_OK)
+                       goto exit;
+               bcopy(&int_val, arg, val_size);
+               break;
+
+       case IOV_SVAL(IOV_PROPTXSTATUS_RXPKT_CHK):
+               dhd_wlfc_set_rxpkt_chk(dhd_pub, int_val);
+               break;
+
 #endif /* PROP_TXSTATUS */
 
        case IOV_GVAL(IOV_BUS_TYPE):
@@ -568,6 +691,175 @@ dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const ch
                break;
        }
 #endif /* DHDTCPACK_SUPPRESS */
+#ifdef DHD_WMF
+       case IOV_GVAL(IOV_WMF_BSS_ENAB): {
+               uint32  bssidx;
+               dhd_wmf_t *wmf;
+               char *val;
+
+               if (dhd_iovar_parse_bssidx(dhd_pub, (char *)name, &bssidx, &val) != BCME_OK) {
+                       DHD_ERROR(("%s: wmf_bss_enable: bad parameter\n", __FUNCTION__));
+                       bcmerror = BCME_BADARG;
+                       break;
+               }
+
+               wmf = dhd_wmf_conf(dhd_pub, bssidx);
+               int_val = wmf->wmf_enable ? 1 :0;
+               bcopy(&int_val, arg, val_size);
+               break;
+       }
+       case IOV_SVAL(IOV_WMF_BSS_ENAB): {
+               /* Enable/Disable WMF */
+               uint32  bssidx;
+               dhd_wmf_t *wmf;
+               char *val;
+
+               if (dhd_iovar_parse_bssidx(dhd_pub, (char *)name, &bssidx, &val) != BCME_OK) {
+                       DHD_ERROR(("%s: wmf_bss_enable: bad parameter\n", __FUNCTION__));
+                       bcmerror = BCME_BADARG;
+                       break;
+               }
+
+               ASSERT(val);
+               bcopy(val, &int_val, sizeof(uint32));
+               wmf = dhd_wmf_conf(dhd_pub, bssidx);
+               if (wmf->wmf_enable == int_val)
+                       break;
+               if (int_val) {
+                       /* Enable WMF */
+                       if (dhd_wmf_instance_add(dhd_pub, bssidx) != BCME_OK) {
+                               DHD_ERROR(("%s: Error in creating WMF instance\n",
+                               __FUNCTION__));
+                               break;
+                       }
+                       if (dhd_wmf_start(dhd_pub, bssidx) != BCME_OK) {
+                               DHD_ERROR(("%s: Failed to start WMF\n", __FUNCTION__));
+                               break;
+                       }
+                       wmf->wmf_enable = TRUE;
+               } else {
+                       /* Disable WMF */
+                       wmf->wmf_enable = FALSE;
+                       dhd_wmf_stop(dhd_pub, bssidx);
+                       dhd_wmf_instance_del(dhd_pub, bssidx);
+               }
+               break;
+       }
+       case IOV_GVAL(IOV_WMF_UCAST_IGMP):
+               int_val = dhd_pub->wmf_ucast_igmp ? 1 : 0;
+               bcopy(&int_val, arg, val_size);
+               break;
+       case IOV_SVAL(IOV_WMF_UCAST_IGMP):
+               if (dhd_pub->wmf_ucast_igmp == int_val)
+                       break;
+
+               if (int_val >= OFF && int_val <= ON)
+                       dhd_pub->wmf_ucast_igmp = int_val;
+               else
+                       bcmerror = BCME_RANGE;
+               break;
+       case IOV_GVAL(IOV_WMF_MCAST_DATA_SENDUP):
+               int_val = dhd_wmf_mcast_data_sendup(dhd_pub, 0, FALSE, FALSE);
+               bcopy(&int_val, arg, val_size);
+               break;
+       case IOV_SVAL(IOV_WMF_MCAST_DATA_SENDUP):
+               dhd_wmf_mcast_data_sendup(dhd_pub, 0, TRUE, int_val);
+               break;
+
+#ifdef WL_IGMP_UCQUERY
+       case IOV_GVAL(IOV_WMF_UCAST_IGMP_QUERY):
+               int_val = dhd_pub->wmf_ucast_igmp_query ? 1 : 0;
+               bcopy(&int_val, arg, val_size);
+               break;
+       case IOV_SVAL(IOV_WMF_UCAST_IGMP_QUERY):
+               if (dhd_pub->wmf_ucast_igmp_query == int_val)
+                       break;
+
+               if (int_val >= OFF && int_val <= ON)
+                       dhd_pub->wmf_ucast_igmp_query = int_val;
+               else
+                       bcmerror = BCME_RANGE;
+               break;
+#endif /* WL_IGMP_UCQUERY */
+#ifdef DHD_UCAST_UPNP
+       case IOV_GVAL(IOV_WMF_UCAST_UPNP):
+               int_val = dhd_pub->wmf_ucast_upnp ? 1 : 0;
+               bcopy(&int_val, arg, val_size);
+               break;
+       case IOV_SVAL(IOV_WMF_UCAST_UPNP):
+               if (dhd_pub->wmf_ucast_upnp == int_val)
+                       break;
+
+               if (int_val >= OFF && int_val <= ON)
+                       dhd_pub->wmf_ucast_upnp = int_val;
+               else
+                       bcmerror = BCME_RANGE;
+               break;
+#endif /* DHD_UCAST_UPNP */
+#endif /* DHD_WMF */
+
+
+#ifdef DHD_UNICAST_DHCP
+       case IOV_GVAL(IOV_DHCP_UNICAST):
+               int_val = dhd_pub->dhcp_unicast;
+               bcopy(&int_val, arg, val_size);
+               break;
+       case IOV_SVAL(IOV_DHCP_UNICAST):
+               if (dhd_pub->dhcp_unicast == int_val)
+                       break;
+
+               if (int_val >= OFF || int_val <= ON) {
+                       dhd_pub->dhcp_unicast = int_val;
+               } else {
+                       bcmerror = BCME_RANGE;
+               }
+               break;
+#endif /* DHD_UNICAST_DHCP */
+#ifdef DHD_L2_FILTER
+       case IOV_GVAL(IOV_BLOCK_PING):
+               int_val = dhd_pub->block_ping;
+               bcopy(&int_val, arg, val_size);
+               break;
+       case IOV_SVAL(IOV_BLOCK_PING):
+               if (dhd_pub->block_ping == int_val)
+                       break;
+               if (int_val >= OFF || int_val <= ON) {
+                       dhd_pub->block_ping = int_val;
+               } else {
+                       bcmerror = BCME_RANGE;
+               }
+               break;
+#endif
+
+       case IOV_GVAL(IOV_AP_ISOLATE): {
+               uint32  bssidx;
+               char *val;
+
+               if (dhd_iovar_parse_bssidx(dhd_pub, (char *)name, &bssidx, &val) != BCME_OK) {
+                       DHD_ERROR(("%s: ap isoalate: bad parameter\n", __FUNCTION__));
+                       bcmerror = BCME_BADARG;
+                       break;
+               }
+
+               int_val = dhd_get_ap_isolate(dhd_pub, bssidx);
+               bcopy(&int_val, arg, val_size);
+               break;
+       }
+       case IOV_SVAL(IOV_AP_ISOLATE): {
+               uint32  bssidx;
+               char *val;
+
+               if (dhd_iovar_parse_bssidx(dhd_pub, (char *)name, &bssidx, &val) != BCME_OK) {
+                       DHD_ERROR(("%s: ap isolate: bad parameter\n", __FUNCTION__));
+                       bcmerror = BCME_BADARG;
+                       break;
+               }
+
+               ASSERT(val);
+               bcopy(val, &int_val, sizeof(uint32));
+               dhd_set_ap_isolate(dhd_pub, bssidx, int_val);
+               break;
+       }
 
        default:
                bcmerror = BCME_UNSUPPORTED;
@@ -868,8 +1160,56 @@ dhd_ioctl(dhd_pub_t * dhd_pub, dhd_ioctl_t *ioc, void * buf, uint buflen)
 }
 
 #ifdef SHOW_EVENTS
+#ifdef SHOW_LOGTRACE
+
+#define AVOID_BYTE 64
+#define MAX_NO_OF_ARG 16
+
+static int
+check_event_log_sequence_number(uint32 seq_no)
+{
+       int32 diff;
+       uint32 ret;
+       static uint32 logtrace_seqnum_prev = 0;
+
+       diff = ntoh32(seq_no)-logtrace_seqnum_prev;
+       switch (diff)
+       {
+               case 0:
+                       ret = -1; /* duplicate packet . drop */
+                       break;
+
+               case 1:
+                       ret =0; /* in order */
+                       break;
+
+               default:
+                       if ((ntoh32(seq_no) == 0) &&
+                               (logtrace_seqnum_prev == 0xFFFFFFFF) ) { /* in-order - Roll over */
+                                       ret = 0;
+                       } else {
+
+                               if (diff > 0) {
+                                       DHD_EVENT(("WLC_E_TRACE:"
+                                               "Event lost (log) seqnum %d nblost %d\n",
+                                               ntoh32(seq_no), (diff-1)));
+                               } else {
+                                       DHD_EVENT(("WLC_E_TRACE:"
+                                               "Event Packets coming out of order!!\n"));
+                               }
+                               ret = 0;
+                       }
+       }
+
+       logtrace_seqnum_prev = ntoh32(seq_no);
+
+       return ret;
+}
+#endif /* SHOW_LOGTRACE */
+
 static void
-wl_show_host_event(wl_event_msg_t *event, void *event_data)
+wl_show_host_event(dhd_pub_t *dhd_pub, wl_event_msg_t *event, void *event_data,
+       void *raw_event_ptr, char *eventmask)
 {
        uint i, status, reason;
        bool group = FALSE, flush_txq = FALSE, link = FALSE;
@@ -896,10 +1236,8 @@ wl_show_host_event(wl_event_msg_t *event, void *event_data)
                (uchar)event->addr.octet[4]&0xff,
                (uchar)event->addr.octet[5]&0xff);
 
-       event_name = "UNKNOWN";
-       for (i = 0; i < (uint)bcmevent_names_size; i++)
-               if (bcmevent_names[i].event == event_type)
-                       event_name = bcmevent_names[i].name;
+       event_name = bcmevent_get_name(event_type);
+       BCM_REFERENCE(event_name);
 
        if (flags & WLC_EVENT_MSG_LINK)
                link = TRUE;
@@ -1042,20 +1380,29 @@ wl_show_host_event(wl_event_msg_t *event, void *event_data)
                break;
 #endif /* WIFI_ACT_FRAME */
 
-       case WLC_E_TRACE: {
-               static uint32 seqnum_prev = 0;
-               static uint32 logtrace_seqnum_prev = 0;
+#ifdef SHOW_LOGTRACE
+       case WLC_E_TRACE:
+       {
                msgtrace_hdr_t hdr;
                uint32 nblost;
+               uint8 count;
                char *s, *p;
+               static uint32 seqnum_prev = 0;
+               uint32 *record = NULL;
+               uint32 *log_ptr =  NULL;
+               uint32 writeindex = 0;
+               event_log_hdr_t event_hdr;
+               int no_of_fmts = 0;
+               char *fmt = NULL;
+               dhd_event_log_t *raw_event = (dhd_event_log_t *) raw_event_ptr;
 
                buf = (uchar *) event_data;
                memcpy(&hdr, buf, MSGTRACE_HDRLEN);
 
                if (hdr.version != MSGTRACE_VERSION) {
-                       printf("\nMACEVENT: %s [unsupported version --> "
-                              "dhd version:%d dongle version:%d]\n",
-                              event_name, MSGTRACE_VERSION, hdr.version);
+                       DHD_EVENT(("\nMACEVENT: %s [unsupported version --> "
+                               "dhd version:%d dongle version:%d]\n",
+                               event_name, MSGTRACE_VERSION, hdr.version));
                        /* Reset datalen to avoid display below */
                        datalen = 0;
                        break;
@@ -1066,70 +1413,169 @@ wl_show_host_event(wl_event_msg_t *event, void *event_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));
+                               DHD_EVENT(("WLC_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 (msg) --> seqnum %d nblost %d\n",
-                                      ntoh32(hdr.seqnum), nblost);
+                               DHD_EVENT(("WLC_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
+                       /* 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) {
+                       while (*p != '\0' && (s = strstr(p, "\n")) != NULL) {
                                *s = '\0';
-                               printf("%s\n", p);
+                               DHD_EVENT(("%s\n", p));
                                p = s+1;
                        }
-                       if (*p) printf("%s", p);
+                       if (*p)
+                               DHD_EVENT(("%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);
+                       uint32 timestamp, w, malloc_len;
+
+                       if (check_event_log_sequence_number(hdr.seqnum)) {
+
+                               DHD_EVENT(("%s: WLC_E_TRACE:"
+                                       "[Event duplicate (log) %d] dropping!!\n",
+                                       __FUNCTION__, hdr.seqnum));
+                               return; /* drop duplicate events */
+                       }
+
+                       p = (char *)&buf[MSGTRACE_HDRLEN];
+                       datalen -= MSGTRACE_HDRLEN;
+                       w = ntoh32((uint32)*p);
+                       p += 4;
+                       datalen -= 4;
+                       timestamp = ntoh32((uint32)*p);
+                       BCM_REFERENCE(timestamp);
+                       BCM_REFERENCE(w);
+
+                       DHD_EVENT(("timestamp %x%x\n", timestamp, w));
+
+                       if (raw_event->fmts) {
+                               malloc_len = datalen+ AVOID_BYTE;
+                               record = (uint32 *)MALLOC(dhd_pub->osh, malloc_len);
+                               if (record == NULL) {
+                                       DHD_EVENT(("MSGTRACE_HDR_TYPE_LOG:"
+                                               "malloc failed\n"));
+                                       return;
+                               }
+                               log_ptr = (uint32 *) (p + datalen);
+                               writeindex = datalen/4;
+
+                               if (record) {
+                                       while (datalen > 4) {
+                                               log_ptr--;
+                                               datalen -= 4;
+                                               event_hdr.t = *log_ptr;
+                                               /*
+                                                * Check for partially overriten entries
+                                                */
+                                               if (log_ptr - (uint32 *) p < event_hdr.count) {
+                                                               break;
+                                               }
+                                               /*
+                                               * Check for end of the Frame.
+                                               */
+                                               if (event_hdr.tag ==  EVENT_LOG_TAG_NULL) {
+                                                       continue;
+                                               }
+                                               /*
+                                               * Check For Special Time Stamp Packet
+                                               */
+                                               if (event_hdr.tag == EVENT_LOG_TAG_TS) {
+                                                       datalen -= 12;
+                                                       log_ptr = log_ptr - 3;
+                                                       continue;
+                                               }
+
+                                               log_ptr[0] = event_hdr.t;
+                                               if (event_hdr.count > MAX_NO_OF_ARG) {
+                                                       break;
+                                               }
+                                               /* Now place the header at the front
+                                               * and copy back.
+                                               */
+                                               log_ptr -= event_hdr.count;
+
+                                               writeindex = writeindex - event_hdr.count;
+                                               record[writeindex++] = event_hdr.t;
+                                               for (count = 0; count < (event_hdr.count-1);
+                                                       count++) {
+                                                       record[writeindex++] = log_ptr[count];
+                                               }
+                                               writeindex = writeindex - event_hdr.count;
+                                               datalen = datalen - (event_hdr.count * 4);
+                                               no_of_fmts++;
+                                       }
                                }
-                               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 (no_of_fmts--)
+                               {
+                                       event_log_hdr_t event_hdr;
+                                       event_hdr.t = record[writeindex];
+
+                                       if ((event_hdr.fmt_num>>2) < raw_event->num_fmts) {
+                                               fmt = raw_event->fmts[event_hdr.fmt_num>>2];
+                                               DHD_EVENT((fmt,
+                                                       record[writeindex + 1],
+                                                       record[writeindex + 2],
+                                                       record[writeindex + 3],
+                                                       record[writeindex + 4],
+                                                       record[writeindex + 5],
+                                                       record[writeindex + 6],
+                                                       record[writeindex + 7],
+                                                       record[writeindex + 8],
+                                                       record[writeindex + 9],
+                                                       record[writeindex + 10],
+                                                       record[writeindex + 11],
+                                                       record[writeindex + 12],
+                                                       record[writeindex + 13],
+                                                       record[writeindex + 14],
+                                                       record[writeindex + 15],
+                                                       record[writeindex + 16]));
+
+                                               if (fmt[strlen(fmt) - 1] != '\n') {
+                                                       /* Add newline if missing */
+                                                       DHD_EVENT(("\n"));
+                                               }
+                                       }
+
+                                       writeindex = writeindex + event_hdr.count;
+                               }
 
+                               if (record) {
+                                       MFREE(dhd_pub->osh, record, malloc_len);
+                                       record = NULL;
+                               }
+                       } else {
                                while (datalen > 4) {
                                        p += 4;
                                        datalen -= 4;
                                        /* Print each word.  DO NOT ntoh it.  */
-                                       printf(" %8.8x", *((uint32 *) p));
+                                       DHD_EVENT((" %8.8x", *((uint32 *) p)));
                                }
-                               printf("\n");
+                               DHD_EVENT(("\n"));
                        }
                        datalen = 0;
                }
-
                break;
        }
-
+#endif /* SHOW_LOGTRACE */
 
        case WLC_E_RSSI:
                DHD_EVENT(("MACEVENT: %s %d\n", event_name, ntoh32(*((int *)event_data))));
@@ -1141,6 +1587,12 @@ wl_show_host_event(wl_event_msg_t *event, void *event_data)
                DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
                break;
 
+#ifdef BT_WIFI_HANDOBER
+       case WLC_E_BT_WIFI_HANDOVER_REQ:
+               DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
+               break;
+#endif
+
        default:
                DHD_EVENT(("MACEVENT: %s %d, MAC %s, status %d, reason %d, auth %d\n",
                       event_name, event_type, eabuf, (int)status, (int)reason,
@@ -1151,6 +1603,7 @@ wl_show_host_event(wl_event_msg_t *event, void *event_data)
        /* show any appended data */
        if (DHD_BYTES_ON() && DHD_EVENT_ON() && datalen) {
                buf = (uchar *) event_data;
+               BCM_REFERENCE(buf);
                DHD_EVENT((" data (%d) : ", datalen));
                for (i = 0; i < datalen; i++)
                        DHD_EVENT((" 0x%02x ", *buf++));
@@ -1161,7 +1614,7 @@ wl_show_host_event(wl_event_msg_t *event, void *event_data)
 
 int
 wl_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata,
-              wl_event_msg_t *event, void **data_ptr)
+       wl_event_msg_t *event, void **data_ptr, void *raw_event)
 {
        /* check whether packet is a BRCM event pkt */
        bcm_event_t *pvt_data = (bcm_event_t *)pktdata;
@@ -1169,6 +1622,7 @@ wl_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata,
        uint32 type, status, datalen;
        uint16 flags;
        int evlen;
+       int hostidx;
 
        if (bcmp(BRCM_OUI, &pvt_data->bcm_hdr.oui[0], DOT11_OUI_LEN)) {
                DHD_ERROR(("%s: mismatched OUI, bailing\n", __FUNCTION__));
@@ -1184,6 +1638,7 @@ wl_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata,
        *data_ptr = &pvt_data[1];
        event_data = *data_ptr;
 
+
        /* memcpy since BRCM event pkt may be unaligned. */
        memcpy(event, &pvt_data->event, sizeof(wl_event_msg_t));
 
@@ -1193,6 +1648,9 @@ wl_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata,
        datalen = ntoh32_ua((void *)&event->datalen);
        evlen = datalen + sizeof(bcm_event_t);
 
+       /* find equivalent host index for event ifidx */
+       hostidx = dhd_ifidx2hostidx(dhd_pub->info, event->ifidx);
+
        switch (type) {
 #ifdef PROP_TXSTATUS
        case WLC_E_FIFO_CREDIT_MAP:
@@ -1209,15 +1667,19 @@ wl_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata,
                break;
 #endif
 
-       case WLC_E_IF: {
+       case WLC_E_IF:
+               {
                struct wl_event_data_if *ifevent = (struct wl_event_data_if *)event_data;
 
                /* Ignore the event if NOIF is set */
                if (ifevent->reserved & WLC_E_IF_FLAGS_BSSCFG_NOIF) {
                        DHD_ERROR(("WLC_E_IF: NO_IF set, event Ignored\r\n"));
-                       return (BCME_OK);
+                       return (BCME_UNSUPPORTED);
                }
-
+#ifdef PCIE_FULL_DONGLE
+               dhd_update_interface_flow_info(dhd_pub, ifevent->ifidx,
+                       ifevent->opcode, ifevent->role);
+#endif
 #ifdef PROP_TXSTATUS
                {
                        uint8* ea = pvt_data->eth.ether_dhost;
@@ -1264,18 +1726,18 @@ wl_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata,
 #endif /* WL_CFG80211 */
                        }
                } else {
-#ifndef PROP_TXSTATUS
+#if !defined(PROP_TXSTATUS) || !defined(PCIE_FULL_DONGLE)
                        DHD_ERROR(("%s: Invalid ifidx %d for %s\n",
-                               __FUNCTION__, ifevent->ifidx, event->ifname));
+                                  __FUNCTION__, ifevent->ifidx, event->ifname));
 #endif /* !PROP_TXSTATUS */
                }
-
-               /* send up the if event: btamp user needs it */
-               *ifidx = dhd_ifname2idx(dhd_pub->info, event->ifname);
-               /* push up to external supp/auth */
-               dhd_event(dhd_pub->info, (char *)pvt_data, evlen, *ifidx);
+                       /* send up the if event: btamp user needs it */
+                       *ifidx = hostidx;
+                       /* push up to external supp/auth */
+                       dhd_event(dhd_pub->info, (char *)pvt_data, evlen, *ifidx);
                break;
        }
+
 #ifdef WLMEDIA_HTSF
        case WLC_E_HTSFSYNC:
                htsf_update(dhd_pub->info, event_data);
@@ -1286,6 +1748,7 @@ wl_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata,
 
                memcpy((void *)(&pvt_data->event.event_type), &temp,
                       sizeof(pvt_data->event.event_type));
+               break;
        }
        case WLC_E_PFN_NET_FOUND:
        case WLC_E_PFN_NET_LOST:
@@ -1298,17 +1761,45 @@ wl_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata,
                break;
 #endif 
                /* These are what external supplicant/authenticator wants */
-               /* fall through */
+       case WLC_E_ASSOC_IND:
+       case WLC_E_AUTH_IND:
+       case WLC_E_REASSOC_IND:
+               dhd_findadd_sta(dhd_pub, hostidx, &event->addr.octet);
+               break;
        case WLC_E_LINK:
+#ifdef PCIE_FULL_DONGLE
+               if (dhd_update_interface_link_status(dhd_pub, (uint8)hostidx,
+                       (uint8)flags) != BCME_OK)
+                       break;
+               if (!flags) {
+                       dhd_flow_rings_delete(dhd_pub, hostidx);
+               }
+               /* fall through */
+#endif
        case WLC_E_DEAUTH:
        case WLC_E_DEAUTH_IND:
        case WLC_E_DISASSOC:
        case WLC_E_DISASSOC_IND:
+               if (type != WLC_E_LINK) {
+                       dhd_del_sta(dhd_pub, hostidx, &event->addr.octet);
+               }
                DHD_EVENT(("%s: Link event %d, flags %x, status %x\n",
                           __FUNCTION__, type, flags, status));
+#ifdef PCIE_FULL_DONGLE
+               if (type != WLC_E_LINK) {
+                       uint8 ifindex = (uint8)hostidx;
+                       uint8 role = dhd_flow_rings_ifindex2role(dhd_pub, ifindex);
+                       if (role == WLC_E_IF_ROLE_STA) {
+                               dhd_flow_rings_delete(dhd_pub, ifindex);
+                       } else {
+                               dhd_flow_rings_delete_for_peer(dhd_pub, ifindex,
+                                       &event->addr.octet[0]);
+                       }
+               }
+#endif
                /* fall through */
        default:
-               *ifidx = dhd_ifname2idx(dhd_pub->info, event->ifname);
+               *ifidx = hostidx;
                /* push up to external supp/auth */
                dhd_event(dhd_pub->info, (char *)pvt_data, evlen, *ifidx);
                DHD_TRACE(("%s: MAC event %d, flags %x, status %x\n",
@@ -1320,7 +1811,8 @@ wl_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata,
        }
 
 #ifdef SHOW_EVENTS
-       wl_show_host_event(event, (void *)event_data);
+       wl_show_host_event(dhd_pub, event,
+               (void *)event_data, raw_event, dhd_pub->enable_log);
 #endif /* SHOW_EVENTS */
 
        return (BCME_OK);
@@ -1400,12 +1892,12 @@ dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_
 {
        char                            *argv[8];
        int                                     i = 0;
-       const char                      *str;
+       const char                      *str;
        int                                     buf_len;
        int                                     str_len;
        char                            *arg_save = 0, *arg_org = 0;
        int                                     rc;
-       char                            buf[128];
+       char                            buf[32] = {0};
        wl_pkt_filter_enable_t  enable_parm;
        wl_pkt_filter_enable_t  * pkt_filterp;
 
@@ -1413,7 +1905,7 @@ dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_
                return;
 
        if (!(arg_save = MALLOC(dhd->osh, strlen(arg) + 1))) {
-               DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__));
+               DHD_ERROR(("%s: malloc failed\n", __FUNCTION__));
                goto fail;
        }
        arg_org = arg_save;
@@ -1429,8 +1921,8 @@ dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_
 
        str = "pkt_filter_enable";
        str_len = strlen(str);
-       bcm_strncpy_s(buf, sizeof(buf), str, str_len);
-       buf[str_len] = '\0';
+       bcm_strncpy_s(buf, sizeof(buf) - 1, str, sizeof(buf) - 1);
+       buf[ sizeof(buf) - 1 ] = '\0';
        buf_len = str_len + 1;
 
        pkt_filterp = (wl_pkt_filter_enable_t *)(buf + str_len + 1);
@@ -1489,14 +1981,14 @@ dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg)
                return;
 
        if (!(arg_save = MALLOC(dhd->osh, strlen(arg) + 1))) {
-               DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__));
+               DHD_ERROR(("%s: malloc failed\n", __FUNCTION__));
                goto fail;
        }
 
        arg_org = arg_save;
 
        if (!(buf = MALLOC(dhd->osh, BUF_SIZE))) {
-               DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__));
+               DHD_ERROR(("%s: malloc failed\n", __FUNCTION__));
                goto fail;
        }
 
@@ -1945,7 +2437,6 @@ bool dhd_is_associated(dhd_pub_t *dhd, void *bss_buf, int *retval)
        }
 }
 
-
 /* Function to estimate possible DTIM_SKIP value */
 int
 dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd)
@@ -1968,12 +2459,6 @@ dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd)
                goto exit;
        }
 
-       /* if associated APs Beacon more  that 100msec do no dtim skip */
-       if (ap_beacon > MAX_DTIM_SKIP_BEACON_INTERVAL) {
-               DHD_ERROR(("%s NO dtim skip for AP with beacon %d ms\n", __FUNCTION__, ap_beacon));
-               goto exit;
-       }
-
        /* read associated ap's dtim setup */
        if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_DTIMPRD,
                &dtim_period, sizeof(dtim_period), FALSE, 0)) < 0) {
@@ -2031,7 +2516,7 @@ bool dhd_support_sta_mode(dhd_pub_t *dhd)
 #if defined(KEEP_ALIVE)
 int dhd_keep_alive_onoff(dhd_pub_t *dhd)
 {
-       char                            buf[256];
+       char                            buf[32] = {0};
        const char                      *str;
        wl_mkeep_alive_pkt_t    mkeep_alive_pkt = {0};
        wl_mkeep_alive_pkt_t    *mkeep_alive_pktp;
@@ -2046,8 +2531,8 @@ int dhd_keep_alive_onoff(dhd_pub_t *dhd)
 
        str = "mkeep_alive";
        str_len = strlen(str);
-       strncpy(buf, str, str_len);
-       buf[ str_len ] = '\0';
+       strncpy(buf, str, sizeof(buf) - 1);
+       buf[ sizeof(buf) - 1 ] = '\0';
        mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) (buf + str_len + 1);
        mkeep_alive_pkt.period_msec = CUSTOM_KEEP_ALIVE_SETTING;
        buf_len = str_len + 1;
old mode 100755 (executable)
new mode 100644 (file)
index 10afdaa..4b9287c
@@ -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 447089 2014-01-08 04:05:58Z $
+* $Id: dhd_custom_gpio.c 447105 2014-01-08 05:27:09Z $
 */
 
 #include <typedefs.h>
old mode 100755 (executable)
new mode 100644 (file)
diff --git a/drivers/net/wireless/bcmdhd/dhd_flowring.c b/drivers/net/wireless/bcmdhd/dhd_flowring.c
new file mode 100644 (file)
index 0000000..97c9098
--- /dev/null
@@ -0,0 +1,729 @@
+/*
+ * Broadcom Dongle Host Driver (DHD), Flow ring specific code at top level
+ * Copyright (C) 1999-2014, 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_flowrings.c jaganlv $
+ */
+
+#include <typedefs.h>
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include <bcmdevs.h>
+
+#include <proto/ethernet.h>
+#include <proto/bcmevent.h>
+#include <dngl_stats.h>
+
+#include <dhd.h>
+
+#include <dhd_flowring.h>
+#include <dhd_bus.h>
+#include <dhd_proto.h>
+#include <dhd_dbg.h>
+#include <proto/802.1d.h>
+
+static INLINE uint16 dhd_flowid_find(dhd_pub_t *dhdp, uint8 ifindex,
+                                     uint8 prio, char *sa, char *da);
+
+static INLINE uint16 dhd_flowid_alloc(dhd_pub_t *dhdp, uint8 ifindex,
+                                      uint8 prio, char *sa, char *da);
+
+static INLINE int dhd_flowid_lookup(dhd_pub_t *dhdp, uint8 ifindex,
+                                uint8 prio, char *sa, char *da, uint16 *flowid);
+int BCMFASTPATH dhd_flow_queue_overflow(flow_queue_t *queue, void *pkt);
+
+#define FLOW_QUEUE_PKT_NEXT(p)          PKTLINK(p)
+#define FLOW_QUEUE_PKT_SETNEXT(p, x)    PKTSETLINK((p), (x))
+
+const uint8 prio2ac[8] = { 0, 1, 1, 0, 2, 2, 3, 3 };
+const uint8 prio2tid[8] = { 0, 1, 2, 3, 4, 5, 6, 7 };
+
+int BCMFASTPATH
+dhd_flow_queue_overflow(flow_queue_t *queue, void *pkt)
+{
+       return BCME_NORESOURCE;
+}
+
+/* Flow ring's queue management functions */
+
+void /* Initialize a flow ring's queue */
+dhd_flow_queue_init(dhd_pub_t *dhdp, flow_queue_t *queue, int max)
+{
+       ASSERT((queue != NULL) && (max > 0));
+
+       dll_init(&queue->list);
+       queue->head = queue->tail = NULL;
+       queue->len = 0;
+       queue->max = max - 1;
+       queue->failures = 0U;
+       queue->cb = &dhd_flow_queue_overflow;
+       queue->lock = dhd_os_spin_lock_init(dhdp->osh);
+
+       if (queue->lock == NULL)
+               DHD_ERROR(("%s: Failed to init spinlock for queue!\n", __FUNCTION__));
+}
+
+void /* Register an enqueue overflow callback handler */
+dhd_flow_queue_register(flow_queue_t *queue, flow_queue_cb_t cb)
+{
+       ASSERT(queue != NULL);
+       queue->cb = cb;
+}
+
+
+int BCMFASTPATH /* Enqueue a packet in a flow ring's queue */
+dhd_flow_queue_enqueue(dhd_pub_t *dhdp, flow_queue_t *queue, void *pkt)
+{
+       int ret = BCME_OK;
+
+       ASSERT(queue != NULL);
+
+       if (queue->len >= queue->max) {
+               queue->failures++;
+               ret = (*queue->cb)(queue, pkt);
+               goto done;
+       }
+
+       if (queue->head) {
+               FLOW_QUEUE_PKT_SETNEXT(queue->tail, pkt);
+       } else {
+               queue->head = pkt;
+       }
+
+       FLOW_QUEUE_PKT_SETNEXT(pkt, NULL);
+
+       queue->tail = pkt; /* at tail */
+
+       queue->len++;
+
+done:
+       return ret;
+}
+
+void * BCMFASTPATH /* Dequeue a packet from a flow ring's queue, from head */
+dhd_flow_queue_dequeue(dhd_pub_t *dhdp, flow_queue_t *queue)
+{
+       void * pkt;
+
+       ASSERT(queue != NULL);
+
+       pkt = queue->head; /* from head */
+
+       if (pkt == NULL) {
+               ASSERT((queue->len == 0) && (queue->tail == NULL));
+               goto done;
+       }
+
+       queue->head = FLOW_QUEUE_PKT_NEXT(pkt);
+       if (queue->head == NULL)
+               queue->tail = NULL;
+
+       queue->len--;
+
+       FLOW_QUEUE_PKT_SETNEXT(pkt, NULL); /* dettach packet from queue */
+
+done:
+       return pkt;
+}
+
+void BCMFASTPATH /* Reinsert a dequeued packet back at the head */
+dhd_flow_queue_reinsert(dhd_pub_t *dhdp, flow_queue_t *queue, void *pkt)
+{
+       if (queue->head == NULL) {
+               queue->tail = pkt;
+       }
+
+       FLOW_QUEUE_PKT_SETNEXT(pkt, queue->head);
+       queue->head = pkt;
+       queue->len++;
+}
+
+
+/* Init Flow Ring specific data structures */
+int
+dhd_flow_rings_init(dhd_pub_t *dhdp, uint32 num_flow_rings)
+{
+       uint32 idx;
+       uint32 flow_ring_table_sz;
+       uint32 if_flow_lkup_sz;
+       void * flowid_allocator;
+       flow_ring_table_t *flow_ring_table;
+       if_flow_lkup_t *if_flow_lkup;
+
+       DHD_INFO(("%s\n", __FUNCTION__));
+
+       /* Construct a 16bit flow1d allocator */
+       flowid_allocator = id16_map_init(dhdp->osh,
+                              num_flow_rings - FLOW_RING_COMMON, FLOWID_RESERVED);
+       if (flowid_allocator == NULL) {
+               DHD_ERROR(("%s: flowid allocator init failure\n", __FUNCTION__));
+               return BCME_ERROR;
+       }
+
+       /* Allocate a flow ring table, comprising of requested number of rings */
+       flow_ring_table_sz = (num_flow_rings * sizeof(flow_ring_node_t));
+       flow_ring_table = (flow_ring_table_t *)MALLOC(dhdp->osh, flow_ring_table_sz);
+       if (flow_ring_table == NULL) {
+               DHD_ERROR(("%s: flow ring table alloc failure\n", __FUNCTION__));
+               id16_map_fini(dhdp->osh, flowid_allocator);
+               return BCME_ERROR;
+       }
+
+       /* Initialize flow ring table state */
+       bzero((uchar *)flow_ring_table, flow_ring_table_sz);
+       for (idx = 0; idx < num_flow_rings; idx++) {
+               flow_ring_table[idx].status = FLOW_RING_STATUS_CLOSED;
+               flow_ring_table[idx].flowid = (uint16)idx;
+               dll_init(&flow_ring_table[idx].list);
+
+               /* Initialize the per flow ring backup queue */
+               dhd_flow_queue_init(dhdp, &flow_ring_table[idx].queue,
+                                   FLOW_RING_QUEUE_THRESHOLD);
+       }
+
+       /* Allocate per interface hash table */
+       if_flow_lkup_sz = sizeof(if_flow_lkup_t) * DHD_MAX_IFS;
+       if_flow_lkup = (if_flow_lkup_t *)MALLOC(dhdp->osh, if_flow_lkup_sz);
+       if (if_flow_lkup == NULL) {
+               DHD_ERROR(("%s: if flow lkup alloc failure\n", __FUNCTION__));
+               MFREE(dhdp->osh, flow_ring_table, flow_ring_table_sz);
+               id16_map_fini(dhdp->osh, flowid_allocator);
+               return BCME_ERROR;
+       }
+
+       /* Initialize per interface hash table */
+       bzero((uchar *)if_flow_lkup, if_flow_lkup_sz);
+       for (idx = 0; idx < DHD_MAX_IFS; idx++) {
+               int hash_ix;
+               if_flow_lkup[idx].status = 0;
+               if_flow_lkup[idx].role = 0;
+               for (hash_ix = 0; hash_ix < DHD_FLOWRING_HASH_SIZE; hash_ix++)
+                       if_flow_lkup[idx].fl_hash[hash_ix] = NULL;
+       }
+
+       /* Now populate into dhd pub */
+       dhdp->num_flow_rings = num_flow_rings;
+       dhdp->flowid_allocator = (void *)flowid_allocator;
+       dhdp->flow_ring_table = (void *)flow_ring_table;
+       dhdp->if_flow_lkup = (void *)if_flow_lkup;
+
+       dhdp->flow_prio_map_type = DHD_FLOW_PRIO_AC_MAP;
+       bcopy(prio2ac, dhdp->flow_prio_map, sizeof(uint8) * NUMPRIO);
+
+       DHD_INFO(("%s done\n", __FUNCTION__));
+       return BCME_OK;
+}
+
+/* Deinit Flow Ring specific data structures */
+void dhd_flow_rings_deinit(dhd_pub_t *dhdp)
+{
+       uint16 idx;
+       uint32 flow_ring_table_sz;
+       uint32 if_flow_lkup_sz;
+       flow_ring_table_t *flow_ring_table;
+       DHD_INFO(("dhd_flow_rings_deinit\n"));
+
+       if (dhdp->flow_ring_table != NULL) {
+
+               ASSERT(dhdp->num_flow_rings > 0);
+
+               flow_ring_table = (flow_ring_table_t *)dhdp->flow_ring_table;
+               for (idx = 0; idx < dhdp->num_flow_rings; idx++) {
+                       if (flow_ring_table[idx].active) {
+                               dhd_bus_clean_flow_ring(dhdp->bus, idx);
+                       }
+                       ASSERT(flow_queue_empty(&flow_ring_table[idx].queue));
+
+                       /* Deinit flow ring queue locks before destroying flow ring table */
+                       dhd_os_spin_lock_deinit(dhdp->osh, flow_ring_table[idx].queue.lock);
+                       flow_ring_table[idx].queue.lock = NULL;
+               }
+
+               /* Destruct the flow ring table */
+               flow_ring_table_sz = dhdp->num_flow_rings * sizeof(flow_ring_table_t);
+               MFREE(dhdp->osh, dhdp->flow_ring_table, flow_ring_table_sz);
+               dhdp->flow_ring_table = NULL;
+       }
+
+       /* Destruct the per interface flow lkup table */
+       if (dhdp->if_flow_lkup != NULL) {
+               if_flow_lkup_sz = sizeof(if_flow_lkup_t) * DHD_MAX_IFS;
+               MFREE(dhdp->osh, dhdp->if_flow_lkup, if_flow_lkup_sz);
+               dhdp->if_flow_lkup = NULL;
+       }
+
+       /* Destruct the flowid allocator */
+       if (dhdp->flowid_allocator != NULL)
+               dhdp->flowid_allocator = id16_map_fini(dhdp->osh, dhdp->flowid_allocator);
+
+       dhdp->num_flow_rings = 0U;
+}
+
+uint8
+dhd_flow_rings_ifindex2role(dhd_pub_t *dhdp, uint8 ifindex)
+{
+       if_flow_lkup_t *if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup;
+       ASSERT(if_flow_lkup);
+       return if_flow_lkup[ifindex].role;
+}
+
+#ifdef WLTDLS
+bool is_tdls_destination(dhd_pub_t *dhdp, uint8 *da)
+{
+       tdls_peer_node_t *cur = dhdp->peer_tbl.node;
+       while (cur != NULL) {
+               if (!memcmp(da, cur->addr, ETHER_ADDR_LEN)) {
+                       return TRUE;
+               }
+               cur = cur->next;
+       }
+       return FALSE;
+}
+#endif /* WLTDLS */
+
+/* For a given interface, search the hash table for a matching flow */
+static INLINE uint16
+dhd_flowid_find(dhd_pub_t *dhdp, uint8 ifindex, uint8 prio, char *sa, char *da)
+{
+       int hash;
+       bool ismcast = FALSE;
+       flow_hash_info_t *cur;
+       if_flow_lkup_t *if_flow_lkup;
+
+       if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup;
+
+       if (if_flow_lkup[ifindex].role == WLC_E_IF_ROLE_STA) {
+#ifdef WLTDLS
+               if (dhdp->peer_tbl.tdls_peer_count && !(ETHER_ISMULTI(da)) &&
+                       is_tdls_destination(dhdp, da)) {
+                       hash = DHD_FLOWRING_HASHINDEX(da, prio);
+                       cur = if_flow_lkup[ifindex].fl_hash[hash];
+                       while (cur != NULL) {
+                               if (!memcmp(cur->flow_info.da, da, ETHER_ADDR_LEN))
+                                       return cur->flowid;
+                               cur = cur->next;
+                       }
+                       return FLOWID_INVALID;
+               }
+#endif /* WLTDLS */
+               cur = if_flow_lkup[ifindex].fl_hash[prio];
+               if (cur) {
+                       return cur->flowid;
+               }
+
+       } else {
+
+               if (ETHER_ISMULTI(da)) {
+                       ismcast = TRUE;
+                       hash = 0;
+               } else {
+                       hash = DHD_FLOWRING_HASHINDEX(da, prio);
+               }
+
+               cur = if_flow_lkup[ifindex].fl_hash[hash];
+
+               while (cur) {
+                       if ((ismcast && ETHER_ISMULTI(cur->flow_info.da)) ||
+                               (!memcmp(cur->flow_info.da, da, ETHER_ADDR_LEN) &&
+                               (cur->flow_info.tid == prio))) {
+                               return cur->flowid;
+                       }
+                       cur = cur->next;
+               }
+       }
+
+       return FLOWID_INVALID;
+}
+
+/* Allocate Flow ID */
+static INLINE uint16
+dhd_flowid_alloc(dhd_pub_t *dhdp, uint8 ifindex, uint8 prio, char *sa, char *da)
+{
+       flow_hash_info_t *fl_hash_node, *cur;
+       if_flow_lkup_t *if_flow_lkup;
+       int hash;
+       uint16 flowid;
+
+       fl_hash_node = (flow_hash_info_t *) MALLOC(dhdp->osh, sizeof(flow_hash_info_t));
+       memcpy(fl_hash_node->flow_info.da, da, sizeof(fl_hash_node->flow_info.da));
+
+       ASSERT(dhdp->flowid_allocator != NULL);
+       flowid = id16_map_alloc(dhdp->flowid_allocator);
+
+       if (flowid == FLOWID_INVALID) {
+               MFREE(dhdp->osh, fl_hash_node,  sizeof(flow_hash_info_t));
+               DHD_ERROR(("%s: cannot get free flowid \n", __FUNCTION__));
+               return FLOWID_INVALID;
+       }
+
+       fl_hash_node->flowid = flowid;
+       fl_hash_node->flow_info.tid = prio;
+       fl_hash_node->flow_info.ifindex = ifindex;
+       fl_hash_node->next = NULL;
+
+       if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup;
+       if (if_flow_lkup[ifindex].role == WLC_E_IF_ROLE_STA) {
+               /* For STA non TDLS dest we allocate entry based on prio only */
+#ifdef WLTDLS
+               if (dhdp->peer_tbl.tdls_peer_count &&
+                       (is_tdls_destination(dhdp, da))) {
+                       hash = DHD_FLOWRING_HASHINDEX(da, prio);
+                       cur = if_flow_lkup[ifindex].fl_hash[hash];
+                       if (cur) {
+                               while (cur->next) {
+                                       cur = cur->next;
+                               }
+                               cur->next = fl_hash_node;
+                       } else {
+                               if_flow_lkup[ifindex].fl_hash[hash] = fl_hash_node;
+                       }
+               } else
+#endif /* WLTDLS */
+                       if_flow_lkup[ifindex].fl_hash[prio] = fl_hash_node;
+       } else {
+
+               /* For bcast/mcast assign first slot in in interface */
+               hash = ETHER_ISMULTI(da) ? 0 : DHD_FLOWRING_HASHINDEX(da, prio);
+               cur = if_flow_lkup[ifindex].fl_hash[hash];
+               if (cur) {
+                       while (cur->next) {
+                               cur = cur->next;
+                       }
+                       cur->next = fl_hash_node;
+               } else
+                       if_flow_lkup[ifindex].fl_hash[hash] = fl_hash_node;
+       }
+
+       DHD_INFO(("%s: allocated flowid %d\n", __FUNCTION__, fl_hash_node->flowid));
+
+       return fl_hash_node->flowid;
+}
+
+/* Get flow ring ID, if not present try to create one */
+static INLINE int
+dhd_flowid_lookup(dhd_pub_t *dhdp, uint8 ifindex,
+                  uint8 prio, char *sa, char *da, uint16 *flowid)
+{
+       uint16 id;
+       flow_ring_node_t *flow_ring_node;
+       flow_ring_table_t *flow_ring_table;
+
+       DHD_INFO(("%s\n", __FUNCTION__));
+
+       flow_ring_table = (flow_ring_table_t *)dhdp->flow_ring_table;
+
+       id = dhd_flowid_find(dhdp, ifindex, prio, sa, da);
+
+       if (id == FLOWID_INVALID) {
+
+               if_flow_lkup_t *if_flow_lkup;
+               if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup;
+
+               if (!if_flow_lkup[ifindex].status)
+                       return BCME_ERROR;
+
+               id = dhd_flowid_alloc(dhdp, ifindex, prio, sa, da);
+               if (id == FLOWID_INVALID) {
+                       DHD_ERROR(("%s: alloc flowid ifindex %u status %u\n",
+                                  __FUNCTION__, ifindex, if_flow_lkup[ifindex].status));
+                       return BCME_ERROR;
+               }
+
+               /* register this flowid in dhd_pub */
+               dhd_add_flowid(dhdp, ifindex, prio, da, id);
+       }
+
+       ASSERT(id < dhdp->num_flow_rings);
+
+       flow_ring_node = (flow_ring_node_t *) &flow_ring_table[id];
+       if (flow_ring_node->active) {
+               *flowid = id;
+               return BCME_OK;
+       }
+
+       /* flow_ring_node->flowid = id; */
+
+       /* Init Flow info */
+       memcpy(flow_ring_node->flow_info.sa, sa, sizeof(flow_ring_node->flow_info.sa));
+       memcpy(flow_ring_node->flow_info.da, da, sizeof(flow_ring_node->flow_info.da));
+       flow_ring_node->flow_info.tid = prio;
+       flow_ring_node->flow_info.ifindex = ifindex;
+
+       /* Create and inform device about the new flow */
+       if (dhd_bus_flow_ring_create_request(dhdp->bus, (void *)flow_ring_node)
+               != BCME_OK) {
+               DHD_ERROR(("%s: create error %d\n", __FUNCTION__, id));
+               return BCME_ERROR;
+       }
+       flow_ring_node->active = TRUE;
+
+       *flowid = id;
+       return BCME_OK;
+}
+
+/* Update flowid information on the packet */
+int BCMFASTPATH
+dhd_flowid_update(dhd_pub_t *dhdp, uint8 ifindex, uint8 prio, void *pktbuf)
+{
+       uint8 *pktdata = (uint8 *)PKTDATA(dhdp->osh, pktbuf);
+       struct ether_header *eh = (struct ether_header *)pktdata;
+       uint16 flowid;
+
+       if (dhd_bus_is_txmode_push(dhdp->bus))
+               return BCME_OK;
+
+       ASSERT(ifindex < DHD_MAX_IFS);
+       if (ifindex >= DHD_MAX_IFS) {
+               return BCME_BADARG;
+       }
+
+       if (!dhdp->flowid_allocator) {
+               DHD_ERROR(("%s: Flow ring not intited yet  \n", __FUNCTION__));
+               return BCME_ERROR;
+       }
+       if (dhd_flowid_lookup(dhdp, ifindex, prio, eh->ether_shost, eh->ether_dhost,
+               &flowid) != BCME_OK) {
+               return BCME_ERROR;
+       }
+
+       DHD_INFO(("%s: prio %d flowid %d\n", __FUNCTION__, prio, flowid));
+
+       /* Tag the packet with flowid */
+       DHD_PKTTAG_SET_FLOWID((dhd_pkttag_fr_t *)PKTTAG(pktbuf), flowid);
+       return BCME_OK;
+}
+
+void
+dhd_flowid_free(dhd_pub_t *dhdp, uint8 ifindex, uint16 flowid)
+{
+       int hashix;
+       bool found = FALSE;
+       flow_hash_info_t *cur, *prev;
+       if_flow_lkup_t *if_flow_lkup;
+
+       if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup;
+
+       for (hashix = 0; hashix < DHD_FLOWRING_HASH_SIZE; hashix++) {
+
+               cur = if_flow_lkup[ifindex].fl_hash[hashix];
+
+               if (cur) {
+                       if (cur->flowid == flowid) {
+                               found = TRUE;
+                       }
+
+                       prev = NULL;
+                       while (!found && cur) {
+                               if (cur->flowid == flowid) {
+                                       found = TRUE;
+                                       break;
+                               }
+                               prev = cur;
+                               cur = cur->next;
+                       }
+                       if (found) {
+                               if (!prev) {
+                                       if_flow_lkup[ifindex].fl_hash[hashix] = cur->next;
+                               } else {
+                                       prev->next = cur->next;
+                               }
+
+                               /* deregister flowid from dhd_pub. */
+                               dhd_del_flowid(dhdp, ifindex, flowid);
+
+                               id16_map_free(dhdp->flowid_allocator, flowid);
+                               MFREE(dhdp->osh, cur, sizeof(flow_hash_info_t));
+
+                               return;
+                       }
+               }
+       }
+
+       DHD_ERROR(("%s: could not free flow ring hash entry flowid %d\n",
+                  __FUNCTION__, flowid));
+}
+
+
+/* Delete all Flow rings assocaited with the given Interface */
+void
+dhd_flow_rings_delete(dhd_pub_t *dhdp, uint8 ifindex)
+{
+       uint32 id;
+       flow_ring_table_t *flow_ring_table;
+
+       DHD_INFO(("%s: ifindex %u\n", __FUNCTION__, ifindex));
+
+       ASSERT(ifindex < DHD_MAX_IFS);
+       if (!dhdp->flow_ring_table)
+               return;
+
+       flow_ring_table = (flow_ring_table_t *)dhdp->flow_ring_table;
+       for (id = 0; id < dhdp->num_flow_rings; id++) {
+               if (flow_ring_table[id].active &&
+                   (flow_ring_table[id].flow_info.ifindex == ifindex)) {
+                       dhd_bus_flow_ring_delete_request(dhdp->bus,
+                                                        (void *) &flow_ring_table[id]);
+               }
+       }
+}
+
+/* Delete flow/s for given peer address */
+void
+dhd_flow_rings_delete_for_peer(dhd_pub_t *dhdp, uint8 ifindex, char *addr)
+{
+       uint32 id;
+       flow_ring_table_t *flow_ring_table;
+
+       DHD_ERROR(("%s: ifindex %u\n", __FUNCTION__, ifindex));
+
+       ASSERT(ifindex < DHD_MAX_IFS);
+       if (ifindex >= DHD_MAX_IFS)
+               return;
+
+       if (!dhdp->flow_ring_table)
+               return;
+
+       flow_ring_table = (flow_ring_table_t *)dhdp->flow_ring_table;
+       for (id = 0; id < dhdp->num_flow_rings; id++) {
+               if (flow_ring_table[id].active &&
+                   (flow_ring_table[id].flow_info.ifindex == ifindex) &&
+                   (!memcmp(flow_ring_table[id].flow_info.da, addr, ETHER_ADDR_LEN)) &&
+                   (flow_ring_table[id].status != FLOW_RING_STATUS_DELETE_PENDING)) {
+                       DHD_INFO(("%s: deleting flowid %d\n",
+                                 __FUNCTION__, flow_ring_table[id].flowid));
+                       dhd_bus_flow_ring_delete_request(dhdp->bus,
+                                                        (void *) &flow_ring_table[id]);
+               }
+       }
+}
+
+/* Handle Interface ADD, DEL operations */
+void
+dhd_update_interface_flow_info(dhd_pub_t *dhdp, uint8 ifindex,
+                               uint8 op, uint8 role)
+{
+       if_flow_lkup_t *if_flow_lkup;
+
+       ASSERT(ifindex < DHD_MAX_IFS);
+       if (ifindex >= DHD_MAX_IFS)
+               return;
+
+       DHD_INFO(("%s: ifindex %u op %u role is %u \n",
+                 __FUNCTION__, ifindex, op, role));
+       if (!dhdp->flowid_allocator) {
+               DHD_ERROR(("%s: Flow ring not intited yet  \n", __FUNCTION__));
+               return;
+       }
+
+       if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup;
+
+       if (op == WLC_E_IF_ADD || op == WLC_E_IF_CHANGE) {
+
+               if_flow_lkup[ifindex].role = role;
+
+               if (role != WLC_E_IF_ROLE_STA) {
+                       if_flow_lkup[ifindex].status = TRUE;
+                       DHD_INFO(("%s: Mcast Flow ring for ifindex %d role is %d \n",
+                                 __FUNCTION__, ifindex, role));
+                       /* Create Mcast Flow */
+               }
+       } else  if (op == WLC_E_IF_DEL) {
+               if_flow_lkup[ifindex].status = FALSE;
+               DHD_INFO(("%s: cleanup all Flow rings for ifindex %d role is %d \n",
+                         __FUNCTION__, ifindex, role));
+       }
+}
+
+/* Handle a STA interface link status update */
+int
+dhd_update_interface_link_status(dhd_pub_t *dhdp, uint8 ifindex, uint8 status)
+{
+       if_flow_lkup_t *if_flow_lkup;
+
+       ASSERT(ifindex < DHD_MAX_IFS);
+       if (ifindex >= DHD_MAX_IFS)
+               return BCME_BADARG;
+
+       if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup;
+       DHD_INFO(("%s: ifindex %d status %d\n", __FUNCTION__, ifindex, status));
+
+       if (if_flow_lkup[ifindex].role == WLC_E_IF_ROLE_STA) {
+               if (status)
+                       if_flow_lkup[ifindex].status = TRUE;
+               else
+                       if_flow_lkup[ifindex].status = FALSE;
+       }
+       return BCME_OK;
+}
+/* Update flow priority mapping */
+int dhd_update_flow_prio_map(dhd_pub_t *dhdp, uint8 map)
+{
+       uint16 flowid;
+       flow_ring_node_t *flow_ring_node;
+
+       if (map > DHD_FLOW_PRIO_TID_MAP)
+               return BCME_BADOPTION;
+
+       /* Check if we need to change prio map */
+       if (map == dhdp->flow_prio_map_type)
+               return BCME_OK;
+
+       /* If any ring is active we cannot change priority mapping for flow rings */
+       for (flowid = 0; flowid < dhdp->num_flow_rings; flowid++) {
+               flow_ring_node = DHD_FLOW_RING(dhdp, flowid);
+               if (flow_ring_node->active)
+                       return BCME_EPERM;
+       }
+       /* Infor firmware about new mapping type */
+       if (BCME_OK != dhd_flow_prio_map(dhdp, &map, TRUE))
+               return BCME_ERROR;
+
+       /* update internal structures */
+       dhdp->flow_prio_map_type = map;
+       if (dhdp->flow_prio_map_type == DHD_FLOW_PRIO_TID_MAP)
+               bcopy(prio2tid, dhdp->flow_prio_map, sizeof(uint8) * NUMPRIO);
+       else
+               bcopy(prio2ac, dhdp->flow_prio_map, sizeof(uint8) * NUMPRIO);
+
+       return BCME_OK;
+}
+
+/* Set/Get flwo ring priority map */
+int dhd_flow_prio_map(dhd_pub_t *dhd, uint8 *map, bool set)
+{
+       uint8 iovbuf[24];
+       if (!set) {
+               bcm_mkiovar("bus:fl_prio_map", NULL, 0, (char*)iovbuf, sizeof(iovbuf));
+               if (dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0) < 0) {
+                       DHD_ERROR(("%s: failed to get fl_prio_map\n", __FUNCTION__));
+                       return BCME_ERROR;
+               }
+               *map = iovbuf[0];
+               return BCME_OK;
+       }
+       bcm_mkiovar("bus:fl_prio_map", (char *)map, 4, (char*)iovbuf, sizeof(iovbuf));
+       if (dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0) < 0) {
+               DHD_ERROR(("%s: failed to set fl_prio_map \n",
+                       __FUNCTION__));
+               return BCME_ERROR;
+       }
+       return BCME_OK;
+}
diff --git a/drivers/net/wireless/bcmdhd/dhd_flowring.h b/drivers/net/wireless/bcmdhd/dhd_flowring.h
new file mode 100644 (file)
index 0000000..c2e2d83
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * Header file describing the flow rings DHD interfaces.
+ *
+ * Provides type definitions and function prototypes used to create, delete and manage
+ *
+ * flow rings at high level
+ *
+ * Copyright (C) 1999-2014, 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_flowrings.h  jaganlv $
+ */
+
+/****************
+ * Common types *
+ */
+
+#ifndef _dhd_flowrings_h_
+#define _dhd_flowrings_h_
+
+/* Max pkts held in a flow ring's backup queue */
+#define FLOW_RING_QUEUE_THRESHOLD       (2048)
+
+/* Number of H2D common rings : PCIE Spec Rev? */
+#define FLOW_RING_COMMON                2
+
+#define FLOWID_INVALID                  (ID16_INVALID)
+#define FLOWID_RESERVED                 (FLOW_RING_COMMON)
+
+#define FLOW_RING_STATUS_OPEN           0
+#define FLOW_RING_STATUS_PENDING        1
+#define FLOW_RING_STATUS_CLOSED         2
+#define FLOW_RING_STATUS_DELETE_PENDING 3
+#define FLOW_RING_STATUS_FLUSH_PENDING  4
+
+#define DHD_FLOWRING_RX_BUFPOST_PKTSZ  2048
+
+#define DHD_FLOW_PRIO_AC_MAP           0
+#define DHD_FLOW_PRIO_TID_MAP          1
+
+
+/* Pkttag not compatible with PROP_TXSTATUS or WLFC */
+typedef struct dhd_pkttag_fr {
+       uint16  flowid;
+       int     dataoff;
+} dhd_pkttag_fr_t;
+
+#define DHD_PKTTAG_SET_FLOWID(tag, flow)    ((tag)->flowid = (uint16)(flow))
+#define DHD_PKTTAG_SET_DATAOFF(tag, offset) ((tag)->dataoff = (int)(offset))
+
+#define DHD_PKTTAG_FLOWID(tag)              ((tag)->flowid)
+#define DHD_PKTTAG_DATAOFF(tag)             ((tag)->dataoff)
+
+/* Hashing a MacAddress for lkup into a per interface flow hash table */
+#define DHD_FLOWRING_HASH_SIZE    256
+#define        DHD_FLOWRING_HASHINDEX(ea, prio) \
+              ((((uint8 *)(ea))[3] ^ ((uint8 *)(ea))[4] ^ ((uint8 *)(ea))[5] ^ ((uint8)(prio))) \
+               % DHD_FLOWRING_HASH_SIZE)
+
+#define DHD_IF_ROLE(pub, idx)          (((if_flow_lkup_t *)(pub)->if_flow_lkup)[idx].role)
+#define DHD_IF_ROLE_AP(pub, idx)       (DHD_IF_ROLE(pub, idx) == WLC_E_IF_ROLE_AP)
+#define DHD_IF_ROLE_P2PGO(pub, idx)    (DHD_IF_ROLE(pub, idx) == WLC_E_IF_ROLE_P2P_GO)
+#define DHD_FLOW_RING(dhdp, flowid) \
+       (flow_ring_node_t *)&(((flow_ring_node_t *)((dhdp)->flow_ring_table))[flowid])
+
+struct flow_queue;
+
+/* Flow Ring Queue Enqueue overflow callback */
+typedef int (*flow_queue_cb_t)(struct flow_queue * queue, void * pkt);
+
+typedef struct flow_queue {
+       dll_t  list;                /* manage a flowring queue in a dll */
+       void * head;                /* first packet in the queue */
+       void * tail;                /* last packet in the queue */
+       uint16 len;                 /* number of packets in the queue */
+       uint16 max;                 /* maximum number of packets, queue may hold */
+       uint32 failures;            /* enqueue failures due to queue overflow */
+       flow_queue_cb_t cb;         /* callback invoked on threshold crossing */
+       void * lock;            /* OS specific lock handle for Q access protection */
+} flow_queue_t;
+
+#define flow_queue_len(queue)   ((int)(queue)->len)
+#define flow_queue_max(queue)   ((int)(queue)->max)
+#define flow_queue_avail(queue) ((int)((queue)->max - (queue)->len))
+#define flow_queue_full(queue)  ((queue)->len >= (queue)->max)
+#define flow_queue_empty(queue) ((queue)->len == 0)
+
+typedef struct flow_info {
+       uint8           tid;
+       uint8           ifindex;
+       char            sa[ETHER_ADDR_LEN];
+       char            da[ETHER_ADDR_LEN];
+} flow_info_t;
+
+typedef struct flow_ring_node {
+       dll_t           list; /* manage a constructed flowring in a dll, must be at first place */
+       flow_queue_t    queue;
+       bool            active;
+       uint8           status;
+       uint16          flowid;
+       flow_info_t     flow_info;
+       void            *prot_info;
+} flow_ring_node_t;
+typedef flow_ring_node_t flow_ring_table_t;
+
+typedef struct flow_hash_info {
+       uint16                  flowid;
+       flow_info_t             flow_info;
+       struct flow_hash_info   *next;
+} flow_hash_info_t;
+
+typedef struct if_flow_lkup {
+       bool            status;
+       uint8           role; /* Interface role: STA/AP */
+       flow_hash_info_t *fl_hash[DHD_FLOWRING_HASH_SIZE]; /* Lkup Hash table */
+} if_flow_lkup_t;
+
+static INLINE flow_ring_node_t *
+dhd_constlist_to_flowring(dll_t *item)
+{
+       return ((flow_ring_node_t *)item);
+}
+
+/* Exported API */
+
+/* Flow ring's queue management functions */
+extern void dhd_flow_queue_init(dhd_pub_t *dhdp, flow_queue_t *queue, int max);
+extern void dhd_flow_queue_register(flow_queue_t *queue, flow_queue_cb_t cb);
+extern int  dhd_flow_queue_enqueue(dhd_pub_t *dhdp, flow_queue_t *queue, void *pkt);
+extern void * dhd_flow_queue_dequeue(dhd_pub_t *dhdp, flow_queue_t *queue);
+extern void dhd_flow_queue_reinsert(dhd_pub_t *dhdp, flow_queue_t *queue, void *pkt);
+
+extern int  dhd_flow_rings_init(dhd_pub_t *dhdp, uint32 num_flow_rings);
+
+extern void dhd_flow_rings_deinit(dhd_pub_t *dhdp);
+
+extern int dhd_flowid_update(dhd_pub_t *dhdp, uint8 ifindex, uint8 prio,
+                void *pktbuf);
+
+extern void dhd_flowid_free(dhd_pub_t *dhdp, uint8 ifindex, uint16 flowid);
+
+extern void dhd_flow_rings_delete(dhd_pub_t *dhdp, uint8 ifindex);
+
+extern void dhd_flow_rings_delete_for_peer(dhd_pub_t *dhdp, uint8 ifindex,
+                char *addr);
+
+/* Handle Interface ADD, DEL operations */
+extern void dhd_update_interface_flow_info(dhd_pub_t *dhdp, uint8 ifindex,
+                uint8 op, uint8 role);
+
+/* Handle a STA interface link status update */
+extern int dhd_update_interface_link_status(dhd_pub_t *dhdp, uint8 ifindex,
+                uint8 status);
+extern int dhd_flow_prio_map(dhd_pub_t *dhd, uint8 *map, bool set);
+extern int dhd_update_flow_prio_map(dhd_pub_t *dhdp, uint8 map);
+
+extern uint8 dhd_flow_rings_ifindex2role(dhd_pub_t *dhdp, uint8 ifindex);
+#endif /* _dhd_flowrings_h_ */
old mode 100755 (executable)
new mode 100644 (file)
index 3db2ed8..c713e94
@@ -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_ip.c 457995 2014-02-25 13:53:31Z $
+ * $Id: dhd_ip.c 468932 2014-04-09 06:58:15Z $
  */
 #include <typedefs.h>
 #include <osl.h>
@@ -38,6 +38,7 @@
 
 #ifdef DHDTCPACK_SUPPRESS
 #include <dhd_bus.h>
+#include <dhd_proto.h>
 #include <proto/bcmtcp.h>
 #endif /* DHDTCPACK_SUPPRESS */
 
@@ -286,7 +287,11 @@ int dhd_tcpack_suppress_set(dhd_pub_t *dhdp, uint8 mode)
                goto exit;
        }
 
-       if (mode > TCPACK_SUP_DELAYTX) {
+       if (mode >= TCPACK_SUP_LAST_MODE ||
+#ifndef BCMSDIO
+               mode == TCPACK_SUP_DELAYTX ||
+#endif
+               FALSE) {
                DHD_ERROR(("%s %d: Invalid mode %d\n", __FUNCTION__, __LINE__, mode));
                ret = BCME_BADARG;
                goto exit;
@@ -374,7 +379,6 @@ inline int dhd_tcpack_check_xmit(dhd_pub_t *dhdp, void *pkt)
        tcpack_sup_module_t *tcpack_sup_mod;
        tcpack_info_t *tcpack_info_tbl;
        int tbl_cnt;
-       uint pushed_len;
        int ret = BCME_OK;
        void *pdata;
        uint32 pktlen;
@@ -383,10 +387,7 @@ inline int dhd_tcpack_check_xmit(dhd_pub_t *dhdp, void *pkt)
                goto exit;
 
        pdata = PKTDATA(dhdp->osh, pkt);
-
-       /* Length of BDC(+WLFC) headers pushed */
-       pushed_len = BDC_HEADER_LEN + (((struct bdc_header *)pdata)->dataOffset * 4);
-       pktlen = PKTLEN(dhdp->osh, pkt) - pushed_len;
+       pktlen = PKTLEN(dhdp->osh, pkt) - dhd_prot_hdrlen(dhdp, pdata);
 
        if (pktlen < TCPACKSZMIN || pktlen > TCPACKSZMAX) {
                DHD_TRACE(("%s %d: Too short or long length %d to be TCP ACK\n",
@@ -679,10 +680,16 @@ dhd_tcpack_suppress(dhd_pub_t *dhdp, void *pkt)
                                tack_tbl.cnt[2]++;
 #endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */
                                ret = TRUE;
-                       } else
-                               DHD_TRACE(("%s %d: lenth mismatch %d != %d || %d != %d\n",
-                                       __FUNCTION__, __LINE__, new_ip_hdr_len, old_ip_hdr_len,
-                                       new_tcp_hdr_len, old_tcp_hdr_len));
+                       } else {
+#if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG)
+                               tack_tbl.cnt[6]++;
+#endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */
+                               DHD_TRACE(("%s %d: lenth mismatch %d != %d || %d != %d"
+                                       " ACK %u -> %u\n", __FUNCTION__, __LINE__,
+                                       new_ip_hdr_len, old_ip_hdr_len,
+                                       new_tcp_hdr_len, old_tcp_hdr_len,
+                                       old_tcpack_num, new_tcp_ack_num));
+                       }
                } else if (new_tcp_ack_num == old_tcpack_num) {
                        set_dotxinrx = TRUE;
                        /* TCPACK retransmission */
old mode 100755 (executable)
new mode 100644 (file)
index 328329e..bd3a898
@@ -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: dhd_ip.h 457888 2014-02-25 03:34:39Z $
+ * $Id: dhd_ip.h 458522 2014-02-27 02:26:15Z $
  */
 
 #ifndef _dhd_ip_h_
@@ -63,6 +63,7 @@ extern int dhd_tcpack_check_xmit(dhd_pub_t *dhdp, void *pkt);
 extern bool dhd_tcpack_suppress(dhd_pub_t *dhdp, void *pkt);
 extern bool dhd_tcpdata_info_get(dhd_pub_t *dhdp, void *pkt);
 
+/* #define DHDTCPACK_SUP_DBG */
 #if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG)
 extern counter_tbl_t tack_tbl;
 #endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */
old mode 100755 (executable)
new mode 100644 (file)
index a50b365..b5acd2a
  * 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 457888 2014-02-25 03:34:39Z $
+ * $Id: dhd_linux.c 490850 2014-07-12 14:54:04Z $
  */
 
 #include <typedefs.h>
 #include <linuxver.h>
 #include <osl.h>
+#ifdef SHOW_LOGTRACE
+#include <linux/syscalls.h>
+#include <event_log.h>
+#endif /* SHOW_LOGTRACE */
+
 
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/fcntl.h>
 #include <linux/fs.h>
 #include <linux/ip.h>
-#include <linux/compat.h>
+#include <linux/reboot.h>
+#include <linux/notifier.h>
 #include <net/addrconf.h>
+#ifdef ENABLE_ADAPTIVE_SCHED
 #include <linux/cpufreq.h>
+#endif /* ENABLE_ADAPTIVE_SCHED */
 
 #include <asm/uaccess.h>
 #include <asm/unaligned.h>
 
 #include <proto/ethernet.h>
 #include <proto/bcmevent.h>
+#include <proto/vlan.h>
+#include <proto/bcmudp.h>
+#include <proto/bcmdhcp.h>
+#ifdef DHD_L2_FILTER
+#include <proto/bcmicmp.h>
+#endif
+#include <proto/802.3.h>
+
 #include <dngl_stats.h>
 #include <dhd_linux_wq.h>
 #include <dhd.h>
 #include <dhd_linux.h>
+#ifdef PCIE_FULL_DONGLE
+#include <dhd_flowring.h>
+#endif
 #include <dhd_bus.h>
 #include <dhd_proto.h>
 #include <dhd_dbg.h>
 #include <dhd_pno.h>
 #endif
 
+#ifdef CONFIG_COMPAT
+#include <linux/compat.h>
+#endif
+
+#ifdef DHD_WMF
+#include <dhd_wmf_linux.h>
+#endif /* DHD_WMF */
+
 #ifdef DHDTCPACK_SUPPRESS
 #include <dhd_ip.h>
 #endif /* DHDTCPACK_SUPPRESS */
@@ -134,6 +161,13 @@ extern bool ap_fw_loaded;
 
 #include <wl_android.h>
 
+/* Maximum STA per radio */
+#define DHD_MAX_STA     32
+
+
+const uint8 wme_fifo2ac[] = { 0, 1, 2, 3, 1, 1 };
+const uint8 prio2fifo[8] = { 1, 0, 0, 1, 2, 2, 3, 3 };
+#define WME_PRIO2AC(prio)  wme_fifo2ac[prio2fifo[(prio)]]
 
 #ifdef ARP_OFFLOAD_SUPPORT
 void aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add, int idx);
@@ -148,6 +182,7 @@ static struct notifier_block dhd_inetaddr_notifier = {
 static bool dhd_inetaddr_notifier_registered = FALSE;
 #endif /* ARP_OFFLOAD_SUPPORT */
 
+#ifdef CONFIG_IPV6
 static int dhd_inet6addr_notifier_call(struct notifier_block *this,
        unsigned long event, void *ptr);
 static struct notifier_block dhd_inet6addr_notifier = {
@@ -157,6 +192,7 @@ static struct notifier_block dhd_inet6addr_notifier = {
  * created in kernel notifier link list (with 'next' pointing to itself)
  */
 static bool dhd_inet6addr_notifier_registered = FALSE;
+#endif
 
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP)
 #include <linux/suspend.h>
@@ -231,6 +267,14 @@ static inline int dhd_write_macaddr(struct ether_addr *mac) { return 0; }
 #endif
 
 
+
+static int dhd_reboot_callback(struct notifier_block *this, unsigned long code, void *unused);
+static struct notifier_block dhd_reboot_notifier = {
+               .notifier_call = dhd_reboot_callback,
+               .priority = 1,
+};
+
+
 typedef struct dhd_if_event {
        struct list_head        list;
        wl_event_data_if_t      event;
@@ -243,16 +287,26 @@ typedef struct dhd_if {
        struct dhd_info *info;                  /* back pointer to dhd_info */
        /* OS/stack specifics */
        struct net_device *net;
-       struct net_device_stats stats;
-       int                     idx;                    /* iface idx in dongle */
-       uint                    subunit;                /* subunit */
+       int                             idx;                    /* iface idx in dongle */
+       uint                    subunit;                /* subunit */
        uint8                   mac_addr[ETHER_ADDR_LEN];       /* assigned MAC address */
+       bool                    set_macaddress;
+       bool                    set_multicast;
+       uint8                   bssidx;                 /* bsscfg index for the interface */
        bool                    attached;               /* Delayed attachment when unset */
        bool                    txflowcontrol;  /* Per interface flow control indicator */
        char                    name[IFNAMSIZ+1]; /* linux interface name */
-       uint8                   bssidx;                 /* bsscfg index for the interface */
-       bool                    set_macaddress;
-       bool                    set_multicast;
+       struct net_device_stats stats;
+#ifdef DHD_WMF
+       dhd_wmf_t               wmf;            /* per bsscfg wmf setting */
+#endif /* DHD_WMF */
+#ifdef PCIE_FULL_DONGLE
+       struct list_head sta_list;              /* sll of associated stations */
+#if !defined(BCM_GMAC3)
+       spinlock_t      sta_list_lock;          /* lock for manipulating sll */
+#endif /* ! BCM_GMAC3 */
+#endif /* PCIE_FULL_DONGLE */
+       uint32  ap_isolate;                     /* ap-isolation settings */
 } dhd_if_t;
 
 #ifdef WLMEDIA_HTSF
@@ -289,20 +343,24 @@ struct ipv6_work_info_t {
        unsigned long           event;
 };
 
+/* When Perimeter locks are deployed, any blocking calls must be preceeded
+ * with a PERIM UNLOCK and followed by a PERIM LOCK.
+ * Examples of blocking calls are: schedule_timeout(), down_interruptible(),
+ * wait_event_timeout().
+ */
+
 /* Local private structure (extension of pub) */
 typedef struct dhd_info {
 #if defined(WL_WIRELESS_EXT)
        wl_iw_t         iw;             /* wireless extensions state (must be first) */
 #endif /* defined(WL_WIRELESS_EXT) */
-
        dhd_pub_t pub;
+       dhd_if_t *iflist[DHD_MAX_IFS]; /* for supporting multiple interfaces */
+
        void *adapter;                  /* adapter information, interrupt, fw path etc. */
        char fw_path[PATH_MAX];         /* path to firmware image */
        char nv_path[PATH_MAX];         /* path to nvram vars file */
 
-       /* For supporting multiple interfaces */
-       dhd_if_t *iflist[DHD_MAX_IFS];
-
        struct semaphore proto_sem;
 #ifdef PROP_TXSTATUS
        spinlock_t      wlfc_spinlock;
@@ -346,16 +404,19 @@ typedef struct dhd_info {
 #endif
        spinlock_t wakelock_spinlock;
        uint32 wakelock_counter;
-       bool waive_wakelock;
-       uint32 wakelock_before_waive;
        int wakelock_wd_counter;
        int wakelock_rx_timeout_enable;
        int wakelock_ctrl_timeout_enable;
+       bool waive_wakelock;
+       uint32 wakelock_before_waive;
 
        /* Thread to issue ioctl for multicast */
        wait_queue_head_t ctrl_wait;
        atomic_t pend_8021x_cnt;
        dhd_attach_states_t dhd_state;
+#ifdef SHOW_LOGTRACE
+       dhd_event_log_t event_data;
+#endif /* SHOW_LOGTRACE */
 
 #if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
        struct early_suspend early_suspend;
@@ -383,6 +444,8 @@ typedef struct dhd_info {
        struct notifier_block pm_notifier;
 } dhd_info_t;
 
+#define DHDIF_FWDER(dhdif)      FALSE
+
 /* Flag to indicate if we should download firmware on driver load */
 uint dhd_download_fw_on_driverload = TRUE;
 
@@ -392,6 +455,10 @@ uint dhd_download_fw_on_driverload = TRUE;
 char firmware_path[MOD_PARAM_PATHLEN];
 char nvram_path[MOD_PARAM_PATHLEN];
 
+/* backup buffer for firmware and nvram path */
+char fw_bak_path[MOD_PARAM_PATHLEN];
+char nv_bak_path[MOD_PARAM_PATHLEN];
+
 /* information string to keep firmware, chio, cheip version info visiable from log */
 char info_string[MOD_PARAM_INFOLEN];
 module_param_string(info_string, info_string, MOD_PARAM_INFOLEN, 0444);
@@ -408,7 +475,13 @@ static void dhd_ifadd_event_handler(void *handle, void *event_info, u8 event);
 static void dhd_ifdel_event_handler(void *handle, void *event_info, u8 event);
 static void dhd_set_mac_addr_handler(void *handle, void *event_info, u8 event);
 static void dhd_set_mcast_list_handler(void *handle, void *event_info, u8 event);
+#ifdef CONFIG_IPV6
 static void dhd_inet6_work_handler(void *dhd_info, void *event_data, u8 event);
+#endif
+
+#ifdef WL_CFG80211
+extern void dhd_netdev_free(struct net_device *ndev);
+#endif /* WL_CFG80211 */
 
 /* Error bits */
 module_param(dhd_msg_level, int, 0);
@@ -436,7 +509,7 @@ module_param_string(nvram_path, nvram_path, MOD_PARAM_PATHLEN, 0660);
 /* extend watchdog expiration to 2 seconds when DPC is running */
 #define WATCHDOG_EXTEND_INTERVAL (2000)
 
-uint dhd_watchdog_ms = 10;
+uint dhd_watchdog_ms = CUSTOM_DHD_WATCHDOG_MS;
 module_param(dhd_watchdog_ms, uint, 0);
 
 #if defined(DHD_DEBUG)
@@ -484,6 +557,28 @@ static int dhd_found = 0;
 static int instance_base = 0; /* Starting instance number */
 module_param(instance_base, int, 0644);
 
+
+/* DHD Perimiter lock only used in router with bypass forwarding. */
+#define DHD_PERIM_RADIO_INIT()              do { /* noop */ } while (0)
+#define DHD_PERIM_LOCK_TRY(unit, flag)      do { /* noop */ } while (0)
+#define DHD_PERIM_UNLOCK_TRY(unit, flag)    do { /* noop */ } while (0)
+#define DHD_PERIM_LOCK_ALL()                do { /* noop */ } while (0)
+#define DHD_PERIM_UNLOCK_ALL()              do { /* noop */ } while (0)
+
+#ifdef PCIE_FULL_DONGLE
+#if defined(BCM_GMAC3)
+#define DHD_IF_STA_LIST_LOCK_INIT(ifp)      do { /* noop */ } while (0)
+#define DHD_IF_STA_LIST_LOCK(ifp, flags)    ({ BCM_REFERENCE(flags); })
+#define DHD_IF_STA_LIST_UNLOCK(ifp, flags)  ({ BCM_REFERENCE(flags); })
+#else /* ! BCM_GMAC3 */
+#define DHD_IF_STA_LIST_LOCK_INIT(ifp) spin_lock_init(&(ifp)->sta_list_lock)
+#define DHD_IF_STA_LIST_LOCK(ifp, flags) \
+       spin_lock_irqsave(&(ifp)->sta_list_lock, (flags))
+#define DHD_IF_STA_LIST_UNLOCK(ifp, flags) \
+       spin_unlock_irqrestore(&(ifp)->sta_list_lock, (flags))
+#endif /* ! BCM_GMAC3 */
+#endif /* PCIE_FULL_DONGLE */
+
 /* Control fw roaming */
 uint dhd_roam_disable = 0;
 
@@ -589,14 +684,19 @@ 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);
-
-#ifdef PROP_TXSTATUS
-static int dhd_wakelock_waive(dhd_info_t *dhdinfo);
-static int dhd_wakelock_restore(dhd_info_t *dhdinfo);
+#ifdef DHD_UNICAST_DHCP
+static const uint8 llc_snap_hdr[SNAP_HDR_LEN] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
+static int dhd_get_pkt_ip_type(dhd_pub_t *dhd, void *skb, uint8 **data_ptr,
+       int *len_ptr, uint8 *prot_ptr);
+static int dhd_get_pkt_ether_type(dhd_pub_t *dhd, void *skb, uint8 **data_ptr,
+       int *len_ptr, uint16 *et_ptr, bool *snap_ptr);
+
+static int dhd_convert_dhcp_broadcast_ack_to_unicast(dhd_pub_t *pub, void *pktbuf, int ifidx);
+#endif /* DHD_UNICAST_DHCP */
+#ifdef DHD_L2_FILTER
+static int dhd_l2_filter_block_ping(dhd_pub_t *pub, void *pktbuf, int ifidx);
 #endif
-
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (LINUX_VERSION_CODE <= \
-        KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM_SLEEP)
+#if defined(CONFIG_PM_SLEEP)
 static int dhd_pm_callback(struct notifier_block *nfb, unsigned long action, void *ignored)
 {
        int ret = NOTIFY_DONE;
@@ -605,35 +705,40 @@ static int dhd_pm_callback(struct notifier_block *nfb, unsigned long action, voi
 
        BCM_REFERENCE(dhdinfo);
        switch (action) {
-               case PM_HIBERNATION_PREPARE:
-               case PM_SUSPEND_PREPARE:
-                       suspend = TRUE;
-                       break;
-               case PM_POST_HIBERNATION:
-               case PM_POST_SUSPEND:
-                       suspend = FALSE;
-                       break;
+       case PM_HIBERNATION_PREPARE:
+       case PM_SUSPEND_PREPARE:
+               suspend = TRUE;
+               break;
+       case PM_POST_HIBERNATION:
+       case PM_POST_SUSPEND:
+               suspend = FALSE;
+               break;
        }
 
+#if defined(SUPPORT_P2P_GO_PS)
 #ifdef PROP_TXSTATUS
        if (suspend) {
-               dhd_wakelock_waive(dhdinfo);
+               DHD_OS_WAKE_LOCK_WAIVE(&dhdinfo->pub);
                dhd_wlfc_suspend(&dhdinfo->pub);
-               dhd_wakelock_restore(dhdinfo);
-       } else {
+               DHD_OS_WAKE_LOCK_RESTORE(&dhdinfo->pub);
+       } else
                dhd_wlfc_resume(&dhdinfo->pub);
-       }
-
 #endif
+#endif /* defined(SUPPORT_P2P_GO_PS) */
 
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (LINUX_VERSION_CODE <= \
        KERNEL_VERSION(2, 6, 39))
        dhd_mmc_suspend = suspend;
        smp_mb();
 #endif
+
        return ret;
 }
 
+static struct notifier_block dhd_pm_notifier = {
+       .notifier_call = dhd_pm_callback,
+       .priority = 10
+};
 /* to make sure we won't register the same notifier twice, otherwise a loop is likely to be
  * created in kernel notifier link list (with 'next' pointing to itself)
  */
@@ -641,13 +746,428 @@ static bool dhd_pm_notifier_registered = FALSE;
 
 extern int register_pm_notifier(struct notifier_block *nb);
 extern int unregister_pm_notifier(struct notifier_block *nb);
-#endif /* (LINUX_VERSION >= 2.6.27 && LINUX_VERSION <= 2.6.39 && CONFIG_PM_SLEEP) */
+#endif /* CONFIG_PM_SLEEP */
 
 /* Request scheduling of the bus rx frame */
 static void dhd_sched_rxf(dhd_pub_t *dhdp, void *skb);
 static void dhd_os_rxflock(dhd_pub_t *pub);
 static void dhd_os_rxfunlock(dhd_pub_t *pub);
 
+/** priv_link is the link between netdev and the dhdif and dhd_info structs. */
+typedef struct dhd_dev_priv {
+       dhd_info_t * dhd; /* cached pointer to dhd_info in netdevice priv */
+       dhd_if_t   * ifp; /* cached pointer to dhd_if in netdevice priv */
+       int          ifidx; /* interface index */
+} dhd_dev_priv_t;
+
+#define DHD_DEV_PRIV_SIZE       (sizeof(dhd_dev_priv_t))
+#define DHD_DEV_PRIV(dev)       ((dhd_dev_priv_t *)DEV_PRIV(dev))
+#define DHD_DEV_INFO(dev)       (((dhd_dev_priv_t *)DEV_PRIV(dev))->dhd)
+#define DHD_DEV_IFP(dev)        (((dhd_dev_priv_t *)DEV_PRIV(dev))->ifp)
+#define DHD_DEV_IFIDX(dev)      (((dhd_dev_priv_t *)DEV_PRIV(dev))->ifidx)
+
+/** Clear the dhd net_device's private structure. */
+static inline void
+dhd_dev_priv_clear(struct net_device * dev)
+{
+       dhd_dev_priv_t * dev_priv;
+       ASSERT(dev != (struct net_device *)NULL);
+       dev_priv = DHD_DEV_PRIV(dev);
+       dev_priv->dhd = (dhd_info_t *)NULL;
+       dev_priv->ifp = (dhd_if_t *)NULL;
+       dev_priv->ifidx = DHD_BAD_IF;
+}
+
+/** Setup the dhd net_device's private structure. */
+static inline void
+dhd_dev_priv_save(struct net_device * dev, dhd_info_t * dhd, dhd_if_t * ifp,
+                  int ifidx)
+{
+       dhd_dev_priv_t * dev_priv;
+       ASSERT(dev != (struct net_device *)NULL);
+       dev_priv = DHD_DEV_PRIV(dev);
+       dev_priv->dhd = dhd;
+       dev_priv->ifp = ifp;
+       dev_priv->ifidx = ifidx;
+}
+
+#ifdef PCIE_FULL_DONGLE
+
+/** Dummy objects are defined with state representing bad|down.
+ * Performance gains from reducing branch conditionals, instruction parallelism,
+ * dual issue, reducing load shadows, avail of larger pipelines.
+ * Use DHD_XXX_NULL instead of (dhd_xxx_t *)NULL, whenever an object pointer
+ * is accessed via the dhd_sta_t.
+ */
+
+/* Dummy dhd_info object */
+dhd_info_t dhd_info_null = {
+#if defined(BCM_GMAC3)
+       .fwdh = FWDER_NULL,
+#endif
+       .pub = {
+                .info = &dhd_info_null,
+#ifdef DHDTCPACK_SUPPRESS
+                .tcpack_sup_mode = TCPACK_SUP_REPLACE,
+#endif /* DHDTCPACK_SUPPRESS */
+                .up = FALSE, .busstate = DHD_BUS_DOWN
+       }
+};
+#define DHD_INFO_NULL (&dhd_info_null)
+#define DHD_PUB_NULL  (&dhd_info_null.pub)
+
+/* Dummy netdevice object */
+struct net_device dhd_net_dev_null = {
+       .reg_state = NETREG_UNREGISTERED
+};
+#define DHD_NET_DEV_NULL (&dhd_net_dev_null)
+
+/* Dummy dhd_if object */
+dhd_if_t dhd_if_null = {
+#if defined(BCM_GMAC3)
+       .fwdh = FWDER_NULL,
+#endif
+#ifdef WMF
+       .wmf = { .wmf_enable = TRUE },
+#endif
+       .info = DHD_INFO_NULL,
+       .net = DHD_NET_DEV_NULL,
+       .idx = DHD_BAD_IF
+};
+#define DHD_IF_NULL  (&dhd_if_null)
+
+#define DHD_STA_NULL ((dhd_sta_t *)NULL)
+
+/** Interface STA list management. */
+
+/** Fetch the dhd_if object, given the interface index in the dhd. */
+static inline dhd_if_t *dhd_get_ifp(dhd_pub_t *dhdp, uint32 ifidx);
+
+/** Alloc/Free a dhd_sta object from the dhd instances' sta_pool. */
+static void dhd_sta_free(dhd_pub_t *pub, dhd_sta_t *sta);
+static dhd_sta_t * dhd_sta_alloc(dhd_pub_t * dhdp);
+
+/* Delete a dhd_sta or flush all dhd_sta in an interface's sta_list. */
+static void dhd_if_del_sta_list(dhd_if_t * ifp);
+static void    dhd_if_flush_sta(dhd_if_t * ifp);
+
+/* Construct/Destruct a sta pool. */
+static int dhd_sta_pool_init(dhd_pub_t *dhdp, int max_sta);
+static void dhd_sta_pool_fini(dhd_pub_t *dhdp, int max_sta);
+
+
+/* Return interface pointer */
+static inline dhd_if_t *dhd_get_ifp(dhd_pub_t *dhdp, uint32 ifidx)
+{
+       ASSERT(ifidx < DHD_MAX_IFS);
+       return dhdp->info->iflist[ifidx];
+}
+
+/** Reset a dhd_sta object and free into the dhd pool. */
+static void
+dhd_sta_free(dhd_pub_t * dhdp, dhd_sta_t * sta)
+{
+       int prio;
+
+       ASSERT((sta != DHD_STA_NULL) && (sta->idx != ID16_INVALID));
+
+       ASSERT((dhdp->staid_allocator != NULL) && (dhdp->sta_pool != NULL));
+       id16_map_free(dhdp->staid_allocator, sta->idx);
+       for (prio = 0; prio < (int)NUMPRIO; prio++)
+               sta->flowid[prio] = FLOWID_INVALID;
+       sta->ifp = DHD_IF_NULL; /* dummy dhd_if object */
+       sta->ifidx = DHD_BAD_IF;
+       bzero(sta->ea.octet, ETHER_ADDR_LEN);
+       INIT_LIST_HEAD(&sta->list);
+       sta->idx = ID16_INVALID; /* implying free */
+}
+
+/** Allocate a dhd_sta object from the dhd pool. */
+static dhd_sta_t *
+dhd_sta_alloc(dhd_pub_t * dhdp)
+{
+       uint16 idx;
+       dhd_sta_t * sta;
+       dhd_sta_pool_t * sta_pool;
+
+       ASSERT((dhdp->staid_allocator != NULL) && (dhdp->sta_pool != NULL));
+
+       idx = id16_map_alloc(dhdp->staid_allocator);
+       if (idx == ID16_INVALID) {
+               DHD_ERROR(("%s: cannot get free staid\n", __FUNCTION__));
+               return DHD_STA_NULL;
+       }
+
+       sta_pool = (dhd_sta_pool_t *)(dhdp->sta_pool);
+       sta = &sta_pool[idx];
+
+       ASSERT((sta->idx == ID16_INVALID) &&
+              (sta->ifp == DHD_IF_NULL) && (sta->ifidx == DHD_BAD_IF));
+       sta->idx = idx; /* implying allocated */
+
+       return sta;
+}
+
+/** Delete all STAs in an interface's STA list. */
+static void
+dhd_if_del_sta_list(dhd_if_t *ifp)
+{
+       dhd_sta_t *sta, *next;
+       unsigned long flags;
+
+       DHD_IF_STA_LIST_LOCK(ifp, flags);
+
+       list_for_each_entry_safe(sta, next, &ifp->sta_list, list) {
+#if defined(BCM_GMAC3)
+               if (ifp->fwdh) {
+                       /* Remove sta from WOFA forwarder. */
+                       fwder_deassoc(ifp->fwdh, (uint16 *)(sta->ea.octet), (wofa_t)sta);
+               }
+#endif /* BCM_GMAC3 */
+               list_del(&sta->list);
+               dhd_sta_free(&ifp->info->pub, sta);
+       }
+
+       DHD_IF_STA_LIST_UNLOCK(ifp, flags);
+
+       return;
+}
+
+/** Router/GMAC3: Flush all station entries in the forwarder's WOFA database. */
+static void
+dhd_if_flush_sta(dhd_if_t * ifp)
+{
+#if defined(BCM_GMAC3)
+
+       if (ifp && (ifp->fwdh != FWDER_NULL)) {
+               dhd_sta_t *sta, *next;
+               unsigned long flags;
+
+               DHD_IF_STA_LIST_LOCK(ifp, flags);
+
+               list_for_each_entry_safe(sta, next, &ifp->sta_list, list) {
+                       /* Remove any sta entry from WOFA forwarder. */
+                       fwder_flush(ifp->fwdh, (wofa_t)sta);
+               }
+
+               DHD_IF_STA_LIST_UNLOCK(ifp, flags);
+       }
+#endif /* BCM_GMAC3 */
+}
+
+/** Construct a pool of dhd_sta_t objects to be used by interfaces. */
+static int
+dhd_sta_pool_init(dhd_pub_t *dhdp, int max_sta)
+{
+       int idx, sta_pool_memsz;
+       dhd_sta_t * sta;
+       dhd_sta_pool_t * sta_pool;
+       void * staid_allocator;
+
+       ASSERT(dhdp != (dhd_pub_t *)NULL);
+       ASSERT((dhdp->staid_allocator == NULL) && (dhdp->sta_pool == NULL));
+
+       /* dhd_sta objects per radio are managed in a table. id#0 reserved. */
+       staid_allocator = id16_map_init(dhdp->osh, max_sta, 1);
+       if (staid_allocator == NULL) {
+               DHD_ERROR(("%s: sta id allocator init failure\n", __FUNCTION__));
+               return BCME_ERROR;
+       }
+
+       /* Pre allocate a pool of dhd_sta objects (one extra). */
+       sta_pool_memsz = ((max_sta + 1) * sizeof(dhd_sta_t)); /* skip idx 0 */
+       sta_pool = (dhd_sta_pool_t *)MALLOC(dhdp->osh, sta_pool_memsz);
+       if (sta_pool == NULL) {
+               DHD_ERROR(("%s: sta table alloc failure\n", __FUNCTION__));
+               id16_map_fini(dhdp->osh, staid_allocator);
+               return BCME_ERROR;
+       }
+
+       dhdp->sta_pool = sta_pool;
+       dhdp->staid_allocator = staid_allocator;
+
+       /* Initialize all sta(s) for the pre-allocated free pool. */
+       bzero((uchar *)sta_pool, sta_pool_memsz);
+       for (idx = max_sta; idx >= 1; idx--) { /* skip sta_pool[0] */
+               sta = &sta_pool[idx];
+               sta->idx = id16_map_alloc(staid_allocator);
+               ASSERT(sta->idx <= max_sta);
+       }
+       /* Now place them into the pre-allocated free pool. */
+       for (idx = 1; idx <= max_sta; idx++) {
+               sta = &sta_pool[idx];
+               dhd_sta_free(dhdp, sta);
+       }
+
+       return BCME_OK;
+}
+
+/** Destruct the pool of dhd_sta_t objects.
+ * Caller must ensure that no STA objects are currently associated with an if.
+ */
+static void
+dhd_sta_pool_fini(dhd_pub_t *dhdp, int max_sta)
+{
+       dhd_sta_pool_t * sta_pool = (dhd_sta_pool_t *)dhdp->sta_pool;
+
+       if (sta_pool) {
+               int idx;
+               int sta_pool_memsz = ((max_sta + 1) * sizeof(dhd_sta_t));
+               for (idx = 1; idx <= max_sta; idx++) {
+                       ASSERT(sta_pool[idx].ifp == DHD_IF_NULL);
+                       ASSERT(sta_pool[idx].idx == ID16_INVALID);
+               }
+               MFREE(dhdp->osh, dhdp->sta_pool, sta_pool_memsz);
+               dhdp->sta_pool = NULL;
+       }
+
+       id16_map_fini(dhdp->osh, dhdp->staid_allocator);
+       dhdp->staid_allocator = NULL;
+}
+
+/** Find STA with MAC address ea in an interface's STA list. */
+dhd_sta_t *
+dhd_find_sta(void *pub, int ifidx, void *ea)
+{
+       dhd_sta_t *sta;
+       dhd_if_t *ifp;
+       unsigned long flags;
+
+       ASSERT(ea != NULL);
+       ifp = dhd_get_ifp((dhd_pub_t *)pub, ifidx);
+
+       DHD_IF_STA_LIST_LOCK(ifp, flags);
+
+       list_for_each_entry(sta, &ifp->sta_list, list) {
+               if (!memcmp(sta->ea.octet, ea, ETHER_ADDR_LEN)) {
+                       DHD_IF_STA_LIST_UNLOCK(ifp, flags);
+                       return sta;
+               }
+       }
+
+       DHD_IF_STA_LIST_UNLOCK(ifp, flags);
+
+       return DHD_STA_NULL;
+}
+
+/** Add STA into the interface's STA list. */
+dhd_sta_t *
+dhd_add_sta(void *pub, int ifidx, void *ea)
+{
+       dhd_sta_t *sta;
+       dhd_if_t *ifp;
+       unsigned long flags;
+
+       ASSERT(ea != NULL);
+       ifp = dhd_get_ifp((dhd_pub_t *)pub, ifidx);
+
+       sta = dhd_sta_alloc((dhd_pub_t *)pub);
+       if (sta == DHD_STA_NULL) {
+               DHD_ERROR(("%s: Alloc failed\n", __FUNCTION__));
+               return DHD_STA_NULL;
+       }
+
+       memcpy(sta->ea.octet, ea, ETHER_ADDR_LEN);
+
+       /* link the sta and the dhd interface */
+       sta->ifp = ifp;
+       sta->ifidx = ifidx;
+       INIT_LIST_HEAD(&sta->list);
+
+       DHD_IF_STA_LIST_LOCK(ifp, flags);
+
+       list_add_tail(&sta->list, &ifp->sta_list);
+
+#if defined(BCM_GMAC3)
+       if (ifp->fwdh) {
+               ASSERT(ISALIGNED(ea, 2));
+               /* Add sta to WOFA forwarder. */
+               fwder_reassoc(ifp->fwdh, (uint16 *)ea, (wofa_t)sta);
+       }
+#endif /* BCM_GMAC3 */
+
+       DHD_IF_STA_LIST_UNLOCK(ifp, flags);
+
+       return sta;
+}
+
+/** Delete STA from the interface's STA list. */
+void
+dhd_del_sta(void *pub, int ifidx, void *ea)
+{
+       dhd_sta_t *sta, *next;
+       dhd_if_t *ifp;
+       unsigned long flags;
+
+       ASSERT(ea != NULL);
+       ifp = dhd_get_ifp((dhd_pub_t *)pub, ifidx);
+
+       DHD_IF_STA_LIST_LOCK(ifp, flags);
+
+       list_for_each_entry_safe(sta, next, &ifp->sta_list, list) {
+               if (!memcmp(sta->ea.octet, ea, ETHER_ADDR_LEN)) {
+#if defined(BCM_GMAC3)
+                       if (ifp->fwdh) { /* Found a sta, remove from WOFA forwarder. */
+                               ASSERT(ISALIGNED(ea, 2));
+                               fwder_deassoc(ifp->fwdh, (uint16 *)ea, (wofa_t)sta);
+                       }
+#endif /* BCM_GMAC3 */
+                       list_del(&sta->list);
+                       dhd_sta_free(&ifp->info->pub, sta);
+               }
+       }
+
+       DHD_IF_STA_LIST_UNLOCK(ifp, flags);
+
+       return;
+}
+
+/** Add STA if it doesn't exist. Not reentrant. */
+dhd_sta_t*
+dhd_findadd_sta(void *pub, int ifidx, void *ea)
+{
+       dhd_sta_t *sta;
+
+       sta = dhd_find_sta(pub, ifidx, ea);
+
+       if (!sta) {
+               /* Add entry */
+               sta = dhd_add_sta(pub, ifidx, ea);
+       }
+
+       return sta;
+}
+#else
+static inline void dhd_if_flush_sta(dhd_if_t * ifp) { }
+static inline void dhd_if_del_sta_list(dhd_if_t *ifp) {}
+static inline int dhd_sta_pool_init(dhd_pub_t *dhdp, int max_sta) { return BCME_OK; }
+static inline void dhd_sta_pool_fini(dhd_pub_t *dhdp, int max_sta) {}
+dhd_sta_t *dhd_findadd_sta(void *pub, int ifidx, void *ea) { return NULL; }
+void dhd_del_sta(void *pub, int ifidx, void *ea) {}
+#endif /* PCIE_FULL_DONGLE */
+
+
+/* Returns dhd iflist index correspondig the the bssidx provided by apps */
+int dhd_bssidx2idx(dhd_pub_t *dhdp, uint32 bssidx)
+{
+       dhd_if_t *ifp;
+       dhd_info_t *dhd = dhdp->info;
+       int i;
+
+       ASSERT(bssidx < DHD_MAX_IFS);
+       ASSERT(dhdp);
+
+       for (i = 0; i < DHD_MAX_IFS; i++) {
+               ifp = dhd->iflist[i];
+               if (ifp && (ifp->bssidx == bssidx)) {
+                       DHD_TRACE(("Index manipulated for %s from %d to %d\n",
+                               ifp->name, bssidx, i));
+                       break;
+               }
+       }
+       return i;
+}
+
 static inline int dhd_rxf_enqueue(dhd_pub_t *dhdp, void* skb)
 {
        uint32 store_idx;
@@ -664,6 +1184,11 @@ static inline int dhd_rxf_enqueue(dhd_pub_t *dhdp, void* skb)
        if (dhdp->skbbuf[store_idx] != NULL) {
                /* Make sure the previous packets are processed */
                dhd_os_rxfunlock(dhdp);
+#ifdef RXF_DEQUEUE_ON_BUSY
+               DHD_TRACE(("dhd_rxf_enqueue: pktbuf not consumed %p, store idx %d sent idx %d\n",
+                       skb, store_idx, sent_idx));
+               return BCME_BUSY;
+#else /* RXF_DEQUEUE_ON_BUSY */
                DHD_ERROR(("dhd_rxf_enqueue: pktbuf not consumed %p, store idx %d sent idx %d\n",
                        skb, store_idx, sent_idx));
                /* removed msleep here, should use wait_event_timeout if we
@@ -673,6 +1198,7 @@ static inline int dhd_rxf_enqueue(dhd_pub_t *dhdp, void* skb)
                OSL_SLEEP(1);
 #endif
                return BCME_ERROR;
+#endif /* RXF_DEQUEUE_ON_BUSY */
        }
        DHD_TRACE(("dhd_rxf_enqueue: Store SKB %p. idx %d -> %d\n",
                skb, store_idx, (store_idx + 1) & (MAXSKBPEND - 1)));
@@ -713,7 +1239,7 @@ static inline void* dhd_rxf_dequeue(dhd_pub_t *dhdp)
        return skb;
 }
 
-static int dhd_process_cid_mac(dhd_pub_t *dhdp, bool prepost)
+int dhd_process_cid_mac(dhd_pub_t *dhdp, bool prepost)
 {
        dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
 
@@ -804,12 +1330,6 @@ static int dhd_set_suspend(int value, dhd_pub_t *dhd)
        uint nd_ra_filter = 0;
        int ret = 0;
 
-#ifdef DYNAMIC_SWOOB_DURATION
-#ifndef CUSTOM_INTR_WIDTH
-#define CUSTOM_INTR_WIDTH 100
-#endif /* CUSTOM_INTR_WIDTH */
-       int intr_width = 0;
-#endif /* DYNAMIC_SWOOB_DURATION */
        if (!dhd)
                return -ENODEV;
 
@@ -867,28 +1387,12 @@ static int dhd_set_suspend(int value, dhd_pub_t *dhd)
                                                DHD_ERROR(("failed to set nd_ra_filter (%d)\n",
                                                        ret));
                                }
-#ifdef DYNAMIC_SWOOB_DURATION
-                               intr_width = CUSTOM_INTR_WIDTH;
-                               bcm_mkiovar("bus:intr_width", (char *)&intr_width, 4,
-                                       iovbuf, sizeof(iovbuf));
-                               if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
-                                       sizeof(iovbuf), TRUE, 0)) < 0)
-                                       DHD_ERROR(("failed to set intr_width (%d)\n", ret));
-#endif /* DYNAMIC_SWOOB_DURATION */
                        } else {
 #ifdef PKT_FILTER_SUPPORT
                                dhd->early_suspended = 0;
 #endif
                                /* Kernel resumed  */
                                DHD_ERROR(("%s: Remove extra suspend setting \n", __FUNCTION__));
-#ifdef DYNAMIC_SWOOB_DURATION
-                               intr_width = 0;
-                               bcm_mkiovar("bus:intr_width", (char *)&intr_width, 4,
-                                       iovbuf, sizeof(iovbuf));
-                               if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
-                                       sizeof(iovbuf), TRUE, 0)) < 0)
-                                       DHD_ERROR(("failed to set intr_width (%d)\n", ret));
-#endif /* DYNAMIC_SWOOB_DURATION */
 
 #ifndef SUPPORT_PM2_ONLY
                                power_mode = PM_FAST;
@@ -934,6 +1438,8 @@ static int dhd_suspend_resume_helper(struct dhd_info *dhd, int val, int force)
        int ret = 0;
 
        DHD_OS_WAKE_LOCK(dhdp);
+       DHD_PERIM_LOCK(dhdp);
+
        /* Set flag when early suspend was called */
        dhdp->in_suspend = val;
        if ((force || !dhdp->suspend_disable_flag) &&
@@ -942,6 +1448,7 @@ static int dhd_suspend_resume_helper(struct dhd_info *dhd, int val, int force)
                ret = dhd_set_suspend(val, dhdp);
        }
 
+       DHD_PERIM_UNLOCK(dhdp);
        DHD_OS_WAKE_UNLOCK(dhdp);
        return ret;
 }
@@ -1013,7 +1520,7 @@ dhd_timeout_expired(dhd_timeout_t *tmo)
                init_waitqueue_head(&delay_wait);
                add_wait_queue(&delay_wait, &wait);
                set_current_state(TASK_INTERRUPTIBLE);
-               schedule_timeout(1);
+               (void)schedule_timeout(1);
                remove_wait_queue(&delay_wait, &wait);
                set_current_state(TASK_RUNNING);
        }
@@ -1068,6 +1575,27 @@ dhd_ifname2idx(dhd_info_t *dhd, char *name)
        return i;       /* default - the primary interface */
 }
 
+int
+dhd_ifidx2hostidx(dhd_info_t *dhd, int ifidx)
+{
+       int i = DHD_MAX_IFS;
+
+       ASSERT(dhd);
+
+       if (ifidx < 0 || ifidx >= DHD_MAX_IFS) {
+               DHD_ERROR(("%s: ifidx %d out of range\n", __FUNCTION__, ifidx));
+               return 0;       /* default - the primary interface */
+       }
+
+       while (--i > 0)
+               if (dhd->iflist[i] && (dhd->iflist[i]->idx == ifidx))
+                               break;
+
+       DHD_TRACE(("%s: return hostidx %d for ifidx %d\n", __FUNCTION__, i, ifidx));
+
+       return i;       /* default - the primary interface */
+}
+
 char *
 dhd_ifname(dhd_pub_t *dhdp, int ifidx)
 {
@@ -1294,6 +1822,10 @@ dhd_ifadd_event_handler(void *handle, void *event_info, u8 event)
        struct net_device *ndev;
        int ifidx, bssidx;
        int ret;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
+       struct wireless_dev *vwdev, *primary_wdev;
+       struct net_device *primary_ndev;
+#endif /* OEM_ANDROID && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) */
 
        if (event != DHD_WQ_WORK_IF_ADD) {
                DHD_ERROR(("%s: unexpected event \n", __FUNCTION__));
@@ -1312,6 +1844,7 @@ dhd_ifadd_event_handler(void *handle, void *event_info, u8 event)
 
        dhd_net_if_lock_local(dhd);
        DHD_OS_WAKE_LOCK(&dhd->pub);
+       DHD_PERIM_LOCK(&dhd->pub);
 
        ifidx = if_event->event.ifidx;
        bssidx = if_event->event.bssidx;
@@ -1324,14 +1857,44 @@ dhd_ifadd_event_handler(void *handle, void *event_info, u8 event)
                goto done;
        }
 
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
+       vwdev = kzalloc(sizeof(*vwdev), GFP_KERNEL);
+       if (unlikely(!vwdev)) {
+               WL_ERR(("Could not allocate wireless device\n"));
+               goto done;
+       }
+       primary_ndev = dhd->pub.info->iflist[0]->net;
+       primary_wdev = ndev_to_wdev(primary_ndev);
+       vwdev->wiphy = primary_wdev->wiphy;
+       vwdev->iftype = if_event->event.role;
+       vwdev->netdev = ndev;
+       ndev->ieee80211_ptr = vwdev;
+       SET_NETDEV_DEV(ndev, wiphy_dev(vwdev->wiphy));
+       DHD_ERROR(("virtual interface(%s) is created\n", if_event->name));
+#endif /* OEM_ANDROID && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) */
+
+       DHD_PERIM_UNLOCK(&dhd->pub);
        ret = dhd_register_if(&dhd->pub, ifidx, TRUE);
+       DHD_PERIM_LOCK(&dhd->pub);
        if (ret != BCME_OK) {
                DHD_ERROR(("%s: dhd_register_if failed\n", __FUNCTION__));
                        dhd_remove_if(&dhd->pub, ifidx, TRUE);
        }
+#ifdef PCIE_FULL_DONGLE
+       /* Turn on AP isolation in the firmware for interfaces operating in AP mode */
+       if (FW_SUPPORTED((&dhd->pub), ap) && (if_event->event.role != WLC_E_IF_ROLE_STA)) {
+               char iovbuf[WLC_IOCTL_SMLEN];
+               uint32 var_int =  1;
+
+               memset(iovbuf, 0, sizeof(iovbuf));
+               bcm_mkiovar("ap_isolate", (char *)&var_int, 4, iovbuf, sizeof(iovbuf));
+               dhd_wl_ioctl_cmd(&dhd->pub, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, ifidx);
+       }
+#endif /* PCIE_FULL_DONGLE */
 done:
        MFREE(dhd->pub.osh, if_event, sizeof(dhd_if_event_t));
 
+       DHD_PERIM_UNLOCK(&dhd->pub);
        DHD_OS_WAKE_UNLOCK(&dhd->pub);
        dhd_net_if_unlock_local(dhd);
 }
@@ -1361,6 +1924,7 @@ dhd_ifdel_event_handler(void *handle, void *event_info, u8 event)
 
        dhd_net_if_lock_local(dhd);
        DHD_OS_WAKE_LOCK(&dhd->pub);
+       DHD_PERIM_LOCK(&dhd->pub);
 
        ifidx = if_event->event.ifidx;
        DHD_TRACE(("Removing interface with idx %d\n", ifidx));
@@ -1369,6 +1933,7 @@ dhd_ifdel_event_handler(void *handle, void *event_info, u8 event)
 
        MFREE(dhd->pub.osh, if_event, sizeof(dhd_if_event_t));
 
+       DHD_PERIM_UNLOCK(&dhd->pub);
        DHD_OS_WAKE_UNLOCK(&dhd->pub);
        dhd_net_if_unlock_local(dhd);
 }
@@ -1379,11 +1944,6 @@ dhd_set_mac_addr_handler(void *handle, void *event_info, u8 event)
        dhd_info_t *dhd = handle;
        dhd_if_t *ifp = event_info;
 
-#ifdef SOFTAP
-       unsigned long flags;
-       bool in_ap = FALSE;
-#endif
-
        if (event != DHD_WQ_WORK_SET_MAC) {
                DHD_ERROR(("%s: unexpected event \n", __FUNCTION__));
        }
@@ -1393,19 +1953,25 @@ dhd_set_mac_addr_handler(void *handle, void *event_info, u8 event)
                return;
        }
 
-#ifdef SOFTAP
-       flags = dhd_os_spin_lock(&dhd->pub);
-       in_ap = (ap_net_dev != NULL);
-       dhd_os_spin_unlock(&dhd->pub, flags);
-
-       if (in_ap)  {
-               DHD_ERROR(("attempt to set MAC for %s in AP Mode, blocked. \n",
-                       ifp->net->name));
-               return;
-       }
-#endif
        dhd_net_if_lock_local(dhd);
        DHD_OS_WAKE_LOCK(&dhd->pub);
+       DHD_PERIM_LOCK(&dhd->pub);
+
+#ifdef SOFTAP
+       {
+               unsigned long flags;
+               bool in_ap = FALSE;
+               DHD_GENERAL_LOCK(&dhd->pub, flags);
+               in_ap = (ap_net_dev != NULL);
+               DHD_GENERAL_UNLOCK(&dhd->pub, flags);
+
+               if (in_ap)  {
+                       DHD_ERROR(("attempt to set MAC for %s in AP Mode, blocked. \n",
+                                  ifp->net->name));
+                       goto done;
+               }
+       }
+#endif /* SOFTAP */
 
        if (ifp == NULL || !dhd->pub.up) {
                DHD_ERROR(("%s: interface info not available/down \n", __FUNCTION__));
@@ -1420,6 +1986,7 @@ dhd_set_mac_addr_handler(void *handle, void *event_info, u8 event)
                DHD_ERROR(("%s: _dhd_set_mac_address() failed\n", __FUNCTION__));
 
 done:
+       DHD_PERIM_UNLOCK(&dhd->pub);
        DHD_OS_WAKE_UNLOCK(&dhd->pub);
        dhd_net_if_unlock_local(dhd);
 }
@@ -1431,11 +1998,6 @@ dhd_set_mcast_list_handler(void *handle, void *event_info, u8 event)
        dhd_if_t *ifp = event_info;
        int ifidx;
 
-#ifdef SOFTAP
-       bool in_ap = FALSE;
-       unsigned long flags;
-#endif
-
        if (event != DHD_WQ_WORK_SET_MCAST_LIST) {
                DHD_ERROR(("%s: unexpected event \n", __FUNCTION__));
                return;
@@ -1446,21 +2008,26 @@ dhd_set_mcast_list_handler(void *handle, void *event_info, u8 event)
                return;
        }
 
-#ifdef SOFTAP
-       flags = dhd_os_spin_lock(&dhd->pub);
-       in_ap = (ap_net_dev != NULL);
-       dhd_os_spin_unlock(&dhd->pub, flags);
-
-       if (in_ap)  {
-               DHD_ERROR(("set MULTICAST list for %s in AP Mode, blocked. \n",
-               ifp->net->name));
-               ifp->set_multicast = FALSE;
-               return;
-       }
-#endif
-
        dhd_net_if_lock_local(dhd);
        DHD_OS_WAKE_LOCK(&dhd->pub);
+       DHD_PERIM_LOCK(&dhd->pub);
+
+#ifdef SOFTAP
+       {
+               bool in_ap = FALSE;
+               unsigned long flags;
+               DHD_GENERAL_LOCK(&dhd->pub, flags);
+               in_ap = (ap_net_dev != NULL);
+               DHD_GENERAL_UNLOCK(&dhd->pub, flags);
+
+               if (in_ap)  {
+                       DHD_ERROR(("set MULTICAST list for %s in AP Mode, blocked. \n",
+                                  ifp->net->name));
+                       ifp->set_multicast = FALSE;
+                       goto done;
+               }
+       }
+#endif /* SOFTAP */
 
        if (ifp == NULL || !dhd->pub.up) {
                DHD_ERROR(("%s: interface info not available/down \n", __FUNCTION__));
@@ -1474,6 +2041,7 @@ dhd_set_mcast_list_handler(void *handle, void *event_info, u8 event)
        DHD_INFO(("%s: set multicast list for if %d\n", __FUNCTION__, ifidx));
 
 done:
+       DHD_PERIM_UNLOCK(&dhd->pub);
        DHD_OS_WAKE_UNLOCK(&dhd->pub);
        dhd_net_if_unlock_local(dhd);
 }
@@ -1483,7 +2051,7 @@ dhd_set_mac_address(struct net_device *dev, void *addr)
 {
        int ret = 0;
 
-       dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
+       dhd_info_t *dhd = DHD_DEV_INFO(dev);
        struct sockaddr *sa = (struct sockaddr *)addr;
        int ifidx;
        dhd_if_t *dhdif;
@@ -1498,7 +2066,7 @@ dhd_set_mac_address(struct net_device *dev, void *addr)
        memcpy(dhdif->mac_addr, sa->sa_data, ETHER_ADDR_LEN);
        dhdif->set_macaddress = TRUE;
        dhd_net_if_unlock_local(dhd);
-       dhd_deferred_schedule_work((void *)dhdif, DHD_WQ_WORK_SET_MAC,
+       dhd_deferred_schedule_work(dhd->dhd_deferred_wq, (void *)dhdif, DHD_WQ_WORK_SET_MAC,
                dhd_set_mac_addr_handler, DHD_WORK_PRIORITY_LOW);
        return ret;
 }
@@ -1506,7 +2074,7 @@ dhd_set_mac_address(struct net_device *dev, void *addr)
 static void
 dhd_set_multicast_list(struct net_device *dev)
 {
-       dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
+       dhd_info_t *dhd = DHD_DEV_INFO(dev);
        int ifidx;
 
        ifidx = dhd_net2idx(dhd, dev);
@@ -1514,8 +2082,8 @@ dhd_set_multicast_list(struct net_device *dev)
                return;
 
        dhd->iflist[ifidx]->set_multicast = TRUE;
-       dhd_deferred_schedule_work((void *)dhd->iflist[ifidx], DHD_WQ_WORK_SET_MCAST_LIST,
-               dhd_set_mcast_list_handler, DHD_WORK_PRIORITY_LOW);
+       dhd_deferred_schedule_work(dhd->dhd_deferred_wq, (void *)dhd->iflist[ifidx],
+               DHD_WQ_WORK_SET_MCAST_LIST, dhd_set_mcast_list_handler, DHD_WORK_PRIORITY_LOW);
 }
 
 #ifdef PROP_TXSTATUS
@@ -1538,11 +2106,8 @@ dhd_os_wlfc_unblock(dhd_pub_t *pub)
        return 1;
 }
 
-const uint8 wme_fifo2ac[] = { 0, 1, 2, 3, 1, 1 };
-uint8 prio2fifo[8] = { 1, 0, 0, 1, 2, 2, 3, 3 };
-#define WME_PRIO2AC(prio)      wme_fifo2ac[prio2fifo[(prio)]]
-
 #endif /* PROP_TXSTATUS */
+
 int BCMFASTPATH
 dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf)
 {
@@ -1557,6 +2122,21 @@ dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf)
                return -ENODEV;
        }
 
+#ifdef PCIE_FULL_DONGLE
+       if (dhdp->busstate == DHD_BUS_SUSPEND) {
+               DHD_ERROR(("%s : pcie is still in suspend state!!\n", __FUNCTION__));
+               PKTFREE(dhdp->osh, pktbuf, TRUE);
+               return -EBUSY;
+       }
+#endif /* PCIE_FULL_DONGLE */
+
+#ifdef DHD_UNICAST_DHCP
+       /* if dhcp_unicast is enabled, we need to convert the */
+       /* broadcast DHCP ACK/REPLY packets to Unicast. */
+       if (dhdp->dhcp_unicast) {
+           dhd_convert_dhcp_broadcast_ack_to_unicast(dhdp, pktbuf, ifidx);
+       }
+#endif /* DHD_UNICAST_DHCP */
        /* Update multicast statistic */
        if (PKTLEN(dhdp->osh, pktbuf) >= ETHER_HDR_LEN) {
                uint8 *pktdata = (uint8 *)PKTDATA(dhdp->osh, pktbuf);