mac80211: brcmfmac: really add early fw crash recovery
authorRafał Miłecki <rafal@milecki.pl>
Thu, 18 Apr 2019 10:37:10 +0000 (12:37 +0200)
committerRafał Miłecki <rafal@milecki.pl>
Thu, 18 Apr 2019 11:44:02 +0000 (13:44 +0200)
Previous commit backported USB fixes instead of firmware crash recovery
patches.

Fixes: eaef74279c8f ("mac80211: brcmfmac: early work on FullMAC firmware crash recovery")
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
(cherry picked from commit 2d2e615dee0421e126af9d4ebd49a720e341e3af)

package/kernel/mac80211/patches/340-v5.2-0001-brcmfmac-fix-race-during-disconnect-when-USB-complet.patch [deleted file]
package/kernel/mac80211/patches/340-v5.2-0001-brcmfmac-support-repeated-brcmf_fw_alloc_request-cal.patch [new file with mode: 0644]
package/kernel/mac80211/patches/340-v5.2-0002-brcmfmac-add-a-function-designated-for-handling-firm.patch [new file with mode: 0644]
package/kernel/mac80211/patches/340-v5.2-0002-brcmfmac-remove-pending-parameter-from-brcmf_usb_fre.patch [deleted file]
package/kernel/mac80211/patches/340-v5.2-0003-brcmfmac-remove-unused-variable-i-from-brcmf_usb_fre.patch [deleted file]
package/kernel/mac80211/patches/340-v5.2-0003-brcmfmac-reset-PCIe-bus-on-a-firmware-crash.patch [new file with mode: 0644]
package/kernel/mac80211/patches/342-v5.2-0001-brcmfmac-fix-race-during-disconnect-when-USB-complet.patch [new file with mode: 0644]
package/kernel/mac80211/patches/342-v5.2-0002-brcmfmac-remove-pending-parameter-from-brcmf_usb_fre.patch [new file with mode: 0644]
package/kernel/mac80211/patches/342-v5.2-0003-brcmfmac-remove-unused-variable-i-from-brcmf_usb_fre.patch [new file with mode: 0644]

diff --git a/package/kernel/mac80211/patches/340-v5.2-0001-brcmfmac-fix-race-during-disconnect-when-USB-complet.patch b/package/kernel/mac80211/patches/340-v5.2-0001-brcmfmac-fix-race-during-disconnect-when-USB-complet.patch
deleted file mode 100644 (file)
index a6d5c34..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-From db3b9e2e1d58080d0754bdf9293dabf8c6491b67 Mon Sep 17 00:00:00 2001
-From: Piotr Figiel <p.figiel@camlintechnologies.com>
-Date: Fri, 8 Mar 2019 15:25:04 +0000
-Subject: [PATCH] brcmfmac: fix race during disconnect when USB completion is
- in progress
-
-It was observed that rarely during USB disconnect happening shortly after
-connect (before full initialization completes) usb_hub_wq would wait
-forever for the dev_init_lock to be unlocked. dev_init_lock would remain
-locked though because of infinite wait during usb_kill_urb:
-
-[ 2730.656472] kworker/0:2     D    0   260      2 0x00000000
-[ 2730.660700] Workqueue: events request_firmware_work_func
-[ 2730.664807] [<809dca20>] (__schedule) from [<809dd164>] (schedule+0x4c/0xac)
-[ 2730.670587] [<809dd164>] (schedule) from [<8069af44>] (usb_kill_urb+0xdc/0x114)
-[ 2730.676815] [<8069af44>] (usb_kill_urb) from [<7f258b50>] (brcmf_usb_free_q+0x34/0xa8 [brcmfmac])
-[ 2730.684833] [<7f258b50>] (brcmf_usb_free_q [brcmfmac]) from [<7f2517d4>] (brcmf_detach+0xa0/0xb8 [brcmfmac])
-[ 2730.693557] [<7f2517d4>] (brcmf_detach [brcmfmac]) from [<7f251a34>] (brcmf_attach+0xac/0x3d8 [brcmfmac])
-[ 2730.702094] [<7f251a34>] (brcmf_attach [brcmfmac]) from [<7f2587ac>] (brcmf_usb_probe_phase2+0x468/0x4a0 [brcmfmac])
-[ 2730.711601] [<7f2587ac>] (brcmf_usb_probe_phase2 [brcmfmac]) from [<7f252888>] (brcmf_fw_request_done+0x194/0x220 [brcmfmac])
-[ 2730.721795] [<7f252888>] (brcmf_fw_request_done [brcmfmac]) from [<805748e4>] (request_firmware_work_func+0x4c/0x88)
-[ 2730.731125] [<805748e4>] (request_firmware_work_func) from [<80141474>] (process_one_work+0x228/0x808)
-[ 2730.739223] [<80141474>] (process_one_work) from [<80141a80>] (worker_thread+0x2c/0x564)
-[ 2730.746105] [<80141a80>] (worker_thread) from [<80147bcc>] (kthread+0x13c/0x16c)
-[ 2730.752227] [<80147bcc>] (kthread) from [<801010b4>] (ret_from_fork+0x14/0x20)
-
-[ 2733.099695] kworker/0:3     D    0  1065      2 0x00000000
-[ 2733.103926] Workqueue: usb_hub_wq hub_event
-[ 2733.106914] [<809dca20>] (__schedule) from [<809dd164>] (schedule+0x4c/0xac)
-[ 2733.112693] [<809dd164>] (schedule) from [<809e2a8c>] (schedule_timeout+0x214/0x3e4)
-[ 2733.119621] [<809e2a8c>] (schedule_timeout) from [<809dde2c>] (wait_for_common+0xc4/0x1c0)
-[ 2733.126810] [<809dde2c>] (wait_for_common) from [<7f258d00>] (brcmf_usb_disconnect+0x1c/0x4c [brcmfmac])
-[ 2733.135206] [<7f258d00>] (brcmf_usb_disconnect [brcmfmac]) from [<8069e0c8>] (usb_unbind_interface+0x5c/0x1e4)
-[ 2733.143943] [<8069e0c8>] (usb_unbind_interface) from [<8056d3e8>] (device_release_driver_internal+0x164/0x1fc)
-[ 2733.152769] [<8056d3e8>] (device_release_driver_internal) from [<8056c078>] (bus_remove_device+0xd0/0xfc)
-[ 2733.161138] [<8056c078>] (bus_remove_device) from [<8056977c>] (device_del+0x11c/0x310)
-[ 2733.167939] [<8056977c>] (device_del) from [<8069cba8>] (usb_disable_device+0xa0/0x1cc)
-[ 2733.174743] [<8069cba8>] (usb_disable_device) from [<8069507c>] (usb_disconnect+0x74/0x1dc)
-[ 2733.181823] [<8069507c>] (usb_disconnect) from [<80695e88>] (hub_event+0x478/0xf88)
-[ 2733.188278] [<80695e88>] (hub_event) from [<80141474>] (process_one_work+0x228/0x808)
-[ 2733.194905] [<80141474>] (process_one_work) from [<80141a80>] (worker_thread+0x2c/0x564)
-[ 2733.201724] [<80141a80>] (worker_thread) from [<80147bcc>] (kthread+0x13c/0x16c)
-[ 2733.207913] [<80147bcc>] (kthread) from [<801010b4>] (ret_from_fork+0x14/0x20)
-
-It was traced down to a case where usb_kill_urb would be called on an URB
-structure containing more or less random data, including large number in
-its use_count. During the debugging it appeared that in brcmf_usb_free_q()
-the traversal over URBs' lists is not synchronized with operations on those
-lists in brcmf_usb_rx_complete() leading to handling
-brcmf_usbdev_info structure (holding lists' head) as lists' element and in
-result causing above problem.
-
-Fix it by walking through all URBs during brcmf_cancel_all_urbs using the
-arrays of requests instead of linked lists.
-
-Signed-off-by: Piotr Figiel <p.figiel@camlintechnologies.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
- drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c | 10 ++++++++--
- 1 file changed, 8 insertions(+), 2 deletions(-)
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
-@@ -684,12 +684,18 @@ static int brcmf_usb_up(struct device *d
- static void brcmf_cancel_all_urbs(struct brcmf_usbdev_info *devinfo)
- {
-+      int i;
-+
-       if (devinfo->ctl_urb)
-               usb_kill_urb(devinfo->ctl_urb);
-       if (devinfo->bulk_urb)
-               usb_kill_urb(devinfo->bulk_urb);
--      brcmf_usb_free_q(&devinfo->tx_postq, true);
--      brcmf_usb_free_q(&devinfo->rx_postq, true);
-+      if (devinfo->tx_reqs)
-+              for (i = 0; i < devinfo->bus_pub.ntxq; i++)
-+                      usb_kill_urb(devinfo->tx_reqs[i].urb);
-+      if (devinfo->rx_reqs)
-+              for (i = 0; i < devinfo->bus_pub.nrxq; i++)
-+                      usb_kill_urb(devinfo->rx_reqs[i].urb);
- }
- static void brcmf_usb_down(struct device *dev)
diff --git a/package/kernel/mac80211/patches/340-v5.2-0001-brcmfmac-support-repeated-brcmf_fw_alloc_request-cal.patch b/package/kernel/mac80211/patches/340-v5.2-0001-brcmfmac-support-repeated-brcmf_fw_alloc_request-cal.patch
new file mode 100644 (file)
index 0000000..ef25172
--- /dev/null
@@ -0,0 +1,32 @@
+From c9692820710f57c826b2e43a6fb1e4cd307508b0 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Date: Tue, 26 Feb 2019 14:11:16 +0100
+Subject: [PATCH] brcmfmac: support repeated brcmf_fw_alloc_request() calls
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+During a normal brcmfmac lifetime brcmf_fw_alloc_request() is called
+once only during the probe. It's safe to assume provided array is clear.
+
+Further brcmfmac improvements may require calling it multiple times
+though. This patch allows it by fixing invalid firmware paths like:
+brcm/brcmfmac4366c-pcie.binbrcm/brcmfmac4366c-pcie.bin
+
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+Reviewed-by: Arend van Spriel <arend.vanspriel@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
+@@ -582,6 +582,7 @@ int brcmf_fw_map_chip_to_name(u32 chip,
+               return -ENODEV;
+       }
++      fw_name[0] = '\0';
+       /* check if firmware path is provided by module parameter */
+       if (brcmf_mp_global.firmware_path[0] != '\0') {
+               strlcpy(fw_name, brcmf_mp_global.firmware_path,
diff --git a/package/kernel/mac80211/patches/340-v5.2-0002-brcmfmac-add-a-function-designated-for-handling-firm.patch b/package/kernel/mac80211/patches/340-v5.2-0002-brcmfmac-add-a-function-designated-for-handling-firm.patch
new file mode 100644 (file)
index 0000000..227fda0
--- /dev/null
@@ -0,0 +1,79 @@
+From a2ec87ddbf1637f854ffcfff9d12d392fa30758b Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Date: Tue, 26 Feb 2019 14:11:18 +0100
+Subject: [PATCH] brcmfmac: add a function designated for handling firmware
+ fails
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This improves handling PCIe firmware halts by printing a clear error
+message and replaces a similar code in the SDIO bus support.
+
+It will also allow further improvements like trying to recover from a
+firmware crash.
+
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+Reviewed-by: Arend van Spriel <arend.vanspriel@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h |  2 ++
+ .../net/wireless/broadcom/brcm80211/brcmfmac/core.c    | 10 ++++++++++
+ .../net/wireless/broadcom/brcm80211/brcmfmac/pcie.c    |  2 +-
+ .../net/wireless/broadcom/brcm80211/brcmfmac/sdio.c    |  4 ++--
+ 4 files changed, 15 insertions(+), 3 deletions(-)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
+@@ -233,6 +233,8 @@ void brcmf_dev_reset(struct device *dev)
+ void brcmf_txflowblock(struct device *dev, bool state);
+ /* Request from bus module to initiate a coredump */
+ void brcmf_dev_coredump(struct device *dev);
++/* Indication that firmware has halted or crashed */
++void brcmf_fw_crashed(struct device *dev);
+ /* Notify the bus has transferred the tx packet to firmware */
+ void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success);
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+@@ -1274,6 +1274,16 @@ void brcmf_dev_coredump(struct device *d
+               brcmf_dbg(TRACE, "failed to create coredump\n");
+ }
++void brcmf_fw_crashed(struct device *dev)
++{
++      struct brcmf_bus *bus_if = dev_get_drvdata(dev);
++      struct brcmf_pub *drvr = bus_if->drvr;
++
++      bphy_err(drvr, "Firmware has halted or crashed\n");
++
++      brcmf_dev_coredump(dev);
++}
++
+ void brcmf_detach(struct device *dev)
+ {
+       s32 i;
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
+@@ -728,7 +728,7 @@ static void brcmf_pcie_handle_mb_data(st
+       }
+       if (dtoh_mb_data & BRCMF_D2H_DEV_FWHALT) {
+               brcmf_dbg(PCIE, "D2H_MB_DATA: FW HALT\n");
+-              brcmf_dev_coredump(&devinfo->pdev->dev);
++              brcmf_fw_crashed(&devinfo->pdev->dev);
+       }
+ }
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
+@@ -1097,8 +1097,8 @@ static u32 brcmf_sdio_hostmail(struct br
+       /* dongle indicates the firmware has halted/crashed */
+       if (hmb_data & HMB_DATA_FWHALT) {
+-              brcmf_err("mailbox indicates firmware halted\n");
+-              brcmf_dev_coredump(&sdiod->func[1]->dev);
++              brcmf_dbg(SDIO, "mailbox indicates firmware halted\n");
++              brcmf_fw_crashed(&sdiod->func[1]->dev);
+       }
+       /* Dongle recomposed rx frames, accept them again */
diff --git a/package/kernel/mac80211/patches/340-v5.2-0002-brcmfmac-remove-pending-parameter-from-brcmf_usb_fre.patch b/package/kernel/mac80211/patches/340-v5.2-0002-brcmfmac-remove-pending-parameter-from-brcmf_usb_fre.patch
deleted file mode 100644 (file)
index 80ad31e..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-From 2b78e5f5223666d403d4fdb30af4ad65c8da3cdb Mon Sep 17 00:00:00 2001
-From: Piotr Figiel <p.figiel@camlintechnologies.com>
-Date: Fri, 8 Mar 2019 15:25:06 +0000
-Subject: [PATCH] brcmfmac: remove pending parameter from brcmf_usb_free_q
-
-brcmf_usb_free_q is no longer called with pending=true thus this boolean
-parameter is no longer needed.
-
-Signed-off-by: Piotr Figiel <p.figiel@camlintechnologies.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
- .../wireless/broadcom/brcm80211/brcmfmac/usb.c    | 15 ++++++---------
- 1 file changed, 6 insertions(+), 9 deletions(-)
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
-@@ -445,9 +445,10 @@ fail:
- }
--static void brcmf_usb_free_q(struct list_head *q, bool pending)
-+static void brcmf_usb_free_q(struct list_head *q)
- {
-       struct brcmf_usbreq *req, *next;
-+
-       int i = 0;
-       list_for_each_entry_safe(req, next, q, list) {
-               if (!req->urb) {
-@@ -455,12 +456,8 @@ static void brcmf_usb_free_q(struct list
-                       break;
-               }
-               i++;
--              if (pending) {
--                      usb_kill_urb(req->urb);
--              } else {
--                      usb_free_urb(req->urb);
--                      list_del_init(&req->list);
--              }
-+              usb_free_urb(req->urb);
-+              list_del_init(&req->list);
-       }
- }
-@@ -1031,8 +1028,8 @@ static void brcmf_usb_detach(struct brcm
-       brcmf_dbg(USB, "Enter, devinfo %p\n", devinfo);
-       /* free the URBS */
--      brcmf_usb_free_q(&devinfo->rx_freeq, false);
--      brcmf_usb_free_q(&devinfo->tx_freeq, false);
-+      brcmf_usb_free_q(&devinfo->rx_freeq);
-+      brcmf_usb_free_q(&devinfo->tx_freeq);
-       usb_free_urb(devinfo->ctl_urb);
-       usb_free_urb(devinfo->bulk_urb);
diff --git a/package/kernel/mac80211/patches/340-v5.2-0003-brcmfmac-remove-unused-variable-i-from-brcmf_usb_fre.patch b/package/kernel/mac80211/patches/340-v5.2-0003-brcmfmac-remove-unused-variable-i-from-brcmf_usb_fre.patch
deleted file mode 100644 (file)
index 4c8d073..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-From 504f06725d015954a0fcafdf1d90a6795ca8f769 Mon Sep 17 00:00:00 2001
-From: Piotr Figiel <p.figiel@camlintechnologies.com>
-Date: Fri, 8 Mar 2019 15:25:09 +0000
-Subject: [PATCH] brcmfmac: remove unused variable i from brcmf_usb_free_q
-
-Variable i is not used so remove it.
-
-Signed-off-by: Piotr Figiel <p.figiel@camlintechnologies.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
- drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c | 2 --
- 1 file changed, 2 deletions(-)
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
-@@ -449,13 +449,11 @@ static void brcmf_usb_free_q(struct list
- {
-       struct brcmf_usbreq *req, *next;
--      int i = 0;
-       list_for_each_entry_safe(req, next, q, list) {
-               if (!req->urb) {
-                       brcmf_err("bad req\n");
-                       break;
-               }
--              i++;
-               usb_free_urb(req->urb);
-               list_del_init(&req->list);
-       }
diff --git a/package/kernel/mac80211/patches/340-v5.2-0003-brcmfmac-reset-PCIe-bus-on-a-firmware-crash.patch b/package/kernel/mac80211/patches/340-v5.2-0003-brcmfmac-reset-PCIe-bus-on-a-firmware-crash.patch
new file mode 100644 (file)
index 0000000..96692c9
--- /dev/null
@@ -0,0 +1,160 @@
+From 4684997d9eea29380000e062755aa6d368d789a3 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Date: Tue, 26 Feb 2019 14:11:19 +0100
+Subject: [PATCH] brcmfmac: reset PCIe bus on a firmware crash
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This includes bus reset & reloading a firmware. It should be sufficient
+for a user space to (setup and) use a wireless device again.
+
+Support for reset on USB & SDIO can be added later.
+
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+Reviewed-by: Arend van Spriel <arend.vanspriel@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+ .../broadcom/brcm80211/brcmfmac/bus.h         | 10 ++++++
+ .../broadcom/brcm80211/brcmfmac/core.c        | 12 +++++++
+ .../broadcom/brcm80211/brcmfmac/core.h        |  2 ++
+ .../broadcom/brcm80211/brcmfmac/pcie.c        | 35 +++++++++++++++++++
+ 4 files changed, 59 insertions(+)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
+@@ -87,6 +87,7 @@ struct brcmf_bus_ops {
+       void (*wowl_config)(struct device *dev, bool enabled);
+       size_t (*get_ramsize)(struct device *dev);
+       int (*get_memdump)(struct device *dev, void *data, size_t len);
++      int (*reset)(struct device *dev);
+ };
+@@ -214,6 +215,15 @@ int brcmf_bus_get_memdump(struct brcmf_b
+       return bus->ops->get_memdump(bus->dev, data, len);
+ }
++static inline
++int brcmf_bus_reset(struct brcmf_bus *bus)
++{
++      if (!bus->ops->reset)
++              return -EOPNOTSUPP;
++
++      return bus->ops->reset(bus->dev);
++}
++
+ /*
+  * interface functions from common layer
+  */
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+@@ -1080,6 +1080,14 @@ static int brcmf_revinfo_read(struct seq
+       return 0;
+ }
++static void brcmf_core_bus_reset(struct work_struct *work)
++{
++      struct brcmf_pub *drvr = container_of(work, struct brcmf_pub,
++                                            bus_reset);
++
++      brcmf_bus_reset(drvr->bus_if);
++}
++
+ int brcmf_bus_started(struct device *dev)
+ {
+       int ret = -1;
+@@ -1161,6 +1169,8 @@ int brcmf_bus_started(struct device *dev
+ #endif
+ #endif /* CONFIG_INET */
++      INIT_WORK(&drvr->bus_reset, brcmf_core_bus_reset);
++
+       return 0;
+ fail:
+@@ -1282,6 +1292,8 @@ void brcmf_fw_crashed(struct device *dev
+       bphy_err(drvr, "Firmware has halted or crashed\n");
+       brcmf_dev_coredump(dev);
++
++      schedule_work(&drvr->bus_reset);
+ }
+ void brcmf_detach(struct device *dev)
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
+@@ -146,6 +146,8 @@ struct brcmf_pub {
+       struct notifier_block inet6addr_notifier;
+       struct brcmf_mp_device *settings;
++      struct work_struct bus_reset;
++
+       /* Pointer needed by OpenWrt due to backporting some fixes */
+       void *cfg80211_ops;
+ };
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
+@@ -343,6 +343,8 @@ static const u32 brcmf_ring_itemsize[BRC
+       BRCMF_D2H_MSGRING_RX_COMPLETE_ITEMSIZE
+ };
++static void brcmf_pcie_setup(struct device *dev, const struct firmware *fw,
++                           void *nvram, u32 nvram_len);
+ static u32
+ brcmf_pcie_read_reg32(struct brcmf_pciedev_info *devinfo, u32 reg_offset)
+@@ -1382,6 +1384,45 @@ static int brcmf_pcie_get_memdump(struct
+ }
++static int brcmf_pcie_reset(struct device *dev)
++{
++      struct brcmf_bus *bus_if = dev_get_drvdata(dev);
++      struct brcmf_pciedev *buspub = bus_if->bus_priv.pcie;
++      struct brcmf_pciedev_info *devinfo = buspub->devinfo;
++      u16 domain_nr;
++      u16 bus_nr;
++      int err;
++
++      brcmf_detach(dev);
++
++      brcmf_pcie_release_irq(devinfo);
++      brcmf_pcie_release_scratchbuffers(devinfo);
++      brcmf_pcie_release_ringbuffers(devinfo);
++      brcmf_pcie_reset_device(devinfo);
++
++      err = brcmf_fw_map_chip_to_name(devinfo->ci->chip, devinfo->ci->chiprev,
++                                      brcmf_pcie_fwnames,
++                                      ARRAY_SIZE(brcmf_pcie_fwnames),
++                                      devinfo->fw_name, devinfo->nvram_name);
++      if (err) {
++              dev_err(dev, "Failed to prepare FW request\n");
++              return err;
++      }
++
++      domain_nr = pci_domain_nr(devinfo->pdev->bus) + 1;
++      bus_nr = devinfo->pdev->bus->number;
++      err = brcmf_fw_get_firmwares_pcie(bus_if->dev, BRCMF_FW_REQUEST_NVRAM |
++                                                     BRCMF_FW_REQ_NV_OPTIONAL,
++                                        devinfo->fw_name, devinfo->nvram_name,
++                                        brcmf_pcie_setup, domain_nr, bus_nr);
++      if (err) {
++              dev_err(dev, "Failed to prepare FW request\n");
++              return err;
++      }
++
++      return err;
++}
++
+ static const struct brcmf_bus_ops brcmf_pcie_bus_ops = {
+       .txdata = brcmf_pcie_tx,
+       .stop = brcmf_pcie_down,
+@@ -1390,6 +1431,7 @@ static const struct brcmf_bus_ops brcmf_
+       .wowl_config = brcmf_pcie_wowl_config,
+       .get_ramsize = brcmf_pcie_get_ramsize,
+       .get_memdump = brcmf_pcie_get_memdump,
++      .reset = brcmf_pcie_reset,
+ };
diff --git a/package/kernel/mac80211/patches/342-v5.2-0001-brcmfmac-fix-race-during-disconnect-when-USB-complet.patch b/package/kernel/mac80211/patches/342-v5.2-0001-brcmfmac-fix-race-during-disconnect-when-USB-complet.patch
new file mode 100644 (file)
index 0000000..a6d5c34
--- /dev/null
@@ -0,0 +1,84 @@
+From db3b9e2e1d58080d0754bdf9293dabf8c6491b67 Mon Sep 17 00:00:00 2001
+From: Piotr Figiel <p.figiel@camlintechnologies.com>
+Date: Fri, 8 Mar 2019 15:25:04 +0000
+Subject: [PATCH] brcmfmac: fix race during disconnect when USB completion is
+ in progress
+
+It was observed that rarely during USB disconnect happening shortly after
+connect (before full initialization completes) usb_hub_wq would wait
+forever for the dev_init_lock to be unlocked. dev_init_lock would remain
+locked though because of infinite wait during usb_kill_urb:
+
+[ 2730.656472] kworker/0:2     D    0   260      2 0x00000000
+[ 2730.660700] Workqueue: events request_firmware_work_func
+[ 2730.664807] [<809dca20>] (__schedule) from [<809dd164>] (schedule+0x4c/0xac)
+[ 2730.670587] [<809dd164>] (schedule) from [<8069af44>] (usb_kill_urb+0xdc/0x114)
+[ 2730.676815] [<8069af44>] (usb_kill_urb) from [<7f258b50>] (brcmf_usb_free_q+0x34/0xa8 [brcmfmac])
+[ 2730.684833] [<7f258b50>] (brcmf_usb_free_q [brcmfmac]) from [<7f2517d4>] (brcmf_detach+0xa0/0xb8 [brcmfmac])
+[ 2730.693557] [<7f2517d4>] (brcmf_detach [brcmfmac]) from [<7f251a34>] (brcmf_attach+0xac/0x3d8 [brcmfmac])
+[ 2730.702094] [<7f251a34>] (brcmf_attach [brcmfmac]) from [<7f2587ac>] (brcmf_usb_probe_phase2+0x468/0x4a0 [brcmfmac])
+[ 2730.711601] [<7f2587ac>] (brcmf_usb_probe_phase2 [brcmfmac]) from [<7f252888>] (brcmf_fw_request_done+0x194/0x220 [brcmfmac])
+[ 2730.721795] [<7f252888>] (brcmf_fw_request_done [brcmfmac]) from [<805748e4>] (request_firmware_work_func+0x4c/0x88)
+[ 2730.731125] [<805748e4>] (request_firmware_work_func) from [<80141474>] (process_one_work+0x228/0x808)
+[ 2730.739223] [<80141474>] (process_one_work) from [<80141a80>] (worker_thread+0x2c/0x564)
+[ 2730.746105] [<80141a80>] (worker_thread) from [<80147bcc>] (kthread+0x13c/0x16c)
+[ 2730.752227] [<80147bcc>] (kthread) from [<801010b4>] (ret_from_fork+0x14/0x20)
+
+[ 2733.099695] kworker/0:3     D    0  1065      2 0x00000000
+[ 2733.103926] Workqueue: usb_hub_wq hub_event
+[ 2733.106914] [<809dca20>] (__schedule) from [<809dd164>] (schedule+0x4c/0xac)
+[ 2733.112693] [<809dd164>] (schedule) from [<809e2a8c>] (schedule_timeout+0x214/0x3e4)
+[ 2733.119621] [<809e2a8c>] (schedule_timeout) from [<809dde2c>] (wait_for_common+0xc4/0x1c0)
+[ 2733.126810] [<809dde2c>] (wait_for_common) from [<7f258d00>] (brcmf_usb_disconnect+0x1c/0x4c [brcmfmac])
+[ 2733.135206] [<7f258d00>] (brcmf_usb_disconnect [brcmfmac]) from [<8069e0c8>] (usb_unbind_interface+0x5c/0x1e4)
+[ 2733.143943] [<8069e0c8>] (usb_unbind_interface) from [<8056d3e8>] (device_release_driver_internal+0x164/0x1fc)
+[ 2733.152769] [<8056d3e8>] (device_release_driver_internal) from [<8056c078>] (bus_remove_device+0xd0/0xfc)
+[ 2733.161138] [<8056c078>] (bus_remove_device) from [<8056977c>] (device_del+0x11c/0x310)
+[ 2733.167939] [<8056977c>] (device_del) from [<8069cba8>] (usb_disable_device+0xa0/0x1cc)
+[ 2733.174743] [<8069cba8>] (usb_disable_device) from [<8069507c>] (usb_disconnect+0x74/0x1dc)
+[ 2733.181823] [<8069507c>] (usb_disconnect) from [<80695e88>] (hub_event+0x478/0xf88)
+[ 2733.188278] [<80695e88>] (hub_event) from [<80141474>] (process_one_work+0x228/0x808)
+[ 2733.194905] [<80141474>] (process_one_work) from [<80141a80>] (worker_thread+0x2c/0x564)
+[ 2733.201724] [<80141a80>] (worker_thread) from [<80147bcc>] (kthread+0x13c/0x16c)
+[ 2733.207913] [<80147bcc>] (kthread) from [<801010b4>] (ret_from_fork+0x14/0x20)
+
+It was traced down to a case where usb_kill_urb would be called on an URB
+structure containing more or less random data, including large number in
+its use_count. During the debugging it appeared that in brcmf_usb_free_q()
+the traversal over URBs' lists is not synchronized with operations on those
+lists in brcmf_usb_rx_complete() leading to handling
+brcmf_usbdev_info structure (holding lists' head) as lists' element and in
+result causing above problem.
+
+Fix it by walking through all URBs during brcmf_cancel_all_urbs using the
+arrays of requests instead of linked lists.
+
+Signed-off-by: Piotr Figiel <p.figiel@camlintechnologies.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c | 10 ++++++++--
+ 1 file changed, 8 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
+@@ -684,12 +684,18 @@ static int brcmf_usb_up(struct device *d
+ static void brcmf_cancel_all_urbs(struct brcmf_usbdev_info *devinfo)
+ {
++      int i;
++
+       if (devinfo->ctl_urb)
+               usb_kill_urb(devinfo->ctl_urb);
+       if (devinfo->bulk_urb)
+               usb_kill_urb(devinfo->bulk_urb);
+-      brcmf_usb_free_q(&devinfo->tx_postq, true);
+-      brcmf_usb_free_q(&devinfo->rx_postq, true);
++      if (devinfo->tx_reqs)
++              for (i = 0; i < devinfo->bus_pub.ntxq; i++)
++                      usb_kill_urb(devinfo->tx_reqs[i].urb);
++      if (devinfo->rx_reqs)
++              for (i = 0; i < devinfo->bus_pub.nrxq; i++)
++                      usb_kill_urb(devinfo->rx_reqs[i].urb);
+ }
+ static void brcmf_usb_down(struct device *dev)
diff --git a/package/kernel/mac80211/patches/342-v5.2-0002-brcmfmac-remove-pending-parameter-from-brcmf_usb_fre.patch b/package/kernel/mac80211/patches/342-v5.2-0002-brcmfmac-remove-pending-parameter-from-brcmf_usb_fre.patch
new file mode 100644 (file)
index 0000000..80ad31e
--- /dev/null
@@ -0,0 +1,54 @@
+From 2b78e5f5223666d403d4fdb30af4ad65c8da3cdb Mon Sep 17 00:00:00 2001
+From: Piotr Figiel <p.figiel@camlintechnologies.com>
+Date: Fri, 8 Mar 2019 15:25:06 +0000
+Subject: [PATCH] brcmfmac: remove pending parameter from brcmf_usb_free_q
+
+brcmf_usb_free_q is no longer called with pending=true thus this boolean
+parameter is no longer needed.
+
+Signed-off-by: Piotr Figiel <p.figiel@camlintechnologies.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+ .../wireless/broadcom/brcm80211/brcmfmac/usb.c    | 15 ++++++---------
+ 1 file changed, 6 insertions(+), 9 deletions(-)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
+@@ -445,9 +445,10 @@ fail:
+ }
+-static void brcmf_usb_free_q(struct list_head *q, bool pending)
++static void brcmf_usb_free_q(struct list_head *q)
+ {
+       struct brcmf_usbreq *req, *next;
++
+       int i = 0;
+       list_for_each_entry_safe(req, next, q, list) {
+               if (!req->urb) {
+@@ -455,12 +456,8 @@ static void brcmf_usb_free_q(struct list
+                       break;
+               }
+               i++;
+-              if (pending) {
+-                      usb_kill_urb(req->urb);
+-              } else {
+-                      usb_free_urb(req->urb);
+-                      list_del_init(&req->list);
+-              }
++              usb_free_urb(req->urb);
++              list_del_init(&req->list);
+       }
+ }
+@@ -1031,8 +1028,8 @@ static void brcmf_usb_detach(struct brcm
+       brcmf_dbg(USB, "Enter, devinfo %p\n", devinfo);
+       /* free the URBS */
+-      brcmf_usb_free_q(&devinfo->rx_freeq, false);
+-      brcmf_usb_free_q(&devinfo->tx_freeq, false);
++      brcmf_usb_free_q(&devinfo->rx_freeq);
++      brcmf_usb_free_q(&devinfo->tx_freeq);
+       usb_free_urb(devinfo->ctl_urb);
+       usb_free_urb(devinfo->bulk_urb);
diff --git a/package/kernel/mac80211/patches/342-v5.2-0003-brcmfmac-remove-unused-variable-i-from-brcmf_usb_fre.patch b/package/kernel/mac80211/patches/342-v5.2-0003-brcmfmac-remove-unused-variable-i-from-brcmf_usb_fre.patch
new file mode 100644 (file)
index 0000000..4c8d073
--- /dev/null
@@ -0,0 +1,29 @@
+From 504f06725d015954a0fcafdf1d90a6795ca8f769 Mon Sep 17 00:00:00 2001
+From: Piotr Figiel <p.figiel@camlintechnologies.com>
+Date: Fri, 8 Mar 2019 15:25:09 +0000
+Subject: [PATCH] brcmfmac: remove unused variable i from brcmf_usb_free_q
+
+Variable i is not used so remove it.
+
+Signed-off-by: Piotr Figiel <p.figiel@camlintechnologies.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c | 2 --
+ 1 file changed, 2 deletions(-)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
+@@ -449,13 +449,11 @@ static void brcmf_usb_free_q(struct list
+ {
+       struct brcmf_usbreq *req, *next;
+-      int i = 0;
+       list_for_each_entry_safe(req, next, q, list) {
+               if (!req->urb) {
+                       brcmf_err("bad req\n");
+                       break;
+               }
+-              i++;
+               usb_free_urb(req->urb);
+               list_del_init(&req->list);
+       }