diff options
author | Robert Jarzmik <robert.jarzmik@free.fr> | 2010-01-27 12:38:03 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-03-02 17:54:47 -0500 |
commit | 5e23e90f33888769ffe253663cc5f3ea0bb6da49 (patch) | |
tree | 9a59d36fdaaecea5eb7fa2d39c655032dc6920a2 /drivers/usb/gadget/pxa27x_udc.h | |
parent | fb088e335d78f866be2e56eac6d500112a96aa11 (diff) |
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 <ospite@studenti.unina.it>
Tested-by: Antonio Ospite <ospite@studenti.unina.it>
Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr>
Cc: David Brownell <dbrownell@users.sourceforge.net>
Cc: Eric Miao <eric.y.miao@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/gadget/pxa27x_udc.h')
-rw-r--r-- | drivers/usb/gadget/pxa27x_udc.h | 6 |
1 files changed, 6 insertions, 0 deletions
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 { | |||
318 | * @queue: requests queue | 318 | * @queue: requests queue |
319 | * @lock: lock to pxa_ep data (queues and stats) | 319 | * @lock: lock to pxa_ep data (queues and stats) |
320 | * @enabled: true when endpoint enabled (not stopped by gadget layer) | 320 | * @enabled: true when endpoint enabled (not stopped by gadget layer) |
321 | * @in_handle_ep: number of recursions of handle_ep() function | ||
322 | * Prevents deadlocks or infinite recursions of types : | ||
323 | * irq->handle_ep()->req_done()->req.complete()->pxa_ep_queue()->handle_ep() | ||
324 | * or | ||
325 | * pxa_ep_queue()->handle_ep()->req_done()->req.complete()->pxa_ep_queue() | ||
321 | * @idx: endpoint index (1 => epA, 2 => epB, ..., 24 => epX) | 326 | * @idx: endpoint index (1 => epA, 2 => epB, ..., 24 => epX) |
322 | * @name: endpoint name (for trace/debug purpose) | 327 | * @name: endpoint name (for trace/debug purpose) |
323 | * @dir_in: 1 if IN endpoint, 0 if OUT endpoint | 328 | * @dir_in: 1 if IN endpoint, 0 if OUT endpoint |
@@ -346,6 +351,7 @@ struct pxa_ep { | |||
346 | spinlock_t lock; /* Protects this structure */ | 351 | spinlock_t lock; /* Protects this structure */ |
347 | /* (queues, stats) */ | 352 | /* (queues, stats) */ |
348 | unsigned enabled:1; | 353 | unsigned enabled:1; |
354 | unsigned in_handle_ep:1; | ||
349 | 355 | ||
350 | unsigned idx:5; | 356 | unsigned idx:5; |
351 | char *name; | 357 | char *name; |