aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/gadget
diff options
context:
space:
mode:
authorAnton Vorontsov <avorontsov@ru.mvista.com>2008-12-25 09:15:05 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2009-02-09 14:19:46 -0500
commita30551db66afa1b53a4fa7ceadddb7122bdcf491 (patch)
treebbd4f0468a7417067bf7ebb5001368b01f8c7e90 /drivers/usb/gadget
parent94f341db3dd080851f918da37e84659ef760da26 (diff)
USB: fsl_qe_udc: Fix recursive locking bug in ch9getstatus()
The call chain is this: qe_udc_irq() <- grabs the udc->lock spinlock rx_irq() qe_ep0_rx() ep0_setup_handle() setup_received_handle() ch9getstatus() qe_ep_queue() <- tries to grab the udc->lock again It seems unsafe to temporarily drop the lock in the ch9getstatus(), so to fix that bug the lock-less __qe_ep_queue() function implemented and used by the ch9getstatus(). Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com> Acked-by: David Brownell <dbrownell@users.sourceforge.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/gadget')
-rw-r--r--drivers/usb/gadget/fsl_qe_udc.c26
1 files changed, 18 insertions, 8 deletions
diff --git a/drivers/usb/gadget/fsl_qe_udc.c b/drivers/usb/gadget/fsl_qe_udc.c
index e8f7862acb3d..064582fb6a87 100644
--- a/drivers/usb/gadget/fsl_qe_udc.c
+++ b/drivers/usb/gadget/fsl_qe_udc.c
@@ -1681,14 +1681,11 @@ static void qe_free_request(struct usb_ep *_ep, struct usb_request *_req)
1681 kfree(req); 1681 kfree(req);
1682} 1682}
1683 1683
1684/* queues (submits) an I/O request to an endpoint */ 1684static int __qe_ep_queue(struct usb_ep *_ep, struct usb_request *_req)
1685static int qe_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
1686 gfp_t gfp_flags)
1687{ 1685{
1688 struct qe_ep *ep = container_of(_ep, struct qe_ep, ep); 1686 struct qe_ep *ep = container_of(_ep, struct qe_ep, ep);
1689 struct qe_req *req = container_of(_req, struct qe_req, req); 1687 struct qe_req *req = container_of(_req, struct qe_req, req);
1690 struct qe_udc *udc; 1688 struct qe_udc *udc;
1691 unsigned long flags;
1692 int reval; 1689 int reval;
1693 1690
1694 udc = ep->udc; 1691 udc = ep->udc;
@@ -1732,7 +1729,7 @@ static int qe_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
1732 list_add_tail(&req->queue, &ep->queue); 1729 list_add_tail(&req->queue, &ep->queue);
1733 dev_vdbg(udc->dev, "gadget have request in %s! %d\n", 1730 dev_vdbg(udc->dev, "gadget have request in %s! %d\n",
1734 ep->name, req->req.length); 1731 ep->name, req->req.length);
1735 spin_lock_irqsave(&udc->lock, flags); 1732
1736 /* push the request to device */ 1733 /* push the request to device */
1737 if (ep_is_in(ep)) 1734 if (ep_is_in(ep))
1738 reval = ep_req_send(ep, req); 1735 reval = ep_req_send(ep, req);
@@ -1748,11 +1745,24 @@ static int qe_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
1748 if (ep->dir == USB_DIR_OUT) 1745 if (ep->dir == USB_DIR_OUT)
1749 reval = ep_req_receive(ep, req); 1746 reval = ep_req_receive(ep, req);
1750 1747
1751 spin_unlock_irqrestore(&udc->lock, flags);
1752
1753 return 0; 1748 return 0;
1754} 1749}
1755 1750
1751/* queues (submits) an I/O request to an endpoint */
1752static int qe_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
1753 gfp_t gfp_flags)
1754{
1755 struct qe_ep *ep = container_of(_ep, struct qe_ep, ep);
1756 struct qe_udc *udc = ep->udc;
1757 unsigned long flags;
1758 int ret;
1759
1760 spin_lock_irqsave(&udc->lock, flags);
1761 ret = __qe_ep_queue(_ep, _req);
1762 spin_unlock_irqrestore(&udc->lock, flags);
1763 return ret;
1764}
1765
1756/* dequeues (cancels, unlinks) an I/O request from an endpoint */ 1766/* dequeues (cancels, unlinks) an I/O request from an endpoint */
1757static int qe_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) 1767static int qe_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
1758{ 1768{
@@ -2008,7 +2018,7 @@ static void ch9getstatus(struct qe_udc *udc, u8 request_type, u16 value,
2008 udc->ep0_dir = USB_DIR_IN; 2018 udc->ep0_dir = USB_DIR_IN;
2009 2019
2010 /* data phase */ 2020 /* data phase */
2011 status = qe_ep_queue(&ep->ep, &req->req, GFP_ATOMIC); 2021 status = __qe_ep_queue(&ep->ep, &req->req);
2012 2022
2013 if (status == 0) 2023 if (status == 0)
2014 return; 2024 return;