From e46c9b02e2422e7b8f8a63ff53f1f8eddc23b247 Mon Sep 17 00:00:00 2001 From: William Wu Date: Mon, 10 Apr 2017 20:33:06 +0800 Subject: [PATCH] usb: dwc3: rockchip: fix possible circular deadlock This patch aims to fix possible unsafe locking scenario when dwc3 probe failed. The possible deadlock warning info is: [4.254320] ====================================================== [4.254327] [ INFO: possible circular locking dependency detected ] [4.254334] 4.4.55 #20 Not tainted [4.254339] ------------------------------------------------------- [4.254346] kworker/4:1/47 is trying to acquire lock: [4.254352] (&rockchip->lock){+.+.+.}, at: [] dwc3_rockchip_otg_extcon_evt_work+0x30/0x42c [4.254382] [4.254382] but task is already holding lock: [4.254388] ((&rockchip->otg_work)){+.+...}, at: [] process_one_work+0x1c4/0x6ac [4.254411] [4.254411] which lock already depends on the new lock. [4.254411] [4.254418] [4.254418] the existing dependency chain (in reverse order) is: [4.254424] -> #1 ((&rockchip->otg_work)){+.+...}: [4.254440] [] __lock_acquire+0x15b4/0x1950 [4.254452] [] lock_acquire+0x190/0x250 [4.254461] [] flush_work+0x4c/0x274 [4.254471] [] __cancel_work_timer+0x130/0x1c0 [4.254480] [] cancel_work_sync+0x10/0x18 [4.254489] [] dwc3_rockchip_probe+0x4f4/0x59c [4.254498] [] platform_drv_probe+0x58/0xa4 [4.254509] [] driver_probe_device+0x118/0x2b0 [4.254521] [] __driver_attach+0x6c/0x98 [4.254531] [] bus_for_each_dev+0x80/0xb0 [4.254543] [] driver_attach+0x20/0x28 [4.254554] [] bus_add_driver+0xe8/0x1ec [4.254565] [] driver_register+0x94/0xe0 [4.254576] [] __platform_driver_register+0x48/0x50 [4.254585] [] dwc3_rockchip_driver_init+0x18/0x20 [4.254598] [] do_one_initcall+0x180/0x19c [4.254609] [] kernel_init_freeable+0x208/0x2c0 [4.254621] [] kernel_init+0x10/0xf8 [4.254632] [] ret_from_fork+0x10/0x40 [4.254641] -> #0 (&rockchip->lock){+.+.+.}: [4.254656] [] print_circular_bug+0x64/0x2c4 [4.254666] [] __lock_acquire+0x1284/0x1950 [4.254675] [] lock_acquire+0x190/0x250 [4.254685] [] mutex_lock_nested+0x80/0x3d0 [4.254695] [] dwc3_rockchip_otg_extcon_evt_work+0x30/0x42c [4.254704] [] process_one_work+0x338/0x6ac [4.254714] [] worker_thread+0x300/0x428 [4.254723] [] kthread+0xf4/0xfc [4.254732] [] ret_from_fork+0x10/0x40 [4.254741] [4.254741] other info that might help us debug this: [4.254741] [4.254749] Possible unsafe locking scenario: [4.254749] [4.254755] CPU0 CPU1 [4.254760] ---- ---- [4.254765] lock((&rockchip->otg_work)); [4.254775] lock(&rockchip->lock); [4.254786] lock((&rockchip->otg_work)); [4.254796] lock(&rockchip->lock); [4.254805] [4.254805] *** DEADLOCK *** [4.254805] [4.254813] 2 locks held by kworker/4:1/47: [4.254818] #0: ("events"){.+.+.+}, at: [] process_one_work+0x1c4/0x6ac [4.254839] #1: ((&rockchip->otg_work)){+.+...}, at: [] process_one_work+0x1c4/0x6ac [4.254860] [4.254860] stack backtrace: [4.254869] CPU: 4 PID: 47 Comm: kworker/4:1 Not tainted 4.4.55 #20 [4.254875] Hardware name: Rockchip RK3399 Evaluation Board v3 (Android) (DT) [4.254885] Workqueue: events dwc3_rockchip_otg_extcon_evt_work [4.254893] Call trace: [4.254902] [] dump_backtrace+0x0/0x1c8 [4.254909] [] show_stack+0x14/0x1c [4.254917] [] dump_stack+0xb0/0xec [4.254925] [] print_circular_bug+0x2a8/0x2c4 [4.254931] [] __lock_acquire+0x1284/0x1950 [4.254938] [] lock_acquire+0x190/0x250 [4.254946] [] mutex_lock_nested+0x80/0x3d0 [4.254952] [] dwc3_rockchip_otg_extcon_evt_work+0x30/0x42c [4.254960] [] process_one_work+0x338/0x6ac [4.254967] [] worker_thread+0x300/0x428 [4.254973] [] kthread+0xf4/0xfc [4.254979] [] ret_from_fork+0x10/0x40 [4.275124] rockchip-dwc3 usb@fe800000: USB peripheral connected Change-Id: I9d34724e1c2af9b8472f79bfe4b088cbdde6394d Signed-off-by: William Wu --- drivers/usb/dwc3/dwc3-rockchip.c | 33 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-rockchip.c b/drivers/usb/dwc3/dwc3-rockchip.c index 1c8829bd2f91..a6e5cbd27ba8 100644 --- a/drivers/usb/dwc3/dwc3-rockchip.c +++ b/drivers/usb/dwc3/dwc3-rockchip.c @@ -676,6 +676,8 @@ static void dwc3_rockchip_extcon_unregister(struct dwc3_rockchip *rockchip) &rockchip->device_nb); extcon_unregister_notifier(rockchip->edev, EXTCON_USB_HOST, &rockchip->host_nb); + + cancel_work_sync(&rockchip->otg_work); } static int dwc3_rockchip_probe(struct platform_device *pdev) @@ -684,6 +686,7 @@ static int dwc3_rockchip_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct device_node *np = dev->of_node, *child; struct platform_device *child_pdev; + struct usb_hcd *hcd = NULL; unsigned int count; int ret; @@ -776,24 +779,24 @@ static int dwc3_rockchip_probe(struct platform_device *pdev) goto err2; } + if (rockchip->dwc->dr_mode == USB_DR_MODE_HOST || + rockchip->dwc->dr_mode == USB_DR_MODE_OTG) { + hcd = dev_get_drvdata(&rockchip->dwc->xhci->dev); + if (!hcd) { + dev_err(dev, "fail to get drvdata hcd\n"); + ret = -EPROBE_DEFER; + goto err2; + } + } + ret = dwc3_rockchip_extcon_register(rockchip); if (ret < 0) goto err2; if (rockchip->edev || (rockchip->dwc->dr_mode == USB_DR_MODE_OTG)) { - if (rockchip->dwc->dr_mode == USB_DR_MODE_HOST || - rockchip->dwc->dr_mode == USB_DR_MODE_OTG) { - struct usb_hcd *hcd = - dev_get_drvdata(&rockchip->dwc->xhci->dev); - if (!hcd) { - dev_err(dev, "fail to get drvdata hcd\n"); - ret = -EPROBE_DEFER; - goto err3; - } - if (hcd->state != HC_STATE_HALT) { - usb_remove_hcd(hcd->shared_hcd); - usb_remove_hcd(hcd); - } + if (hcd && hcd->state != HC_STATE_HALT) { + usb_remove_hcd(hcd->shared_hcd); + usb_remove_hcd(hcd); } pm_runtime_set_autosuspend_delay(&child_pdev->dev, @@ -815,11 +818,7 @@ static int dwc3_rockchip_probe(struct platform_device *pdev) return ret; -err3: - dwc3_rockchip_extcon_unregister(rockchip); - err2: - cancel_work_sync(&rockchip->otg_work); of_platform_depopulate(dev); err1: -- 2.34.1