Commit 6d06bc83 authored by Sergey Senozhatsky's avatar Sergey Senozhatsky Committed by Jakub Kicinski
Browse files

net: usb: r8152: fix resume reset deadlock



rtl8152 can trigger device reset during reset which
potentially can result in a deadlock:

 **** DPM device timeout after 10 seconds; 15 seconds until panic ****
 Call Trace:
 <TASK>
 schedule+0x483/0x1370
 schedule_preempt_disabled+0x15/0x30
 __mutex_lock_common+0x1fd/0x470
 __rtl8152_set_mac_address+0x80/0x1f0
 dev_set_mac_address+0x7f/0x150
 rtl8152_post_reset+0x72/0x150
 usb_reset_device+0x1d0/0x220
 rtl8152_resume+0x99/0xc0
 usb_resume_interface+0x3e/0xc0
 usb_resume_both+0x104/0x150
 usb_resume+0x22/0x110

The problem is that rtl8152 resume calls reset under
tp->control mutex while reset basically re-enters rtl8152
and attempts to acquire the same tp->control lock once
again.

Reset INACCESSIBLE device outside of tp->control mutex
scope to avoid recursive mutex_lock() deadlock.

Fixes: 4933b066 ("r8152: If inaccessible at resume time, issue a reset")
Reviewed-by: default avatarDouglas Anderson <dianders@chromium.org>
Signed-off-by: default avatarSergey Senozhatsky <senozhatsky@chromium.org>
Link: https://patch.msgid.link/20260129031106.3805887-1-senozhatsky@chromium.org


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent f8db6475
Loading
Loading
Loading
Loading
+15 −14
Original line number Diff line number Diff line
@@ -8535,19 +8535,6 @@ static int rtl8152_system_resume(struct r8152 *tp)
		usb_submit_urb(tp->intr_urb, GFP_NOIO);
	}

	/* If the device is RTL8152_INACCESSIBLE here then we should do a
	 * reset. This is important because the usb_lock_device_for_reset()
	 * that happens as a result of usb_queue_reset_device() will silently
	 * fail if the device was suspended or if too much time passed.
	 *
	 * NOTE: The device is locked here so we can directly do the reset.
	 * We don't need usb_lock_device_for_reset() because that's just a
	 * wrapper over device_lock() and device_resume() (which calls us)
	 * does that for us.
	 */
	if (test_bit(RTL8152_INACCESSIBLE, &tp->flags))
		usb_reset_device(tp->udev);

	return 0;
}

@@ -8658,19 +8645,33 @@ static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message)
static int rtl8152_resume(struct usb_interface *intf)
{
	struct r8152 *tp = usb_get_intfdata(intf);
	bool runtime_resume = test_bit(SELECTIVE_SUSPEND, &tp->flags);
	int ret;

	mutex_lock(&tp->control);

	rtl_reset_ocp_base(tp);

	if (test_bit(SELECTIVE_SUSPEND, &tp->flags))
	if (runtime_resume)
		ret = rtl8152_runtime_resume(tp);
	else
		ret = rtl8152_system_resume(tp);

	mutex_unlock(&tp->control);

	/* If the device is RTL8152_INACCESSIBLE here then we should do a
	 * reset. This is important because the usb_lock_device_for_reset()
	 * that happens as a result of usb_queue_reset_device() will silently
	 * fail if the device was suspended or if too much time passed.
	 *
	 * NOTE: The device is locked here so we can directly do the reset.
	 * We don't need usb_lock_device_for_reset() because that's just a
	 * wrapper over device_lock() and device_resume() (which calls us)
	 * does that for us.
	 */
	if (!runtime_resume && test_bit(RTL8152_INACCESSIBLE, &tp->flags))
		usb_reset_device(tp->udev);

	return ret;
}