mac80211: brcmfmac: early work on FullMAC firmware crash recovery
authorRafał Miłecki <rafal@milecki.pl>
Thu, 18 Apr 2019 09:47:43 +0000 (11:47 +0200)
committerRafał Miłecki <rafal@milecki.pl>
Thu, 18 Apr 2019 09:48:21 +0000 (11:48 +0200)
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
package/kernel/mac80211/patches/381-v5.1-0011-brcmfmac-fix-size-of-the-struct-msgbuf_ring_status.patch [new file with mode: 0644]
package/kernel/mac80211/patches/381-v5.1-0012-brcmfmac-print-firmware-reported-general-status-erro.patch [new file with mode: 0644]
package/kernel/mac80211/patches/450-v5.2-0001-brcmfmac-fix-race-during-disconnect-when-USB-complet.patch [new file with mode: 0644]
package/kernel/mac80211/patches/450-v5.2-0002-brcmfmac-remove-pending-parameter-from-brcmf_usb_fre.patch [new file with mode: 0644]
package/kernel/mac80211/patches/450-v5.2-0003-brcmfmac-remove-unused-variable-i-from-brcmf_usb_fre.patch [new file with mode: 0644]
package/kernel/mac80211/patches/865-brcmfmac-get-RAM-info-right-before-downloading-PCIe-.patch [new file with mode: 0644]

diff --git a/package/kernel/mac80211/patches/381-v5.1-0011-brcmfmac-fix-size-of-the-struct-msgbuf_ring_status.patch b/package/kernel/mac80211/patches/381-v5.1-0011-brcmfmac-fix-size-of-the-struct-msgbuf_ring_status.patch
new file mode 100644 (file)
index 0000000..10834db
--- /dev/null
@@ -0,0 +1,29 @@
+From 0c7051610c577b60b01b3b5aec14d6765e177b0d Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Date: Thu, 21 Feb 2019 11:33:24 +0100
+Subject: [PATCH] brcmfmac: fix size of the struct msgbuf_ring_status
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This updates host struct to match the in-firmawre definition. It's a
+cosmetic change as it only applies to the reserved struct space.
+
+Fixes: c988b78244df ("brcmfmac: print firmware reported ring status errors")
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+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
+@@ -139,7 +139,7 @@ struct msgbuf_ring_status {
+       struct msgbuf_common_hdr        msg;
+       struct msgbuf_completion_hdr    compl_hdr;
+       __le16                          write_idx;
+-      __le32                          rsvd0[5];
++      __le16                          rsvd0[5];
+ };
+ struct msgbuf_rx_event {
diff --git a/package/kernel/mac80211/patches/381-v5.1-0012-brcmfmac-print-firmware-reported-general-status-erro.patch b/package/kernel/mac80211/patches/381-v5.1-0012-brcmfmac-print-firmware-reported-general-status-erro.patch
new file mode 100644 (file)
index 0000000..313d501
--- /dev/null
@@ -0,0 +1,69 @@
+From c91377495192cda096e52dc09c266b0d05f16d86 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Date: Thu, 21 Feb 2019 11:33:25 +0100
+Subject: [PATCH] brcmfmac: print firmware reported general status errors
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Firmware may report general errors using a special message type. Add
+basic support for it by simply decoding & printing an error number.
+
+A sample situation in which firmware reports a buf error:
+CONSOLE: 027084.733 no host response IOCTL buffer available..so fail the request
+will now produce a "Firmware reported general error: 9" on the host.
+
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+Acked-by: Arend van Spriel <arend.vanspriel@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+ .../broadcom/brcm80211/brcmfmac/msgbuf.c      | 24 +++++++++++++++++++
+ 1 file changed, 24 insertions(+)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
+@@ -134,6 +134,14 @@ struct msgbuf_completion_hdr {
+       __le16                          flow_ring_id;
+ };
++/* Data struct for the MSGBUF_TYPE_GEN_STATUS */
++struct msgbuf_gen_status {
++      struct msgbuf_common_hdr        msg;
++      struct msgbuf_completion_hdr    compl_hdr;
++      __le16                          write_idx;
++      __le32                          rsvd0[3];
++};
++
+ /* Data struct for the MSGBUF_TYPE_RING_STATUS */
+ struct msgbuf_ring_status {
+       struct msgbuf_common_hdr        msg;
+@@ -1194,6 +1202,18 @@ brcmf_msgbuf_process_rx_complete(struct
+       brcmf_netif_rx(ifp, skb);
+ }
++static void brcmf_msgbuf_process_gen_status(struct brcmf_msgbuf *msgbuf,
++                                          void *buf)
++{
++      struct msgbuf_gen_status *gen_status = buf;
++      struct brcmf_pub *drvr = msgbuf->drvr;
++      int err;
++
++      err = le16_to_cpu(gen_status->compl_hdr.status);
++      if (err)
++              bphy_err(drvr, "Firmware reported general error: %d\n", err);
++}
++
+ static void brcmf_msgbuf_process_ring_status(struct brcmf_msgbuf *msgbuf,
+                                            void *buf)
+ {
+@@ -1273,6 +1293,10 @@ static void brcmf_msgbuf_process_msgtype
+       msg = (struct msgbuf_common_hdr *)buf;
+       switch (msg->msgtype) {
++      case MSGBUF_TYPE_GEN_STATUS:
++              brcmf_dbg(MSGBUF, "MSGBUF_TYPE_GEN_STATUS\n");
++              brcmf_msgbuf_process_gen_status(msgbuf, buf);
++              break;
+       case MSGBUF_TYPE_RING_STATUS:
+               brcmf_dbg(MSGBUF, "MSGBUF_TYPE_RING_STATUS\n");
+               brcmf_msgbuf_process_ring_status(msgbuf, buf);
diff --git a/package/kernel/mac80211/patches/450-v5.2-0001-brcmfmac-fix-race-during-disconnect-when-USB-complet.patch b/package/kernel/mac80211/patches/450-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/450-v5.2-0002-brcmfmac-remove-pending-parameter-from-brcmf_usb_fre.patch b/package/kernel/mac80211/patches/450-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/450-v5.2-0003-brcmfmac-remove-unused-variable-i-from-brcmf_usb_fre.patch b/package/kernel/mac80211/patches/450-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);
+       }
diff --git a/package/kernel/mac80211/patches/865-brcmfmac-get-RAM-info-right-before-downloading-PCIe-.patch b/package/kernel/mac80211/patches/865-brcmfmac-get-RAM-info-right-before-downloading-PCIe-.patch
new file mode 100644 (file)
index 0000000..020594d
--- /dev/null
@@ -0,0 +1,70 @@
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Subject: [PATCH] brcmfmac: get RAM info right before downloading PCIe firmware
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+It's important as brcmf_chip_get_raminfo() also makes sure that memory
+is properly setup. Without it the firmware could report invalid RAM
+address like 0x04000001.
+
+During a normal brcmfmac lifetime brcmf_chip_get_raminfo() is called on
+probe by the brcmf_chip_recognition(). This change allows implementing
+further improvements like handling errors by resetting a device with
+the brcmf_pcie_reset_device() and redownloading a firmware afterwards.
+
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+---
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c | 6 ++++--
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h | 1 +
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c | 6 ++++++
+ 3 files changed, 11 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
+@@ -700,8 +700,10 @@ static u32 brcmf_chip_tcm_rambase(struct
+       return 0;
+ }
+-static int brcmf_chip_get_raminfo(struct brcmf_chip_priv *ci)
++int brcmf_chip_get_raminfo(struct brcmf_chip *pub)
+ {
++      struct brcmf_chip_priv *ci = container_of(pub, struct brcmf_chip_priv,
++                                                pub);
+       struct brcmf_core_priv *mem_core;
+       struct brcmf_core *mem;
+@@ -981,7 +983,7 @@ static int brcmf_chip_recognition(struct
+               brcmf_chip_set_passive(&ci->pub);
+       }
+-      return brcmf_chip_get_raminfo(ci);
++      return brcmf_chip_get_raminfo(&ci->pub);
+ }
+ static void brcmf_chip_disable_arm(struct brcmf_chip_priv *chip, u16 id)
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h
+@@ -80,6 +80,7 @@ struct brcmf_buscore_ops {
+       void (*activate)(void *ctx, struct brcmf_chip *chip, u32 rstvec);
+ };
++int brcmf_chip_get_raminfo(struct brcmf_chip *pub);
+ struct brcmf_chip *brcmf_chip_attach(void *ctx,
+                                    const struct brcmf_buscore_ops *ops);
+ void brcmf_chip_detach(struct brcmf_chip *chip);
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
+@@ -1727,6 +1727,12 @@ static void brcmf_pcie_setup(struct devi
+       nvram_len = fwreq->items[BRCMF_PCIE_FW_NVRAM].nv_data.len;
+       kfree(fwreq);
++      ret = brcmf_chip_get_raminfo(devinfo->ci);
++      if (ret) {
++              brcmf_err(bus, "Failed to get RAM info\n");
++              goto fail;
++      }
++
+       /* Some of the firmwares have the size of the memory of the device
+        * defined inside the firmware. This is because part of the memory in
+        * the device is shared and the devision is determined by FW. Parse