From 5e23e90f33888769ffe253663cc5f3ea0bb6da49 Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Wed, 27 Jan 2010 18:38:03 +0100 Subject: USB: pxa27x_udc: Fix deadlocks on request queueing As reported by Antonio, there are cases where the ep->lock can be taken twice, triggering a deadlock. The typical sequence is : irq_handler \ -> gadget.complete() \ -> pxa27x_udc.pxa_ep_queue() : ep->lock is taken \ -> gadget.complete() \ -> pxa27x_udc.pxa_ep_queue() : ep->lock is taken ==> *deadlock* The patch fixes this by : - releasing the lock each time gadget.complete() is called - adding a check in handle_ep() to detect a recursive call, in which case the function becomes on no-op. The patch is still not good enough for ep0. For this unique endpoint, another well thought over patch will be needed. Reported-by: Antonio Ospite Tested-by: Antonio Ospite Signed-off-by: Robert Jarzmik Cc: David Brownell Cc: Eric Miao Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/pxa27x_udc.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/usb/gadget/pxa27x_udc.h') diff --git a/drivers/usb/gadget/pxa27x_udc.h b/drivers/usb/gadget/pxa27x_udc.h index e25225e26586..ff61e4866e8a 100644 --- a/drivers/usb/gadget/pxa27x_udc.h +++ b/drivers/usb/gadget/pxa27x_udc.h @@ -318,6 +318,11 @@ struct udc_usb_ep { * @queue: requests queue * @lock: lock to pxa_ep data (queues and stats) * @enabled: true when endpoint enabled (not stopped by gadget layer) + * @in_handle_ep: number of recursions of handle_ep() function + * Prevents deadlocks or infinite recursions of types : + * irq->handle_ep()->req_done()->req.complete()->pxa_ep_queue()->handle_ep() + * or + * pxa_ep_queue()->handle_ep()->req_done()->req.complete()->pxa_ep_queue() * @idx: endpoint index (1 => epA, 2 => epB, ..., 24 => epX) * @name: endpoint name (for trace/debug purpose) * @dir_in: 1 if IN endpoint, 0 if OUT endpoint @@ -346,6 +351,7 @@ struct pxa_ep { spinlock_t lock; /* Protects this structure */ /* (queues, stats) */ unsigned enabled:1; + unsigned in_handle_ep:1; unsigned idx:5; char *name; -- cgit v1.2.1