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

Commit ccf7f209 authored by Yoshihiro Shimoda's avatar Yoshihiro Shimoda Committed by Sasha Levin
Browse files

usb: renesas_usbhs: fix spinlock suspected in a gadget complete function



[ Upstream commit 00f30d29b497577954b20237b405e9d22b5286c2 ]

According to the gadget.h, a "complete" function will always be called
with interrupts disabled. However, sometimes usbhsg_queue_pop() function
is called with interrupts enabled. So, this function should be held by
usbhs_lock() to disable interruption. Also, this driver has to call
spin_unlock() to avoid spinlock recursion by this driver before calling
usb_gadget_giveback_request().
Otherwise, there is possible to cause a spinlock suspected in a gadget
complete function.

Signed-off-by: default avatarYoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Signed-off-by: default avatarFelipe Balbi <balbi@ti.com>
Signed-off-by: default avatarSasha Levin <sasha.levin@oracle.com>
parent 1491937f
Loading
Loading
Loading
Loading
+19 −3
Original line number Diff line number Diff line
@@ -118,18 +118,34 @@ struct usbhsg_recip_handle {
/*
 *		queue push/pop
 */
static void usbhsg_queue_pop(struct usbhsg_uep *uep,
static void __usbhsg_queue_pop(struct usbhsg_uep *uep,
			       struct usbhsg_request *ureq,
			       int status)
{
	struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep);
	struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep);
	struct device *dev = usbhsg_gpriv_to_dev(gpriv);
	struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv);

	dev_dbg(dev, "pipe %d : queue pop\n", usbhs_pipe_number(pipe));

	ureq->req.status = status;
	spin_unlock(usbhs_priv_to_lock(priv));
	usb_gadget_giveback_request(&uep->ep, &ureq->req);
	spin_lock(usbhs_priv_to_lock(priv));
}

static void usbhsg_queue_pop(struct usbhsg_uep *uep,
			     struct usbhsg_request *ureq,
			     int status)
{
	struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep);
	struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv);
	unsigned long flags;

	usbhs_lock(priv, flags);
	__usbhsg_queue_pop(uep, ureq, status);
	usbhs_unlock(priv, flags);
}

static void usbhsg_queue_done(struct usbhs_priv *priv, struct usbhs_pkt *pkt)