Date:2010-03-23 17:15:29 (10 years 6 months ago)
Author:Yauhen Kharuzhy
Commit:7e391cd299ee54224b243bfbb5380cda9575ce56
Message:jz4740_udc: Fix recursive spinlocks (partially fixes: #853)

Driver had recursive spinlock locking:

1. jz4740_queue() acquires lock
2. done() is called in chain:
jz4740_queue()->jz4740_ep0_kick()->jz4740_ep0_in()->write_fifo_ep0()->done()
and it tries to acquire same lock.
3. Deadlock.

Lock and unlock calls in the done() function were swapped mistakenly
during porting to Qi's architecture support code.

This patch is only "quick fix" and should be reviewed.

Signed-off-by: Yauhen Kharuzhy <jekhor@gmail.com>
Files: drivers/usb/gadget/jz4740_udc.c (5 diffs)
drivers/usb/gadget/jz4740_udc.h (1 diff)

Change Details

drivers/usb/gadget/jz4740_udc.c
773773static void done(struct jz4740_ep *ep, struct jz4740_request *req, int status)
774774{
775775    unsigned int stopped = ep->stopped;
776    unsigned long flags;
777776    uint32_t index;
778777
779778    DEBUG("%s, %p\n", __FUNCTION__, ep);
...... 
792791    /* don't modify queue heads during completion callback */
793792    ep->stopped = 1;
794793    /* Read current index (completion may modify it) */
795    spin_lock_irqsave(&ep->dev->lock, flags);
796794    index = usb_readb(ep->dev, JZ_REG_UDC_INDEX);
795    spin_unlock_irqrestore(&ep->dev->lock, ep->dev->lock_flags);
797796
798797    req->req.complete(&ep->ep, &req->req);
799798
799    spin_lock_irqsave(&ep->dev->lock, ep->dev->lock_flags);
800800    /* Restore index */
801801    jz_udc_set_index(ep->dev, index);
802    spin_unlock_irqrestore(&ep->dev->lock, flags);
803802    ep->stopped = stopped;
804803}
805804
...... 
12541253    struct jz4740_request *req;
12551254    struct jz4740_ep *ep;
12561255    struct jz4740_udc *dev;
1257    unsigned long flags;
12581256
12591257    DEBUG("%s, %p\n", __FUNCTION__, _ep);
12601258
...... 
12811279    DEBUG("%s queue req %p, len %d buf %p\n", _ep->name, _req, _req->length,
12821280          _req->buf);
12831281
1284    spin_lock_irqsave(&dev->lock, flags);
1282    spin_lock_irqsave(&dev->lock, dev->lock_flags);
12851283
12861284    _req->status = -EINPROGRESS;
12871285    _req->actual = 0;
...... 
13271325    if (likely(req != 0))
13281326        list_add_tail(&req->queue, &ep->queue);
13291327
1330    spin_unlock_irqrestore(&dev->lock, flags);
1328    spin_unlock_irqrestore(&dev->lock, dev->lock_flags);
13311329
13321330    return 0;
13331331}
drivers/usb/gadget/jz4740_udc.h
7373    struct usb_gadget_driver *driver;
7474    struct device *dev;
7575    spinlock_t lock;
76    unsigned long lock_flags;
7677
7778    enum ep0state ep0state;
7879    struct jz4740_ep ep[UDC_MAX_ENDPOINTS];

Archive Download the corresponding diff file



interactive