mac80211: update brcmfmac to the latest version
authorrmilecki <rmilecki@3c298f89-4303-0410-b956-a3cf2f4a3e73>
Wed, 26 Aug 2015 22:57:54 +0000 (22:57 +0000)
committerrmilecki <rmilecki@3c298f89-4303-0410-b956-a3cf2f4a3e73>
Wed, 26 Aug 2015 22:57:54 +0000 (22:57 +0000)
This also adds one patchset of pending changes that fix support for
multiple interfaces. It was somehow broken.
Driver couldn't correctly match firmware and system interfaces resulting
in not working APs and WARNINGs.

Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
git-svn-id: svn://svn.openwrt.org/openwrt/branches/chaos_calmer@46736 3c298f89-4303-0410-b956-a3cf2f4a3e73

28 files changed:
package/kernel/mac80211/patches/389-0006-brcmfmac-free-ifp-for-non-netdev-interface-in-p2p-mo.patch [new file with mode: 0644]
package/kernel/mac80211/patches/389-0007-brcmfmac-move-p2p-attach-detach-functions.patch [new file with mode: 0644]
package/kernel/mac80211/patches/389-0008-brcmfmac-assure-p2pdev-is-unregistered-upon-driver-u.patch [new file with mode: 0644]
package/kernel/mac80211/patches/390-0001-brcmfmac-fix-double-free-of-p2pdev-interface.patch [new file with mode: 0644]
package/kernel/mac80211/patches/390-0002-brcmfmac-make-brcmf_p2p_detach-call-conditional.patch [new file with mode: 0644]
package/kernel/mac80211/patches/391-brcmfmac-set-wiphy-s-addresses-to-provide-valid-MACs.patch [new file with mode: 0644]
package/kernel/mac80211/patches/392-brcmfmac-dhd_sdio.c-use-existing-atomic_or-primitive.patch [new file with mode: 0644]
package/kernel/mac80211/patches/393-0001-brcmfmac-check-all-combinations-when-setting-wiphy-s.patch [new file with mode: 0644]
package/kernel/mac80211/patches/393-0002-brcmfmac-correct-interface-combination-info.patch [new file with mode: 0644]
package/kernel/mac80211/patches/393-0003-brcmfmac-add-debugfs-entry-for-msgbuf-statistics.patch [new file with mode: 0644]
package/kernel/mac80211/patches/393-0004-brcmfmac-make-use-of-cfg80211_check_combinations.patch [new file with mode: 0644]
package/kernel/mac80211/patches/393-0005-brcmfmac-block-the-correct-flowring-when-backup-queu.patch [new file with mode: 0644]
package/kernel/mac80211/patches/393-0006-brcmfmac-bump-highest-event-number-for-4339-firmware.patch [new file with mode: 0644]
package/kernel/mac80211/patches/394-0001-brcmfmac-consolidate-ifp-lookup-in-driver-core.patch [new file with mode: 0644]
package/kernel/mac80211/patches/394-0002-brcmfmac-make-brcmf_proto_hdrpull-return-struct-brcm.patch [new file with mode: 0644]
package/kernel/mac80211/patches/394-0003-brcmfmac-change-parameters-for-brcmf_remove_interfac.patch [new file with mode: 0644]
package/kernel/mac80211/patches/394-0004-brcmfmac-only-call-brcmf_cfg80211_detach-when-attach.patch [new file with mode: 0644]
package/kernel/mac80211/patches/394-0005-brcmfmac-correct-detection-of-p2pdev-interface-event.patch [new file with mode: 0644]
package/kernel/mac80211/patches/394-0006-brcmfmac-use-brcmf_get_ifp-to-map-ifidx-to-struct-br.patch [new file with mode: 0644]
package/kernel/mac80211/patches/394-0007-brcmfmac-pass-struct-brcmf_if-instance-in-brcmf_txfi.patch [new file with mode: 0644]
package/kernel/mac80211/patches/394-0008-brcmfmac-add-mapping-for-interface-index-to-bsscfg-i.patch [new file with mode: 0644]
package/kernel/mac80211/patches/394-0009-brcmfmac-add-dedicated-debug-level-for-firmware-cons.patch [new file with mode: 0644]
package/kernel/mac80211/patches/394-0010-brcmfmac-remove-ifidx-parameter-from-brcmf_fws_txsta.patch [new file with mode: 0644]
package/kernel/mac80211/patches/394-0011-brcmfmac-change-prototype-for-brcmf_fws_hdrpull.patch [new file with mode: 0644]
package/kernel/mac80211/patches/394-0012-brcmfmac-introduce-brcmf_net_detach-function.patch [new file with mode: 0644]
package/kernel/mac80211/patches/861-brcmfmac-register-wiphy-s-during-module_init.patch
package/kernel/mac80211/patches/862-brcmfmac-workaround-bug-with-some-inconsistent-BSSes.patch
package/kernel/mac80211/patches/863-brcmfmac-set-wiphy-s-addresses-to-provide-valid-MACs.patch [deleted file]

diff --git a/package/kernel/mac80211/patches/389-0006-brcmfmac-free-ifp-for-non-netdev-interface-in-p2p-mo.patch b/package/kernel/mac80211/patches/389-0006-brcmfmac-free-ifp-for-non-netdev-interface-in-p2p-mo.patch
new file mode 100644 (file)
index 0000000..06f2dce
--- /dev/null
@@ -0,0 +1,44 @@
+From: Arend van Spriel <arend@broadcom.com>
+Date: Thu, 11 Jun 2015 00:12:21 +0200
+Subject: [PATCH] brcmfmac: free ifp for non-netdev interface in p2p module
+
+Making it more clear by freeing the ifp in same place where the
+vif object is freed.
+
+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/brcmfmac/core.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c
+@@ -867,8 +867,6 @@ static void brcmf_del_if(struct brcmf_pu
+               }
+               /* unregister will take care of freeing it */
+               unregister_netdev(ifp->ndev);
+-      } else {
+-              kfree(ifp);
+       }
+ }
+--- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
+@@ -2238,6 +2238,7 @@ static void brcmf_p2p_delete_p2pdev(stru
+ {
+       cfg80211_unregister_wdev(&vif->wdev);
+       p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL;
++      kfree(vif->ifp);
+       brcmf_free_vif(vif);
+ }
+@@ -2361,6 +2362,8 @@ int brcmf_p2p_del_vif(struct wiphy *wiph
+               break;
+       case NL80211_IFTYPE_P2P_DEVICE:
++              brcmf_p2p_cancel_remain_on_channel(vif->ifp);
++              brcmf_p2p_deinit_discovery(p2p);
+               brcmf_p2p_delete_p2pdev(p2p, vif);
+               return 0;
+       default:
diff --git a/package/kernel/mac80211/patches/389-0007-brcmfmac-move-p2p-attach-detach-functions.patch b/package/kernel/mac80211/patches/389-0007-brcmfmac-move-p2p-attach-detach-functions.patch
new file mode 100644 (file)
index 0000000..0a6e093
--- /dev/null
@@ -0,0 +1,225 @@
+From: Arend van Spriel <arend@broadcom.com>
+Date: Thu, 11 Jun 2015 00:12:22 +0200
+Subject: [PATCH] brcmfmac: move p2p attach/detach functions
+
+Moving two functions in p2p.c as is so next change will be
+easier to review.
+
+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/brcmfmac/p2p.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
+@@ -1908,105 +1908,6 @@ s32 brcmf_p2p_notify_rx_mgmt_p2p_probere
+ /**
+- * brcmf_p2p_attach() - attach for P2P.
+- *
+- * @cfg: driver private data for cfg80211 interface.
+- */
+-s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg)
+-{
+-      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;
+-      s32 err = 0;
+-
+-      p2p = &cfg->p2p;
+-      p2p->cfg = cfg;
+-
+-      drvr = cfg->pub;
+-
+-      pri_ifp = drvr->iflist[0];
+-      p2p_ifp = drvr->iflist[1];
+-
+-      p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif = pri_ifp->vif;
+-
+-      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);
+-
+-              /* 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:
+-      return err;
+-}
+-
+-
+-/**
+- * brcmf_p2p_detach() - detach P2P.
+- *
+- * @p2p: P2P specific data.
+- */
+-void brcmf_p2p_detach(struct brcmf_p2p_info *p2p)
+-{
+-      struct brcmf_cfg80211_vif *vif;
+-
+-      vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
+-      if (vif != NULL) {
+-              brcmf_p2p_cancel_remain_on_channel(vif->ifp);
+-              brcmf_p2p_deinit_discovery(p2p);
+-              /* remove discovery interface */
+-              brcmf_free_vif(vif);
+-              p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL;
+-      }
+-      /* just set it all to zero */
+-      memset(p2p, 0, sizeof(*p2p));
+-}
+-
+-/**
+  * brcmf_p2p_get_current_chanspec() - Get current operation channel.
+  *
+  * @p2p: P2P specific data.
+@@ -2425,3 +2326,102 @@ void brcmf_p2p_stop_device(struct wiphy
+       clear_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state);
+       mutex_unlock(&cfg->usr_sync);
+ }
++
++/**
++ * brcmf_p2p_attach() - attach for P2P.
++ *
++ * @cfg: driver private data for cfg80211 interface.
++ */
++s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg)
++{
++      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;
++      s32 err = 0;
++
++      p2p = &cfg->p2p;
++      p2p->cfg = cfg;
++
++      drvr = cfg->pub;
++
++      pri_ifp = drvr->iflist[0];
++      p2p_ifp = drvr->iflist[1];
++
++      p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif = pri_ifp->vif;
++
++      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);
++
++              /* 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:
++      return err;
++}
++
++/**
++ * brcmf_p2p_detach() - detach P2P.
++ *
++ * @p2p: P2P specific data.
++ */
++void brcmf_p2p_detach(struct brcmf_p2p_info *p2p)
++{
++      struct brcmf_cfg80211_vif *vif;
++
++      vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
++      if (vif != NULL) {
++              brcmf_p2p_cancel_remain_on_channel(vif->ifp);
++              brcmf_p2p_deinit_discovery(p2p);
++              /* remove discovery interface */
++              brcmf_free_vif(vif);
++              p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL;
++      }
++      /* just set it all to zero */
++      memset(p2p, 0, sizeof(*p2p));
++}
++
diff --git a/package/kernel/mac80211/patches/389-0008-brcmfmac-assure-p2pdev-is-unregistered-upon-driver-u.patch b/package/kernel/mac80211/patches/389-0008-brcmfmac-assure-p2pdev-is-unregistered-upon-driver-u.patch
new file mode 100644 (file)
index 0000000..72e8eed
--- /dev/null
@@ -0,0 +1,63 @@
+From: Arend van Spriel <arend@broadcom.com>
+Date: Thu, 11 Jun 2015 00:12:23 +0200
+Subject: [PATCH] brcmfmac: assure p2pdev is unregistered upon driver
+ unload
+
+When unloading the driver with a p2pdev interface it resulted in
+a warning upon calling wiphy_unregister() and subsequently a crash
+in the driver. This patch assures the p2pdev is unregistered calling
+unregister_wdev() before doing the wiphy_unregister().
+
+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/brcmfmac/cfg80211.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
+@@ -6206,10 +6206,8 @@ void brcmf_cfg80211_detach(struct brcmf_
+       if (!cfg)
+               return;
+-      WARN_ON(!list_empty(&cfg->vif_list));
+-      wiphy_unregister(cfg->wiphy);
+       brcmf_btcoex_detach(cfg);
+-      brcmf_p2p_detach(&cfg->p2p);
++      wiphy_unregister(cfg->wiphy);
+       wl_deinit_priv(cfg);
+       brcmf_free_wiphy(cfg->wiphy);
+ }
+--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c
+@@ -1098,6 +1098,7 @@ void brcmf_detach(struct device *dev)
+       /* stop firmware event handling */
+       brcmf_fweh_detach(drvr);
++      brcmf_p2p_detach(&drvr->config->p2p);
+       brcmf_bus_change_state(bus_if, BRCMF_BUS_DOWN);
+--- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
+@@ -16,6 +16,7 @@
+ #include <linux/slab.h>
+ #include <linux/netdevice.h>
+ #include <linux/etherdevice.h>
++#include <linux/rtnetlink.h>
+ #include <net/cfg80211.h>
+ #include <brcmu_wifi.h>
+@@ -2418,8 +2419,9 @@ void brcmf_p2p_detach(struct brcmf_p2p_i
+               brcmf_p2p_cancel_remain_on_channel(vif->ifp);
+               brcmf_p2p_deinit_discovery(p2p);
+               /* remove discovery interface */
+-              brcmf_free_vif(vif);
+-              p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL;
++              rtnl_lock();
++              brcmf_p2p_delete_p2pdev(p2p, vif);
++              rtnl_unlock();
+       }
+       /* just set it all to zero */
+       memset(p2p, 0, sizeof(*p2p));
diff --git a/package/kernel/mac80211/patches/390-0001-brcmfmac-fix-double-free-of-p2pdev-interface.patch b/package/kernel/mac80211/patches/390-0001-brcmfmac-fix-double-free-of-p2pdev-interface.patch
new file mode 100644 (file)
index 0000000..179c77e
--- /dev/null
@@ -0,0 +1,27 @@
+From: Arend van Spriel <arend@broadcom.com>
+Date: Mon, 15 Jun 2015 22:48:38 +0200
+Subject: [PATCH] brcmfmac: fix double free of p2pdev interface
+
+When freeing the driver ifp pointer it should also be removed from
+the driver interface list, which is what brcmf_remove_interface()
+does. Otherwise, the ifp pointer will be freed twice triggering
+a kernel oops.
+
+Fixes: f37d69a4babc ("brcmfmac: free ifp for non-netdev interface in p2p module")
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+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/p2p.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
+@@ -2140,7 +2140,7 @@ static void brcmf_p2p_delete_p2pdev(stru
+ {
+       cfg80211_unregister_wdev(&vif->wdev);
+       p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL;
+-      kfree(vif->ifp);
++      brcmf_remove_interface(vif->ifp->drvr, vif->ifp->bssidx);
+       brcmf_free_vif(vif);
+ }
diff --git a/package/kernel/mac80211/patches/390-0002-brcmfmac-make-brcmf_p2p_detach-call-conditional.patch b/package/kernel/mac80211/patches/390-0002-brcmfmac-make-brcmf_p2p_detach-call-conditional.patch
new file mode 100644 (file)
index 0000000..e4f88b5
--- /dev/null
@@ -0,0 +1,29 @@
+From: Arend van Spriel <arend@broadcom.com>
+Date: Mon, 15 Jun 2015 22:48:39 +0200
+Subject: [PATCH] brcmfmac: make brcmf_p2p_detach() call conditional
+
+During verification of error handling in brcmf_cfg80211_attach() a
+null pointer dereference occurred upon calling brcmf_p2p_detach()
+from brcmf_detach(). This should only be called when the
+brcmf_cfg80211_attach() has succeeded.
+
+Fixes: f7a40873d2fa ("brcmfmac: assure p2pdev is unregistered upon driver unload")
+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/brcmfmac/core.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c
+@@ -1098,7 +1098,8 @@ void brcmf_detach(struct device *dev)
+       /* stop firmware event handling */
+       brcmf_fweh_detach(drvr);
+-      brcmf_p2p_detach(&drvr->config->p2p);
++      if (drvr->config)
++              brcmf_p2p_detach(&drvr->config->p2p);
+       brcmf_bus_change_state(bus_if, BRCMF_BUS_DOWN);
diff --git a/package/kernel/mac80211/patches/391-brcmfmac-set-wiphy-s-addresses-to-provide-valid-MACs.patch b/package/kernel/mac80211/patches/391-brcmfmac-set-wiphy-s-addresses-to-provide-valid-MACs.patch
new file mode 100644 (file)
index 0000000..0a81237
--- /dev/null
@@ -0,0 +1,67 @@
+From: Rafa? Mi?ecki <zajec5@gmail.com>
+Date: Thu, 9 Jul 2015 17:07:08 +0200
+Subject: [PATCH] brcmfmac: set wiphy's addresses to provide valid MACs
+
+Broadcom's firmware requires every BSS to use MAC address with unique
+last few bits. The amount of bits may depend on a particular firmware,
+it was verified to be 2 for BCM43602 one.
+If this condition won't be fulfilled firmware will reject such MAC:
+brcmfmac: _brcmf_set_mac_address: Setting cur_etheraddr failed, -52
+
+We don't want to simply set addr_mask as it would also disallow using
+locally administrated bit. Instead let's build a list of addresses
+manually enabling 0x2 bit for extra interfaces.
+
+Signed-off-by: Rafa? Mi?ecki <zajec5@gmail.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
+@@ -5784,6 +5784,7 @@ static void brcmf_wiphy_wowl_params(stru
+ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
+ {
++      struct brcmf_pub *drvr = ifp->drvr;
+       struct ieee80211_supported_band *band;
+       __le32 bandlist[3];
+       u32 n_bands;
+@@ -5797,6 +5798,19 @@ static int brcmf_setup_wiphy(struct wiph
+       if (err)
+               return err;
++      for (i = 0; i < wiphy->iface_combinations->max_interfaces &&
++           i < ARRAY_SIZE(drvr->addresses); i++) {
++              u8 *addr = drvr->addresses[i].addr;
++
++              memcpy(addr, drvr->mac, ETH_ALEN);
++              if (i) {
++                      addr[0] |= BIT(1);
++                      addr[ETH_ALEN - 1] ^= i;
++              }
++      }
++      wiphy->addresses = drvr->addresses;
++      wiphy->n_addresses = i;
++
+       wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+       wiphy->cipher_suites = __wl_cipher_suites;
+       wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
+--- a/drivers/net/wireless/brcm80211/brcmfmac/core.h
++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.h
+@@ -21,6 +21,7 @@
+ #ifndef BRCMFMAC_CORE_H
+ #define BRCMFMAC_CORE_H
++#include <net/cfg80211.h>
+ #include "fweh.h"
+ #define TOE_TX_CSUM_OL                0x00000001
+@@ -118,6 +119,8 @@ struct brcmf_pub {
+       /* Multicast data packets sent to dongle */
+       unsigned long tx_multicast;
++      struct mac_address addresses[BRCMF_MAX_IFS];
++
+       struct brcmf_if *iflist[BRCMF_MAX_IFS];
+       struct mutex proto_block;
diff --git a/package/kernel/mac80211/patches/392-brcmfmac-dhd_sdio.c-use-existing-atomic_or-primitive.patch b/package/kernel/mac80211/patches/392-brcmfmac-dhd_sdio.c-use-existing-atomic_or-primitive.patch
new file mode 100644 (file)
index 0000000..e44f121
--- /dev/null
@@ -0,0 +1,45 @@
+From: Vineet Gupta <Vineet.Gupta1@synopsys.com>
+Date: Thu, 9 Jul 2015 13:43:18 +0530
+Subject: [PATCH] brcmfmac: dhd_sdio.c: use existing atomic_or primitive
+
+There's already a generic implementation so use that instead.
+
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
+@@ -2564,15 +2564,6 @@ static inline void brcmf_sdio_clrintr(st
+       }
+ }
+-static void atomic_orr(int val, atomic_t *v)
+-{
+-      int old_val;
+-
+-      old_val = atomic_read(v);
+-      while (atomic_cmpxchg(v, old_val, val | old_val) != old_val)
+-              old_val = atomic_read(v);
+-}
+-
+ static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus)
+ {
+       struct brcmf_core *buscore;
+@@ -2595,7 +2586,7 @@ static int brcmf_sdio_intr_rstatus(struc
+       if (val) {
+               brcmf_sdiod_regwl(bus->sdiodev, addr, val, &ret);
+               bus->sdcnt.f1regdata++;
+-              atomic_orr(val, &bus->intstatus);
++              atomic_or(val, &bus->intstatus);
+       }
+       return ret;
+@@ -2712,7 +2703,7 @@ static void brcmf_sdio_dpc(struct brcmf_
+       /* Keep still-pending events for next scheduling */
+       if (intstatus)
+-              atomic_orr(intstatus, &bus->intstatus);
++              atomic_or(intstatus, &bus->intstatus);
+       brcmf_sdio_clrintr(bus);
diff --git a/package/kernel/mac80211/patches/393-0001-brcmfmac-check-all-combinations-when-setting-wiphy-s.patch b/package/kernel/mac80211/patches/393-0001-brcmfmac-check-all-combinations-when-setting-wiphy-s.patch
new file mode 100644 (file)
index 0000000..76ca143
--- /dev/null
@@ -0,0 +1,46 @@
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Thu, 20 Aug 2015 00:16:42 +0200
+Subject: [PATCH] brcmfmac: check all combinations when setting wiphy's
+ addresses
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Broadcom is working on better reflection of interface combinations. With
+upcoming patches we may have 1st combination supporting less interfaces
+than others.
+To don't run out of addresses check all combinations to find the one
+with the greatest max_interfaces value.
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.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
+@@ -5785,7 +5785,9 @@ static void brcmf_wiphy_wowl_params(stru
+ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
+ {
+       struct brcmf_pub *drvr = ifp->drvr;
++      const struct ieee80211_iface_combination *combo;
+       struct ieee80211_supported_band *band;
++      u16 max_interfaces = 0;
+       __le32 bandlist[3];
+       u32 n_bands;
+       int err, i;
+@@ -5798,8 +5800,13 @@ static int brcmf_setup_wiphy(struct wiph
+       if (err)
+               return err;
+-      for (i = 0; i < wiphy->iface_combinations->max_interfaces &&
+-           i < ARRAY_SIZE(drvr->addresses); i++) {
++      for (i = 0, combo = wiphy->iface_combinations;
++           i < wiphy->n_iface_combinations; i++, combo++) {
++              max_interfaces = max(max_interfaces, combo->max_interfaces);
++      }
++
++      for (i = 0; i < max_interfaces && i < ARRAY_SIZE(drvr->addresses);
++           i++) {
+               u8 *addr = drvr->addresses[i].addr;
+               memcpy(addr, drvr->mac, ETH_ALEN);
diff --git a/package/kernel/mac80211/patches/393-0002-brcmfmac-correct-interface-combination-info.patch b/package/kernel/mac80211/patches/393-0002-brcmfmac-correct-interface-combination-info.patch
new file mode 100644 (file)
index 0000000..c4a0720
--- /dev/null
@@ -0,0 +1,204 @@
+From: Arend van Spriel <arend@broadcom.com>
+Date: Thu, 20 Aug 2015 22:06:03 +0200
+Subject: [PATCH] brcmfmac: correct interface combination info
+
+The interface combination provided by brcmfmac did not truly reflect
+the combinations supported by driver and/or firmware.
+
+Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
+Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+Reviewed-by: Pontus Fuchs <pontusf@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
+@@ -5694,63 +5694,132 @@ brcmf_txrx_stypes[NUM_NL80211_IFTYPES] =
+       }
+ };
++/**
++ * brcmf_setup_ifmodes() - determine interface modes and combinations.
++ *
++ * @wiphy: wiphy object.
++ * @ifp: interface object needed for feat module api.
++ *
++ * The interface modes and combinations are determined dynamically here
++ * based on firmware functionality.
++ *
++ * no p2p and no mbss:
++ *
++ *    #STA <= 1, #AP <= 1, channels = 1, 2 total
++ *
++ * no p2p and mbss:
++ *
++ *    #STA <= 1, #AP <= 1, channels = 1, 2 total
++ *    #AP <= 4, matching BI, channels = 1, 4 total
++ *
++ * p2p, no mchan, and mbss:
++ *
++ *    #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 1, 3 total
++ *    #STA <= 1, #P2P-DEV <= 1, #AP <= 1, #P2P-CL <= 1, channels = 1, 4 total
++ *    #AP <= 4, matching BI, channels = 1, 4 total
++ *
++ * p2p, mchan, and mbss:
++ *
++ *    #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 2, 3 total
++ *    #STA <= 1, #P2P-DEV <= 1, #AP <= 1, #P2P-CL <= 1, channels = 1, 4 total
++ *    #AP <= 4, matching BI, channels = 1, 4 total
++ */
+ static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp)
+ {
+       struct ieee80211_iface_combination *combo = NULL;
+-      struct ieee80211_iface_limit *limits = NULL;
+-      int i = 0, max_iface_cnt;
++      struct ieee80211_iface_limit *c0_limits = NULL;
++      struct ieee80211_iface_limit *p2p_limits = NULL;
++      struct ieee80211_iface_limit *mbss_limits = NULL;
++      bool mbss, p2p;
++      int i, c, n_combos;
+-      combo = kzalloc(sizeof(*combo), GFP_KERNEL);
++      mbss = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS);
++      p2p = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_P2P);
++
++      n_combos = 1 + !!p2p + !!mbss;
++      combo = kcalloc(n_combos, sizeof(*combo), GFP_KERNEL);
+       if (!combo)
+               goto err;
+-      limits = kzalloc(sizeof(*limits) * 4, GFP_KERNEL);
+-      if (!limits)
++      c0_limits = kcalloc(p2p ? 3 : 2, sizeof(*c0_limits), GFP_KERNEL);
++      if (!c0_limits)
+               goto err;
++      if (p2p) {
++              p2p_limits = kcalloc(4, sizeof(*p2p_limits), GFP_KERNEL);
++              if (!p2p_limits)
++                      goto err;
++      }
++
++      if (mbss) {
++              mbss_limits = kcalloc(1, sizeof(*mbss_limits), GFP_KERNEL);
++              if (!mbss_limits)
++                      goto err;
++      }
++
+       wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+                                BIT(NL80211_IFTYPE_ADHOC) |
+                                BIT(NL80211_IFTYPE_AP);
+-      if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN))
+-              combo->num_different_channels = 2;
+-      else
+-              combo->num_different_channels = 1;
+-
+-      if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) {
+-              limits[i].max = 1;
+-              limits[i++].types = BIT(NL80211_IFTYPE_STATION);
+-              limits[i].max = 4;
+-              limits[i++].types = BIT(NL80211_IFTYPE_AP);
+-              max_iface_cnt = 5;
+-      } else {
+-              limits[i].max = 2;
+-              limits[i++].types = BIT(NL80211_IFTYPE_STATION) |
+-                                  BIT(NL80211_IFTYPE_AP);
+-              max_iface_cnt = 2;
+-      }
+-
+-      if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_P2P)) {
++      c = 0;
++      i = 0;
++      combo[c].num_different_channels = 1;
++      c0_limits[i].max = 1;
++      c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
++      if (p2p) {
++              if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN))
++                      combo[c].num_different_channels = 2;
+               wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_CLIENT) |
+                                         BIT(NL80211_IFTYPE_P2P_GO) |
+                                         BIT(NL80211_IFTYPE_P2P_DEVICE);
+-              limits[i].max = 1;
+-              limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
+-                                  BIT(NL80211_IFTYPE_P2P_GO);
+-              limits[i].max = 1;
+-              limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
+-              max_iface_cnt += 2;
+-      }
+-      combo->max_interfaces = max_iface_cnt;
+-      combo->limits = limits;
+-      combo->n_limits = i;
++              c0_limits[i].max = 1;
++              c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
++              c0_limits[i].max = 1;
++              c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
++                                     BIT(NL80211_IFTYPE_P2P_GO);
++      } else {
++              c0_limits[i].max = 1;
++              c0_limits[i++].types = BIT(NL80211_IFTYPE_AP);
++      }
++      combo[c].max_interfaces = i;
++      combo[c].n_limits = i;
++      combo[c].limits = c0_limits;
++
++      if (p2p) {
++              c++;
++              i = 0;
++              combo[c].num_different_channels = 1;
++              p2p_limits[i].max = 1;
++              p2p_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
++              p2p_limits[i].max = 1;
++              p2p_limits[i++].types = BIT(NL80211_IFTYPE_AP);
++              p2p_limits[i].max = 1;
++              p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT);
++              p2p_limits[i].max = 1;
++              p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
++              combo[c].max_interfaces = i;
++              combo[c].n_limits = i;
++              combo[c].limits = p2p_limits;
++      }
++      if (mbss) {
++              c++;
++              combo[c].beacon_int_infra_match = true;
++              combo[c].num_different_channels = 1;
++              mbss_limits[0].max = 4;
++              mbss_limits[0].types = BIT(NL80211_IFTYPE_AP);
++              combo[c].max_interfaces = 4;
++              combo[c].n_limits = 1;
++              combo[c].limits = mbss_limits;
++      }
++      wiphy->n_iface_combinations = n_combos;
+       wiphy->iface_combinations = combo;
+-      wiphy->n_iface_combinations = 1;
+       return 0;
+ err:
+-      kfree(limits);
++      kfree(c0_limits);
++      kfree(p2p_limits);
++      kfree(mbss_limits);
+       kfree(combo);
+       return -ENOMEM;
+ }
+@@ -6079,11 +6148,15 @@ static void brcmf_cfg80211_reg_notifier(
+ static void brcmf_free_wiphy(struct wiphy *wiphy)
+ {
++      int i;
++
+       if (!wiphy)
+               return;
+-      if (wiphy->iface_combinations)
+-              kfree(wiphy->iface_combinations->limits);
++      if (wiphy->iface_combinations) {
++              for (i = 0; i < wiphy->n_iface_combinations; i++)
++                      kfree(wiphy->iface_combinations[i].limits);
++      }
+       kfree(wiphy->iface_combinations);
+       if (wiphy->bands[IEEE80211_BAND_2GHZ]) {
+               kfree(wiphy->bands[IEEE80211_BAND_2GHZ]->channels);
diff --git a/package/kernel/mac80211/patches/393-0003-brcmfmac-add-debugfs-entry-for-msgbuf-statistics.patch b/package/kernel/mac80211/patches/393-0003-brcmfmac-add-debugfs-entry-for-msgbuf-statistics.patch
new file mode 100644 (file)
index 0000000..9768ef2
--- /dev/null
@@ -0,0 +1,87 @@
+From: Franky Lin <frankyl@broadcom.com>
+Date: Thu, 20 Aug 2015 22:06:04 +0200
+Subject: [PATCH] brcmfmac: add debugfs entry for msgbuf statistics
+
+Expose ring buffer read/write pointers and other useful statistics
+through debugfs.
+
+Reviewed-by: Arend Van Spriel <arend@broadcom.com>
+Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@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/msgbuf.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
+@@ -1360,6 +1360,60 @@ void brcmf_msgbuf_delete_flowring(struct
+       }
+ }
++#ifdef DEBUG
++static int brcmf_msgbuf_stats_read(struct seq_file *seq, void *data)
++{
++      struct brcmf_bus *bus_if = dev_get_drvdata(seq->private);
++      struct brcmf_pub *drvr = bus_if->drvr;
++      struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd;
++      struct brcmf_commonring *commonring;
++      u16 i;
++      struct brcmf_flowring_ring *ring;
++      struct brcmf_flowring_hash *hash;
++
++      commonring = msgbuf->commonrings[BRCMF_H2D_MSGRING_CONTROL_SUBMIT];
++      seq_printf(seq, "h2d_ctl_submit: rp %4u, wp %4u, depth %4u\n",
++                 commonring->r_ptr, commonring->w_ptr, commonring->depth);
++      commonring = msgbuf->commonrings[BRCMF_H2D_MSGRING_RXPOST_SUBMIT];
++      seq_printf(seq, "h2d_rx_submit:  rp %4u, wp %4u, depth %4u\n",
++                 commonring->r_ptr, commonring->w_ptr, commonring->depth);
++      commonring = msgbuf->commonrings[BRCMF_D2H_MSGRING_CONTROL_COMPLETE];
++      seq_printf(seq, "d2h_ctl_cmplt:  rp %4u, wp %4u, depth %4u\n",
++                 commonring->r_ptr, commonring->w_ptr, commonring->depth);
++      commonring = msgbuf->commonrings[BRCMF_D2H_MSGRING_TX_COMPLETE];
++      seq_printf(seq, "d2h_tx_cmplt:   rp %4u, wp %4u, depth %4u\n",
++                 commonring->r_ptr, commonring->w_ptr, commonring->depth);
++      commonring = msgbuf->commonrings[BRCMF_D2H_MSGRING_RX_COMPLETE];
++      seq_printf(seq, "d2h_rx_cmplt:   rp %4u, wp %4u, depth %4u\n",
++                 commonring->r_ptr, commonring->w_ptr, commonring->depth);
++
++      seq_printf(seq, "\nh2d_flowrings: depth %u\n",
++                 BRCMF_H2D_TXFLOWRING_MAX_ITEM);
++      seq_puts(seq, "Active flowrings:\n");
++      hash = msgbuf->flow->hash;
++      for (i = 0; i < msgbuf->flow->nrofrings; i++) {
++              if (!msgbuf->flow->rings[i])
++                      continue;
++              ring = msgbuf->flow->rings[i];
++              if (ring->status != RING_OPEN)
++                      continue;
++              commonring = msgbuf->flowrings[i];
++              hash = &msgbuf->flow->hash[ring->hash_id];
++              seq_printf(seq, "id %3u: rp %4u, wp %4u, qlen %4u, blocked %u\n"
++                              "        ifidx %u, fifo %u, da %pM\n",
++                              i, commonring->r_ptr, commonring->w_ptr,
++                              skb_queue_len(&ring->skblist), ring->blocked,
++                              hash->ifidx, hash->fifo, hash->mac);
++      }
++
++      return 0;
++}
++#else
++static int brcmf_msgbuf_stats_read(struct seq_file *seq, void *data)
++{
++      return 0;
++}
++#endif
+ int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr)
+ {
+@@ -1460,6 +1514,8 @@ int brcmf_proto_msgbuf_attach(struct brc
+       spin_lock_init(&msgbuf->flowring_work_lock);
+       INIT_LIST_HEAD(&msgbuf->work_queue);
++      brcmf_debugfs_add_entry(drvr, "msgbuf_stats", brcmf_msgbuf_stats_read);
++
+       return 0;
+ fail:
diff --git a/package/kernel/mac80211/patches/393-0004-brcmfmac-make-use-of-cfg80211_check_combinations.patch b/package/kernel/mac80211/patches/393-0004-brcmfmac-make-use-of-cfg80211_check_combinations.patch
new file mode 100644 (file)
index 0000000..2b84cf9
--- /dev/null
@@ -0,0 +1,83 @@
+From: Arend van Spriel <arend@broadcom.com>
+Date: Thu, 20 Aug 2015 22:06:05 +0200
+Subject: [PATCH] brcmfmac: make use of cfg80211_check_combinations()
+
+Use cfg80211_check_combinations() so we can bail out early when an
+interface add or change results in an invalid combination.
+
+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/brcmfmac/cfg80211.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
+@@ -469,6 +469,36 @@ brcmf_find_wpsie(const u8 *parse, u32 le
+       return NULL;
+ }
++static int brcmf_vif_change_validate(struct brcmf_cfg80211_info *cfg,
++                                   struct brcmf_cfg80211_vif *vif,
++                                   enum nl80211_iftype new_type)
++{
++      int iftype_num[NUM_NL80211_IFTYPES];
++      struct brcmf_cfg80211_vif *pos;
++
++      memset(&iftype_num[0], 0, sizeof(iftype_num));
++      list_for_each_entry(pos, &cfg->vif_list, list)
++              if (pos == vif)
++                      iftype_num[new_type]++;
++              else
++                      iftype_num[pos->wdev.iftype]++;
++
++      return cfg80211_check_combinations(cfg->wiphy, 1, 0, iftype_num);
++}
++
++static int brcmf_vif_add_validate(struct brcmf_cfg80211_info *cfg,
++                                enum nl80211_iftype new_type)
++{
++      int iftype_num[NUM_NL80211_IFTYPES];
++      struct brcmf_cfg80211_vif *pos;
++
++      memset(&iftype_num[0], 0, sizeof(iftype_num));
++      list_for_each_entry(pos, &cfg->vif_list, list)
++              iftype_num[pos->wdev.iftype]++;
++
++      iftype_num[new_type]++;
++      return cfg80211_check_combinations(cfg->wiphy, 1, 0, iftype_num);
++}
+ static void convert_key_from_CPU(struct brcmf_wsec_key *key,
+                                struct brcmf_wsec_key_le *key_le)
+@@ -662,8 +692,14 @@ static struct wireless_dev *brcmf_cfg802
+                                                    struct vif_params *params)
+ {
+       struct wireless_dev *wdev;
++      int err;
+       brcmf_dbg(TRACE, "enter: %s type %d\n", name, type);
++      err = brcmf_vif_add_validate(wiphy_to_cfg(wiphy), type);
++      if (err) {
++              brcmf_err("iface validation failed: err=%d\n", err);
++              return ERR_PTR(err);
++      }
+       switch (type) {
+       case NL80211_IFTYPE_ADHOC:
+       case NL80211_IFTYPE_STATION:
+@@ -822,8 +858,12 @@ brcmf_cfg80211_change_iface(struct wiphy
+       s32 ap = 0;
+       s32 err = 0;
+-      brcmf_dbg(TRACE, "Enter, ndev=%p, type=%d\n", ndev, type);
+-
++      brcmf_dbg(TRACE, "Enter, idx=%d, type=%d\n", ifp->bssidx, type);
++      err = brcmf_vif_change_validate(wiphy_to_cfg(wiphy), vif, type);
++      if (err) {
++              brcmf_err("iface validation failed: err=%d\n", err);
++              return err;
++      }
+       switch (type) {
+       case NL80211_IFTYPE_MONITOR:
+       case NL80211_IFTYPE_WDS:
diff --git a/package/kernel/mac80211/patches/393-0005-brcmfmac-block-the-correct-flowring-when-backup-queu.patch b/package/kernel/mac80211/patches/393-0005-brcmfmac-block-the-correct-flowring-when-backup-queu.patch
new file mode 100644 (file)
index 0000000..2d5f7b9
--- /dev/null
@@ -0,0 +1,48 @@
+From: Franky Lin <frankyl@broadcom.com>
+Date: Thu, 20 Aug 2015 22:06:06 +0200
+Subject: [PATCH] brcmfmac: block the correct flowring when backup queue
+ overflow
+
+brcmf_flowring_block blocks the last active flowring under the same
+interface instead of the one provided by caller. This could lead to a
+dead lock of netif stop if there are more than one flowring under the
+interface and the traffic is high enough so brcmf_flowring_enqueue can
+not unblock the ring right away.
+
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@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/flowring.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/flowring.c
+@@ -194,11 +194,15 @@ static void brcmf_flowring_block(struct
+       spin_lock_irqsave(&flow->block_lock, flags);
+       ring = flow->rings[flowid];
++      if (ring->blocked == blocked) {
++              spin_unlock_irqrestore(&flow->block_lock, flags);
++              return;
++      }
+       ifidx = brcmf_flowring_ifidx_get(flow, flowid);
+       currently_blocked = false;
+       for (i = 0; i < flow->nrofrings; i++) {
+-              if (flow->rings[i]) {
++              if ((flow->rings[i]) && (i != flowid)) {
+                       ring = flow->rings[i];
+                       if ((ring->status == RING_OPEN) &&
+                           (brcmf_flowring_ifidx_get(flow, i) == ifidx)) {
+@@ -209,8 +213,8 @@ static void brcmf_flowring_block(struct
+                       }
+               }
+       }
+-      ring->blocked = blocked;
+-      if (currently_blocked == blocked) {
++      flow->rings[flowid]->blocked = blocked;
++      if (currently_blocked) {
+               spin_unlock_irqrestore(&flow->block_lock, flags);
+               return;
+       }
diff --git a/package/kernel/mac80211/patches/393-0006-brcmfmac-bump-highest-event-number-for-4339-firmware.patch b/package/kernel/mac80211/patches/393-0006-brcmfmac-bump-highest-event-number-for-4339-firmware.patch
new file mode 100644 (file)
index 0000000..7378401
--- /dev/null
@@ -0,0 +1,52 @@
+From: Arend van Spriel <arend@broadcom.com>
+Date: Thu, 20 Aug 2015 22:06:07 +0200
+Subject: [PATCH] brcmfmac: bump highest event number for 4339 firmware
+
+The event mask length is determined by the highest event number
+that is specified in the driver. When this length is shorter than
+firmware expects setting event mask will fail and device becomes
+pretty useless. This issue was reported with bcm4339 firmware that
+was recently released.
+
+Reported-by: Pontus Fuchs <pontusf@broadcom.com>
+Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
+Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+Reviewed-by: Pontus Fuchs <pontusf@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/fweh.h
++++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.h
+@@ -85,7 +85,6 @@ struct brcmf_event;
+       BRCMF_ENUM_DEF(IF, 54) \
+       BRCMF_ENUM_DEF(P2P_DISC_LISTEN_COMPLETE, 55) \
+       BRCMF_ENUM_DEF(RSSI, 56) \
+-      BRCMF_ENUM_DEF(PFN_SCAN_COMPLETE, 57) \
+       BRCMF_ENUM_DEF(EXTLOG_MSG, 58) \
+       BRCMF_ENUM_DEF(ACTION_FRAME, 59) \
+       BRCMF_ENUM_DEF(ACTION_FRAME_COMPLETE, 60) \
+@@ -103,8 +102,7 @@ struct brcmf_event;
+       BRCMF_ENUM_DEF(FIFO_CREDIT_MAP, 74) \
+       BRCMF_ENUM_DEF(ACTION_FRAME_RX, 75) \
+       BRCMF_ENUM_DEF(TDLS_PEER_EVENT, 92) \
+-      BRCMF_ENUM_DEF(BCMC_CREDIT_SUPPORT, 127) \
+-      BRCMF_ENUM_DEF(PSTA_PRIMARY_INTF_IND, 128)
++      BRCMF_ENUM_DEF(BCMC_CREDIT_SUPPORT, 127)
+ #define BRCMF_ENUM_DEF(id, val) \
+       BRCMF_E_##id = (val),
+@@ -112,7 +110,11 @@ struct brcmf_event;
+ /* firmware event codes sent by the dongle */
+ enum brcmf_fweh_event_code {
+       BRCMF_FWEH_EVENT_ENUM_DEFLIST
+-      BRCMF_E_LAST
++      /* this determines event mask length which must match
++       * minimum length check in device firmware so it is
++       * hard-coded here.
++       */
++      BRCMF_E_LAST = 139
+ };
+ #undef BRCMF_ENUM_DEF
diff --git a/package/kernel/mac80211/patches/394-0001-brcmfmac-consolidate-ifp-lookup-in-driver-core.patch b/package/kernel/mac80211/patches/394-0001-brcmfmac-consolidate-ifp-lookup-in-driver-core.patch
new file mode 100644 (file)
index 0000000..97444b3
--- /dev/null
@@ -0,0 +1,138 @@
+From: Arend van Spriel <arend@broadcom.com>
+Date: Wed, 26 Aug 2015 22:14:53 +0200
+Subject: [PATCH] brcmfmac: consolidate ifp lookup in driver core
+
+In rx path the firmware provide an interface index which is used to
+map to a struct brcmf_if instance. However, this involves some trick
+that is done in two places. This is changed by having driver core
+providing brcmf_get_ifp() function.
+
+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>
+---
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c
+@@ -276,6 +276,7 @@ brcmf_proto_bcdc_hdrpull(struct brcmf_pu
+                        struct sk_buff *pktbuf)
+ {
+       struct brcmf_proto_bcdc_header *h;
++      struct brcmf_if *ifp;
+       brcmf_dbg(BCDC, "Enter\n");
+@@ -289,30 +290,21 @@ brcmf_proto_bcdc_hdrpull(struct brcmf_pu
+       trace_brcmf_bcdchdr(pktbuf->data);
+       h = (struct brcmf_proto_bcdc_header *)(pktbuf->data);
+-      *ifidx = BCDC_GET_IF_IDX(h);
+-      if (*ifidx >= BRCMF_MAX_IFS) {
+-              brcmf_err("rx data ifnum out of range (%d)\n", *ifidx);
++      ifp = brcmf_get_ifp(drvr, BCDC_GET_IF_IDX(h));
++      if (IS_ERR_OR_NULL(ifp)) {
++              brcmf_dbg(INFO, "no matching ifp found\n");
+               return -EBADE;
+       }
+-      /* The ifidx is the idx to map to matching netdev/ifp. When receiving
+-       * events this is easy because it contains the bssidx which maps
+-       * 1-on-1 to the netdev/ifp. But for data frames the ifidx is rcvd.
+-       * bssidx 1 is used for p2p0 and no data can be received or
+-       * transmitted on it. Therefor bssidx is ifidx + 1 if ifidx > 0
+-       */
+-      if (*ifidx)
+-              (*ifidx)++;
+-
+       if (((h->flags & BCDC_FLAG_VER_MASK) >> BCDC_FLAG_VER_SHIFT) !=
+           BCDC_PROTO_VER) {
+               brcmf_err("%s: non-BCDC packet received, flags 0x%x\n",
+-                        brcmf_ifname(drvr, *ifidx), h->flags);
++                        brcmf_ifname(drvr, ifp->ifidx), h->flags);
+               return -EBADE;
+       }
+       if (h->flags & BCDC_FLAG_SUM_GOOD) {
+               brcmf_dbg(BCDC, "%s: BDC rcv, good checksum, flags 0x%x\n",
+-                        brcmf_ifname(drvr, *ifidx), h->flags);
++                        brcmf_ifname(drvr, ifp->ifidx), h->flags);
+               pktbuf->ip_summed = CHECKSUM_UNNECESSARY;
+       }
+@@ -320,12 +312,15 @@ brcmf_proto_bcdc_hdrpull(struct brcmf_pu
+       skb_pull(pktbuf, BCDC_HEADER_LEN);
+       if (do_fws)
+-              brcmf_fws_hdrpull(drvr, *ifidx, h->data_offset << 2, pktbuf);
++              brcmf_fws_hdrpull(drvr, ifp->ifidx, h->data_offset << 2,
++                                pktbuf);
+       else
+               skb_pull(pktbuf, h->data_offset << 2);
+       if (pktbuf->len == 0)
+               return -ENODATA;
++
++      *ifidx = ifp->ifidx;
+       return 0;
+ }
+--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c
+@@ -83,6 +83,25 @@ char *brcmf_ifname(struct brcmf_pub *drv
+       return "<if_none>";
+ }
++struct brcmf_if *brcmf_get_ifp(struct brcmf_pub *drvr, int ifidx)
++{
++      if (ifidx < 0 || ifidx >= BRCMF_MAX_IFS) {
++              brcmf_err("ifidx %d out of range\n", ifidx);
++              return ERR_PTR(-ERANGE);
++      }
++
++      /* The ifidx is the idx to map to matching netdev/ifp. When receiving
++       * events this is easy because it contains the bssidx which maps
++       * 1-on-1 to the netdev/ifp. But for data frames the ifidx is rcvd.
++       * bssidx 1 is used for p2p0 and no data can be received or
++       * transmitted on it. Therefor bssidx is ifidx + 1 if ifidx > 0
++       */
++      if (ifidx)
++              ifidx++;
++
++      return drvr->iflist[ifidx];
++}
++
+ static void _brcmf_set_multicast_list(struct work_struct *work)
+ {
+       struct brcmf_if *ifp;
+--- a/drivers/net/wireless/brcm80211/brcmfmac/core.h
++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.h
+@@ -202,7 +202,7 @@ int brcmf_netdev_wait_pend8021x(struct b
+ /* Return pointer to interface name */
+ char *brcmf_ifname(struct brcmf_pub *drvr, int idx);
+-
++struct brcmf_if *brcmf_get_ifp(struct brcmf_pub *drvr, int ifidx);
+ int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked);
+ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx,
+                             char *name, u8 *mac_addr);
+--- a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
+@@ -1081,16 +1081,8 @@ brcmf_msgbuf_rx_skb(struct brcmf_msgbuf
+ {
+       struct brcmf_if *ifp;
+-      /* The ifidx is the idx to map to matching netdev/ifp. When receiving
+-       * events this is easy because it contains the bssidx which maps
+-       * 1-on-1 to the netdev/ifp. But for data frames the ifidx is rcvd.
+-       * bssidx 1 is used for p2p0 and no data can be received or
+-       * transmitted on it. Therefor bssidx is ifidx + 1 if ifidx > 0
+-       */
+-      if (ifidx)
+-              (ifidx)++;
+-      ifp = msgbuf->drvr->iflist[ifidx];
+-      if (!ifp || !ifp->ndev) {
++      ifp = brcmf_get_ifp(msgbuf->drvr, ifidx);
++      if (IS_ERR_OR_NULL(ifp) || !ifp->ndev) {
+               brcmf_err("Received pkt for invalid ifidx %d\n", ifidx);
+               brcmu_pkt_buf_free_skb(skb);
+               return;
diff --git a/package/kernel/mac80211/patches/394-0002-brcmfmac-make-brcmf_proto_hdrpull-return-struct-brcm.patch b/package/kernel/mac80211/patches/394-0002-brcmfmac-make-brcmf_proto_hdrpull-return-struct-brcm.patch
new file mode 100644 (file)
index 0000000..632714c
--- /dev/null
@@ -0,0 +1,222 @@
+From: Arend van Spriel <arend@broadcom.com>
+Date: Wed, 26 Aug 2015 22:14:54 +0200
+Subject: [PATCH] brcmfmac: make brcmf_proto_hdrpull() return struct
+ brcmf_if instance
+
+Avoid spreading the ifidx in the driver, but have it return the
+struct brcmf_if instance.
+
+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>
+---
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c
+@@ -272,11 +272,11 @@ brcmf_proto_bcdc_hdrpush(struct brcmf_pu
+ }
+ static int
+-brcmf_proto_bcdc_hdrpull(struct brcmf_pub *drvr, bool do_fws, u8 *ifidx,
+-                       struct sk_buff *pktbuf)
++brcmf_proto_bcdc_hdrpull(struct brcmf_pub *drvr, bool do_fws,
++                       struct sk_buff *pktbuf, struct brcmf_if **ifp)
+ {
+       struct brcmf_proto_bcdc_header *h;
+-      struct brcmf_if *ifp;
++      struct brcmf_if *tmp_if;
+       brcmf_dbg(BCDC, "Enter\n");
+@@ -290,21 +290,21 @@ brcmf_proto_bcdc_hdrpull(struct brcmf_pu
+       trace_brcmf_bcdchdr(pktbuf->data);
+       h = (struct brcmf_proto_bcdc_header *)(pktbuf->data);
+-      ifp = brcmf_get_ifp(drvr, BCDC_GET_IF_IDX(h));
+-      if (IS_ERR_OR_NULL(ifp)) {
++      tmp_if = brcmf_get_ifp(drvr, BCDC_GET_IF_IDX(h));
++      if (!tmp_if) {
+               brcmf_dbg(INFO, "no matching ifp found\n");
+               return -EBADE;
+       }
+       if (((h->flags & BCDC_FLAG_VER_MASK) >> BCDC_FLAG_VER_SHIFT) !=
+           BCDC_PROTO_VER) {
+               brcmf_err("%s: non-BCDC packet received, flags 0x%x\n",
+-                        brcmf_ifname(drvr, ifp->ifidx), h->flags);
++                        brcmf_ifname(drvr, tmp_if->ifidx), h->flags);
+               return -EBADE;
+       }
+       if (h->flags & BCDC_FLAG_SUM_GOOD) {
+               brcmf_dbg(BCDC, "%s: BDC rcv, good checksum, flags 0x%x\n",
+-                        brcmf_ifname(drvr, ifp->ifidx), h->flags);
++                        brcmf_ifname(drvr, tmp_if->ifidx), h->flags);
+               pktbuf->ip_summed = CHECKSUM_UNNECESSARY;
+       }
+@@ -312,7 +312,7 @@ brcmf_proto_bcdc_hdrpull(struct brcmf_pu
+       skb_pull(pktbuf, BCDC_HEADER_LEN);
+       if (do_fws)
+-              brcmf_fws_hdrpull(drvr, ifp->ifidx, h->data_offset << 2,
++              brcmf_fws_hdrpull(drvr, tmp_if->ifidx, h->data_offset << 2,
+                                 pktbuf);
+       else
+               skb_pull(pktbuf, h->data_offset << 2);
+@@ -320,7 +320,7 @@ brcmf_proto_bcdc_hdrpull(struct brcmf_pu
+       if (pktbuf->len == 0)
+               return -ENODATA;
+-      *ifidx = ifp->ifidx;
++      *ifp = tmp_if;
+       return 0;
+ }
+--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c
+@@ -87,7 +87,7 @@ struct brcmf_if *brcmf_get_ifp(struct br
+ {
+       if (ifidx < 0 || ifidx >= BRCMF_MAX_IFS) {
+               brcmf_err("ifidx %d out of range\n", ifidx);
+-              return ERR_PTR(-ERANGE);
++              return NULL;
+       }
+       /* The ifidx is the idx to map to matching netdev/ifp. When receiving
+@@ -539,17 +539,15 @@ void brcmf_rx_frame(struct device *dev,
+       struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+       struct brcmf_pub *drvr = bus_if->drvr;
+       struct brcmf_skb_reorder_data *rd;
+-      u8 ifidx;
+       int ret;
+       brcmf_dbg(DATA, "Enter: %s: rxp=%p\n", dev_name(dev), skb);
+       /* process and remove protocol-specific header */
+-      ret = brcmf_proto_hdrpull(drvr, true, &ifidx, skb);
+-      ifp = drvr->iflist[ifidx];
++      ret = brcmf_proto_hdrpull(drvr, true, skb, &ifp);
+       if (ret || !ifp || !ifp->ndev) {
+-              if ((ret != -ENODATA) && ifp)
++              if (ret != -ENODATA && ifp)
+                       ifp->stats.rx_errors++;
+               brcmu_pkt_buf_free_skb(skb);
+               return;
+@@ -592,17 +590,17 @@ void brcmf_txcomplete(struct device *dev
+ {
+       struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+       struct brcmf_pub *drvr = bus_if->drvr;
+-      u8 ifidx;
++      struct brcmf_if *ifp;
+       /* await txstatus signal for firmware if active */
+       if (brcmf_fws_fc_active(drvr->fws)) {
+               if (!success)
+                       brcmf_fws_bustxfail(drvr->fws, txp);
+       } else {
+-              if (brcmf_proto_hdrpull(drvr, false, &ifidx, txp))
++              if (brcmf_proto_hdrpull(drvr, false, txp, &ifp))
+                       brcmu_pkt_buf_free_skb(txp);
+               else
+-                      brcmf_txfinalize(drvr, txp, ifidx, success);
++                      brcmf_txfinalize(drvr, txp, ifp->ifidx, success);
+       }
+ }
+--- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
+@@ -1448,7 +1448,7 @@ brcmf_fws_txs_process(struct brcmf_fws_i
+       struct sk_buff *skb;
+       struct brcmf_skbuff_cb *skcb;
+       struct brcmf_fws_mac_descriptor *entry = NULL;
+-      u8 ifidx;
++      struct brcmf_if *ifp;
+       brcmf_dbg(DATA, "flags %d\n", flags);
+@@ -1497,15 +1497,16 @@ brcmf_fws_txs_process(struct brcmf_fws_i
+       }
+       brcmf_fws_macdesc_return_req_credit(skb);
+-      if (brcmf_proto_hdrpull(fws->drvr, false, &ifidx, skb)) {
++      ret = brcmf_proto_hdrpull(fws->drvr, false, skb, &ifp);
++      if (ret) {
+               brcmu_pkt_buf_free_skb(skb);
+               return -EINVAL;
+       }
+       if (!remove_from_hanger)
+-              ret = brcmf_fws_txstatus_suppressed(fws, fifo, skb, ifidx,
++              ret = brcmf_fws_txstatus_suppressed(fws, fifo, skb, ifp->ifidx,
+                                                   genbit, seq);
+       if (remove_from_hanger || ret)
+-              brcmf_txfinalize(fws->drvr, skb, ifidx, true);
++              brcmf_txfinalize(fws->drvr, skb, ifp->ifidx, true);
+       return 0;
+ }
+@@ -1848,7 +1849,7 @@ static int brcmf_fws_commit_skb(struct b
+               entry->transit_count--;
+               if (entry->suppressed)
+                       entry->suppr_transit_count--;
+-              brcmf_proto_hdrpull(fws->drvr, false, &ifidx, skb);
++              (void)brcmf_proto_hdrpull(fws->drvr, false, skb, NULL);
+               goto rollback;
+       }
+--- a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
+@@ -522,7 +522,7 @@ static int brcmf_msgbuf_set_dcmd(struct
+ static int brcmf_msgbuf_hdrpull(struct brcmf_pub *drvr, bool do_fws,
+-                              u8 *ifidx, struct sk_buff *skb)
++                              struct sk_buff *skb, struct brcmf_if **ifp)
+ {
+       return -ENODEV;
+ }
+@@ -1082,7 +1082,7 @@ brcmf_msgbuf_rx_skb(struct brcmf_msgbuf
+       struct brcmf_if *ifp;
+       ifp = brcmf_get_ifp(msgbuf->drvr, ifidx);
+-      if (IS_ERR_OR_NULL(ifp) || !ifp->ndev) {
++      if (!ifp || !ifp->ndev) {
+               brcmf_err("Received pkt for invalid ifidx %d\n", ifidx);
+               brcmu_pkt_buf_free_skb(skb);
+               return;
+--- a/drivers/net/wireless/brcm80211/brcmfmac/proto.h
++++ b/drivers/net/wireless/brcm80211/brcmfmac/proto.h
+@@ -24,8 +24,8 @@ enum proto_addr_mode {
+ struct brcmf_proto {
+-      int (*hdrpull)(struct brcmf_pub *drvr, bool do_fws, u8 *ifidx,
+-                     struct sk_buff *skb);
++      int (*hdrpull)(struct brcmf_pub *drvr, bool do_fws,
++                     struct sk_buff *skb, struct brcmf_if **ifp);
+       int (*query_dcmd)(struct brcmf_pub *drvr, int ifidx, uint cmd,
+                         void *buf, uint len);
+       int (*set_dcmd)(struct brcmf_pub *drvr, int ifidx, uint cmd, void *buf,
+@@ -46,9 +46,19 @@ int brcmf_proto_attach(struct brcmf_pub
+ void brcmf_proto_detach(struct brcmf_pub *drvr);
+ static inline int brcmf_proto_hdrpull(struct brcmf_pub *drvr, bool do_fws,
+-                                    u8 *ifidx, struct sk_buff *skb)
++                                    struct sk_buff *skb,
++                                    struct brcmf_if **ifp)
+ {
+-      return drvr->proto->hdrpull(drvr, do_fws, ifidx, skb);
++      struct brcmf_if *tmp = NULL;
++
++      /* assure protocol is always called with
++       * non-null initialized pointer.
++       */
++      if (ifp)
++              *ifp = NULL;
++      else
++              ifp = &tmp;
++      return drvr->proto->hdrpull(drvr, do_fws, skb, ifp);
+ }
+ static inline int brcmf_proto_query_dcmd(struct brcmf_pub *drvr, int ifidx,
+                                        uint cmd, void *buf, uint len)
diff --git a/package/kernel/mac80211/patches/394-0003-brcmfmac-change-parameters-for-brcmf_remove_interfac.patch b/package/kernel/mac80211/patches/394-0003-brcmfmac-change-parameters-for-brcmf_remove_interfac.patch
new file mode 100644 (file)
index 0000000..2d15a77
--- /dev/null
@@ -0,0 +1,87 @@
+From: Arend van Spriel <arend@broadcom.com>
+Date: Wed, 26 Aug 2015 22:14:55 +0200
+Subject: [PATCH] brcmfmac: change parameters for
+ brcmf_remove_interface()
+
+Just pass the interface to be removed, ie. the struct brcmf_if instance.
+
+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>
+---
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
+@@ -4982,7 +4982,7 @@ brcmf_notify_connect_status_ap(struct br
+               brcmf_dbg(CONN, "AP mode link down\n");
+               complete(&cfg->vif_disabled);
+               if (ifp->vif->mbss)
+-                      brcmf_remove_interface(ifp->drvr, ifp->bssidx);
++                      brcmf_remove_interface(ifp);
+               return 0;
+       }
+--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c
+@@ -887,12 +887,13 @@ static void brcmf_del_if(struct brcmf_pu
+       }
+ }
+-void brcmf_remove_interface(struct brcmf_pub *drvr, u32 bssidx)
++void brcmf_remove_interface(struct brcmf_if *ifp)
+ {
+-      if (drvr->iflist[bssidx]) {
+-              brcmf_fws_del_interface(drvr->iflist[bssidx]);
+-              brcmf_del_if(drvr, bssidx);
+-      }
++      if (!ifp || WARN_ON(ifp->drvr->iflist[ifp->bssidx] != ifp))
++              return;
++
++      brcmf_fws_del_interface(ifp);
++      brcmf_del_if(ifp->drvr, ifp->bssidx);
+ }
+ int brcmf_get_next_free_bsscfgidx(struct brcmf_pub *drvr)
+@@ -1122,7 +1123,7 @@ void brcmf_detach(struct device *dev)
+       /* make sure primary interface removed last */
+       for (i = BRCMF_MAX_IFS-1; i > -1; i--)
+-              brcmf_remove_interface(drvr, i);
++              brcmf_remove_interface(drvr->iflist[i]);
+       brcmf_cfg80211_detach(drvr->config);
+--- a/drivers/net/wireless/brcm80211/brcmfmac/core.h
++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.h
+@@ -206,7 +206,7 @@ struct brcmf_if *brcmf_get_ifp(struct br
+ int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked);
+ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx,
+                             char *name, u8 *mac_addr);
+-void brcmf_remove_interface(struct brcmf_pub *drvr, u32 bssidx);
++void brcmf_remove_interface(struct brcmf_if *ifp);
+ int brcmf_get_next_free_bsscfgidx(struct brcmf_pub *drvr);
+ void brcmf_txflowblock_if(struct brcmf_if *ifp,
+                         enum brcmf_netif_stop_reason reason, bool state);
+--- a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c
+@@ -222,7 +222,7 @@ static void brcmf_fweh_handle_if_event(s
+       err = brcmf_fweh_call_event_handler(ifp, emsg->event_code, emsg, data);
+       if (ifp && ifevent->action == BRCMF_E_IF_DEL)
+-              brcmf_remove_interface(drvr, ifevent->bssidx);
++              brcmf_remove_interface(ifp);
+ }
+ /**
+--- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
+@@ -2140,7 +2140,7 @@ static void brcmf_p2p_delete_p2pdev(stru
+ {
+       cfg80211_unregister_wdev(&vif->wdev);
+       p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL;
+-      brcmf_remove_interface(vif->ifp->drvr, vif->ifp->bssidx);
++      brcmf_remove_interface(vif->ifp);
+       brcmf_free_vif(vif);
+ }
diff --git a/package/kernel/mac80211/patches/394-0004-brcmfmac-only-call-brcmf_cfg80211_detach-when-attach.patch b/package/kernel/mac80211/patches/394-0004-brcmfmac-only-call-brcmf_cfg80211_detach-when-attach.patch
new file mode 100644 (file)
index 0000000..2b61f4e
--- /dev/null
@@ -0,0 +1,92 @@
+From: Arend van Spriel <arend@broadcom.com>
+Date: Wed, 26 Aug 2015 22:14:56 +0200
+Subject: [PATCH] brcmfmac: only call brcmf_cfg80211_detach() when attach
+ was successful
+
+In brcmf_bus_start() the function brcmf_cfg80211_attach() is called which
+may fail. If this happens we should not call brcmf_cfg80211_detach() in
+the failure path as it will result in NULL pointer dereference:
+
+  brcmf_fweh_activate_events: Set event_msgs error (-5)
+  brcmf_bus_start: failed: -5
+  brcmf_sdio_firmware_callback: dongle is not responding
+  BUG: unable to handle kernel NULL pointer dereference at 0000000000000068
+  IP: [<ffffffff811e8f08>] kernfs_find_ns+0x18/0xd0
+  PGD 0
+  Oops: 0000 [#1] SMP
+  Modules linked in: brcmfmac(O) brcmutil(O) cfg80211 auth_rpcgss
+  CPU: 1 PID: 45 Comm: kworker/1:1 Tainted: G           O
+  Hardware name: Dell Inc. Latitude E6410/07XJP9, BIOS A07 02/15/2011
+  Workqueue: events request_firmware_work_func
+  task: ffff880036c09ac0 ti: ffff880036dd4000 task.ti: ffff880036dd4000
+  RIP: 0010:[<ffffffff811e8f08>]  [<ffffffff811e8f08>] kernfs_find_ns+0x18/0xd0
+  RSP: 0018:ffff880036dd7a28  EFLAGS: 00010246
+  RAX: ffff880036c09ac0 RBX: 0000000000000000 RCX: 000000007fffffff
+  RDX: 0000000000000000 RSI: ffffffff816578b9 RDI: 0000000000000000
+  RBP: ffff880036dd7a48 R08: 0000000000000000 R09: ffff880036c0b340
+  R10: 00000000000002ec R11: ffff880036dd7b08 R12: ffffffff816578b9
+  R13: 0000000000000000 R14: ffffffff816578b9 R15: ffff8800c6c87000
+  FS:  0000000000000000(0000) GS:ffff88012bc40000(0000) knlGS:0000000000000000
+  CS:  0010 DS: 0000 ES: 0000 CR0: 000000008005003b
+  CR2: 0000000000000068 CR3: 0000000001a0b000 CR4: 00000000000006e0
+  Stack:
+   0000000000000000 ffffffff816578b9 0000000000000000 ffff8800c0d003c8
+   ffff880036dd7a78 ffffffff811e8ff5 0000000ffffffff1 ffffffff81a9b060
+   ffff8800c789f880 ffff8800c0d00000 ffff880036dd7a98 ffffffff811ebe0d
+  Call Trace:
+   [<ffffffff811e8ff5>] kernfs_find_and_get_ns+0x35/0x60
+   [<ffffffff811ebe0d>] sysfs_unmerge_group+0x1d/0x60
+   [<ffffffff81404ef2>] dpm_sysfs_remove+0x22/0x60
+   [<ffffffff813f9db9>] device_del+0x49/0x240
+   [<ffffffff815da768>] rfkill_unregister+0x58/0xc0
+   [<ffffffffa06bd91b>] wiphy_unregister+0xab/0x2f0 [cfg80211]
+   [<ffffffffa0742fe3>] brcmf_cfg80211_detach+0x23/0x50 [brcmfmac]
+   [<ffffffffa074d986>] brcmf_detach+0x86/0xe0 [brcmfmac]
+   [<ffffffffa0757de8>] brcmf_sdio_remove+0x48/0x120 [brcmfmac]
+   [<ffffffffa0758ed9>] brcmf_sdiod_remove+0x29/0xd0 [brcmfmac]
+   [<ffffffffa0759031>] brcmf_ops_sdio_remove+0xb1/0x110 [brcmfmac]
+   [<ffffffffa001c267>] sdio_bus_remove+0x37/0x100 [mmc_core]
+   [<ffffffff813fe026>] __device_release_driver+0x96/0x130
+   [<ffffffff813fe0e3>] device_release_driver+0x23/0x30
+   [<ffffffffa0754bc8>] brcmf_sdio_firmware_callback+0x2a8/0x5d0 [brcmfmac]
+   [<ffffffffa074deaf>] brcmf_fw_request_nvram_done+0x15f/0x5e0 [brcmfmac]
+   [<ffffffff8140142f>] ? devres_add+0x3f/0x50
+   [<ffffffff810642b5>] ? usermodehelper_read_unlock+0x15/0x20
+   [<ffffffff81400000>] ? platform_match+0x70/0xa0
+   [<ffffffff8140f400>] request_firmware_work_func+0x30/0x60
+   [<ffffffff8106828c>] process_one_work+0x14c/0x3d0
+   [<ffffffff8106862a>] worker_thread+0x11a/0x450
+   [<ffffffff81068510>] ? process_one_work+0x3d0/0x3d0
+   [<ffffffff8106d692>] kthread+0xd2/0xf0
+   [<ffffffff8106d5c0>] ? kthread_create_on_node+0x180/0x180
+   [<ffffffff815ed35f>] ret_from_fork+0x3f/0x70
+   [<ffffffff8106d5c0>] ? kthread_create_on_node+0x180/0x180
+  Code: e9 40 fe ff ff 48 89 d8 eb 87 66 0f 1f 84 00 00 00 00 00 66 66 66 66
+       90 55 48 89 e5 41 56 49 89 f6 41 55 49 89 d5 31 d2 41 54 53 <0f> b7
+       47 68 48 8b 5f 48 66 c1 e8 05 83 e0 01 4d 85 ed 0f b6 c8
+  RIP  [<ffffffff811e8f08>] kernfs_find_ns+0x18/0xd0
+   RSP <ffff880036dd7a28>
+  CR2: 0000000000000068
+  ---[ end trace 87d6ec0d3fe46740 ]---
+
+Reported-by: Daniel (Deognyoun) Kim <dekim@broadcom.com>
+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>
+---
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c
+@@ -1049,7 +1049,10 @@ int brcmf_bus_start(struct device *dev)
+ fail:
+       if (ret < 0) {
+               brcmf_err("failed: %d\n", ret);
+-              brcmf_cfg80211_detach(drvr->config);
++              if (drvr->config) {
++                      brcmf_cfg80211_detach(drvr->config);
++                      drvr->config = NULL;
++              }
+               if (drvr->fws) {
+                       brcmf_fws_del_interface(ifp);
+                       brcmf_fws_deinit(drvr);
diff --git a/package/kernel/mac80211/patches/394-0005-brcmfmac-correct-detection-of-p2pdev-interface-event.patch b/package/kernel/mac80211/patches/394-0005-brcmfmac-correct-detection-of-p2pdev-interface-event.patch
new file mode 100644 (file)
index 0000000..868b0a8
--- /dev/null
@@ -0,0 +1,105 @@
+From: Arend van Spriel <arend@broadcom.com>
+Date: Wed, 26 Aug 2015 22:14:57 +0200
+Subject: [PATCH] brcmfmac: correct detection of p2pdev interface event
+
+The p2pdev interface is setup in firmware resulting in a interface
+event. This event has role and no-if flag. When role is p2p client
+and no-if flag is set it indicates that this is the p2pdev interface.
+This info is used in handling the event and adding interface in the
+driver.
+
+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>
+---
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c
+@@ -795,7 +795,7 @@ fail:
+ }
+ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx,
+-                            char *name, u8 *mac_addr)
++                            bool is_p2pdev, char *name, u8 *mac_addr)
+ {
+       struct brcmf_if *ifp;
+       struct net_device *ndev;
+@@ -821,7 +821,7 @@ struct brcmf_if *brcmf_add_if(struct brc
+               }
+       }
+-      if (!brcmf_p2p_enable && bssidx == 1) {
++      if (!brcmf_p2p_enable && is_p2pdev) {
+               /* this is P2P_DEVICE interface */
+               brcmf_dbg(INFO, "allocate non-netdev interface\n");
+               ifp = kzalloc(sizeof(*ifp), GFP_KERNEL);
+@@ -999,12 +999,12 @@ int brcmf_bus_start(struct device *dev)
+       brcmf_dbg(TRACE, "\n");
+       /* add primary networking interface */
+-      ifp = brcmf_add_if(drvr, 0, 0, "wlan%d", NULL);
++      ifp = brcmf_add_if(drvr, 0, 0, false, "wlan%d", NULL);
+       if (IS_ERR(ifp))
+               return PTR_ERR(ifp);
+       if (brcmf_p2p_enable)
+-              p2p_ifp = brcmf_add_if(drvr, 1, 0, "p2p%d", NULL);
++              p2p_ifp = brcmf_add_if(drvr, 1, 0, false, "p2p%d", NULL);
+       else
+               p2p_ifp = NULL;
+       if (IS_ERR(p2p_ifp))
+--- a/drivers/net/wireless/brcm80211/brcmfmac/core.h
++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.h
+@@ -205,7 +205,7 @@ char *brcmf_ifname(struct brcmf_pub *drv
+ struct brcmf_if *brcmf_get_ifp(struct brcmf_pub *drvr, int ifidx);
+ int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked);
+ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx,
+-                            char *name, u8 *mac_addr);
++                            bool is_p2pdev, char *name, u8 *mac_addr);
+ void brcmf_remove_interface(struct brcmf_if *ifp);
+ int brcmf_get_next_free_bsscfgidx(struct brcmf_pub *drvr);
+ void brcmf_txflowblock_if(struct brcmf_if *ifp,
+--- a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c
+@@ -179,6 +179,7 @@ static void brcmf_fweh_handle_if_event(s
+ {
+       struct brcmf_if_event *ifevent = data;
+       struct brcmf_if *ifp;
++      bool is_p2pdev;
+       int err = 0;
+       brcmf_dbg(EVENT, "action: %u idx: %u bsscfg: %u flags: %u role: %u\n",
+@@ -186,18 +187,16 @@ static void brcmf_fweh_handle_if_event(s
+                 ifevent->flags, ifevent->role);
+       /* The P2P Device interface event must not be ignored
+-       * contrary to what firmware tells us. The only way to
+-       * distinguish the P2P Device is by looking at the ifidx
+-       * and bssidx received.
++       * contrary to what firmware tells us.
+        */
+-      if (!(ifevent->ifidx == 0 && ifevent->bssidx == 1) &&
+-          (ifevent->flags & BRCMF_E_IF_FLAG_NOIF)) {
++      is_p2pdev = (ifevent->flags & BRCMF_E_IF_FLAG_NOIF) &&
++                  ifevent->role == BRCMF_E_IF_ROLE_P2P_CLIENT;
++      if (!is_p2pdev && (ifevent->flags & BRCMF_E_IF_FLAG_NOIF)) {
+               brcmf_dbg(EVENT, "event can be ignored\n");
+               return;
+       }
+       if (ifevent->ifidx >= BRCMF_MAX_IFS) {
+-              brcmf_err("invalid interface index: %u\n",
+-                        ifevent->ifidx);
++              brcmf_err("invalid interface index: %u\n", ifevent->ifidx);
+               return;
+       }
+@@ -207,7 +206,7 @@ static void brcmf_fweh_handle_if_event(s
+               brcmf_dbg(EVENT, "adding %s (%pM)\n", emsg->ifname,
+                         emsg->addr);
+               ifp = brcmf_add_if(drvr, ifevent->bssidx, ifevent->ifidx,
+-                                 emsg->ifname, emsg->addr);
++                                 is_p2pdev, emsg->ifname, emsg->addr);
+               if (IS_ERR(ifp))
+                       return;
+               brcmf_fws_add_interface(ifp);
diff --git a/package/kernel/mac80211/patches/394-0006-brcmfmac-use-brcmf_get_ifp-to-map-ifidx-to-struct-br.patch b/package/kernel/mac80211/patches/394-0006-brcmfmac-use-brcmf_get_ifp-to-map-ifidx-to-struct-br.patch
new file mode 100644 (file)
index 0000000..aebbfa6
--- /dev/null
@@ -0,0 +1,126 @@
+From: Arend van Spriel <arend@broadcom.com>
+Date: Wed, 26 Aug 2015 22:14:58 +0200
+Subject: [PATCH] brcmfmac: use brcmf_get_ifp() to map ifidx to struct
+ brcmf_if instance
+
+The knowledge on how to map the interface index to a struct brcmf_if
+instance is in brcmf_get_ifp() so use that function when only the
+interface index is known instead of accessing brcmf_pub::iflist
+directly.
+
+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>
+---
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/btcoex.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/btcoex.c
+@@ -149,7 +149,7 @@ static s32 brcmf_btcoex_params_read(stru
+ static void brcmf_btcoex_boost_wifi(struct brcmf_btcoex_info *btci,
+                                   bool trump_sco)
+ {
+-      struct brcmf_if *ifp = btci->cfg->pub->iflist[0];
++      struct brcmf_if *ifp = brcmf_get_ifp(btci->cfg->pub, 0);
+       if (trump_sco && !btci->saved_regs_part2) {
+               /* this should reduce eSCO agressive
+@@ -468,7 +468,7 @@ int brcmf_btcoex_set_mode(struct brcmf_c
+ {
+       struct brcmf_cfg80211_info *cfg = wiphy_priv(vif->wdev.wiphy);
+       struct brcmf_btcoex_info *btci = cfg->btcoex;
+-      struct brcmf_if *ifp = cfg->pub->iflist[0];
++      struct brcmf_if *ifp = brcmf_get_ifp(cfg->pub, 0);
+       switch (mode) {
+       case BRCMF_BTCOEX_DISABLED:
+--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
+@@ -6212,7 +6212,7 @@ static void brcmf_free_wiphy(struct wiph
+ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
+                                                 struct device *busdev)
+ {
+-      struct net_device *ndev = drvr->iflist[0]->ndev;
++      struct net_device *ndev = brcmf_get_ifp(drvr, 0)->ndev;
+       struct brcmf_cfg80211_info *cfg;
+       struct wiphy *wiphy;
+       struct brcmf_cfg80211_vif *vif;
+--- a/drivers/net/wireless/brcm80211/brcmfmac/feature.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/feature.c
+@@ -121,7 +121,7 @@ static void brcmf_feat_iovar_int_set(str
+ void brcmf_feat_attach(struct brcmf_pub *drvr)
+ {
+-      struct brcmf_if *ifp = drvr->iflist[0];
++      struct brcmf_if *ifp = brcmf_get_ifp(drvr, 0);
+       brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_MCHAN, "mchan");
+       brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_PNO, "pfn");
+--- a/drivers/net/wireless/brcm80211/brcmfmac/flowring.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/flowring.c
+@@ -221,7 +221,7 @@ static void brcmf_flowring_block(struct
+       bus_if = dev_get_drvdata(flow->dev);
+       drvr = bus_if->drvr;
+-      ifp = drvr->iflist[ifidx];
++      ifp = brcmf_get_ifp(drvr, ifidx);
+       brcmf_txflowblock_if(ifp, BRCMF_NETIF_STOP_REASON_FLOW, blocked);
+       spin_unlock_irqrestore(&flow->block_lock, flags);
+--- a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c
+@@ -334,7 +334,7 @@ void brcmf_fweh_attach(struct brcmf_pub
+ void brcmf_fweh_detach(struct brcmf_pub *drvr)
+ {
+       struct brcmf_fweh_info *fweh = &drvr->fweh;
+-      struct brcmf_if *ifp = drvr->iflist[0];
++      struct brcmf_if *ifp = brcmf_get_ifp(drvr, 0);
+       s8 eventmask[BRCMF_EVENTING_MASK_LEN];
+       if (ifp) {
+--- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
+@@ -972,7 +972,7 @@ static void
+ brcmf_fws_flow_control_check(struct brcmf_fws_info *fws, struct pktq *pq,
+                            u8 if_id)
+ {
+-      struct brcmf_if *ifp = fws->drvr->iflist[!if_id ? 0 : if_id + 1];
++      struct brcmf_if *ifp = brcmf_get_ifp(fws->drvr, if_id);
+       if (WARN_ON(!ifp))
+               return;
+@@ -2118,6 +2118,7 @@ static int brcmf_debugfs_fws_stats_read(
+ int brcmf_fws_init(struct brcmf_pub *drvr)
+ {
+       struct brcmf_fws_info *fws;
++      struct brcmf_if *ifp;
+       u32 tlv = BRCMF_FWS_FLAGS_RSSI_SIGNALS;
+       int rc;
+       u32 mode;
+@@ -2177,21 +2178,22 @@ int brcmf_fws_init(struct brcmf_pub *drv
+        * continue. Set mode back to none indicating not enabled.
+        */
+       fws->fw_signals = true;
+-      if (brcmf_fil_iovar_int_set(drvr->iflist[0], "tlv", tlv)) {
++      ifp = brcmf_get_ifp(drvr, 0);
++      if (brcmf_fil_iovar_int_set(ifp, "tlv", tlv)) {
+               brcmf_err("failed to set bdcv2 tlv signaling\n");
+               fws->fcmode = BRCMF_FWS_FCMODE_NONE;
+               fws->fw_signals = false;
+       }
+-      if (brcmf_fil_iovar_int_set(drvr->iflist[0], "ampdu_hostreorder", 1))
++      if (brcmf_fil_iovar_int_set(ifp, "ampdu_hostreorder", 1))
+               brcmf_dbg(INFO, "enabling AMPDU host-reorder failed\n");
+       /* Enable seq number reuse, if supported */
+-      if (brcmf_fil_iovar_int_get(drvr->iflist[0], "wlfc_mode", &mode) == 0) {
++      if (brcmf_fil_iovar_int_get(ifp, "wlfc_mode", &mode) == 0) {
+               if (BRCMF_FWS_MODE_GET_REUSESEQ(mode)) {
+                       mode = 0;
+                       BRCMF_FWS_MODE_SET_REUSESEQ(mode, 1);
+-                      if (brcmf_fil_iovar_int_set(drvr->iflist[0],
++                      if (brcmf_fil_iovar_int_set(ifp,
+                                                   "wlfc_mode", mode) == 0) {
+                               BRCMF_FWS_MODE_SET_REUSESEQ(fws->mode, 1);
+                       }
diff --git a/package/kernel/mac80211/patches/394-0007-brcmfmac-pass-struct-brcmf_if-instance-in-brcmf_txfi.patch b/package/kernel/mac80211/patches/394-0007-brcmfmac-pass-struct-brcmf_if-instance-in-brcmf_txfi.patch
new file mode 100644 (file)
index 0000000..23a7b6f
--- /dev/null
@@ -0,0 +1,122 @@
+From: Arend van Spriel <arend@broadcom.com>
+Date: Wed, 26 Aug 2015 22:14:59 +0200
+Subject: [PATCH] brcmfmac: pass struct brcmf_if instance in
+ brcmf_txfinalize()
+
+Most call sites of brcmf_txfinalize already have struct brcmf_if
+instance so pass that to brcmf_txfinalize() as the function
+needs it anyway.
+
+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>
+---
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c
+@@ -560,17 +560,11 @@ void brcmf_rx_frame(struct device *dev,
+               brcmf_netif_rx(ifp, skb);
+ }
+-void brcmf_txfinalize(struct brcmf_pub *drvr, struct sk_buff *txp, u8 ifidx,
+-                    bool success)
++void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success)
+ {
+-      struct brcmf_if *ifp;
+       struct ethhdr *eh;
+       u16 type;
+-      ifp = drvr->iflist[ifidx];
+-      if (!ifp)
+-              goto done;
+-
+       eh = (struct ethhdr *)(txp->data);
+       type = ntohs(eh->h_proto);
+@@ -582,7 +576,7 @@ void brcmf_txfinalize(struct brcmf_pub *
+       if (!success)
+               ifp->stats.tx_errors++;
+-done:
++
+       brcmu_pkt_buf_free_skb(txp);
+ }
+@@ -600,7 +594,7 @@ void brcmf_txcomplete(struct device *dev
+               if (brcmf_proto_hdrpull(drvr, false, txp, &ifp))
+                       brcmu_pkt_buf_free_skb(txp);
+               else
+-                      brcmf_txfinalize(drvr, txp, ifp->ifidx, success);
++                      brcmf_txfinalize(ifp, txp, success);
+       }
+ }
+--- a/drivers/net/wireless/brcm80211/brcmfmac/core.h
++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.h
+@@ -210,8 +210,7 @@ void brcmf_remove_interface(struct brcmf
+ int brcmf_get_next_free_bsscfgidx(struct brcmf_pub *drvr);
+ void brcmf_txflowblock_if(struct brcmf_if *ifp,
+                         enum brcmf_netif_stop_reason reason, bool state);
+-void brcmf_txfinalize(struct brcmf_pub *drvr, struct sk_buff *txp, u8 ifidx,
+-                    bool success);
++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). */
+--- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
+@@ -1506,7 +1506,7 @@ brcmf_fws_txs_process(struct brcmf_fws_i
+               ret = brcmf_fws_txstatus_suppressed(fws, fifo, skb, ifp->ifidx,
+                                                   genbit, seq);
+       if (remove_from_hanger || ret)
+-              brcmf_txfinalize(fws->drvr, skb, ifp->ifidx, true);
++              brcmf_txfinalize(ifp, skb, true);
+       return 0;
+ }
+@@ -1905,7 +1905,7 @@ int brcmf_fws_process_skb(struct brcmf_i
+       if (fws->avoid_queueing) {
+               rc = brcmf_proto_txdata(drvr, ifp->ifidx, 0, skb);
+               if (rc < 0)
+-                      brcmf_txfinalize(drvr, skb, ifp->ifidx, false);
++                      brcmf_txfinalize(ifp, skb, false);
+               return rc;
+       }
+@@ -1929,7 +1929,7 @@ int brcmf_fws_process_skb(struct brcmf_i
+               brcmf_fws_schedule_deq(fws);
+       } else {
+               brcmf_err("drop skb: no hanger slot\n");
+-              brcmf_txfinalize(drvr, skb, ifp->ifidx, false);
++              brcmf_txfinalize(ifp, skb, false);
+               rc = -ENOMEM;
+       }
+       brcmf_fws_unlock(fws);
+@@ -2009,8 +2009,9 @@ static void brcmf_fws_dequeue_worker(str
+                               ret = brcmf_proto_txdata(drvr, ifidx, 0, skb);
+                               brcmf_fws_lock(fws);
+                               if (ret < 0)
+-                                      brcmf_txfinalize(drvr, skb, ifidx,
+-                                                       false);
++                                      brcmf_txfinalize(brcmf_get_ifp(drvr,
++                                                                     ifidx),
++                                                       skb, false);
+                               if (fws->bus_flow_blocked)
+                                       break;
+                       }
+--- a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
+@@ -873,7 +873,11 @@ brcmf_msgbuf_process_txstatus(struct brc
+       commonring = msgbuf->flowrings[flowid];
+       atomic_dec(&commonring->outstanding_tx);
+-      brcmf_txfinalize(msgbuf->drvr, skb, tx_status->msg.ifidx, true);
++      /* 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);
+ }
diff --git a/package/kernel/mac80211/patches/394-0008-brcmfmac-add-mapping-for-interface-index-to-bsscfg-i.patch b/package/kernel/mac80211/patches/394-0008-brcmfmac-add-mapping-for-interface-index-to-bsscfg-i.patch
new file mode 100644 (file)
index 0000000..8ddc0a6
--- /dev/null
@@ -0,0 +1,92 @@
+From: Arend van Spriel <arend@broadcom.com>
+Date: Wed, 26 Aug 2015 22:15:00 +0200
+Subject: [PATCH] brcmfmac: add mapping for interface index to bsscfg
+ index
+
+Because the P2P Device interface in firmware uses the same interface
+index as the primary interface we use the bsscfg index as index in the
+struct brcmf_pub::iflist. However, in the data path we get the interface
+index and not the bsscfg index. So we need a mapping of interface index
+to bsscfg index, which can be determined upon handle adding the interface.
+
+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>
+---
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c
+@@ -85,21 +85,20 @@ char *brcmf_ifname(struct brcmf_pub *drv
+ struct brcmf_if *brcmf_get_ifp(struct brcmf_pub *drvr, int ifidx)
+ {
++      struct brcmf_if *ifp;
++      s32 bssidx;
++
+       if (ifidx < 0 || ifidx >= BRCMF_MAX_IFS) {
+               brcmf_err("ifidx %d out of range\n", ifidx);
+               return NULL;
+       }
+-      /* The ifidx is the idx to map to matching netdev/ifp. When receiving
+-       * events this is easy because it contains the bssidx which maps
+-       * 1-on-1 to the netdev/ifp. But for data frames the ifidx is rcvd.
+-       * bssidx 1 is used for p2p0 and no data can be received or
+-       * transmitted on it. Therefor bssidx is ifidx + 1 if ifidx > 0
+-       */
+-      if (ifidx)
+-              ifidx++;
++      ifp = NULL;
++      bssidx = drvr->if2bss[ifidx];
++      if (bssidx >= 0)
++              ifp = drvr->iflist[bssidx];
+-      return drvr->iflist[ifidx];
++      return ifp;
+ }
+ static void _brcmf_set_multicast_list(struct work_struct *work)
+@@ -831,6 +830,8 @@ struct brcmf_if *brcmf_add_if(struct brc
+               ifp = netdev_priv(ndev);
+               ifp->ndev = ndev;
++              /* store mapping ifidx to bssidx */
++              drvr->if2bss[ifidx] = bssidx;
+       }
+       ifp->drvr = drvr;
+@@ -855,6 +856,7 @@ static void brcmf_del_if(struct brcmf_pu
+       struct brcmf_if *ifp;
+       ifp = drvr->iflist[bssidx];
++      drvr->if2bss[ifp->ifidx] = -1;
+       drvr->iflist[bssidx] = NULL;
+       if (!ifp) {
+               brcmf_err("Null interface, idx=%d\n", bssidx);
+@@ -862,6 +864,7 @@ static void brcmf_del_if(struct brcmf_pu
+       }
+       brcmf_dbg(TRACE, "Enter, idx=%d, ifidx=%d\n", bssidx, ifp->ifidx);
+       if (ifp->ndev) {
++              drvr->if2bss[ifp->ifidx] = -1;
+               if (bssidx == 0) {
+                       if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) {
+                               rtnl_lock();
+@@ -926,6 +929,7 @@ int brcmf_attach(struct device *dev)
+       if (!drvr)
+               return -ENOMEM;
++      memset(drvr->if2bss, 0xFF, sizeof(drvr->if2bss));
+       mutex_init(&drvr->proto_block);
+       /* Link to bus module */
+--- a/drivers/net/wireless/brcm80211/brcmfmac/core.h
++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.h
+@@ -122,6 +122,7 @@ struct brcmf_pub {
+       struct mac_address addresses[BRCMF_MAX_IFS];
+       struct brcmf_if *iflist[BRCMF_MAX_IFS];
++      s32 if2bss[BRCMF_MAX_IFS];
+       struct mutex proto_block;
+       unsigned char proto_buf[BRCMF_DCMD_MAXLEN];
diff --git a/package/kernel/mac80211/patches/394-0009-brcmfmac-add-dedicated-debug-level-for-firmware-cons.patch b/package/kernel/mac80211/patches/394-0009-brcmfmac-add-dedicated-debug-level-for-firmware-cons.patch
new file mode 100644 (file)
index 0000000..a0a798b
--- /dev/null
@@ -0,0 +1,103 @@
+From: Arend van Spriel <arend@broadcom.com>
+Date: Wed, 26 Aug 2015 22:15:01 +0200
+Subject: [PATCH] brcmfmac: add dedicated debug level for firmware
+ console logging
+
+Both PCIe and SDIO devices have the possibility to log the firmware
+console output in kernel log. For PCIe it is logged when PCIE debug
+level is enabled. For SDIO it is logged when user specifies a non-zero
+console interval through debugfs. This patch tries to make it a
+bit more consistent. The firmware console output is only logged when
+FWCON debug level is enabled.
+
+Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
+Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+Reviewed-by: Pontus Fuchs <pontusf@broadcom.com>
+Signed-off-by: Arend van Spriel <arend@broadcom.com>
+---
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/debug.h
++++ b/drivers/net/wireless/brcm80211/brcmfmac/debug.h
+@@ -37,6 +37,7 @@
+ #define BRCMF_SDIO_VAL                0x00020000
+ #define BRCMF_MSGBUF_VAL      0x00040000
+ #define BRCMF_PCIE_VAL                0x00080000
++#define BRCMF_FWCON_VAL               0x00100000
+ /* set default print format */
+ #undef pr_fmt
+@@ -78,6 +79,7 @@ do {                                                         \
+ #define BRCMF_GLOM_ON()               (brcmf_msg_level & BRCMF_GLOM_VAL)
+ #define BRCMF_EVENT_ON()      (brcmf_msg_level & BRCMF_EVENT_VAL)
+ #define BRCMF_FIL_ON()                (brcmf_msg_level & BRCMF_FIL_VAL)
++#define BRCMF_FWCON_ON()      (brcmf_msg_level & BRCMF_FWCON_VAL)
+ #else /* defined(DEBUG) || defined(CPTCFG_BRCM_TRACING) */
+@@ -90,6 +92,7 @@ do {                                                         \
+ #define BRCMF_GLOM_ON()               0
+ #define BRCMF_EVENT_ON()      0
+ #define BRCMF_FIL_ON()                0
++#define BRCMF_FWCON_ON()      0
+ #endif /* defined(DEBUG) || defined(CPTCFG_BRCM_TRACING) */
+--- a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
+@@ -644,7 +644,7 @@ static void brcmf_pcie_bus_console_init(
+       addr = console->base_addr + BRCMF_CONSOLE_BUFSIZE_OFFSET;
+       console->bufsize = brcmf_pcie_read_tcm32(devinfo, addr);
+-      brcmf_dbg(PCIE, "Console: base %x, buf %x, size %d\n",
++      brcmf_dbg(FWCON, "Console: base %x, buf %x, size %d\n",
+                 console->base_addr, console->buf_addr, console->bufsize);
+ }
+@@ -656,6 +656,9 @@ static void brcmf_pcie_bus_console_read(
+       u8 ch;
+       u32 newidx;
++      if (!BRCMF_FWCON_ON())
++              return;
++
+       console = &devinfo->shared.console;
+       addr = console->base_addr + BRCMF_CONSOLE_WRITEIDX_OFFSET;
+       newidx = brcmf_pcie_read_tcm32(devinfo, addr);
+@@ -677,7 +680,7 @@ static void brcmf_pcie_bus_console_read(
+               }
+               if (ch == '\n') {
+                       console->log_str[console->log_idx] = 0;
+-                      brcmf_dbg(PCIE, "CONSOLE: %s", console->log_str);
++                      pr_debug("CONSOLE: %s", console->log_str);
+                       console->log_idx = 0;
+               }
+       }
+--- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
+@@ -123,6 +123,7 @@ struct rte_console {
+ #define BRCMF_FIRSTREAD       (1 << 6)
++#define BRCMF_CONSOLE 10      /* watchdog interval to poll console */
+ /* SBSDIO_DEVICE_CTL */
+@@ -3204,6 +3205,8 @@ static void brcmf_sdio_debugfs_create(st
+       if (IS_ERR_OR_NULL(dentry))
+               return;
++      bus->console_interval = BRCMF_CONSOLE;
++
+       brcmf_debugfs_add_entry(drvr, "forensics", brcmf_sdio_forensic_read);
+       brcmf_debugfs_add_entry(drvr, "counters",
+                               brcmf_debugfs_sdio_count_read);
+@@ -3613,7 +3616,7 @@ static void brcmf_sdio_bus_watchdog(stru
+       }
+ #ifdef DEBUG
+       /* Poll for console output periodically */
+-      if (bus->sdiodev->state == BRCMF_SDIOD_DATA &&
++      if (bus->sdiodev->state == BRCMF_SDIOD_DATA && BRCMF_FWCON_ON() &&
+           bus->console_interval != 0) {
+               bus->console.count += BRCMF_WD_POLL_MS;
+               if (bus->console.count >= bus->console_interval) {
diff --git a/package/kernel/mac80211/patches/394-0010-brcmfmac-remove-ifidx-parameter-from-brcmf_fws_txsta.patch b/package/kernel/mac80211/patches/394-0010-brcmfmac-remove-ifidx-parameter-from-brcmf_fws_txsta.patch
new file mode 100644 (file)
index 0000000..53e7ede
--- /dev/null
@@ -0,0 +1,34 @@
+From: Arend van Spriel <arend@broadcom.com>
+Date: Wed, 26 Aug 2015 22:15:02 +0200
+Subject: [PATCH] brcmfmac: remove ifidx parameter from
+ brcmf_fws_txstatus_suppressed()
+
+The brcmf_fws_txstatus_suppressed() function prototype specifies an
+ifidx parameter which is not used within the function implementation.
+
+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>
+---
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
+@@ -1398,7 +1398,7 @@ done:
+ }
+ static int brcmf_fws_txstatus_suppressed(struct brcmf_fws_info *fws, int fifo,
+-                                       struct sk_buff *skb, u8 ifidx,
++                                       struct sk_buff *skb,
+                                        u32 genbit, u16 seq)
+ {
+       struct brcmf_fws_mac_descriptor *entry = brcmf_skbcb(skb)->mac;
+@@ -1503,7 +1503,7 @@ brcmf_fws_txs_process(struct brcmf_fws_i
+               return -EINVAL;
+       }
+       if (!remove_from_hanger)
+-              ret = brcmf_fws_txstatus_suppressed(fws, fifo, skb, ifp->ifidx,
++              ret = brcmf_fws_txstatus_suppressed(fws, fifo, skb,
+                                                   genbit, seq);
+       if (remove_from_hanger || ret)
+               brcmf_txfinalize(ifp, skb, true);
diff --git a/package/kernel/mac80211/patches/394-0011-brcmfmac-change-prototype-for-brcmf_fws_hdrpull.patch b/package/kernel/mac80211/patches/394-0011-brcmfmac-change-prototype-for-brcmf_fws_hdrpull.patch
new file mode 100644 (file)
index 0000000..bb05235
--- /dev/null
@@ -0,0 +1,97 @@
+From: Arend van Spriel <arend@broadcom.com>
+Date: Wed, 26 Aug 2015 22:15:03 +0200
+Subject: [PATCH] brcmfmac: change prototype for brcmf_fws_hdrpull()
+
+Instead of passing ifidx and drvr just pass struct brcmf_if pointer
+which holds both parameters.
+
+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>
+---
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c
+@@ -312,8 +312,7 @@ brcmf_proto_bcdc_hdrpull(struct brcmf_pu
+       skb_pull(pktbuf, BCDC_HEADER_LEN);
+       if (do_fws)
+-              brcmf_fws_hdrpull(drvr, tmp_if->ifidx, h->data_offset << 2,
+-                                pktbuf);
++              brcmf_fws_hdrpull(tmp_if, h->data_offset << 2, pktbuf);
+       else
+               skb_pull(pktbuf, h->data_offset << 2);
+--- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
+@@ -1616,11 +1616,10 @@ static int brcmf_fws_notify_bcmc_credit_
+       return 0;
+ }
+-int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len,
+-                    struct sk_buff *skb)
++void brcmf_fws_hdrpull(struct brcmf_if *ifp, s16 siglen, struct sk_buff *skb)
+ {
+       struct brcmf_skb_reorder_data *rd;
+-      struct brcmf_fws_info *fws = drvr->fws;
++      struct brcmf_fws_info *fws = ifp->drvr->fws;
+       u8 *signal_data;
+       s16 data_len;
+       u8 type;
+@@ -1630,20 +1629,20 @@ int brcmf_fws_hdrpull(struct brcmf_pub *
+       s32 err;
+       brcmf_dbg(HDRS, "enter: ifidx %d, skblen %u, sig %d\n",
+-                ifidx, skb->len, signal_len);
++                ifp->ifidx, skb->len, siglen);
+-      WARN_ON(signal_len > skb->len);
++      WARN_ON(siglen > skb->len);
+-      if (!signal_len)
+-              return 0;
++      if (!siglen)
++              return;
+       /* if flow control disabled, skip to packet data and leave */
+       if ((!fws) || (!fws->fw_signals)) {
+-              skb_pull(skb, signal_len);
+-              return 0;
++              skb_pull(skb, siglen);
++              return;
+       }
+       fws->stats.header_pulls++;
+-      data_len = signal_len;
++      data_len = siglen;
+       signal_data = skb->data;
+       status = BRCMF_FWS_RET_OK_NOSCHEDULE;
+@@ -1731,14 +1730,12 @@ int brcmf_fws_hdrpull(struct brcmf_pub *
+       /* signalling processing result does
+        * not affect the actual ethernet packet.
+        */
+-      skb_pull(skb, signal_len);
++      skb_pull(skb, siglen);
+       /* this may be a signal-only packet
+        */
+       if (skb->len == 0)
+               fws->stats.header_only_pkt++;
+-
+-      return 0;
+ }
+ static u8 brcmf_fws_precommit_skb(struct brcmf_fws_info *fws, int fifo,
+--- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.h
++++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.h
+@@ -21,8 +21,7 @@
+ int brcmf_fws_init(struct brcmf_pub *drvr);
+ void brcmf_fws_deinit(struct brcmf_pub *drvr);
+ bool brcmf_fws_fc_active(struct brcmf_fws_info *fws);
+-int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len,
+-                    struct sk_buff *skb);
++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);
+ void brcmf_fws_reset_interface(struct brcmf_if *ifp);
diff --git a/package/kernel/mac80211/patches/394-0012-brcmfmac-introduce-brcmf_net_detach-function.patch b/package/kernel/mac80211/patches/394-0012-brcmfmac-introduce-brcmf_net_detach-function.patch
new file mode 100644 (file)
index 0000000..ba92c67
--- /dev/null
@@ -0,0 +1,99 @@
+From: Arend van Spriel <arend@broadcom.com>
+Date: Wed, 26 Aug 2015 22:15:04 +0200
+Subject: [PATCH] brcmfmac: introduce brcmf_net_detach() function
+
+In case of error during brcmf_bus_start() the network interfaces were
+freed using free_netdev(). However, the interfaces may have additional
+memory allocated which is not freed. The netdev has destructor set to
+brcmf_cfg80211_free_netdev() which frees the additional memory if
+allocated and call free_netdev(). The brcmf_net_detach() either calls
+brcmf_cfg80211_free_netdev() directly or uses unregister_netdev() when
+struct net_device::reg_state indicates the netdev was registered.
+
+Reported-by: Daniel (Deognyoun) Kim <dekim@broadcom.com>
+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>
+---
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
+@@ -4746,7 +4746,8 @@ void brcmf_cfg80211_free_netdev(struct n
+       ifp = netdev_priv(ndev);
+       vif = ifp->vif;
+-      brcmf_free_vif(vif);
++      if (vif)
++              brcmf_free_vif(vif);
+       free_netdev(ndev);
+ }
+--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c
+@@ -718,8 +718,6 @@ int brcmf_net_attach(struct brcmf_if *if
+       }
+       brcmf_dbg(INFO, "%s: Broadcom Dongle Host Driver\n", ndev->name);
+-
+-      ndev->destructor = brcmf_cfg80211_free_netdev;
+       return 0;
+ fail:
+@@ -729,6 +727,14 @@ fail:
+       return -EBADE;
+ }
++static void brcmf_net_detach(struct net_device *ndev)
++{
++      if (ndev->reg_state == NETREG_REGISTERED)
++              unregister_netdev(ndev);
++      else
++              brcmf_cfg80211_free_netdev(ndev);
++}
++
+ static int brcmf_net_p2p_open(struct net_device *ndev)
+ {
+       brcmf_dbg(TRACE, "Enter\n");
+@@ -805,8 +811,7 @@ struct brcmf_if *brcmf_add_if(struct brc
+                         ifp->ndev->name);
+               if (ifidx) {
+                       netif_stop_queue(ifp->ndev);
+-                      unregister_netdev(ifp->ndev);
+-                      free_netdev(ifp->ndev);
++                      brcmf_net_detach(ifp->ndev);
+                       drvr->iflist[bssidx] = NULL;
+               } else {
+                       brcmf_err("ignore IF event\n");
+@@ -828,6 +833,7 @@ struct brcmf_if *brcmf_add_if(struct brc
+               if (!ndev)
+                       return ERR_PTR(-ENOMEM);
++              ndev->destructor = brcmf_cfg80211_free_netdev;
+               ifp = netdev_priv(ndev);
+               ifp->ndev = ndev;
+               /* store mapping ifidx to bssidx */
+@@ -879,8 +885,7 @@ static void brcmf_del_if(struct brcmf_pu
+                       cancel_work_sync(&ifp->setmacaddr_work);
+                       cancel_work_sync(&ifp->multicast_work);
+               }
+-              /* unregister will take care of freeing it */
+-              unregister_netdev(ifp->ndev);
++              brcmf_net_detach(ifp->ndev);
+       }
+ }
+@@ -1056,11 +1061,11 @@ fail:
+                       brcmf_fws_deinit(drvr);
+               }
+               if (drvr->iflist[0]) {
+-                      free_netdev(ifp->ndev);
++                      brcmf_net_detach(ifp->ndev);
+                       drvr->iflist[0] = NULL;
+               }
+               if (p2p_ifp) {
+-                      free_netdev(p2p_ifp->ndev);
++                      brcmf_net_detach(p2p_ifp->ndev);
+                       drvr->iflist[1] = NULL;
+               }
+               return ret;
index f9799ce..685a5f9 100644 (file)
@@ -13,7 +13,7 @@ Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
 
 --- a/drivers/net/wireless/brcm80211/brcmfmac/core.c
 +++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c
-@@ -1189,6 +1189,7 @@ static int __init brcmfmac_module_init(v
+@@ -1213,6 +1213,7 @@ static int __init brcmfmac_module_init(v
  #endif
        if (!schedule_work(&brcmf_driver_work))
                return -EBUSY;
index 542e88b..1cba2b3 100644 (file)
@@ -10,12 +10,13 @@ Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
 
 --- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
 +++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
-@@ -661,8 +661,36 @@ static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy,
+@@ -691,9 +691,37 @@ static struct wireless_dev *brcmf_cfg802
                                                     u32 *flags,
                                                     struct vif_params *params)
  {
 +      struct net_device *dev;
        struct wireless_dev *wdev;
+       int err;
  
 +      /*
 +       * There is a bug with in-firmware BSS management. When adding virtual
@@ -45,5 +46,5 @@ Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
 +      }
 +
        brcmf_dbg(TRACE, "enter: %s type %d\n", name, type);
-       switch (type) {
-       case NL80211_IFTYPE_ADHOC:
+       err = brcmf_vif_add_validate(wiphy_to_cfg(wiphy), type);
+       if (err) {
diff --git a/package/kernel/mac80211/patches/863-brcmfmac-set-wiphy-s-addresses-to-provide-valid-MACs.patch b/package/kernel/mac80211/patches/863-brcmfmac-set-wiphy-s-addresses-to-provide-valid-MACs.patch
deleted file mode 100644 (file)
index 24ccadd..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
-Date: Thu, 9 Jul 2015 16:53:30 +0200
-Subject: [PATCH] brcmfmac: set wiphy's addresses to provide valid MACs
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Broadcom's firmware requires every BSS to use MAC address with unique
-last few bits. The amount of bits may depend on a particular firmware,
-it was verified to be 2 for BCM43602 one.
-If this condition won't be fulfilled firmware will reject such MAC:
-brcmfmac: _brcmf_set_mac_address: Setting cur_etheraddr failed, -52
-
-We don't want to simply set addr_mask as it would also disallow using
-locally administrated bit. Instead let's build a list of addresses
-manually enabling 0x2 bit for extra interfaces.
-
-Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
----
-
---- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
-+++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
-@@ -5812,6 +5812,7 @@ static void brcmf_wiphy_wowl_params(struct wiphy *wiphy)
- static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
- {
-+      struct brcmf_pub *drvr = ifp->drvr;
-       struct ieee80211_supported_band *band;
-       __le32 bandlist[3];
-       u32 n_bands;
-@@ -5825,6 +5826,19 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
-       if (err)
-               return err;
-+      for (i = 0; i < wiphy->iface_combinations->max_interfaces &&
-+           i < ARRAY_SIZE(drvr->addresses); i++) {
-+              u8 *addr = drvr->addresses[i].addr;
-+
-+              memcpy(addr, drvr->mac, ETH_ALEN);
-+              if (i) {
-+                      addr[0] |= BIT(1);
-+                      addr[ETH_ALEN - 1] ^= i;
-+              }
-+      }
-+      wiphy->addresses = drvr->addresses;
-+      wiphy->n_addresses = i;
-+
-       wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
-       wiphy->cipher_suites = __wl_cipher_suites;
-       wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
---- a/drivers/net/wireless/brcm80211/brcmfmac/core.h
-+++ b/drivers/net/wireless/brcm80211/brcmfmac/core.h
-@@ -21,6 +21,7 @@
- #ifndef BRCMFMAC_CORE_H
- #define BRCMFMAC_CORE_H
-+#include <net/cfg80211.h>
- #include "fweh.h"
- #define TOE_TX_CSUM_OL                0x00000001
-@@ -118,6 +119,8 @@ struct brcmf_pub {
-       /* Multicast data packets sent to dongle */
-       unsigned long tx_multicast;
-+      struct mac_address addresses[BRCMF_MAX_IFS];
-+
-       struct brcmf_if *iflist[BRCMF_MAX_IFS];
-       struct mutex proto_block;