--- /dev/null
+From b96a5398abb102cda75abb642b247a061e1b1358 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Date: Wed, 21 Sep 2016 07:42:32 +0200
+Subject: [PATCH] brcmfmac: fix memory leak in brcmf_fill_bss_param
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This function is called from get_station callback which means that every
+time user space was getting/dumping station(s) we were leaking 2 KiB.
+
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+Fixes: 1f0dc59a6de ("brcmfmac: rework .get_station() callback")
+Cc: stable@vger.kernel.org # 4.2+
+---
+Kalle, ideally this should go as 4.8 fix, but I'm aware it's quite late.
+If you are not planning to send another pull request, just get it for
+the next release and let's let stable guys backport it.
+---
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+@@ -2529,7 +2529,7 @@ static void brcmf_fill_bss_param(struct
+ WL_BSS_INFO_MAX);
+ if (err) {
+ brcmf_err("Failed to get bss info (%d)\n", err);
+- return;
++ goto out_kfree;
+ }
+ si->filled |= BIT(NL80211_STA_INFO_BSS_PARAM);
+ si->bss_param.beacon_interval = le16_to_cpu(buf->bss_le.beacon_period);
+@@ -2541,6 +2541,9 @@ static void brcmf_fill_bss_param(struct
+ si->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE;
+ if (capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
+ si->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME;
++
++out_kfree:
++ kfree(buf);
+ }
+
+ static s32
--- /dev/null
+From 9ef5e87962eb35d7e03809266b1a5a1aafd3c7d3 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Date: Fri, 23 Sep 2016 15:24:58 +0200
+Subject: [PATCH] brcmfmac: drop unused fields from struct brcmf_pub
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+They seem to be there from the first day. We calculate these values but
+never use them.
+
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+---
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c | 3 ---
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h | 4 ----
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c | 2 --
+ 3 files changed, 9 deletions(-)
+
+diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+index 65e8c87..27cd50a 100644
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+@@ -519,9 +519,6 @@ int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked)
+ ndev->needed_headroom += drvr->hdrlen;
+ ndev->ethtool_ops = &brcmf_ethtool_ops;
+
+- drvr->rxsz = ndev->mtu + ndev->hard_header_len +
+- drvr->hdrlen;
+-
+ /* set the mac address */
+ memcpy(ndev->dev_addr, ifp->mac_addr, ETH_ALEN);
+
+diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
+index 8fa34ca..f16cfc9 100644
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
+@@ -112,15 +112,11 @@ struct brcmf_pub {
+
+ /* Internal brcmf items */
+ uint hdrlen; /* Total BRCMF header length (proto + bus) */
+- uint rxsz; /* Rx buffer size bus module should use */
+
+ /* Dongle media info */
+ char fwver[BRCMF_DRIVER_FIRMWARE_VERSION_LEN];
+ u8 mac[ETH_ALEN]; /* MAC address obtained from dongle */
+
+- /* Multicast data packets sent to dongle */
+- unsigned long tx_multicast;
+-
+ struct mac_address addresses[BRCMF_MAX_IFS];
+
+ struct brcmf_if *iflist[BRCMF_MAX_IFS];
+diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
+index 9f9024a..a190f53 100644
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
+@@ -2104,8 +2104,6 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb)
+ if ((skb->priority == 0) || (skb->priority > 7))
+ skb->priority = cfg80211_classify8021d(skb, NULL);
+
+- drvr->tx_multicast += !!multicast;
+-
+ if (fws->avoid_queueing) {
+ rc = brcmf_proto_txdata(drvr, ifp->ifidx, 0, skb);
+ if (rc < 0)
+--
+2.9.3
+
--- /dev/null
+From 8931da16a3cb2e0646b1430a9fd94c0a6a5bfd41 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Date: Sat, 24 Sep 2016 22:06:31 +0200
+Subject: [PATCH 1/2] brcmfmac: initialize fws(ignal) for BCDC protocol only
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+There are two protocols used by Broadcom FullMAC devices: BCDC and
+msgbuf. They use different ways for (some part of) communication with
+the firmware. Firmware Signaling is required for the first one only
+(BCDC).
+
+So far we were always initializing fws and always calling it's skb
+processing function. It was fws that was passing skb processing to the
+protocol specific function. It was redundant for the msgbuf case.
+
+Simply taking few lines of code out of fws allows us to totally avoid
+using it. This simplifies code flow, saves some memory & will allow
+further optimizations like not compiling fwsignal.c.
+
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+---
+ .../wireless/broadcom/brcm80211/brcmfmac/core.c | 24 ++++++++++++++++------
+ .../broadcom/brcm80211/brcmfmac/fwsignal.c | 17 ++++++---------
+ .../broadcom/brcm80211/brcmfmac/fwsignal.h | 1 +
+ 3 files changed, 25 insertions(+), 17 deletions(-)
+
+diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+index 27cd50a..bc3d8ab 100644
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+@@ -250,7 +250,17 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb,
+ if (eh->h_proto == htons(ETH_P_PAE))
+ atomic_inc(&ifp->pend_8021x_cnt);
+
+- ret = brcmf_fws_process_skb(ifp, skb);
++ /* determine the priority */
++ if (skb->priority == 0 || skb->priority > 7)
++ skb->priority = cfg80211_classify8021d(skb, NULL);
++
++ if (drvr->fws && brcmf_fws_skbs_queueing(drvr->fws)) {
++ ret = brcmf_fws_process_skb(ifp, skb);
++ } else {
++ ret = brcmf_proto_txdata(drvr, ifp->ifidx, 0, skb);
++ if (ret < 0)
++ brcmf_txfinalize(ifp, skb, false);
++ }
+
+ done:
+ if (ret) {
+@@ -405,7 +415,7 @@ void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success)
+ struct brcmf_if *ifp;
+
+ /* await txstatus signal for firmware if active */
+- if (brcmf_fws_fc_active(drvr->fws)) {
++ if (drvr->fws && brcmf_fws_fc_active(drvr->fws)) {
+ if (!success)
+ brcmf_fws_bustxfail(drvr->fws, txp);
+ } else {
+@@ -1006,11 +1016,13 @@ int brcmf_bus_start(struct device *dev)
+ }
+ brcmf_feat_attach(drvr);
+
+- ret = brcmf_fws_init(drvr);
+- if (ret < 0)
+- goto fail;
++ if (bus_if->proto_type == BRCMF_PROTO_BCDC) {
++ ret = brcmf_fws_init(drvr);
++ if (ret < 0)
++ goto fail;
+
+- brcmf_fws_add_interface(ifp);
++ brcmf_fws_add_interface(ifp);
++ }
+
+ drvr->config = brcmf_cfg80211_attach(drvr, bus_if->dev,
+ drvr->settings->p2p_enable);
+diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
+index a190f53..495eaf8 100644
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
+@@ -2100,16 +2100,6 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb)
+ int rc = 0;
+
+ brcmf_dbg(DATA, "tx proto=0x%X\n", ntohs(eh->h_proto));
+- /* determine the priority */
+- if ((skb->priority == 0) || (skb->priority > 7))
+- skb->priority = cfg80211_classify8021d(skb, NULL);
+-
+- if (fws->avoid_queueing) {
+- rc = brcmf_proto_txdata(drvr, ifp->ifidx, 0, skb);
+- if (rc < 0)
+- brcmf_txfinalize(ifp, skb, false);
+- return rc;
+- }
+
+ /* set control buffer information */
+ skcb->if_flags = 0;
+@@ -2155,7 +2145,7 @@ void brcmf_fws_add_interface(struct brcmf_if *ifp)
+ struct brcmf_fws_info *fws = ifp->drvr->fws;
+ struct brcmf_fws_mac_descriptor *entry;
+
+- if (!ifp->ndev)
++ if (!fws || !ifp->ndev)
+ return;
+
+ entry = &fws->desc.iface[ifp->ifidx];
+@@ -2442,6 +2432,11 @@ void brcmf_fws_deinit(struct brcmf_pub *drvr)
+ kfree(fws);
+ }
+
++bool brcmf_fws_skbs_queueing(struct brcmf_fws_info *fws)
++{
++ return !fws->avoid_queueing;
++}
++
+ bool brcmf_fws_fc_active(struct brcmf_fws_info *fws)
+ {
+ if (!fws->creditmap_received)
+diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h
+index ef0ad85..8f7c1d7 100644
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h
+@@ -20,6 +20,7 @@
+
+ int brcmf_fws_init(struct brcmf_pub *drvr);
+ void brcmf_fws_deinit(struct brcmf_pub *drvr);
++bool brcmf_fws_skbs_queueing(struct brcmf_fws_info *fws);
+ bool brcmf_fws_fc_active(struct brcmf_fws_info *fws);
+ void brcmf_fws_hdrpull(struct brcmf_if *ifp, s16 siglen, struct sk_buff *skb);
+ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb);
+--
+2.9.3
+
--- /dev/null
+From 8708697ab5f203f095b551c5f4abd0d9517498ef Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Date: Sat, 24 Sep 2016 22:35:47 +0200
+Subject: [PATCH 2/2] brcmfmac: compile fws(ignal) code only with BCDC support
+ enabled
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+It's not needed by the other (msgbuf) protocol, so let's save some size
+and compile it conditionally.
+
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+---
+ .../wireless/broadcom/brcm80211/brcmfmac/Makefile | 4 +-
+ .../broadcom/brcm80211/brcmfmac/fwsignal.h | 59 ++++++++++++++++++++++
+ 2 files changed, 61 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile
+@@ -27,7 +27,6 @@ brcmfmac-objs += \
+ chip.o \
+ fwil.o \
+ fweh.o \
+- fwsignal.o \
+ p2p.o \
+ proto.o \
+ common.o \
+@@ -37,7 +36,8 @@ brcmfmac-objs += \
+ btcoex.o \
+ vendor.o
+ brcmfmac-$(CPTCFG_BRCMFMAC_PROTO_BCDC) += \
+- bcdc.o
++ bcdc.o \
++ fwsignal.o
+ brcmfmac-$(CPTCFG_BRCMFMAC_PROTO_MSGBUF) += \
+ commonring.o \
+ flowring.o \
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h
+@@ -18,6 +18,7 @@
+ #ifndef FWSIGNAL_H_
+ #define FWSIGNAL_H_
+
++#ifdef CPTCFG_BRCMFMAC_PROTO_BCDC
+ int brcmf_fws_init(struct brcmf_pub *drvr);
+ void brcmf_fws_deinit(struct brcmf_pub *drvr);
+ bool brcmf_fws_skbs_queueing(struct brcmf_fws_info *fws);
+@@ -31,5 +32,63 @@ void brcmf_fws_del_interface(struct brcm
+ void brcmf_fws_bustxfail(struct brcmf_fws_info *fws, struct sk_buff *skb);
+ void brcmf_fws_bus_blocked(struct brcmf_pub *drvr, bool flow_blocked);
+ void brcmf_fws_rxreorder(struct brcmf_if *ifp, struct sk_buff *skb);
++#else
++static inline int brcmf_fws_init(struct brcmf_pub *drvr)
++{
++ return -ENOTSUPP;
++}
++
++static inline void brcmf_fws_deinit(struct brcmf_pub *drvr)
++{
++}
++
++static inline bool brcmf_fws_skbs_queueing(struct brcmf_fws_info *fws)
++{
++ return false;
++}
++
++static inline bool brcmf_fws_fc_active(struct brcmf_fws_info *fws)
++{
++ return false;
++}
++
++static inline void brcmf_fws_hdrpull(struct brcmf_if *ifp, s16 siglen,
++ struct sk_buff *skb)
++{
++}
++
++static inline int brcmf_fws_process_skb(struct brcmf_if *ifp,
++ struct sk_buff *skb)
++{
++ return -ENOTSUPP;
++}
++
++static inline void brcmf_fws_reset_interface(struct brcmf_if *ifp)
++{
++}
++
++static inline void brcmf_fws_add_interface(struct brcmf_if *ifp)
++{
++}
++
++static inline void brcmf_fws_del_interface(struct brcmf_if *ifp)
++{
++}
++
++static inline void brcmf_fws_bustxfail(struct brcmf_fws_info *fws,
++ struct sk_buff *skb)
++{
++}
++
++static inline void brcmf_fws_bus_blocked(struct brcmf_pub *drvr,
++ bool flow_blocked)
++{
++}
++
++static inline void brcmf_fws_rxreorder(struct brcmf_if *ifp,
++ struct sk_buff *skb)
++{
++}
++#endif
+
+ #endif /* FWSIGNAL_H_ */
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
-@@ -1213,6 +1213,7 @@ int __init brcmf_core_init(void)
+@@ -1222,6 +1222,7 @@ int __init brcmf_core_init(void)
{
if (!schedule_work(&brcmf_driver_work))
return -EBUSY;
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
-@@ -2783,6 +2783,10 @@ brcmf_cfg80211_set_power_mgmt(struct wip
+@@ -2786,6 +2786,10 @@ brcmf_cfg80211_set_power_mgmt(struct wip
* preference in cfg struct to apply this to
* FW later while initializing the dongle
*/