From 00f30d29b497577954b20237b405e9d22b5286c2 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Mon, 16 Mar 2015 16:36:48 +0900 Subject: [PATCH] usb: renesas_usbhs: fix spinlock suspected in a gadget complete function 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: Yoshihiro Shimoda Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/mod_gadget.c | 28 ++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index e0384af77e56..dc2aa3261202 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -119,18 +119,34 @@ struct usbhsg_recip_handle { /* * queue push/pop */ +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_pipe *pipe = usbhsg_uep_to_pipe(uep); - struct device *dev = usbhsg_gpriv_to_dev(gpriv); + struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv); + unsigned long flags; - dev_dbg(dev, "pipe %d : queue pop\n", usbhs_pipe_number(pipe)); - - ureq->req.status = status; - usb_gadget_giveback_request(&uep->ep, &ureq->req); + 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)