--- /dev/null
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sat, 19 Sep 2015 12:47:20 +0200
+Subject: [PATCH] brcmfmac: include linux/atomic.h
+
+brcmfmac uses atomic_or() and other atomic_* functions, but does not
+include linux/atomic.h. This file gets included by some other header
+file so this normally does not cause problems.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+Acked-by: Arend van Spriel <arend@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
+@@ -15,6 +15,7 @@
+ */
+
+ #include <linux/types.h>
++#include <linux/atomic.h>
+ #include <linux/kernel.h>
+ #include <linux/kthread.h>
+ #include <linux/printk.h>
--- /dev/null
+From: Arend van Spriel <arend@broadcom.com>
+Date: Thu, 8 Oct 2015 20:33:11 +0200
+Subject: [PATCH] brcmfmac: expose device memory to devcoredump subsystem
+
+Upon PSM watchdog event received from firmware the driver will obtain
+a memory snapshot of the device and expose it to user-space through
+the devcoredump framework. This will trigger a uevent.
+
+Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
+Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+Signed-off-by: Arend van Spriel <arend@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/brcm80211/Kconfig
++++ b/drivers/net/wireless/brcm80211/Kconfig
+@@ -85,5 +85,6 @@ config BRCM_TRACING
+ config BRCMDBG
+ bool "Broadcom driver debug functions"
+ depends on BRCMSMAC || BRCMFMAC
++ select WANT_DEV_COREDUMP
+ ---help---
+ Selecting this enables additional code for debug purposes.
+--- a/drivers/net/wireless/brcm80211/brcmfmac/bus.h
++++ b/drivers/net/wireless/brcm80211/brcmfmac/bus.h
+@@ -65,6 +65,8 @@ struct brcmf_bus_dcmd {
+ * @rxctl: receive a control response message from dongle.
+ * @gettxq: obtain a reference of bus transmit queue (optional).
+ * @wowl_config: specify if dongle is configured for wowl when going to suspend
++ * @get_ramsize: obtain size of device memory.
++ * @get_memdump: obtain device memory dump in provided buffer.
+ *
+ * This structure provides an abstract interface towards the
+ * bus specific driver. For control messages to common driver
+@@ -79,6 +81,8 @@ struct brcmf_bus_ops {
+ int (*rxctl)(struct device *dev, unsigned char *msg, uint len);
+ struct pktq * (*gettxq)(struct device *dev);
+ void (*wowl_config)(struct device *dev, bool enabled);
++ size_t (*get_ramsize)(struct device *dev);
++ int (*get_memdump)(struct device *dev, void *data, size_t len);
+ };
+
+
+@@ -185,6 +189,23 @@ void brcmf_bus_wowl_config(struct brcmf_
+ bus->ops->wowl_config(bus->dev, enabled);
+ }
+
++static inline size_t brcmf_bus_get_ramsize(struct brcmf_bus *bus)
++{
++ if (!bus->ops->get_ramsize)
++ return 0;
++
++ return bus->ops->get_ramsize(bus->dev);
++}
++
++static inline
++int brcmf_bus_get_memdump(struct brcmf_bus *bus, void *data, size_t len)
++{
++ if (!bus->ops->get_memdump)
++ return -EOPNOTSUPP;
++
++ return bus->ops->get_memdump(bus->dev, data, len);
++}
++
+ /*
+ * interface functions from common layer
+ */
+--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c
+@@ -957,8 +957,8 @@ int brcmf_attach(struct device *dev)
+ drvr->bus_if = dev_get_drvdata(dev);
+ drvr->bus_if->drvr = drvr;
+
+- /* create device debugfs folder */
+- brcmf_debugfs_attach(drvr);
++ /* attach debug facilities */
++ brcmf_debug_attach(drvr);
+
+ /* Attach and link in the protocol */
+ ret = brcmf_proto_attach(drvr);
+@@ -1155,7 +1155,7 @@ void brcmf_detach(struct device *dev)
+
+ brcmf_proto_detach(drvr);
+
+- brcmf_debugfs_detach(drvr);
++ brcmf_debug_detach(drvr);
+ bus_if->drvr = NULL;
+ kfree(drvr);
+ }
+--- a/drivers/net/wireless/brcm80211/brcmfmac/debug.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/debug.c
+@@ -16,15 +16,45 @@
+ #include <linux/debugfs.h>
+ #include <linux/netdevice.h>
+ #include <linux/module.h>
++#include <linux/devcoredump.h>
+
+ #include <brcmu_wifi.h>
+ #include <brcmu_utils.h>
+ #include "core.h"
+ #include "bus.h"
++#include "fweh.h"
+ #include "debug.h"
+
+ static struct dentry *root_folder;
+
++static int brcmf_debug_create_memdump(struct brcmf_bus *bus, const void *data,
++ size_t len)
++{
++ void *dump;
++ size_t ramsize;
++
++ ramsize = brcmf_bus_get_ramsize(bus);
++ if (ramsize) {
++ dump = vzalloc(len + ramsize);
++ if (!dump)
++ return -ENOMEM;
++ memcpy(dump, data, len);
++ brcmf_bus_get_memdump(bus, dump + len, ramsize);
++ dev_coredumpv(bus->dev, dump, len + ramsize, GFP_KERNEL);
++ }
++ return 0;
++}
++
++static int brcmf_debug_psm_watchdog_notify(struct brcmf_if *ifp,
++ const struct brcmf_event_msg *evtmsg,
++ void *data)
++{
++ brcmf_dbg(TRACE, "enter: idx=%d\n", ifp->bssidx);
++
++ return brcmf_debug_create_memdump(ifp->drvr->bus_if, data,
++ evtmsg->datalen);
++}
++
+ void brcmf_debugfs_init(void)
+ {
+ root_folder = debugfs_create_dir(KBUILD_MODNAME, NULL);
+@@ -41,7 +71,7 @@ void brcmf_debugfs_exit(void)
+ root_folder = NULL;
+ }
+
+-int brcmf_debugfs_attach(struct brcmf_pub *drvr)
++int brcmf_debug_attach(struct brcmf_pub *drvr)
+ {
+ struct device *dev = drvr->bus_if->dev;
+
+@@ -49,12 +79,18 @@ int brcmf_debugfs_attach(struct brcmf_pu
+ return -ENODEV;
+
+ drvr->dbgfs_dir = debugfs_create_dir(dev_name(dev), root_folder);
++ if (IS_ERR(drvr->dbgfs_dir))
++ return PTR_ERR(drvr->dbgfs_dir);
+
+- return PTR_ERR_OR_ZERO(drvr->dbgfs_dir);
++
++ return brcmf_fweh_register(drvr, BRCMF_E_PSM_WATCHDOG,
++ brcmf_debug_psm_watchdog_notify);
+ }
+
+-void brcmf_debugfs_detach(struct brcmf_pub *drvr)
++void brcmf_debug_detach(struct brcmf_pub *drvr)
+ {
++ brcmf_fweh_unregister(drvr, BRCMF_E_PSM_WATCHDOG);
++
+ if (!IS_ERR_OR_NULL(drvr->dbgfs_dir))
+ debugfs_remove_recursive(drvr->dbgfs_dir);
+ }
+--- a/drivers/net/wireless/brcm80211/brcmfmac/debug.h
++++ b/drivers/net/wireless/brcm80211/brcmfmac/debug.h
+@@ -109,8 +109,8 @@ struct brcmf_pub;
+ #ifdef DEBUG
+ void brcmf_debugfs_init(void);
+ void brcmf_debugfs_exit(void);
+-int brcmf_debugfs_attach(struct brcmf_pub *drvr);
+-void brcmf_debugfs_detach(struct brcmf_pub *drvr);
++int brcmf_debug_attach(struct brcmf_pub *drvr);
++void brcmf_debug_detach(struct brcmf_pub *drvr);
+ struct dentry *brcmf_debugfs_get_devdir(struct brcmf_pub *drvr);
+ int brcmf_debugfs_add_entry(struct brcmf_pub *drvr, const char *fn,
+ int (*read_fn)(struct seq_file *seq, void *data));
+@@ -121,11 +121,11 @@ static inline void brcmf_debugfs_init(vo
+ static inline void brcmf_debugfs_exit(void)
+ {
+ }
+-static inline int brcmf_debugfs_attach(struct brcmf_pub *drvr)
++static inline int brcmf_debug_attach(struct brcmf_pub *drvr)
+ {
+ return 0;
+ }
+-static inline void brcmf_debugfs_detach(struct brcmf_pub *drvr)
++static inline void brcmf_debug_detach(struct brcmf_pub *drvr)
+ {
+ }
+ static inline
+--- a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
+@@ -448,6 +448,47 @@ brcmf_pcie_copy_mem_todev(struct brcmf_p
+ }
+
+
++static void
++brcmf_pcie_copy_dev_tomem(struct brcmf_pciedev_info *devinfo, u32 mem_offset,
++ void *dstaddr, u32 len)
++{
++ void __iomem *address = devinfo->tcm + mem_offset;
++ __le32 *dst32;
++ __le16 *dst16;
++ u8 *dst8;
++
++ if (((ulong)address & 4) || ((ulong)dstaddr & 4) || (len & 4)) {
++ if (((ulong)address & 2) || ((ulong)dstaddr & 2) || (len & 2)) {
++ dst8 = (u8 *)dstaddr;
++ while (len) {
++ *dst8 = ioread8(address);
++ address++;
++ dst8++;
++ len--;
++ }
++ } else {
++ len = len / 2;
++ dst16 = (__le16 *)dstaddr;
++ while (len) {
++ *dst16 = cpu_to_le16(ioread16(address));
++ address += 2;
++ dst16++;
++ len--;
++ }
++ }
++ } else {
++ len = len / 4;
++ dst32 = (__le32 *)dstaddr;
++ while (len) {
++ *dst32 = cpu_to_le32(ioread32(address));
++ address += 4;
++ dst32++;
++ len--;
++ }
++ }
++}
++
++
+ #define WRITECC32(devinfo, reg, value) brcmf_pcie_write_reg32(devinfo, \
+ CHIPCREGOFFS(reg), value)
+
+@@ -1352,12 +1393,36 @@ static void brcmf_pcie_wowl_config(struc
+ }
+
+
++static size_t brcmf_pcie_get_ramsize(struct device *dev)
++{
++ struct brcmf_bus *bus_if = dev_get_drvdata(dev);
++ struct brcmf_pciedev *buspub = bus_if->bus_priv.pcie;
++ struct brcmf_pciedev_info *devinfo = buspub->devinfo;
++
++ return devinfo->ci->ramsize - devinfo->ci->srsize;
++}
++
++
++static int brcmf_pcie_get_memdump(struct device *dev, void *data, size_t len)
++{
++ struct brcmf_bus *bus_if = dev_get_drvdata(dev);
++ struct brcmf_pciedev *buspub = bus_if->bus_priv.pcie;
++ struct brcmf_pciedev_info *devinfo = buspub->devinfo;
++
++ brcmf_dbg(PCIE, "dump at 0x%08X: len=%zu\n", devinfo->ci->rambase, len);
++ brcmf_pcie_copy_dev_tomem(devinfo, devinfo->ci->rambase, data, len);
++ return 0;
++}
++
++
+ static struct brcmf_bus_ops brcmf_pcie_bus_ops = {
+ .txdata = brcmf_pcie_tx,
+ .stop = brcmf_pcie_down,
+ .txctl = brcmf_pcie_tx_ctlpkt,
+ .rxctl = brcmf_pcie_rx_ctlpkt,
+ .wowl_config = brcmf_pcie_wowl_config,
++ .get_ramsize = brcmf_pcie_get_ramsize,
++ .get_memdump = brcmf_pcie_get_memdump,
+ };
+
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
+@@ -3539,6 +3539,51 @@ done:
+ return err;
+ }
+
++static size_t brcmf_sdio_bus_get_ramsize(struct device *dev)
++{
++ struct brcmf_bus *bus_if = dev_get_drvdata(dev);
++ struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
++ struct brcmf_sdio *bus = sdiodev->bus;
++
++ return bus->ci->ramsize - bus->ci->srsize;
++}
++
++static int brcmf_sdio_bus_get_memdump(struct device *dev, void *data,
++ size_t mem_size)
++{
++ struct brcmf_bus *bus_if = dev_get_drvdata(dev);
++ struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
++ struct brcmf_sdio *bus = sdiodev->bus;
++ int err;
++ int address;
++ int offset;
++ int len;
++
++ brcmf_dbg(INFO, "dump at 0x%08x: size=%zu\n", bus->ci->rambase,
++ mem_size);
++
++ address = bus->ci->rambase;
++ offset = err = 0;
++ sdio_claim_host(sdiodev->func[1]);
++ while (offset < mem_size) {
++ len = ((offset + MEMBLOCK) < mem_size) ? MEMBLOCK :
++ mem_size - offset;
++ err = brcmf_sdiod_ramrw(sdiodev, false, address, data, len);
++ if (err) {
++ brcmf_err("error %d on reading %d membytes at 0x%08x\n",
++ err, len, address);
++ goto done;
++ }
++ data += len;
++ offset += len;
++ address += len;
++ }
++
++done:
++ sdio_release_host(sdiodev->func[1]);
++ return err;
++}
++
+ void brcmf_sdio_trigger_dpc(struct brcmf_sdio *bus)
+ {
+ if (!bus->dpc_triggered) {
+@@ -3987,7 +4032,9 @@ static struct brcmf_bus_ops brcmf_sdio_b
+ .txctl = brcmf_sdio_bus_txctl,
+ .rxctl = brcmf_sdio_bus_rxctl,
+ .gettxq = brcmf_sdio_bus_gettxq,
+- .wowl_config = brcmf_sdio_wowl_config
++ .wowl_config = brcmf_sdio_wowl_config,
++ .get_ramsize = brcmf_sdio_bus_get_ramsize,
++ .get_memdump = brcmf_sdio_bus_get_memdump,
+ };
+
+ static void brcmf_sdio_firmware_callback(struct device *dev,
--- /dev/null
+From: Hante Meuleman <meuleman@broadcom.com>
+Date: Thu, 8 Oct 2015 20:33:12 +0200
+Subject: [PATCH] brcmfmac: Fix race condition between USB probe/load and
+ disconnect.
+
+When a USB device gets disconnected due to for example removal
+then it is possible that it is still in the loading phase due to
+the asynchronous load routines. These routines can then possible
+access memory which has been freed. Fix this by mutex locking the
+device init phase.
+
+Reviewed-by: Arend Van Spriel <arend@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+Signed-off-by: Hante Meuleman <meuleman@broadcom.com>
+Signed-off-by: Arend van Spriel <arend@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c
+@@ -144,6 +144,7 @@ struct brcmf_usbdev_info {
+
+ struct usb_device *usbdev;
+ struct device *dev;
++ struct mutex dev_init_lock;
+
+ int ctl_in_pipe, ctl_out_pipe;
+ struct urb *ctl_urb; /* URB for control endpoint */
+@@ -1204,6 +1205,8 @@ static void brcmf_usb_probe_phase2(struc
+ int ret;
+
+ brcmf_dbg(USB, "Start fw downloading\n");
++
++ devinfo = bus->bus_priv.usb->devinfo;
+ ret = check_file(fw->data);
+ if (ret < 0) {
+ brcmf_err("invalid firmware\n");
+@@ -1211,7 +1214,6 @@ static void brcmf_usb_probe_phase2(struc
+ goto error;
+ }
+
+- devinfo = bus->bus_priv.usb->devinfo;
+ devinfo->image = fw->data;
+ devinfo->image_len = fw->size;
+
+@@ -1224,9 +1226,11 @@ static void brcmf_usb_probe_phase2(struc
+ if (ret)
+ goto error;
+
++ mutex_unlock(&devinfo->dev_init_lock);
+ return;
+ error:
+ brcmf_dbg(TRACE, "failed: dev=%s, err=%d\n", dev_name(dev), ret);
++ mutex_unlock(&devinfo->dev_init_lock);
+ device_release_driver(dev);
+ }
+
+@@ -1264,6 +1268,7 @@ static int brcmf_usb_probe_cb(struct brc
+ if (ret)
+ goto fail;
+ /* we are done */
++ mutex_unlock(&devinfo->dev_init_lock);
+ return 0;
+ }
+ bus->chip = bus_pub->devid;
+@@ -1317,6 +1322,12 @@ brcmf_usb_probe(struct usb_interface *in
+
+ devinfo->usbdev = usb;
+ devinfo->dev = &usb->dev;
++ /* Take an init lock, to protect for disconnect while still loading.
++ * Necessary because of the asynchronous firmware load construction
++ */
++ mutex_init(&devinfo->dev_init_lock);
++ mutex_lock(&devinfo->dev_init_lock);
++
+ usb_set_intfdata(intf, devinfo);
+
+ /* Check that the device supports only one configuration */
+@@ -1391,6 +1402,7 @@ brcmf_usb_probe(struct usb_interface *in
+ return 0;
+
+ fail:
++ mutex_unlock(&devinfo->dev_init_lock);
+ kfree(devinfo);
+ usb_set_intfdata(intf, NULL);
+ return ret;
+@@ -1403,8 +1415,19 @@ brcmf_usb_disconnect(struct usb_interfac
+
+ brcmf_dbg(USB, "Enter\n");
+ devinfo = (struct brcmf_usbdev_info *)usb_get_intfdata(intf);
+- brcmf_usb_disconnect_cb(devinfo);
+- kfree(devinfo);
++
++ if (devinfo) {
++ mutex_lock(&devinfo->dev_init_lock);
++ /* Make sure that devinfo still exists. Firmware probe routines
++ * may have released the device and cleared the intfdata.
++ */
++ if (!usb_get_intfdata(intf))
++ goto done;
++
++ brcmf_usb_disconnect_cb(devinfo);
++ kfree(devinfo);
++ }
++done:
+ brcmf_dbg(USB, "Exit\n");
+ }
+
--- /dev/null
+From: Franky Lin <frankyl@broadcom.com>
+Date: Thu, 8 Oct 2015 20:33:13 +0200
+Subject: [PATCH] brcmfmac: rename firmware_path to alternative_fw_path
+
+In brcmfmac the module parameter "firmware_path" is used as an
+alternative relative path under the search path used by firmware_class
+or ueventhelper. Rename the parameter to alternative_fw_path to avoid
+confusion.
+
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+Reviewed-by: Arend Van Spriel <arend@broadcom.com>
+Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
+Signed-off-by: Franky Lin <frankyl@broadcom.com>
+Signed-off-by: Arend van Spriel <arend@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/firmware.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/firmware.c
+@@ -28,7 +28,7 @@
+ #define BRCMF_FW_NVRAM_PCIEDEV_LEN 10 /* pcie/1/4/ + \0 */
+
+ char brcmf_firmware_path[BRCMF_FW_PATH_LEN];
+-module_param_string(firmware_path, brcmf_firmware_path,
++module_param_string(alternative_fw_path, brcmf_firmware_path,
+ BRCMF_FW_PATH_LEN, 0440);
+
+ enum nvram_parser_state {
--- /dev/null
+From: Arend van Spriel <arend@broadcom.com>
+Date: Thu, 8 Oct 2015 20:33:14 +0200
+Subject: [PATCH] brcmfmac: remove conversational comment
+
+Removing a comment that was only useful during the review of
+the change that introduced it and which should never have been
+submitted.
+
+Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
+Signed-off-by: Arend van Spriel <arend@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
+@@ -873,9 +873,6 @@ brcmf_msgbuf_process_txstatus(struct brc
+ commonring = msgbuf->flowrings[flowid];
+ atomic_dec(&commonring->outstanding_tx);
+
+- /* Hante: i believe this was a bug as tx_status->msg.ifidx was used
+- * in brcmf_txfinalize as index in drvr->iflist. Can you confirm/deny?
+- */
+ brcmf_txfinalize(brcmf_get_ifp(msgbuf->drvr, tx_status->msg.ifidx),
+ skb, true);
+ }
--- /dev/null
+From: Hante Meuleman <meuleman@broadcom.com>
+Date: Thu, 8 Oct 2015 20:33:15 +0200
+Subject: [PATCH] brcmfmac: Rework p2p attach, use single method for p2p dev
+ creation.
+
+When module param p2pon is used a p2p device is created at init.
+This patch reworks how this is done by using the same method as
+for a dynamically (by user space) created p2p device.
+
+Reviewed-by: Arend Van Spriel <arend@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
+Signed-off-by: Hante Meuleman <meuleman@broadcom.com>
+Signed-off-by: Arend van Spriel <arend@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
+@@ -6237,6 +6237,17 @@ struct brcmf_cfg80211_info *brcmf_cfg802
+ else
+ *cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+ }
++ /* p2p might require that "if-events" get processed by fweh. So
++ * activate the already registered event handlers now and activate
++ * the rest when initialization has completed. drvr->config needs to
++ * be assigned before activating events.
++ */
++ drvr->config = cfg;
++ err = brcmf_fweh_activate_events(ifp);
++ if (err) {
++ brcmf_err("FWEH activation failed (%d)\n", err);
++ goto wiphy_unreg_out;
++ }
+
+ err = brcmf_p2p_attach(cfg, p2pdev_forced);
+ if (err) {
+@@ -6259,6 +6270,13 @@ struct brcmf_cfg80211_info *brcmf_cfg802
+ brcmf_notify_tdls_peer_event);
+ }
+
++ /* (re-) activate FWEH event handling */
++ err = brcmf_fweh_activate_events(ifp);
++ if (err) {
++ brcmf_err("FWEH activation failed (%d)\n", err);
++ goto wiphy_unreg_out;
++ }
++
+ return cfg;
+
+ wiphy_unreg_out:
+--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c
+@@ -828,8 +828,8 @@ struct brcmf_if *brcmf_add_if(struct brc
+ } else {
+ brcmf_dbg(INFO, "allocate netdev interface\n");
+ /* Allocate netdev, including space for private structure */
+- ndev = alloc_netdev(sizeof(*ifp), name, NET_NAME_UNKNOWN,
+- ether_setup);
++ ndev = alloc_netdev(sizeof(*ifp), is_p2pdev ? "p2p%d" : name,
++ NET_NAME_UNKNOWN, ether_setup);
+ if (!ndev)
+ return ERR_PTR(-ENOMEM);
+
+@@ -1021,12 +1021,7 @@ int brcmf_bus_start(struct device *dev)
+ if (IS_ERR(ifp))
+ return PTR_ERR(ifp);
+
+- if (brcmf_p2p_enable)
+- p2p_ifp = brcmf_add_if(drvr, 1, 0, false, "p2p%d", NULL);
+- else
+- p2p_ifp = NULL;
+- if (IS_ERR(p2p_ifp))
+- p2p_ifp = NULL;
++ p2p_ifp = NULL;
+
+ /* signal bus ready */
+ brcmf_bus_change_state(bus_if, BRCMF_BUS_UP);
+@@ -1060,11 +1055,13 @@ int brcmf_bus_start(struct device *dev)
+ goto fail;
+ }
+
+- ret = brcmf_fweh_activate_events(ifp);
+- if (ret < 0)
+- goto fail;
+-
+ ret = brcmf_net_attach(ifp, false);
++
++ if ((!ret) && (brcmf_p2p_enable)) {
++ p2p_ifp = drvr->iflist[1];
++ if (p2p_ifp)
++ ret = brcmf_net_p2p_attach(p2p_ifp);
++ }
+ fail:
+ if (ret < 0) {
+ brcmf_err("failed: %d\n", ret);
+@@ -1076,20 +1073,12 @@ fail:
+ brcmf_fws_del_interface(ifp);
+ brcmf_fws_deinit(drvr);
+ }
+- if (drvr->iflist[0]) {
++ if (ifp)
+ brcmf_net_detach(ifp->ndev);
+- drvr->iflist[0] = NULL;
+- }
+- if (p2p_ifp) {
++ if (p2p_ifp)
+ brcmf_net_detach(p2p_ifp->ndev);
+- drvr->iflist[1] = NULL;
+- }
+ return ret;
+ }
+- if ((brcmf_p2p_enable) && (p2p_ifp))
+- if (brcmf_net_p2p_attach(p2p_ifp) < 0)
+- brcmf_p2p_enable = 0;
+-
+ return 0;
+ }
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c
+@@ -213,7 +213,8 @@ static void brcmf_fweh_handle_if_event(s
+ is_p2pdev, emsg->ifname, emsg->addr);
+ if (IS_ERR(ifp))
+ return;
+- brcmf_fws_add_interface(ifp);
++ if (!is_p2pdev)
++ brcmf_fws_add_interface(ifp);
+ if (!drvr->fweh.evt_handler[BRCMF_E_IF])
+ if (brcmf_net_attach(ifp, false) < 0)
+ return;
+--- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
+@@ -2350,83 +2350,30 @@ void brcmf_p2p_stop_device(struct wiphy
+ * brcmf_p2p_attach() - attach for P2P.
+ *
+ * @cfg: driver private data for cfg80211 interface.
++ * @p2pdev_forced: create p2p device interface at attach.
+ */
+ s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg, bool p2pdev_forced)
+ {
+- struct brcmf_if *pri_ifp;
+- struct brcmf_if *p2p_ifp;
+- struct brcmf_cfg80211_vif *p2p_vif;
+ struct brcmf_p2p_info *p2p;
+- struct brcmf_pub *drvr;
+- s32 bssidx;
++ struct brcmf_if *pri_ifp;
+ s32 err = 0;
++ void *err_ptr;
+
+ p2p = &cfg->p2p;
+ p2p->cfg = cfg;
+
+- drvr = cfg->pub;
+-
+- pri_ifp = brcmf_get_ifp(drvr, 0);
++ pri_ifp = brcmf_get_ifp(cfg->pub, 0);
+ p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif = pri_ifp->vif;
+
+ if (p2pdev_forced) {
+- p2p_ifp = drvr->iflist[1];
++ err_ptr = brcmf_p2p_create_p2pdev(p2p, NULL, NULL);
++ if (IS_ERR(err_ptr)) {
++ brcmf_err("P2P device creation failed.\n");
++ err = PTR_ERR(err_ptr);
++ }
+ } else {
+- p2p_ifp = NULL;
+ p2p->p2pdev_dynamically = true;
+ }
+- if (p2p_ifp) {
+- p2p_vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_P2P_DEVICE,
+- false);
+- if (IS_ERR(p2p_vif)) {
+- brcmf_err("could not create discovery vif\n");
+- err = -ENOMEM;
+- goto exit;
+- }
+-
+- p2p_vif->ifp = p2p_ifp;
+- p2p_ifp->vif = p2p_vif;
+- p2p_vif->wdev.netdev = p2p_ifp->ndev;
+- p2p_ifp->ndev->ieee80211_ptr = &p2p_vif->wdev;
+- SET_NETDEV_DEV(p2p_ifp->ndev, wiphy_dev(cfg->wiphy));
+-
+- p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = p2p_vif;
+-
+- brcmf_p2p_generate_bss_mac(p2p, NULL);
+- memcpy(p2p_ifp->mac_addr, p2p->dev_addr, ETH_ALEN);
+- brcmf_p2p_set_firmware(pri_ifp, p2p->dev_addr);
+-
+- brcmf_fweh_p2pdev_setup(pri_ifp, true);
+-
+- /* Initialize P2P Discovery in the firmware */
+- err = brcmf_fil_iovar_int_set(pri_ifp, "p2p_disc", 1);
+- if (err < 0) {
+- brcmf_err("set p2p_disc error\n");
+- brcmf_free_vif(p2p_vif);
+- goto exit;
+- }
+- /* obtain bsscfg index for P2P discovery */
+- err = brcmf_fil_iovar_int_get(pri_ifp, "p2p_dev", &bssidx);
+- if (err < 0) {
+- brcmf_err("retrieving discover bsscfg index failed\n");
+- brcmf_free_vif(p2p_vif);
+- goto exit;
+- }
+- /* Verify that firmware uses same bssidx as driver !! */
+- if (p2p_ifp->bssidx != bssidx) {
+- brcmf_err("Incorrect bssidx=%d, compared to p2p_ifp->bssidx=%d\n",
+- bssidx, p2p_ifp->bssidx);
+- brcmf_free_vif(p2p_vif);
+- goto exit;
+- }
+-
+- init_completion(&p2p->send_af_done);
+- INIT_WORK(&p2p->afx_hdl.afx_work, brcmf_p2p_afx_handler);
+- init_completion(&p2p->afx_hdl.act_frm_scan);
+- init_completion(&p2p->wait_next_af);
+-exit:
+- brcmf_fweh_p2pdev_setup(pri_ifp, false);
+- }
+ return err;
+ }
+
--- /dev/null
+From: Hante Meuleman <meuleman@broadcom.com>
+Date: Thu, 8 Oct 2015 20:33:16 +0200
+Subject: [PATCH] brcmfmac: Fix station info rate information.
+
+Txrate and rxrate in get_station got assigned first with value
+in kbps and then divided by 100 to get it in 100kbps unit. The
+problem with that is that type of rate is u16 which resulted
+in incorrect values for high data rate values.
+
+Reviewed-by: Arend Van Spriel <arend@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+Signed-off-by: Hante Meuleman <meuleman@broadcom.com>
+Signed-off-by: Arend van Spriel <arend@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
+@@ -2477,13 +2477,13 @@ brcmf_cfg80211_get_station(struct wiphy
+ sinfo->rx_packets += le32_to_cpu(sta_info_le.rx_mcast_pkts);
+ if (sinfo->tx_packets) {
+ sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
+- sinfo->txrate.legacy = le32_to_cpu(sta_info_le.tx_rate);
+- sinfo->txrate.legacy /= 100;
++ sinfo->txrate.legacy =
++ le32_to_cpu(sta_info_le.tx_rate) / 100;
+ }
+ if (sinfo->rx_packets) {
+ sinfo->filled |= BIT(NL80211_STA_INFO_RX_BITRATE);
+- sinfo->rxrate.legacy = le32_to_cpu(sta_info_le.rx_rate);
+- sinfo->rxrate.legacy /= 100;
++ sinfo->rxrate.legacy =
++ le32_to_cpu(sta_info_le.rx_rate) / 100;
+ }
+ if (le16_to_cpu(sta_info_le.ver) >= 4) {
+ sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES);
--- /dev/null
+From: Hante Meuleman <meuleman@broadcom.com>
+Date: Thu, 8 Oct 2015 20:33:17 +0200
+Subject: [PATCH] brcmfmac: Add RSSI information to get_station.
+
+Reviewed-by: Arend Van Spriel <arend@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+Signed-off-by: Hante Meuleman <meuleman@broadcom.com>
+Signed-off-by: Arend van Spriel <arend@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
+@@ -2431,6 +2431,9 @@ brcmf_cfg80211_get_station(struct wiphy
+ struct brcmf_sta_info_le sta_info_le;
+ u32 sta_flags;
+ u32 is_tdls_peer;
++ s32 total_rssi;
++ s32 count_rssi;
++ u32 i;
+
+ brcmf_dbg(TRACE, "Enter, MAC %pM\n", mac);
+ if (!check_vif_up(ifp->vif))
+@@ -2491,6 +2494,26 @@ brcmf_cfg80211_get_station(struct wiphy
+ sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES);
+ sinfo->rx_bytes = le64_to_cpu(sta_info_le.rx_tot_bytes);
+ }
++ total_rssi = 0;
++ count_rssi = 0;
++ for (i = 0; i < BRCMF_ANT_MAX; i++) {
++ if (sta_info_le.rssi[i]) {
++ sinfo->chain_signal_avg[count_rssi] =
++ sta_info_le.rssi[i];
++ sinfo->chain_signal[count_rssi] =
++ sta_info_le.rssi[i];
++ total_rssi += sta_info_le.rssi[i];
++ count_rssi++;
++ }
++ }
++ if (count_rssi) {
++ sinfo->filled |= BIT(NL80211_STA_INFO_CHAIN_SIGNAL);
++ sinfo->chains = count_rssi;
++
++ sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
++ total_rssi /= count_rssi;
++ sinfo->signal = total_rssi;
++ }
+ }
+ done:
+ brcmf_dbg(TRACE, "Exit\n");
--- /dev/null
+From: Hante Meuleman <meuleman@broadcom.com>
+Date: Thu, 8 Oct 2015 20:33:18 +0200
+Subject: [PATCH] brcmfmac: Add dump_station support to cfg80221 ops.
+
+With this feature it becomes possible to request a station
+assoc list.
+
+Reviewed-by: Arend Van Spriel <arend@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+Signed-off-by: Hante Meuleman <meuleman@broadcom.com>
+Signed-off-by: Arend van Spriel <arend@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
+@@ -2520,6 +2520,35 @@ done:
+ return err;
+ }
+
++static int
++brcmf_cfg80211_dump_station(struct wiphy *wiphy, struct net_device *ndev,
++ int idx, u8 *mac, struct station_info *sinfo)
++{
++ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
++ struct brcmf_if *ifp = netdev_priv(ndev);
++ s32 err;
++
++ brcmf_dbg(TRACE, "Enter, idx %d\n", idx);
++
++ if (idx == 0) {
++ cfg->assoclist.count = cpu_to_le32(BRCMF_MAX_ASSOCLIST);
++ err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_ASSOCLIST,
++ &cfg->assoclist,
++ sizeof(cfg->assoclist));
++ if (err) {
++ brcmf_err("BRCMF_C_GET_ASSOCLIST unsupported, err=%d\n",
++ err);
++ cfg->assoclist.count = 0;
++ return -EOPNOTSUPP;
++ }
++ }
++ if (idx < le32_to_cpu(cfg->assoclist.count)) {
++ memcpy(mac, cfg->assoclist.mac[idx], ETH_ALEN);
++ return brcmf_cfg80211_get_station(wiphy, ndev, mac, sinfo);
++ }
++ return -ENOENT;
++}
++
+ static s32
+ brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev,
+ bool enabled, s32 timeout)
+@@ -4619,6 +4648,7 @@ static struct cfg80211_ops wl_cfg80211_o
+ .join_ibss = brcmf_cfg80211_join_ibss,
+ .leave_ibss = brcmf_cfg80211_leave_ibss,
+ .get_station = brcmf_cfg80211_get_station,
++ .dump_station = brcmf_cfg80211_dump_station,
+ .set_tx_power = brcmf_cfg80211_set_tx_power,
+ .get_tx_power = brcmf_cfg80211_get_tx_power,
+ .add_key = brcmf_cfg80211_add_key,
+--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.h
++++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.h
+@@ -407,6 +407,7 @@ struct brcmf_cfg80211_info {
+ struct brcmu_d11inf d11inf;
+ bool wowl_enabled;
+ u32 pre_wowl_pmmode;
++ struct brcmf_assoclist_le assoclist;
+ };
+
+ /**
+--- a/drivers/net/wireless/brcm80211/brcmfmac/fwil.h
++++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil.h
+@@ -72,6 +72,7 @@
+ #define BRCMF_C_GET_BSS_INFO 136
+ #define BRCMF_C_GET_BANDLIST 140
+ #define BRCMF_C_SET_SCB_TIMEOUT 158
++#define BRCMF_C_GET_ASSOCLIST 159
+ #define BRCMF_C_GET_PHYLIST 180
+ #define BRCMF_C_SET_SCAN_CHANNEL_TIME 185
+ #define BRCMF_C_SET_SCAN_UNASSOC_TIME 187
+--- a/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h
++++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h
+@@ -119,6 +119,8 @@
+ #define BRCMF_COUNTRY_BUF_SZ 4
+ #define BRCMF_ANT_MAX 4
+
++#define BRCMF_MAX_ASSOCLIST 128
++
+ /* join preference types for join_pref iovar */
+ enum brcmf_join_pref_types {
+ BRCMF_JOIN_PREF_RSSI = 1,
+@@ -621,4 +623,15 @@ struct brcmf_rev_info_le {
+ __le32 nvramrev;
+ };
+
++/**
++ * struct brcmf_assoclist_le - request assoc list.
++ *
++ * @count: indicates number of stations.
++ * @mac: MAC addresses of stations.
++ */
++struct brcmf_assoclist_le {
++ __le32 count;
++ u8 mac[BRCMF_MAX_ASSOCLIST][ETH_ALEN];
++};
++
+ #endif /* FWIL_TYPES_H_ */
--- /dev/null
+From: Hante Meuleman <meuleman@broadcom.com>
+Date: Thu, 8 Oct 2015 20:33:19 +0200
+Subject: [PATCH] brcmfmac: Move brcmf_c_preinit_dcmds prototype to correct
+ file.
+
+Reviewed-by: Arend Van Spriel <arend@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+Signed-off-by: Hante Meuleman <meuleman@broadcom.com>
+Signed-off-by: Arend van Spriel <arend@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/common.h
++++ b/drivers/net/wireless/brcm80211/brcmfmac/common.h
+@@ -17,4 +17,7 @@
+
+ extern const u8 ALLFFMAC[ETH_ALEN];
+
++/* Sets dongle media info (drv_version, mac address). */
++int brcmf_c_preinit_dcmds(struct brcmf_if *ifp);
++
+ #endif /* BRCMFMAC_COMMON_H */
+--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c
+@@ -33,6 +33,7 @@
+ #include "feature.h"
+ #include "proto.h"
+ #include "pcie.h"
++#include "common.h"
+
+ MODULE_AUTHOR("Broadcom Corporation");
+ MODULE_DESCRIPTION("Broadcom 802.11 wireless LAN fullmac driver.");
+--- a/drivers/net/wireless/brcm80211/brcmfmac/core.h
++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.h
+@@ -214,7 +214,4 @@ void brcmf_txflowblock_if(struct brcmf_i
+ void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success);
+ void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb);
+
+-/* Sets dongle media info (drv_version, mac address). */
+-int brcmf_c_preinit_dcmds(struct brcmf_if *ifp);
+-
+ #endif /* BRCMFMAC_CORE_H */
--- /dev/null
+From: Hante Meuleman <meuleman@broadcom.com>
+Date: Thu, 8 Oct 2015 20:33:20 +0200
+Subject: [PATCH] brcmfmac: Remove unused state AP creating.
+
+Reviewed-by: Arend Van Spriel <arend@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+Signed-off-by: Hante Meuleman <meuleman@broadcom.com>
+Signed-off-by: Arend van Spriel <arend@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
+@@ -839,7 +839,6 @@ brcmf_cfg80211_change_iface(struct wiphy
+ err = brcmf_p2p_ifchange(cfg, BRCMF_FIL_P2P_IF_GO);
+ }
+ if (!err) {
+- set_bit(BRCMF_VIF_STATUS_AP_CREATING, &vif->sme_state);
+ brcmf_dbg(INFO, "IF Type = AP\n");
+ }
+ } else {
+@@ -4250,7 +4249,6 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
+
+ brcmf_dbg(TRACE, "GO mode configuration complete\n");
+ }
+- clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
+ set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
+
+ exit:
+@@ -4315,7 +4313,6 @@ static int brcmf_cfg80211_stop_ap(struct
+ }
+ brcmf_set_mpc(ifp, 1);
+ brcmf_configure_arp_offload(ifp, true);
+- set_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
+ clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
+
+ return err;
+--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.h
++++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.h
+@@ -143,7 +143,6 @@ struct brcmf_cfg80211_profile {
+ * @BRCMF_VIF_STATUS_CONNECTING: connect/join in progress.
+ * @BRCMF_VIF_STATUS_CONNECTED: connected/joined succesfully.
+ * @BRCMF_VIF_STATUS_DISCONNECTING: disconnect/disable in progress.
+- * @BRCMF_VIF_STATUS_AP_CREATING: interface configured for AP operation.
+ * @BRCMF_VIF_STATUS_AP_CREATED: AP operation started.
+ */
+ enum brcmf_vif_status {
+@@ -151,7 +150,6 @@ enum brcmf_vif_status {
+ BRCMF_VIF_STATUS_CONNECTING,
+ BRCMF_VIF_STATUS_CONNECTED,
+ BRCMF_VIF_STATUS_DISCONNECTING,
+- BRCMF_VIF_STATUS_AP_CREATING,
+ BRCMF_VIF_STATUS_AP_CREATED
+ };
+
--- /dev/null
+From: Hante Meuleman <meuleman@broadcom.com>
+Date: Thu, 8 Oct 2015 20:33:21 +0200
+Subject: [PATCH] brcmfmac: Properly set carrier state of netdev.
+
+Use the netif_carrier api to correctly set carrier state on the
+different modes.
+
+Reviewed-by: Arend Van Spriel <arend@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
+Signed-off-by: Hante Meuleman <meuleman@broadcom.com>
+Signed-off-by: Arend van Spriel <arend@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
+@@ -4250,6 +4250,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
+ brcmf_dbg(TRACE, "GO mode configuration complete\n");
+ }
+ set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
++ brcmf_net_setcarrier(ifp, true);
+
+ exit:
+ if ((err) && (!mbss)) {
+@@ -4314,6 +4315,7 @@ static int brcmf_cfg80211_stop_ap(struct
+ brcmf_set_mpc(ifp, 1);
+ brcmf_configure_arp_offload(ifp, true);
+ clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
++ brcmf_net_setcarrier(ifp, false);
+
+ return err;
+ }
+@@ -5023,6 +5025,7 @@ brcmf_notify_connect_status(struct brcmf
+ &ifp->vif->sme_state);
+ } else
+ brcmf_bss_connect_done(cfg, ndev, e, true);
++ brcmf_net_setcarrier(ifp, true);
+ } else if (brcmf_is_linkdown(e)) {
+ brcmf_dbg(CONN, "Linkdown\n");
+ if (!brcmf_is_ibssmode(ifp->vif)) {
+@@ -5032,6 +5035,7 @@ brcmf_notify_connect_status(struct brcmf
+ brcmf_init_prof(ndev_to_prof(ndev));
+ if (ndev != cfg_to_ndev(cfg))
+ complete(&cfg->vif_disabled);
++ brcmf_net_setcarrier(ifp, false);
+ } else if (brcmf_is_nonetwork(cfg, e)) {
+ if (brcmf_is_ibssmode(ifp->vif))
+ clear_bit(BRCMF_VIF_STATUS_CONNECTING,
+--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c
+@@ -635,8 +635,7 @@ static int brcmf_netdev_stop(struct net_
+
+ brcmf_cfg80211_down(ndev);
+
+- /* Set state and stop OS transmissions */
+- netif_stop_queue(ndev);
++ brcmf_net_setcarrier(ifp, false);
+
+ return 0;
+ }
+@@ -670,8 +669,8 @@ static int brcmf_netdev_open(struct net_
+ return -EIO;
+ }
+
+- /* Allow transmit calls */
+- netif_start_queue(ndev);
++ /* Clear, carrier, set when connected or AP mode. */
++ netif_carrier_off(ndev);
+ return 0;
+ }
+
+@@ -736,6 +735,24 @@ static void brcmf_net_detach(struct net_
+ brcmf_cfg80211_free_netdev(ndev);
+ }
+
++void brcmf_net_setcarrier(struct brcmf_if *ifp, bool on)
++{
++ struct net_device *ndev;
++
++ brcmf_dbg(TRACE, "Enter, idx=%d carrier=%d\n", ifp->bssidx, on);
++
++ ndev = ifp->ndev;
++ brcmf_txflowblock_if(ifp, BRCMF_NETIF_STOP_REASON_DISCONNECTED, !on);
++ if (on) {
++ if (!netif_carrier_ok(ndev))
++ netif_carrier_on(ndev);
++
++ } else {
++ if (netif_carrier_ok(ndev))
++ netif_carrier_off(ndev);
++ }
++}
++
+ static int brcmf_net_p2p_open(struct net_device *ndev)
+ {
+ brcmf_dbg(TRACE, "Enter\n");
+--- a/drivers/net/wireless/brcm80211/brcmfmac/core.h
++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.h
+@@ -154,10 +154,13 @@ struct brcmf_fws_mac_descriptor;
+ * netif stopped due to firmware signalling flow control.
+ * @BRCMF_NETIF_STOP_REASON_FLOW:
+ * netif stopped due to flowring full.
++ * @BRCMF_NETIF_STOP_REASON_DISCONNECTED:
++ * netif stopped due to not being connected (STA mode).
+ */
+ enum brcmf_netif_stop_reason {
+- BRCMF_NETIF_STOP_REASON_FWS_FC = 1,
+- BRCMF_NETIF_STOP_REASON_FLOW = 2
++ BRCMF_NETIF_STOP_REASON_FWS_FC = BIT(0),
++ BRCMF_NETIF_STOP_REASON_FLOW = BIT(1),
++ BRCMF_NETIF_STOP_REASON_DISCONNECTED = BIT(2)
+ };
+
+ /**
+@@ -213,5 +216,6 @@ void brcmf_txflowblock_if(struct brcmf_i
+ enum brcmf_netif_stop_reason reason, bool state);
+ void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success);
+ void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb);
++void brcmf_net_setcarrier(struct brcmf_if *ifp, bool on);
+
+ #endif /* BRCMFMAC_CORE_H */
--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c
-@@ -1229,6 +1229,7 @@ static int __init brcmfmac_module_init(v
+@@ -1236,6 +1236,7 @@ static int __init brcmfmac_module_init(v
#endif
if (!schedule_work(&brcmf_driver_work))
return -EBUSY;