--- /dev/null
+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 {
--- /dev/null
+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);
--- /dev/null
+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)
--- /dev/null
+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);
--- /dev/null
+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);
+ }
--- /dev/null
+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
+@@ -1702,6 +1702,12 @@ static void brcmf_pcie_setup(struct devi
+
+ brcmf_pcie_attach(devinfo);
+
++ 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