diff options
author | Rafał Miłecki <rafal@milecki.pl> | 2019-04-18 11:47:43 +0200 |
---|---|---|
committer | Rafał Miłecki <rafal@milecki.pl> | 2019-04-18 12:07:47 +0200 |
commit | eaef74279c8f392d9656e616a9e958b31333fd4f (patch) | |
tree | 7dbde09f8918b6fb49bc17d9d0caa05e24b3cf59 /package/kernel/mac80211/patches/340-v5.2-0001-brcmfmac-fix-race-during-disconnect-when-USB-complet.patch | |
parent | 981f5f7e40cbf26bc0beb0a2aa5f3c562b83c85b (diff) | |
download | upstream-eaef74279c8f392d9656e616a9e958b31333fd4f.tar.gz upstream-eaef74279c8f392d9656e616a9e958b31333fd4f.tar.bz2 upstream-eaef74279c8f392d9656e616a9e958b31333fd4f.zip |
mac80211: brcmfmac: early work on FullMAC firmware crash recovery
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
(cherry picked from commit 02aed76968d60d254ab9d0d8768f0c54dbfc6d9d)
Diffstat (limited to 'package/kernel/mac80211/patches/340-v5.2-0001-brcmfmac-fix-race-during-disconnect-when-USB-complet.patch')
-rw-r--r-- | package/kernel/mac80211/patches/340-v5.2-0001-brcmfmac-fix-race-during-disconnect-when-USB-complet.patch | 84 |
1 files changed, 84 insertions, 0 deletions
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 new file mode 100644 index 0000000000..a6d5c34007 --- /dev/null +++ b/package/kernel/mac80211/patches/340-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 <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) |