mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-14 17:14:09 +00:00
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 <yoshihiro.shimoda.uh@renesas.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
This commit is contained in:
parent
990919cad5
commit
00f30d29b4
@ -119,18 +119,34 @@ struct usbhsg_recip_handle {
|
|||||||
/*
|
/*
|
||||||
* queue push/pop
|
* 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,
|
static void usbhsg_queue_pop(struct usbhsg_uep *uep,
|
||||||
struct usbhsg_request *ureq,
|
struct usbhsg_request *ureq,
|
||||||
int status)
|
int status)
|
||||||
{
|
{
|
||||||
struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep);
|
struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep);
|
||||||
struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep);
|
struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv);
|
||||||
struct device *dev = usbhsg_gpriv_to_dev(gpriv);
|
unsigned long flags;
|
||||||
|
|
||||||
dev_dbg(dev, "pipe %d : queue pop\n", usbhs_pipe_number(pipe));
|
usbhs_lock(priv, flags);
|
||||||
|
__usbhsg_queue_pop(uep, ureq, status);
|
||||||
ureq->req.status = status;
|
usbhs_unlock(priv, flags);
|
||||||
usb_gadget_giveback_request(&uep->ep, &ureq->req);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void usbhsg_queue_done(struct usbhs_priv *priv, struct usbhs_pkt *pkt)
|
static void usbhsg_queue_done(struct usbhs_priv *priv, struct usbhs_pkt *pkt)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user