mac80211: brcm: backport remaining 5.6 kernel patches
authorRafał Miłecki <rafal@milecki.pl>
Thu, 6 Feb 2020 10:36:15 +0000 (11:36 +0100)
committerRafał Miłecki <rafal@milecki.pl>
Fri, 7 Feb 2020 10:05:24 +0000 (11:05 +0100)
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
(cherry picked from commit aca274091ad3b50b770c0dd44f3ceefe8095d528)

package/kernel/mac80211/patches/brcm/415-v5.6-brcmfmac-Fix-memory-leak-in-brcmf_usbdev_qinit.patch [new file with mode: 0644]
package/kernel/mac80211/patches/brcm/416-v5.6-brcmfmac-Keep-OOB-wake-interrupt-disabled-when-it-sh.patch [new file with mode: 0644]
package/kernel/mac80211/patches/brcm/417-v5.6-brcmfmac-use-true-false-for-bool-variable.patch [new file with mode: 0644]
package/kernel/mac80211/patches/brcm/418-v5.6-brcmfmac-sdio-Fix-OOB-interrupt-initialization-on-br.patch [new file with mode: 0644]
package/kernel/mac80211/patches/brcm/419-v5.6-0001-brcmfmac-simplify-building-interface-combinations.patch [new file with mode: 0644]
package/kernel/mac80211/patches/brcm/419-v5.6-0002-brcmfmac-add-initial-support-for-monitor-mode.patch [new file with mode: 0644]
package/kernel/mac80211/patches/brcm/420-v5.6-brcmfmac-Remove-always-false-idx-0-statement.patch [new file with mode: 0644]
package/kernel/mac80211/patches/brcm/860-brcmfmac-register-wiphy-s-during-module_init.patch
package/kernel/mac80211/patches/brcm/861-brcmfmac-workaround-bug-with-some-inconsistent-BSSes.patch
package/kernel/mac80211/patches/brcm/862-brcmfmac-Disable-power-management.patch

diff --git a/package/kernel/mac80211/patches/brcm/415-v5.6-brcmfmac-Fix-memory-leak-in-brcmf_usbdev_qinit.patch b/package/kernel/mac80211/patches/brcm/415-v5.6-brcmfmac-Fix-memory-leak-in-brcmf_usbdev_qinit.patch
new file mode 100644 (file)
index 0000000..a55d286
--- /dev/null
@@ -0,0 +1,26 @@
+From 4282dc057d750c6a7dd92953564b15c26b54c22c Mon Sep 17 00:00:00 2001
+From: Navid Emamdoost <navid.emamdoost@gmail.com>
+Date: Sat, 14 Dec 2019 19:51:14 -0600
+Subject: [PATCH] brcmfmac: Fix memory leak in brcmf_usbdev_qinit
+
+In the implementation of brcmf_usbdev_qinit() the allocated memory for
+reqs is leaking if usb_alloc_urb() fails. Release reqs in the error
+handling path.
+
+Fixes: 71bb244ba2fd ("brcm80211: fmac: add USB support for bcm43235/6/8 chipsets")
+Signed-off-by: Navid Emamdoost <navid.emamdoost@gmail.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
+@@ -430,6 +430,7 @@ fail:
+                       usb_free_urb(req->urb);
+               list_del(q->next);
+       }
++      kfree(reqs);
+       return NULL;
+ }
diff --git a/package/kernel/mac80211/patches/brcm/416-v5.6-brcmfmac-Keep-OOB-wake-interrupt-disabled-when-it-sh.patch b/package/kernel/mac80211/patches/brcm/416-v5.6-brcmfmac-Keep-OOB-wake-interrupt-disabled-when-it-sh.patch
new file mode 100644 (file)
index 0000000..3d193df
--- /dev/null
@@ -0,0 +1,66 @@
+From a32de68edab7b73ded850bcf76cdf6858e92a7e5 Mon Sep 17 00:00:00 2001
+From: Dmitry Osipenko <digetx@gmail.com>
+Date: Sun, 15 Dec 2019 21:42:24 +0300
+Subject: [PATCH] brcmfmac: Keep OOB wake-interrupt disabled when it shouldn't
+ be enabled
+
+NVIDIA Tegra SoCs do not like when OOB wake is enabled and WiFi interface
+is in DOWN state during suspend. This results in a CPU hang on programming
+OOB wake-up state of the GPIO controller during of system's suspend.
+
+The solution is trivial: don't enable wake for the OOB interrupt when it
+should be disabled.
+
+This fixes hang on Tegra20 (Acer A500) and Tegra30 (Nexus 7) devices which
+are using BCM4329 and BCM4330 WiFi chips respectively.
+
+Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+ .../net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c  | 10 +++++-----
+ .../net/wireless/broadcom/brcm80211/brcmfmac/sdio.h    |  1 -
+ 2 files changed, 5 insertions(+), 6 deletions(-)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
+@@ -120,7 +120,7 @@ int brcmf_sdiod_intr_register(struct brc
+                       brcmf_err("enable_irq_wake failed %d\n", ret);
+                       return ret;
+               }
+-              sdiodev->irq_wake = true;
++              disable_irq_wake(pdata->oob_irq_nr);
+               sdio_claim_host(sdiodev->func1);
+@@ -179,10 +179,6 @@ void brcmf_sdiod_intr_unregister(struct
+               sdio_release_host(sdiodev->func1);
+               sdiodev->oob_irq_requested = false;
+-              if (sdiodev->irq_wake) {
+-                      disable_irq_wake(pdata->oob_irq_nr);
+-                      sdiodev->irq_wake = false;
+-              }
+               free_irq(pdata->oob_irq_nr, &sdiodev->func1->dev);
+               sdiodev->irq_en = false;
+               sdiodev->oob_irq_requested = false;
+@@ -1162,6 +1158,10 @@ static int brcmf_ops_sdio_resume(struct
+               if (ret)
+                       brcmf_err("Failed to probe device on resume\n");
+       } else {
++              if (sdiodev->wowl_enabled &&
++                  sdiodev->settings->bus.sdio.oob_irq_supported)
++                      disable_irq_wake(sdiodev->settings->bus.sdio.oob_irq_nr);
++
+               brcmf_sdiod_freezer_off(sdiodev);
+       }
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h
+@@ -178,7 +178,6 @@ struct brcmf_sdio_dev {
+       bool sd_irq_requested;
+       bool irq_en;                    /* irq enable flags */
+       spinlock_t irq_en_lock;
+-      bool irq_wake;                  /* irq wake enable flags */
+       bool sg_support;
+       uint max_request_size;
+       ushort max_segment_count;
diff --git a/package/kernel/mac80211/patches/brcm/417-v5.6-brcmfmac-use-true-false-for-bool-variable.patch b/package/kernel/mac80211/patches/brcm/417-v5.6-brcmfmac-use-true-false-for-bool-variable.patch
new file mode 100644 (file)
index 0000000..0eb169c
--- /dev/null
@@ -0,0 +1,27 @@
+From b92c017deda819e45a0f054f6df6b53e645d7fe4 Mon Sep 17 00:00:00 2001
+From: zhengbin <zhengbin13@huawei.com>
+Date: Tue, 24 Dec 2019 22:16:06 +0800
+Subject: [PATCH] brcmfmac: use true,false for bool variable
+
+Fixes coccicheck warning:
+
+drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c:911:2-24: WARNING: Assignment of 0/1 to bool variable
+
+Reported-by: Hulk Robot <hulkci@huawei.com>
+Signed-off-by: zhengbin <zhengbin13@huawei.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
+@@ -908,7 +908,7 @@ static u8 brcmf_fws_hdrpush(struct brcmf
+       wlh += wlh[1] + 2;
+       if (entry->send_tim_signal) {
+-              entry->send_tim_signal = 0;
++              entry->send_tim_signal = false;
+               wlh[0] = BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP;
+               wlh[1] = BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP_LEN;
+               wlh[2] = entry->mac_handle;
diff --git a/package/kernel/mac80211/patches/brcm/418-v5.6-brcmfmac-sdio-Fix-OOB-interrupt-initialization-on-br.patch b/package/kernel/mac80211/patches/brcm/418-v5.6-brcmfmac-sdio-Fix-OOB-interrupt-initialization-on-br.patch
new file mode 100644 (file)
index 0000000..3b1b00c
--- /dev/null
@@ -0,0 +1,57 @@
+From 8c8e60fb86a90a30721bbd797f58f96b3980dcc1 Mon Sep 17 00:00:00 2001
+From: Jean-Philippe Brucker <jean-philippe@linaro.org>
+Date: Thu, 26 Dec 2019 10:20:33 +0100
+Subject: [PATCH] brcmfmac: sdio: Fix OOB interrupt initialization on brcm43362
+
+Commit 262f2b53f679 ("brcmfmac: call brcmf_attach() just before calling
+brcmf_bus_started()") changed the initialization order of the brcmfmac
+SDIO driver. Unfortunately since brcmf_sdiod_intr_register() is now
+called before the sdiodev->bus_if initialization, it reads the wrong
+chip ID and fails to initialize the GPIO on brcm43362. Thus the chip
+cannot send interrupts and fails to probe:
+
+[   12.517023] brcmfmac: brcmf_sdio_bus_rxctl: resumed on timeout
+[   12.531214] ieee80211 phy0: brcmf_bus_started: failed: -110
+[   12.536976] ieee80211 phy0: brcmf_attach: dongle is not responding: err=-110
+[   12.566467] brcmfmac: brcmf_sdio_firmware_callback: brcmf_attach failed
+
+Initialize the bus interface earlier to ensure that
+brcmf_sdiod_intr_register() properly sets up the OOB interrupt.
+
+BugLink: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=908438
+Fixes: 262f2b53f679 ("brcmfmac: call brcmf_attach() just before calling brcmf_bus_started()")
+Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
+Reviewed-by: Arend van Spriel <arend.vanspriel@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+ .../net/wireless/broadcom/brcm80211/brcmfmac/sdio.c  | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
+@@ -4247,6 +4247,12 @@ static void brcmf_sdio_firmware_callback
+       }
+       if (err == 0) {
++              /* Assign bus interface call back */
++              sdiod->bus_if->dev = sdiod->dev;
++              sdiod->bus_if->ops = &brcmf_sdio_bus_ops;
++              sdiod->bus_if->chip = bus->ci->chip;
++              sdiod->bus_if->chiprev = bus->ci->chiprev;
++
+               /* Allow full data communication using DPC from now on. */
+               brcmf_sdiod_change_state(bus->sdiodev, BRCMF_SDIOD_DATA);
+@@ -4263,12 +4269,6 @@ static void brcmf_sdio_firmware_callback
+       sdio_release_host(sdiod->func1);
+-      /* Assign bus interface call back */
+-      sdiod->bus_if->dev = sdiod->dev;
+-      sdiod->bus_if->ops = &brcmf_sdio_bus_ops;
+-      sdiod->bus_if->chip = bus->ci->chip;
+-      sdiod->bus_if->chiprev = bus->ci->chiprev;
+-
+       err = brcmf_alloc(sdiod->dev, sdiod->settings);
+       if (err) {
+               brcmf_err("brcmf_alloc failed\n");
diff --git a/package/kernel/mac80211/patches/brcm/419-v5.6-0001-brcmfmac-simplify-building-interface-combinations.patch b/package/kernel/mac80211/patches/brcm/419-v5.6-0001-brcmfmac-simplify-building-interface-combinations.patch
new file mode 100644 (file)
index 0000000..8c231cb
--- /dev/null
@@ -0,0 +1,103 @@
+From 24332f8068ff6df7f16aefee45d514de1de4de80 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Date: Thu, 26 Dec 2019 14:30:49 +0100
+Subject: [PATCH] brcmfmac: simplify building interface combinations
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Move similar/duplicated code out of combination specific code blocks.
+This simplifies code a bit and allows adding more combinations later.
+A list of combinations remains unchanged.
+
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+ .../broadcom/brcm80211/brcmfmac/cfg80211.c    | 43 ++++++-------------
+ 1 file changed, 14 insertions(+), 29 deletions(-)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+@@ -6471,12 +6471,13 @@ static int brcmf_setup_ifmodes(struct wi
+       struct ieee80211_iface_limit *c0_limits = NULL;
+       struct ieee80211_iface_limit *p2p_limits = NULL;
+       struct ieee80211_iface_limit *mbss_limits = NULL;
+-      bool mbss, p2p, rsdb;
++      bool mbss, p2p, rsdb, mchan;
+       int i, c, n_combos;
+       mbss = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS);
+       p2p = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_P2P);
+       rsdb = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_RSDB);
++      mchan = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN);
+       n_combos = 1 + !!(p2p && !rsdb) + !!mbss;
+       combo = kcalloc(n_combos, sizeof(*combo), GFP_KERNEL);
+@@ -6486,6 +6487,10 @@ static int brcmf_setup_ifmodes(struct wi
+       wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+                                BIT(NL80211_IFTYPE_ADHOC) |
+                                BIT(NL80211_IFTYPE_AP);
++      if (p2p)
++              wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_CLIENT) |
++                                        BIT(NL80211_IFTYPE_P2P_GO) |
++                                        BIT(NL80211_IFTYPE_P2P_DEVICE);
+       c = 0;
+       i = 0;
+@@ -6497,48 +6502,28 @@ static int brcmf_setup_ifmodes(struct wi
+               c0_limits = kcalloc(2, sizeof(*c0_limits), GFP_KERNEL);
+       if (!c0_limits)
+               goto err;
+-      if (p2p && rsdb) {
+-              combo[c].num_different_channels = 2;
+-              wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_CLIENT) |
+-                                        BIT(NL80211_IFTYPE_P2P_GO) |
+-                                        BIT(NL80211_IFTYPE_P2P_DEVICE);
+-              c0_limits[i].max = 2;
+-              c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
++
++      combo[c].num_different_channels = 1 + (rsdb || (p2p && mchan));
++      c0_limits[i].max = 1 + rsdb;
++      c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
++      if (p2p) {
+               c0_limits[i].max = 1;
+               c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
+-              c0_limits[i].max = 2;
++              c0_limits[i].max = 1 + rsdb;
+               c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
+                                      BIT(NL80211_IFTYPE_P2P_GO);
++      }
++      if (p2p && rsdb) {
+               c0_limits[i].max = 2;
+               c0_limits[i++].types = BIT(NL80211_IFTYPE_AP);
+               combo[c].max_interfaces = 5;
+       } else if (p2p) {
+-              if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN))
+-                      combo[c].num_different_channels = 2;
+-              else
+-                      combo[c].num_different_channels = 1;
+-              c0_limits[i].max = 1;
+-              c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
+-              wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_CLIENT) |
+-                                        BIT(NL80211_IFTYPE_P2P_GO) |
+-                                        BIT(NL80211_IFTYPE_P2P_DEVICE);
+-              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);
+               combo[c].max_interfaces = i;
+       } else if (rsdb) {
+-              combo[c].num_different_channels = 2;
+-              c0_limits[i].max = 2;
+-              c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
+               c0_limits[i].max = 2;
+               c0_limits[i++].types = BIT(NL80211_IFTYPE_AP);
+               combo[c].max_interfaces = 3;
+       } else {
+-              combo[c].num_different_channels = 1;
+-              c0_limits[i].max = 1;
+-              c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
+               c0_limits[i].max = 1;
+               c0_limits[i++].types = BIT(NL80211_IFTYPE_AP);
+               combo[c].max_interfaces = i;
diff --git a/package/kernel/mac80211/patches/brcm/419-v5.6-0002-brcmfmac-add-initial-support-for-monitor-mode.patch b/package/kernel/mac80211/patches/brcm/419-v5.6-0002-brcmfmac-add-initial-support-for-monitor-mode.patch
new file mode 100644 (file)
index 0000000..f64ff1e
--- /dev/null
@@ -0,0 +1,345 @@
+From 20f2c5fa3af060401c72e444999470a4cab641cf Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Date: Thu, 26 Dec 2019 14:30:50 +0100
+Subject: [PATCH] brcmfmac: add initial support for monitor mode
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Report monitor interface availability using cfg80211 and support it in
+the add_virtual_intf() and del_virtual_intf() callbacks. This new
+feature is conditional and depends on firmware flagging monitor packets.
+Receiving monitor frames is already handled by the brcmf_netif_mon_rx().
+
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+ .../broadcom/brcm80211/brcmfmac/cfg80211.c    | 112 ++++++++++++++++--
+ .../broadcom/brcm80211/brcmfmac/core.c        |  68 ++++++++++-
+ .../broadcom/brcm80211/brcmfmac/core.h        |   2 +
+ .../broadcom/brcm80211/brcmfmac/feature.c     |   1 +
+ .../broadcom/brcm80211/brcmfmac/feature.h     |   2 +
+ .../broadcom/brcm80211/brcmfmac/fwil.h        |   2 +
+ 6 files changed, 174 insertions(+), 13 deletions(-)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+@@ -11,6 +11,7 @@
+ #include <linux/vmalloc.h>
+ #include <net/cfg80211.h>
+ #include <net/netlink.h>
++#include <uapi/linux/if_arp.h>
+ #include <brcmu_utils.h>
+ #include <defs.h>
+@@ -619,6 +620,82 @@ static bool brcmf_is_ibssmode(struct brc
+       return vif->wdev.iftype == NL80211_IFTYPE_ADHOC;
+ }
++/**
++ * brcmf_mon_add_vif() - create monitor mode virtual interface
++ *
++ * @wiphy: wiphy device of new interface.
++ * @name: name of the new interface.
++ */
++static struct wireless_dev *brcmf_mon_add_vif(struct wiphy *wiphy,
++                                            const char *name)
++{
++      struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
++      struct brcmf_cfg80211_vif *vif;
++      struct net_device *ndev;
++      struct brcmf_if *ifp;
++      int err;
++
++      if (cfg->pub->mon_if) {
++              err = -EEXIST;
++              goto err_out;
++      }
++
++      vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_MONITOR);
++      if (IS_ERR(vif)) {
++              err = PTR_ERR(vif);
++              goto err_out;
++      }
++
++      ndev = alloc_netdev(sizeof(*ifp), name, NET_NAME_UNKNOWN, ether_setup);
++      if (!ndev) {
++              err = -ENOMEM;
++              goto err_free_vif;
++      }
++      ndev->type = ARPHRD_IEEE80211_RADIOTAP;
++      ndev->ieee80211_ptr = &vif->wdev;
++      ndev->needs_free_netdev = true;
++      ndev->priv_destructor = brcmf_cfg80211_free_netdev;
++      SET_NETDEV_DEV(ndev, wiphy_dev(cfg->wiphy));
++
++      ifp = netdev_priv(ndev);
++      ifp->vif = vif;
++      ifp->ndev = ndev;
++      ifp->drvr = cfg->pub;
++
++      vif->ifp = ifp;
++      vif->wdev.netdev = ndev;
++
++      err = brcmf_net_mon_attach(ifp);
++      if (err) {
++              brcmf_err("Failed to attach %s device\n", ndev->name);
++              free_netdev(ndev);
++              goto err_free_vif;
++      }
++
++      cfg->pub->mon_if = ifp;
++
++      return &vif->wdev;
++
++err_free_vif:
++      brcmf_free_vif(vif);
++err_out:
++      return ERR_PTR(err);
++}
++
++static int brcmf_mon_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev)
++{
++      struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
++      struct net_device *ndev = wdev->netdev;
++
++      ndev->netdev_ops->ndo_stop(ndev);
++
++      brcmf_net_detach(ndev, true);
++
++      cfg->pub->mon_if = NULL;
++
++      return 0;
++}
++
+ static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy,
+                                                    const char *name,
+                                                    unsigned char name_assign_type,
+@@ -641,9 +718,10 @@ static struct wireless_dev *brcmf_cfg802
+       case NL80211_IFTYPE_STATION:
+       case NL80211_IFTYPE_AP_VLAN:
+       case NL80211_IFTYPE_WDS:
+-      case NL80211_IFTYPE_MONITOR:
+       case NL80211_IFTYPE_MESH_POINT:
+               return ERR_PTR(-EOPNOTSUPP);
++      case NL80211_IFTYPE_MONITOR:
++              return brcmf_mon_add_vif(wiphy, name);
+       case NL80211_IFTYPE_AP:
+               wdev = brcmf_ap_add_vif(wiphy, name, params);
+               break;
+@@ -826,9 +904,10 @@ int brcmf_cfg80211_del_iface(struct wiph
+       case NL80211_IFTYPE_STATION:
+       case NL80211_IFTYPE_AP_VLAN:
+       case NL80211_IFTYPE_WDS:
+-      case NL80211_IFTYPE_MONITOR:
+       case NL80211_IFTYPE_MESH_POINT:
+               return -EOPNOTSUPP;
++      case NL80211_IFTYPE_MONITOR:
++              return brcmf_mon_del_vif(wiphy, wdev);
+       case NL80211_IFTYPE_AP:
+               return brcmf_cfg80211_del_ap_iface(wiphy, wdev);
+       case NL80211_IFTYPE_P2P_CLIENT:
+@@ -6471,9 +6550,10 @@ static int brcmf_setup_ifmodes(struct wi
+       struct ieee80211_iface_limit *c0_limits = NULL;
+       struct ieee80211_iface_limit *p2p_limits = NULL;
+       struct ieee80211_iface_limit *mbss_limits = NULL;
+-      bool mbss, p2p, rsdb, mchan;
+-      int i, c, n_combos;
++      bool mon_flag, mbss, p2p, rsdb, mchan;
++      int i, c, n_combos, n_limits;
++      mon_flag = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MONITOR_FLAG);
+       mbss = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS);
+       p2p = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_P2P);
+       rsdb = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_RSDB);
+@@ -6487,6 +6567,8 @@ static int brcmf_setup_ifmodes(struct wi
+       wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+                                BIT(NL80211_IFTYPE_ADHOC) |
+                                BIT(NL80211_IFTYPE_AP);
++      if (mon_flag)
++              wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);
+       if (p2p)
+               wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_CLIENT) |
+                                         BIT(NL80211_IFTYPE_P2P_GO) |
+@@ -6494,18 +6576,18 @@ static int brcmf_setup_ifmodes(struct wi
+       c = 0;
+       i = 0;
+-      if (p2p && rsdb)
+-              c0_limits = kcalloc(4, sizeof(*c0_limits), GFP_KERNEL);
+-      else if (p2p)
+-              c0_limits = kcalloc(3, sizeof(*c0_limits), GFP_KERNEL);
+-      else
+-              c0_limits = kcalloc(2, sizeof(*c0_limits), GFP_KERNEL);
++      n_limits = 1 + mon_flag + (p2p ? 2 : 0) + (rsdb || !p2p);
++      c0_limits = kcalloc(n_limits, sizeof(*c0_limits), GFP_KERNEL);
+       if (!c0_limits)
+               goto err;
+       combo[c].num_different_channels = 1 + (rsdb || (p2p && mchan));
+       c0_limits[i].max = 1 + rsdb;
+       c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
++      if (mon_flag) {
++              c0_limits[i].max = 1;
++              c0_limits[i++].types = BIT(NL80211_IFTYPE_MONITOR);
++      }
+       if (p2p) {
+               c0_limits[i].max = 1;
+               c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
+@@ -6554,14 +6636,20 @@ static int brcmf_setup_ifmodes(struct wi
+       if (mbss) {
+               c++;
+               i = 0;
+-              mbss_limits = kcalloc(1, sizeof(*mbss_limits), GFP_KERNEL);
++              n_limits = 1 + mon_flag;
++              mbss_limits = kcalloc(n_limits, sizeof(*mbss_limits),
++                                    GFP_KERNEL);
+               if (!mbss_limits)
+                       goto err;
+               mbss_limits[i].max = 4;
+               mbss_limits[i++].types = BIT(NL80211_IFTYPE_AP);
++              if (mon_flag) {
++                      mbss_limits[i].max = 1;
++                      mbss_limits[i++].types = BIT(NL80211_IFTYPE_MONITOR);
++              }
+               combo[c].beacon_int_infra_match = true;
+               combo[c].num_different_channels = 1;
+-              combo[c].max_interfaces = 4;
++              combo[c].max_interfaces = 4 + mon_flag;
+               combo[c].n_limits = i;
+               combo[c].limits = mbss_limits;
+       }
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+@@ -690,7 +690,7 @@ fail:
+       return -EBADE;
+ }
+-static void brcmf_net_detach(struct net_device *ndev, bool rtnl_locked)
++void brcmf_net_detach(struct net_device *ndev, bool rtnl_locked)
+ {
+       if (ndev->reg_state == NETREG_REGISTERED) {
+               if (rtnl_locked)
+@@ -703,6 +703,72 @@ static void brcmf_net_detach(struct net_
+       }
+ }
++static int brcmf_net_mon_open(struct net_device *ndev)
++{
++      struct brcmf_if *ifp = netdev_priv(ndev);
++      struct brcmf_pub *drvr = ifp->drvr;
++      u32 monitor;
++      int err;
++
++      brcmf_dbg(TRACE, "Enter\n");
++
++      err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_MONITOR, &monitor);
++      if (err) {
++              bphy_err(drvr, "BRCMF_C_GET_MONITOR error (%d)\n", err);
++              return err;
++      } else if (monitor) {
++              bphy_err(drvr, "Monitor mode is already enabled\n");
++              return -EEXIST;
++      }
++
++      monitor = 3;
++      err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_MONITOR, monitor);
++      if (err)
++              bphy_err(drvr, "BRCMF_C_SET_MONITOR error (%d)\n", err);
++
++      return err;
++}
++
++static int brcmf_net_mon_stop(struct net_device *ndev)
++{
++      struct brcmf_if *ifp = netdev_priv(ndev);
++      struct brcmf_pub *drvr = ifp->drvr;
++      u32 monitor;
++      int err;
++
++      brcmf_dbg(TRACE, "Enter\n");
++
++      monitor = 0;
++      err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_MONITOR, monitor);
++      if (err)
++              bphy_err(drvr, "BRCMF_C_SET_MONITOR error (%d)\n", err);
++
++      return err;
++}
++
++static const struct net_device_ops brcmf_netdev_ops_mon = {
++      .ndo_open = brcmf_net_mon_open,
++      .ndo_stop = brcmf_net_mon_stop,
++};
++
++int brcmf_net_mon_attach(struct brcmf_if *ifp)
++{
++      struct brcmf_pub *drvr = ifp->drvr;
++      struct net_device *ndev;
++      int err;
++
++      brcmf_dbg(TRACE, "Enter\n");
++
++      ndev = ifp->ndev;
++      ndev->netdev_ops = &brcmf_netdev_ops_mon;
++
++      err = register_netdevice(ndev);
++      if (err)
++              bphy_err(drvr, "Failed to register %s device\n", ndev->name);
++
++      return err;
++}
++
+ void brcmf_net_setcarrier(struct brcmf_if *ifp, bool on)
+ {
+       struct net_device *ndev;
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
+@@ -210,6 +210,8 @@ void brcmf_txflowblock_if(struct brcmf_i
+ void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success);
+ void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb);
+ void brcmf_netif_mon_rx(struct brcmf_if *ifp, struct sk_buff *skb);
++void brcmf_net_detach(struct net_device *ndev, bool rtnl_locked);
++int brcmf_net_mon_attach(struct brcmf_if *ifp);
+ void brcmf_net_setcarrier(struct brcmf_if *ifp, bool on);
+ int __init brcmf_core_init(void);
+ void __exit brcmf_core_exit(void);
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
+@@ -38,6 +38,7 @@ static const struct brcmf_feat_fwcap brc
+       { BRCMF_FEAT_MCHAN, "mchan" },
+       { BRCMF_FEAT_P2P, "p2p" },
+       { BRCMF_FEAT_MONITOR, "monitor" },
++      { BRCMF_FEAT_MONITOR_FLAG, "rtap" },
+       { BRCMF_FEAT_MONITOR_FMT_RADIOTAP, "rtap" },
+       { BRCMF_FEAT_DOT11H, "802.11h" }
+ };
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
+@@ -23,6 +23,7 @@
+  * GSCAN: enhanced scan offload feature.
+  * FWSUP: Firmware supplicant.
+  * MONITOR: firmware can pass monitor packets to host.
++ * MONITOR_FLAG: firmware flags monitor packets.
+  * MONITOR_FMT_RADIOTAP: firmware provides monitor packets with radiotap header
+  * MONITOR_FMT_HW_RX_HDR: firmware provides monitor packets with hw/ucode header
+  * DOT11H: firmware supports 802.11h
+@@ -43,6 +44,7 @@
+       BRCMF_FEAT_DEF(GSCAN) \
+       BRCMF_FEAT_DEF(FWSUP) \
+       BRCMF_FEAT_DEF(MONITOR) \
++      BRCMF_FEAT_DEF(MONITOR_FLAG) \
+       BRCMF_FEAT_DEF(MONITOR_FMT_RADIOTAP) \
+       BRCMF_FEAT_DEF(MONITOR_FMT_HW_RX_HDR) \
+       BRCMF_FEAT_DEF(DOT11H)
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h
+@@ -49,6 +49,8 @@
+ #define BRCMF_C_GET_PM                                85
+ #define BRCMF_C_SET_PM                                86
+ #define BRCMF_C_GET_REVINFO                   98
++#define BRCMF_C_GET_MONITOR                   107
++#define BRCMF_C_SET_MONITOR                   108
+ #define BRCMF_C_GET_CURR_RATESET              114
+ #define BRCMF_C_GET_AP                                117
+ #define BRCMF_C_SET_AP                                118
diff --git a/package/kernel/mac80211/patches/brcm/420-v5.6-brcmfmac-Remove-always-false-idx-0-statement.patch b/package/kernel/mac80211/patches/brcm/420-v5.6-brcmfmac-Remove-always-false-idx-0-statement.patch
new file mode 100644 (file)
index 0000000..9efa762
--- /dev/null
@@ -0,0 +1,24 @@
+From 627b0d094240c38393b2f2d40626c33a8fff6103 Mon Sep 17 00:00:00 2001
+From: yuehaibing <yuehaibing@huawei.com>
+Date: Wed, 8 Jan 2020 21:57:48 +0800
+Subject: [PATCH] brcmfmac: Remove always false 'idx < 0' statement
+
+idx is declared as u32, it will never less than 0.
+
+Signed-off-by: yuehaibing <yuehaibing@huawei.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
+@@ -365,7 +365,7 @@ brcmf_msgbuf_get_pktid(struct device *de
+       struct brcmf_msgbuf_pktid *pktid;
+       struct sk_buff *skb;
+-      if (idx < 0 || idx >= pktids->array_size) {
++      if (idx >= pktids->array_size) {
+               brcmf_err("Invalid packet id %d (max %d)\n", idx,
+                         pktids->array_size);
+               return NULL;
index f64167b..a1bcbfa 100644 (file)
@@ -13,7 +13,7 @@ Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
 
 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
-@@ -1479,6 +1479,7 @@ int __init brcmf_core_init(void)
+@@ -1545,6 +1545,7 @@ int __init brcmf_core_init(void)
  {
        if (!schedule_work(&brcmf_driver_work))
                return -EBUSY;
index 5f0fa7f..37ebb51 100644 (file)
@@ -10,7 +10,7 @@ Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
 
 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
-@@ -628,8 +628,36 @@ static struct wireless_dev *brcmf_cfg802
+@@ -705,8 +705,36 @@ static struct wireless_dev *brcmf_cfg802
        struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
        struct brcmf_pub *drvr = cfg->pub;
        struct wireless_dev *wdev;
index c5501b9..afbd2cc 100644 (file)
@@ -14,7 +14,7 @@ Signed-off-by: Phil Elwell <phil@raspberrypi.org>
 
 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
-@@ -2787,6 +2787,10 @@ brcmf_cfg80211_set_power_mgmt(struct wip
+@@ -2866,6 +2866,10 @@ brcmf_cfg80211_set_power_mgmt(struct wip
         * preference in cfg struct to apply this to
         * FW later while initializing the dongle
         */