Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c757700f authored by Danny Segal's avatar Danny Segal Committed by Mayank Rana
Browse files

usb: gadget: Resolve recursive spinlock during remote wakeup



When a USB function wishes to send new data during USB suspend state, it
needs to issue USB remote wakeup and send a function wakeup notification
after then. This scenario leads to recursive spin locking inside the
_usb_func_wakeup() function, because this function gets called recursively.
This function issues remote wakeup, which internally calls the resume
interrupt callback, which calls the _usb_func_wakeup() function again.
This issue is resolved by performing the remote wakeup in a deferred work
context, and this splits the recursion loop.

CRs-fixed: 700667
Change-Id: I59c8efde098781587d29f08cd60e4aa3521949d8
Signed-off-by: default avatarDanny Segal <dsegal@codeaurora.org>
Signed-off-by: default avatarMayank Rana <mrana@codeaurora.org>
parent de7cd8dd
Loading
Loading
Loading
Loading
+13 −7
Original line number Diff line number Diff line
@@ -443,7 +443,8 @@ int usb_get_func_interface_id(struct usb_function *func)
	return -ENODEV;
}

static int _usb_func_wakeup(struct usb_function *func, bool use_pending_flag)
static int usb_func_wakeup_int(struct usb_function *func,
					bool use_pending_flag)
{
	int ret;
	int interface_id;
@@ -451,8 +452,8 @@ static int _usb_func_wakeup(struct usb_function *func, bool use_pending_flag)
	struct usb_gadget *gadget;
	struct usb_composite_dev *cdev;

	pr_debug("%s function wakeup\n",
		func->name ? func->name : "");
	pr_debug("%s - %s function wakeup, use pending: %u\n",
		__func__, func->name ? func->name : "", use_pending_flag);

	if (!func || !func->config || !func->config->cdev ||
		!func->config->cdev->gadget)
@@ -482,14 +483,20 @@ static int _usb_func_wakeup(struct usb_function *func, bool use_pending_flag)
		ERROR(func->config->cdev,
			"Function %s - Unknown interface id. Canceling USB request. ret=%d\n",
			func->name ? func->name : "", ret);

		spin_unlock_irqrestore(&cdev->lock, flags);
		return ret;
	}

	interface_id = ret;
	ret = usb_gadget_func_wakeup(gadget, interface_id);

	if (use_pending_flag)
	if (use_pending_flag) {
		func->func_wakeup_pending = false;
	} else {
		if (ret == -EAGAIN)
			func->func_wakeup_pending = true;
	}

	spin_unlock_irqrestore(&cdev->lock, flags);

@@ -503,12 +510,11 @@ int usb_func_wakeup(struct usb_function *func)
	pr_debug("%s function wakeup\n",
		func->name ? func->name : "");

	ret = _usb_func_wakeup(func, false);
	ret = usb_func_wakeup_int(func, false);
	if (ret == -EAGAIN) {
		DBG(func->config->cdev,
			"Function wakeup for %s could not complete due to suspend state. Delayed until after bus resume.\n",
			func->name ? func->name : "");
		func->func_wakeup_pending = true;
		ret = 0;
	} else if (ret < 0) {
		ERROR(func->config->cdev,
@@ -2426,7 +2432,7 @@ void composite_resume(struct usb_gadget *gadget)

	if (cdev->config) {
		list_for_each_entry(f, &cdev->config->functions, list) {
			ret = _usb_func_wakeup(f, true);
			ret = usb_func_wakeup_int(f, true);
			if (ret) {
				if (ret == -EAGAIN) {
					ERROR(f->config->cdev,