From 2d2e615dee0421e126af9d4ebd49a720e341e3af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Thu, 18 Apr 2019 12:37:10 +0200 Subject: mac80211: brcmfmac: really add early fw crash recovery MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previous commit backported USB fixes instead of firmware crash recovery patches. Fixes: 02aed76968d6 ("mac80211: brcmfmac: early work on FullMAC firmware crash recovery") Signed-off-by: Rafał Miłecki --- ...x-race-during-disconnect-when-USB-complet.patch | 84 -------- ...pport-repeated-brcmf_fw_alloc_request-cal.patch | 32 +++ ...d-a-function-designated-for-handling-firm.patch | 79 ++++++++ ...move-pending-parameter-from-brcmf_usb_fre.patch | 54 ----- ...move-unused-variable-i-from-brcmf_usb_fre.patch | 29 --- ...cmfmac-reset-PCIe-bus-on-a-firmware-crash.patch | 153 +++++++++++++++ ...x-WARNING-during-USB-disconnect-in-case-o.patch | 124 ++++++++++++ ...x-NULL-pointer-derefence-during-USB-disco.patch | 217 +++++++++++++++++++++ ...x-race-during-disconnect-when-USB-complet.patch | 84 ++++++++ ...move-pending-parameter-from-brcmf_usb_fre.patch | 54 +++++ ...move-unused-variable-i-from-brcmf_usb_fre.patch | 29 +++ 11 files changed, 772 insertions(+), 167 deletions(-) delete mode 100644 package/kernel/mac80211/patches/450-v5.2-0001-brcmfmac-fix-race-during-disconnect-when-USB-complet.patch create mode 100644 package/kernel/mac80211/patches/450-v5.2-0001-brcmfmac-support-repeated-brcmf_fw_alloc_request-cal.patch create mode 100644 package/kernel/mac80211/patches/450-v5.2-0002-brcmfmac-add-a-function-designated-for-handling-firm.patch delete mode 100644 package/kernel/mac80211/patches/450-v5.2-0002-brcmfmac-remove-pending-parameter-from-brcmf_usb_fre.patch delete mode 100644 package/kernel/mac80211/patches/450-v5.2-0003-brcmfmac-remove-unused-variable-i-from-brcmf_usb_fre.patch create mode 100644 package/kernel/mac80211/patches/450-v5.2-0003-brcmfmac-reset-PCIe-bus-on-a-firmware-crash.patch create mode 100644 package/kernel/mac80211/patches/451-v5.2-0001-brcmfmac-fix-WARNING-during-USB-disconnect-in-case-o.patch create mode 100644 package/kernel/mac80211/patches/451-v5.2-0002-brcmfmac-fix-NULL-pointer-derefence-during-USB-disco.patch create mode 100644 package/kernel/mac80211/patches/452-v5.2-0001-brcmfmac-fix-race-during-disconnect-when-USB-complet.patch create mode 100644 package/kernel/mac80211/patches/452-v5.2-0002-brcmfmac-remove-pending-parameter-from-brcmf_usb_fre.patch create mode 100644 package/kernel/mac80211/patches/452-v5.2-0003-brcmfmac-remove-unused-variable-i-from-brcmf_usb_fre.patch (limited to 'package') 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 deleted file mode 100644 index a6d5c34007..0000000000 --- a/package/kernel/mac80211/patches/450-v5.2-0001-brcmfmac-fix-race-during-disconnect-when-USB-complet.patch +++ /dev/null @@ -1,84 +0,0 @@ -From db3b9e2e1d58080d0754bdf9293dabf8c6491b67 Mon Sep 17 00:00:00 2001 -From: Piotr Figiel -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 -Signed-off-by: Kalle Valo ---- - 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-0001-brcmfmac-support-repeated-brcmf_fw_alloc_request-cal.patch b/package/kernel/mac80211/patches/450-v5.2-0001-brcmfmac-support-repeated-brcmf_fw_alloc_request-cal.patch new file mode 100644 index 0000000000..ef694f079f --- /dev/null +++ b/package/kernel/mac80211/patches/450-v5.2-0001-brcmfmac-support-repeated-brcmf_fw_alloc_request-cal.patch @@ -0,0 +1,32 @@ +From c9692820710f57c826b2e43a6fb1e4cd307508b0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +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 +Reviewed-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + 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 +@@ -743,6 +743,7 @@ brcmf_fw_alloc_request(u32 chip, u32 chi + + for (j = 0; j < n_fwnames; j++) { + fwreq->items[j].path = fwnames[j].path; ++ fwnames[j].path[0] = '\0'; + /* check if firmware path is provided by module parameter */ + if (brcmf_mp_global.firmware_path[0] != '\0') { + strlcpy(fwnames[j].path, mp_path, diff --git a/package/kernel/mac80211/patches/450-v5.2-0002-brcmfmac-add-a-function-designated-for-handling-firm.patch b/package/kernel/mac80211/patches/450-v5.2-0002-brcmfmac-add-a-function-designated-for-handling-firm.patch new file mode 100644 index 0000000000..595b8948c7 --- /dev/null +++ b/package/kernel/mac80211/patches/450-v5.2-0002-brcmfmac-add-a-function-designated-for-handling-firm.patch @@ -0,0 +1,79 @@ +From a2ec87ddbf1637f854ffcfff9d12d392fa30758b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +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 +Reviewed-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + 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 +@@ -262,6 +262,8 @@ void brcmf_detach(struct device *dev); + void brcmf_dev_reset(struct device *dev); + /* 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); + + /* Configure the "global" bus state used by upper layers */ + void brcmf_bus_change_state(struct brcmf_bus *bus, enum brcmf_bus_state state); +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +@@ -1294,6 +1294,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 +@@ -730,7 +730,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 +@@ -1090,8 +1090,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->func1->dev); ++ brcmf_dbg(SDIO, "mailbox indicates firmware halted\n"); ++ brcmf_fw_crashed(&sdiod->func1->dev); + } + + /* Dongle recomposed rx frames, accept them again */ 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 deleted file mode 100644 index 80ad31ece6..0000000000 --- a/package/kernel/mac80211/patches/450-v5.2-0002-brcmfmac-remove-pending-parameter-from-brcmf_usb_fre.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 2b78e5f5223666d403d4fdb30af4ad65c8da3cdb Mon Sep 17 00:00:00 2001 -From: Piotr Figiel -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 -Signed-off-by: Kalle Valo ---- - .../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 deleted file mode 100644 index 4c8d073914..0000000000 --- a/package/kernel/mac80211/patches/450-v5.2-0003-brcmfmac-remove-unused-variable-i-from-brcmf_usb_fre.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 504f06725d015954a0fcafdf1d90a6795ca8f769 Mon Sep 17 00:00:00 2001 -From: Piotr Figiel -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 -Signed-off-by: Kalle Valo ---- - 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/450-v5.2-0003-brcmfmac-reset-PCIe-bus-on-a-firmware-crash.patch b/package/kernel/mac80211/patches/450-v5.2-0003-brcmfmac-reset-PCIe-bus-on-a-firmware-crash.patch new file mode 100644 index 0000000000..0f2fc42954 --- /dev/null +++ b/package/kernel/mac80211/patches/450-v5.2-0003-brcmfmac-reset-PCIe-bus-on-a-firmware-crash.patch @@ -0,0 +1,153 @@ +From 4684997d9eea29380000e062755aa6d368d789a3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +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 +Reviewed-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + .../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 +@@ -90,6 +90,7 @@ struct brcmf_bus_ops { + int (*get_memdump)(struct device *dev, void *data, size_t len); + int (*get_fwname)(struct device *dev, const char *ext, + unsigned char *fw_name); ++ int (*reset)(struct device *dev); + }; + + +@@ -235,6 +236,15 @@ int brcmf_bus_get_fwname(struct brcmf_bu + return bus->ops->get_fwname(bus->dev, ext, fw_name); + } + ++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 +@@ -1104,6 +1104,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); ++} ++ + static int brcmf_bus_started(struct brcmf_pub *drvr, struct cfg80211_ops *ops) + { + int ret = -1; +@@ -1175,6 +1183,8 @@ static int brcmf_bus_started(struct brcm + #endif + #endif /* CONFIG_INET */ + ++ INIT_WORK(&drvr->bus_reset, brcmf_core_bus_reset); ++ + /* populate debugfs */ + brcmf_debugfs_add_entry(drvr, "revinfo", brcmf_revinfo_read); + brcmf_feat_debugfs_create(drvr); +@@ -1300,6 +1310,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 +@@ -143,6 +143,8 @@ struct brcmf_pub { + struct notifier_block inet6addr_notifier; + struct brcmf_mp_device *settings; + ++ struct work_struct bus_reset; ++ + u8 clmver[BRCMF_DCMD_SMLEN]; + }; + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +@@ -345,6 +345,10 @@ static const u32 brcmf_ring_itemsize[BRC + BRCMF_D2H_MSGRING_RX_COMPLETE_ITEMSIZE + }; + ++static void brcmf_pcie_setup(struct device *dev, int ret, ++ struct brcmf_fw_request *fwreq); ++static struct brcmf_fw_request * ++brcmf_pcie_prepare_fw_request(struct brcmf_pciedev_info *devinfo); + + static u32 + brcmf_pcie_read_reg32(struct brcmf_pciedev_info *devinfo, u32 reg_offset) +@@ -1409,6 +1413,36 @@ int brcmf_pcie_get_fwname(struct device + return 0; + } + ++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; ++ struct brcmf_fw_request *fwreq; ++ 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); ++ ++ fwreq = brcmf_pcie_prepare_fw_request(devinfo); ++ if (!fwreq) { ++ dev_err(dev, "Failed to prepare FW request\n"); ++ return -ENOMEM; ++ } ++ ++ err = brcmf_fw_get_firmwares(dev, fwreq, brcmf_pcie_setup); ++ if (err) { ++ dev_err(dev, "Failed to prepare FW request\n"); ++ kfree(fwreq); ++ } ++ ++ return err; ++} ++ + static const struct brcmf_bus_ops brcmf_pcie_bus_ops = { + .txdata = brcmf_pcie_tx, + .stop = brcmf_pcie_down, +@@ -1418,6 +1452,7 @@ static const struct brcmf_bus_ops brcmf_ + .get_ramsize = brcmf_pcie_get_ramsize, + .get_memdump = brcmf_pcie_get_memdump, + .get_fwname = brcmf_pcie_get_fwname, ++ .reset = brcmf_pcie_reset, + }; + + diff --git a/package/kernel/mac80211/patches/451-v5.2-0001-brcmfmac-fix-WARNING-during-USB-disconnect-in-case-o.patch b/package/kernel/mac80211/patches/451-v5.2-0001-brcmfmac-fix-WARNING-during-USB-disconnect-in-case-o.patch new file mode 100644 index 0000000000..cb4b5c924f --- /dev/null +++ b/package/kernel/mac80211/patches/451-v5.2-0001-brcmfmac-fix-WARNING-during-USB-disconnect-in-case-o.patch @@ -0,0 +1,124 @@ +From c80d26e81ef1802f30364b4ad1955c1443a592b9 Mon Sep 17 00:00:00 2001 +From: Piotr Figiel +Date: Mon, 4 Mar 2019 15:42:49 +0000 +Subject: [PATCH] brcmfmac: fix WARNING during USB disconnect in case of + unempty psq + +brcmu_pkt_buf_free_skb emits WARNING when attempting to free a sk_buff +which is part of any queue. After USB disconnect this may have happened +when brcmf_fws_hanger_cleanup() is called as per-interface psq was never +cleaned when removing the interface. +Change brcmf_fws_macdesc_cleanup() in a way that it removes the +corresponding packets from hanger table (to avoid double-free when +brcmf_fws_hanger_cleanup() is called) and add a call to clean-up the +interface specific packet queue. + +Below is a WARNING during USB disconnect with Raspberry Pi WiFi dongle +running in AP mode. This was reproducible when the interface was +transmitting during the disconnect and is fixed with this commit. + +------------[ cut here ]------------ +WARNING: CPU: 0 PID: 1171 at drivers/net/wireless/broadcom/brcm80211/brcmutil/utils.c:49 brcmu_pkt_buf_free_skb+0x3c/0x40 +Modules linked in: nf_log_ipv4 nf_log_common xt_LOG xt_limit iptable_mangle xt_connmark xt_tcpudp xt_conntrack nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 iptable_filter ip_tables x_tables usb_f_mass_storage usb_f_rndis u_ether cdc_acm smsc95xx usbnet ci_hdrc_imx ci_hdrc ulpi usbmisc_imx 8250_exar 8250_pci 8250 8250_base libcomposite configfs udc_core +CPU: 0 PID: 1171 Comm: kworker/0:0 Not tainted 4.19.23-00075-gde33ed8 #99 +Hardware name: Freescale i.MX6 Quad/DualLite (Device Tree) +Workqueue: usb_hub_wq hub_event +[<8010ff84>] (unwind_backtrace) from [<8010bb64>] (show_stack+0x10/0x14) +[<8010bb64>] (show_stack) from [<80840278>] (dump_stack+0x88/0x9c) +[<80840278>] (dump_stack) from [<8011f5ec>] (__warn+0xfc/0x114) +[<8011f5ec>] (__warn) from [<8011f71c>] (warn_slowpath_null+0x40/0x48) +[<8011f71c>] (warn_slowpath_null) from [<805a476c>] (brcmu_pkt_buf_free_skb+0x3c/0x40) +[<805a476c>] (brcmu_pkt_buf_free_skb) from [<805bb6c4>] (brcmf_fws_cleanup+0x1e4/0x22c) +[<805bb6c4>] (brcmf_fws_cleanup) from [<805bc854>] (brcmf_fws_del_interface+0x58/0x68) +[<805bc854>] (brcmf_fws_del_interface) from [<805b66ac>] (brcmf_remove_interface+0x40/0x150) +[<805b66ac>] (brcmf_remove_interface) from [<805b6870>] (brcmf_detach+0x6c/0xb0) +[<805b6870>] (brcmf_detach) from [<805bdbb8>] (brcmf_usb_disconnect+0x30/0x4c) +[<805bdbb8>] (brcmf_usb_disconnect) from [<805e5d64>] (usb_unbind_interface+0x5c/0x1e0) +[<805e5d64>] (usb_unbind_interface) from [<804aab10>] (device_release_driver_internal+0x154/0x1ec) +[<804aab10>] (device_release_driver_internal) from [<804a97f4>] (bus_remove_device+0xcc/0xf8) +[<804a97f4>] (bus_remove_device) from [<804a6fc0>] (device_del+0x118/0x308) +[<804a6fc0>] (device_del) from [<805e488c>] (usb_disable_device+0xa0/0x1c8) +[<805e488c>] (usb_disable_device) from [<805dcf98>] (usb_disconnect+0x70/0x1d8) +[<805dcf98>] (usb_disconnect) from [<805ddd84>] (hub_event+0x464/0xf50) +[<805ddd84>] (hub_event) from [<80135a70>] (process_one_work+0x138/0x3f8) +[<80135a70>] (process_one_work) from [<80135d5c>] (worker_thread+0x2c/0x554) +[<80135d5c>] (worker_thread) from [<8013b1a0>] (kthread+0x124/0x154) +[<8013b1a0>] (kthread) from [<801010e8>] (ret_from_fork+0x14/0x2c) +Exception stack(0xecf8dfb0 to 0xecf8dff8) +dfa0: 00000000 00000000 00000000 00000000 +dfc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 +dfe0: 00000000 00000000 00000000 00000000 00000013 00000000 +---[ end trace 38d234018e9e2a90 ]--- +------------[ cut here ]------------ + +Signed-off-by: Piotr Figiel +Signed-off-by: Kalle Valo +--- + .../broadcom/brcm80211/brcmfmac/fwsignal.c | 42 +++++++++++-------- + 1 file changed, 24 insertions(+), 18 deletions(-) + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c +@@ -580,24 +580,6 @@ static bool brcmf_fws_ifidx_match(struct + return ifidx == *(int *)arg; + } + +-static void brcmf_fws_psq_flush(struct brcmf_fws_info *fws, struct pktq *q, +- int ifidx) +-{ +- bool (*matchfn)(struct sk_buff *, void *) = NULL; +- struct sk_buff *skb; +- int prec; +- +- if (ifidx != -1) +- matchfn = brcmf_fws_ifidx_match; +- for (prec = 0; prec < q->num_prec; prec++) { +- skb = brcmu_pktq_pdeq_match(q, prec, matchfn, &ifidx); +- while (skb) { +- brcmu_pkt_buf_free_skb(skb); +- skb = brcmu_pktq_pdeq_match(q, prec, matchfn, &ifidx); +- } +- } +-} +- + static void brcmf_fws_hanger_init(struct brcmf_fws_hanger *hanger) + { + int i; +@@ -669,6 +651,28 @@ static inline int brcmf_fws_hanger_poppk + return 0; + } + ++static void brcmf_fws_psq_flush(struct brcmf_fws_info *fws, struct pktq *q, ++ int ifidx) ++{ ++ bool (*matchfn)(struct sk_buff *, void *) = NULL; ++ struct sk_buff *skb; ++ int prec; ++ u32 hslot; ++ ++ if (ifidx != -1) ++ matchfn = brcmf_fws_ifidx_match; ++ for (prec = 0; prec < q->num_prec; prec++) { ++ skb = brcmu_pktq_pdeq_match(q, prec, matchfn, &ifidx); ++ while (skb) { ++ hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT); ++ brcmf_fws_hanger_poppkt(&fws->hanger, hslot, &skb, ++ true); ++ brcmu_pkt_buf_free_skb(skb); ++ skb = brcmu_pktq_pdeq_match(q, prec, matchfn, &ifidx); ++ } ++ } ++} ++ + static int brcmf_fws_hanger_mark_suppressed(struct brcmf_fws_hanger *h, + u32 slot_id) + { +@@ -2200,6 +2204,8 @@ void brcmf_fws_del_interface(struct brcm + brcmf_fws_lock(fws); + ifp->fws_desc = NULL; + brcmf_dbg(TRACE, "deleting %s\n", entry->name); ++ brcmf_fws_macdesc_cleanup(fws, &fws->desc.iface[ifp->ifidx], ++ ifp->ifidx); + brcmf_fws_macdesc_deinit(entry); + brcmf_fws_cleanup(fws, ifp->ifidx); + brcmf_fws_unlock(fws); diff --git a/package/kernel/mac80211/patches/451-v5.2-0002-brcmfmac-fix-NULL-pointer-derefence-during-USB-disco.patch b/package/kernel/mac80211/patches/451-v5.2-0002-brcmfmac-fix-NULL-pointer-derefence-during-USB-disco.patch new file mode 100644 index 0000000000..e45288b63b --- /dev/null +++ b/package/kernel/mac80211/patches/451-v5.2-0002-brcmfmac-fix-NULL-pointer-derefence-during-USB-disco.patch @@ -0,0 +1,217 @@ +From 5cdb0ef6144f47440850553579aa923c20a63f23 Mon Sep 17 00:00:00 2001 +From: Piotr Figiel +Date: Mon, 4 Mar 2019 15:42:52 +0000 +Subject: [PATCH] brcmfmac: fix NULL pointer derefence during USB disconnect + +In case USB disconnect happens at the moment transmitting workqueue is in +progress the underlying interface may be gone causing a NULL pointer +dereference. Add synchronization of the workqueue destruction with the +detach implementation in core so that the transmitting workqueue is stopped +during detach before the interfaces are removed. + +Fix following Oops: + +Unable to handle kernel NULL pointer dereference at virtual address 00000008 +pgd = 9e6a802d +[00000008] *pgd=00000000 +Internal error: Oops: 5 [#1] PREEMPT SMP ARM +Modules linked in: nf_log_ipv4 nf_log_common xt_LOG xt_limit iptable_mangle +xt_connmark xt_tcpudp xt_conntrack nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 +iptable_filter ip_tables x_tables usb_f_mass_storage usb_f_rndis u_ether +usb_serial_simple usbserial cdc_acm brcmfmac brcmutil smsc95xx usbnet +ci_hdrc_imx ci_hdrc ulpi usbmisc_imx 8250_exar 8250_pci 8250 8250_base +libcomposite configfs udc_core +CPU: 0 PID: 7 Comm: kworker/u8:0 Not tainted 4.19.23-00076-g03740aa-dirty #102 +Hardware name: Freescale i.MX6 Quad/DualLite (Device Tree) +Workqueue: brcmf_fws_wq brcmf_fws_dequeue_worker [brcmfmac] +PC is at brcmf_txfinalize+0x34/0x90 [brcmfmac] +LR is at brcmf_fws_dequeue_worker+0x218/0x33c [brcmfmac] +pc : [<7f0dee64>] lr : [<7f0e4140>] psr: 60010093 +sp : ee8abef0 ip : 00000000 fp : edf38000 +r10: ffffffed r9 : edf38970 r8 : edf38004 +r7 : edf3e970 r6 : 00000000 r5 : ede69000 r4 : 00000000 +r3 : 00000a97 r2 : 00000000 r1 : 0000888e r0 : ede69000 +Flags: nZCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment none +Control: 10c5387d Table: 7d03c04a DAC: 00000051 +Process kworker/u8:0 (pid: 7, stack limit = 0x24ec3e04) +Stack: (0xee8abef0 to 0xee8ac000) +bee0: ede69000 00000000 ed56c3e0 7f0e4140 +bf00: 00000001 00000000 edf38004 edf3e99c ed56c3e0 80d03d00 edfea43a edf3e970 +bf20: ee809880 ee804200 ee971100 00000000 edf3e974 00000000 ee804200 80135a70 +bf40: 80d03d00 ee804218 ee809880 ee809894 ee804200 80d03d00 ee804218 ee8aa000 +bf60: 00000088 80135d5c 00000000 ee829f00 ee829dc0 00000000 ee809880 80135d30 +bf80: ee829f1c ee873eac 00000000 8013b1a0 ee829dc0 8013b07c 00000000 00000000 +bfa0: 00000000 00000000 00000000 801010e8 00000000 00000000 00000000 00000000 +bfc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 +bfe0: 00000000 00000000 00000000 00000000 00000013 00000000 00000000 00000000 +[<7f0dee64>] (brcmf_txfinalize [brcmfmac]) from [<7f0e4140>] (brcmf_fws_dequeue_worker+0x218/0x33c [brcmfmac]) +[<7f0e4140>] (brcmf_fws_dequeue_worker [brcmfmac]) from [<80135a70>] (process_one_work+0x138/0x3f8) +[<80135a70>] (process_one_work) from [<80135d5c>] (worker_thread+0x2c/0x554) +[<80135d5c>] (worker_thread) from [<8013b1a0>] (kthread+0x124/0x154) +[<8013b1a0>] (kthread) from [<801010e8>] (ret_from_fork+0x14/0x2c) +Exception stack(0xee8abfb0 to 0xee8abff8) +bfa0: 00000000 00000000 00000000 00000000 +bfc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 +bfe0: 00000000 00000000 00000000 00000000 00000013 00000000 +Code: e1530001 0a000007 e3560000 e1a00005 (05942008) +---[ end trace 079239dd31c86e90 ]--- + +Signed-off-by: Piotr Figiel +Signed-off-by: Kalle Valo +--- + .../wireless/broadcom/brcm80211/brcmfmac/bcdc.c | 11 +++++++++-- + .../wireless/broadcom/brcm80211/brcmfmac/bcdc.h | 6 ++++-- + .../wireless/broadcom/brcm80211/brcmfmac/core.c | 4 +++- + .../broadcom/brcm80211/brcmfmac/fwsignal.c | 16 ++++++++++++---- + .../broadcom/brcm80211/brcmfmac/fwsignal.h | 3 ++- + .../wireless/broadcom/brcm80211/brcmfmac/proto.c | 10 ++++++++-- + .../wireless/broadcom/brcm80211/brcmfmac/proto.h | 3 ++- + 7 files changed, 40 insertions(+), 13 deletions(-) + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c +@@ -490,11 +490,18 @@ fail: + return -ENOMEM; + } + +-void brcmf_proto_bcdc_detach(struct brcmf_pub *drvr) ++void brcmf_proto_bcdc_detach_pre_delif(struct brcmf_pub *drvr) ++{ ++ struct brcmf_bcdc *bcdc = drvr->proto->pd; ++ ++ brcmf_fws_detach_pre_delif(bcdc->fws); ++} ++ ++void brcmf_proto_bcdc_detach_post_delif(struct brcmf_pub *drvr) + { + struct brcmf_bcdc *bcdc = drvr->proto->pd; + + drvr->proto->pd = NULL; +- brcmf_fws_detach(bcdc->fws); ++ brcmf_fws_detach_post_delif(bcdc->fws); + kfree(bcdc); + } +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.h +@@ -18,14 +18,16 @@ + + #ifdef CPTCFG_BRCMFMAC_PROTO_BCDC + int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr); +-void brcmf_proto_bcdc_detach(struct brcmf_pub *drvr); ++void brcmf_proto_bcdc_detach_pre_delif(struct brcmf_pub *drvr); ++void brcmf_proto_bcdc_detach_post_delif(struct brcmf_pub *drvr); + void brcmf_proto_bcdc_txflowblock(struct device *dev, bool state); + void brcmf_proto_bcdc_txcomplete(struct device *dev, struct sk_buff *txp, + bool success); + struct brcmf_fws_info *drvr_to_fws(struct brcmf_pub *drvr); + #else + static inline int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr) { return 0; } +-static inline void brcmf_proto_bcdc_detach(struct brcmf_pub *drvr) {} ++static void brcmf_proto_bcdc_detach_pre_delif(struct brcmf_pub *drvr) {}; ++static inline void brcmf_proto_bcdc_detach_post_delif(struct brcmf_pub *drvr) {} + #endif + + #endif /* BRCMFMAC_BCDC_H */ +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +@@ -1342,6 +1342,8 @@ void brcmf_detach(struct device *dev) + + brcmf_bus_change_state(bus_if, BRCMF_BUS_DOWN); + ++ brcmf_proto_detach_pre_delif(drvr); ++ + /* make sure primary interface removed last */ + for (i = BRCMF_MAX_IFS-1; i > -1; i--) + brcmf_remove_interface(drvr->iflist[i], false); +@@ -1351,7 +1353,7 @@ void brcmf_detach(struct device *dev) + + brcmf_bus_stop(drvr->bus_if); + +- brcmf_proto_detach(drvr); ++ brcmf_proto_detach_post_delif(drvr); + + bus_if->drvr = NULL; + wiphy_free(drvr->wiphy); +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c +@@ -2443,17 +2443,25 @@ struct brcmf_fws_info *brcmf_fws_attach( + return fws; + + fail: +- brcmf_fws_detach(fws); ++ brcmf_fws_detach_pre_delif(fws); ++ brcmf_fws_detach_post_delif(fws); + return ERR_PTR(rc); + } + +-void brcmf_fws_detach(struct brcmf_fws_info *fws) ++void brcmf_fws_detach_pre_delif(struct brcmf_fws_info *fws) + { + if (!fws) + return; +- +- if (fws->fws_wq) ++ if (fws->fws_wq) { + destroy_workqueue(fws->fws_wq); ++ fws->fws_wq = NULL; ++ } ++} ++ ++void brcmf_fws_detach_post_delif(struct brcmf_fws_info *fws) ++{ ++ if (!fws) ++ return; + + /* cleanup */ + brcmf_fws_lock(fws); +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h +@@ -19,7 +19,8 @@ + #define FWSIGNAL_H_ + + struct brcmf_fws_info *brcmf_fws_attach(struct brcmf_pub *drvr); +-void brcmf_fws_detach(struct brcmf_fws_info *fws); ++void brcmf_fws_detach_pre_delif(struct brcmf_fws_info *fws); ++void brcmf_fws_detach_post_delif(struct brcmf_fws_info *fws); + void brcmf_fws_debugfs_create(struct brcmf_pub *drvr); + bool brcmf_fws_queue_skbs(struct brcmf_fws_info *fws); + bool brcmf_fws_fc_active(struct brcmf_fws_info *fws); +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.c +@@ -67,16 +67,22 @@ fail: + return -ENOMEM; + } + +-void brcmf_proto_detach(struct brcmf_pub *drvr) ++void brcmf_proto_detach_post_delif(struct brcmf_pub *drvr) + { + brcmf_dbg(TRACE, "Enter\n"); + + if (drvr->proto) { + if (drvr->bus_if->proto_type == BRCMF_PROTO_BCDC) +- brcmf_proto_bcdc_detach(drvr); ++ brcmf_proto_bcdc_detach_post_delif(drvr); + else if (drvr->bus_if->proto_type == BRCMF_PROTO_MSGBUF) + brcmf_proto_msgbuf_detach(drvr); + kfree(drvr->proto); + drvr->proto = NULL; + } + } ++ ++void brcmf_proto_detach_pre_delif(struct brcmf_pub *drvr) ++{ ++ if (drvr->proto && drvr->bus_if->proto_type == BRCMF_PROTO_BCDC) ++ brcmf_proto_bcdc_detach_pre_delif(drvr); ++} +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h +@@ -54,7 +54,8 @@ struct brcmf_proto { + + + int brcmf_proto_attach(struct brcmf_pub *drvr); +-void brcmf_proto_detach(struct brcmf_pub *drvr); ++void brcmf_proto_detach_pre_delif(struct brcmf_pub *drvr); ++void brcmf_proto_detach_post_delif(struct brcmf_pub *drvr); + + static inline int brcmf_proto_hdrpull(struct brcmf_pub *drvr, bool do_fws, + struct sk_buff *skb, diff --git a/package/kernel/mac80211/patches/452-v5.2-0001-brcmfmac-fix-race-during-disconnect-when-USB-complet.patch b/package/kernel/mac80211/patches/452-v5.2-0001-brcmfmac-fix-race-during-disconnect-when-USB-complet.patch new file mode 100644 index 0000000000..a6d5c34007 --- /dev/null +++ b/package/kernel/mac80211/patches/452-v5.2-0001-brcmfmac-fix-race-during-disconnect-when-USB-complet.patch @@ -0,0 +1,84 @@ +From db3b9e2e1d58080d0754bdf9293dabf8c6491b67 Mon Sep 17 00:00:00 2001 +From: Piotr Figiel +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 +Signed-off-by: Kalle Valo +--- + 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/452-v5.2-0002-brcmfmac-remove-pending-parameter-from-brcmf_usb_fre.patch b/package/kernel/mac80211/patches/452-v5.2-0002-brcmfmac-remove-pending-parameter-from-brcmf_usb_fre.patch new file mode 100644 index 0000000000..80ad31ece6 --- /dev/null +++ b/package/kernel/mac80211/patches/452-v5.2-0002-brcmfmac-remove-pending-parameter-from-brcmf_usb_fre.patch @@ -0,0 +1,54 @@ +From 2b78e5f5223666d403d4fdb30af4ad65c8da3cdb Mon Sep 17 00:00:00 2001 +From: Piotr Figiel +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 +Signed-off-by: Kalle Valo +--- + .../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/452-v5.2-0003-brcmfmac-remove-unused-variable-i-from-brcmf_usb_fre.patch b/package/kernel/mac80211/patches/452-v5.2-0003-brcmfmac-remove-unused-variable-i-from-brcmf_usb_fre.patch new file mode 100644 index 0000000000..4c8d073914 --- /dev/null +++ b/package/kernel/mac80211/patches/452-v5.2-0003-brcmfmac-remove-unused-variable-i-from-brcmf_usb_fre.patch @@ -0,0 +1,29 @@ +From 504f06725d015954a0fcafdf1d90a6795ca8f769 Mon Sep 17 00:00:00 2001 +From: Piotr Figiel +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 +Signed-off-by: Kalle Valo +--- + 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); + } -- cgit v1.2.3