From patchwork Wed Nov 14 16:19:09 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michael Grzeschik X-Patchwork-Id: 1742501 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by patchwork1.kernel.org (Postfix) with ESMTP id 5469D3FC64 for ; Wed, 14 Nov 2012 16:22:25 +0000 (UTC) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1TYfhQ-0005xn-Tr; Wed, 14 Nov 2012 16:20:25 +0000 Received: from metis.ext.pengutronix.de ([2001:6f8:1178:4:290:27ff:fe1d:cc33]) by merlin.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1TYfgh-0005mo-44 for linux-arm-kernel@lists.infradead.org; Wed, 14 Nov 2012 16:19:42 +0000 Received: from dude.hi.pengutronix.de ([2001:6f8:1178:2:21e:67ff:fe11:9c5c]) by metis.ext.pengutronix.de with esmtp (Exim 4.72) (envelope-from ) id 1TYfgL-0006eC-QK; Wed, 14 Nov 2012 17:19:17 +0100 Received: from mgr by dude.hi.pengutronix.de with local (Exim 4.80) (envelope-from ) id 1TYfgK-00006Z-7s; Wed, 14 Nov 2012 17:19:16 +0100 From: Michael Grzeschik To: linux-usb@vger.kernel.org, linux-arm-kernel@lists.infradead.org Subject: [PATCH 8/9] usb: chipidea: udc: remove unlocked ep_queue which can lead to an race Date: Wed, 14 Nov 2012 17:19:09 +0100 Message-Id: <1352909950-32555-9-git-send-email-m.grzeschik@pengutronix.de> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1352909950-32555-1-git-send-email-m.grzeschik@pengutronix.de> References: <1352909950-32555-1-git-send-email-m.grzeschik@pengutronix.de> X-SA-Exim-Connect-IP: 2001:6f8:1178:2:21e:67ff:fe11:9c5c X-SA-Exim-Mail-From: mgr@pengutronix.de X-SA-Exim-Scanned: No (on metis.ext.pengutronix.de); SAEximRunCond expanded to false X-PTX-Original-Recipient: linux-arm-kernel@lists.infradead.org X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20121114_111939_522859_2121C17A X-CRM114-Status: GOOD ( 19.26 ) X-Spam-Score: -2.6 (--) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-2.6 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.7 RP_MATCHES_RCVD Envelope sender domain matches handover relay domain -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] Cc: fabio.estevam@freescale.com, alexander.shishkin@linux.intel.com, gregkh@linuxfoundation.org, devicetree-discuss@lists.ozlabs.org, mkl@pengutronix.de, kernel@pengutronix.de X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: linux-arm-kernel-bounces@lists.infradead.org Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org Its not nessecary to call ep_queue unlocked while in the own driver. So we move the function to an unlocked version and call it conditionaly. Signed-off-by: Michael Grzeschik Signed-off-by: Marc Kleine-Budde --- drivers/usb/chipidea/udc.c | 115 +++++++++++++++++++++++++------------------- 1 file changed, 65 insertions(+), 50 deletions(-) diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index 0ed2e1a..2999b0d 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -648,6 +648,68 @@ static void isr_get_status_complete(struct usb_ep *ep, struct usb_request *req) } /** + * _ep_queue: queues (submits) an I/O request to an endpoint + * + * Caller must hold lock + */ +static int _ep_queue(struct usb_ep *ep, struct usb_request *req, + gfp_t __maybe_unused gfp_flags) +{ + struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); + struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req); + struct ci13xxx *ci = mEp->ci; + int retval = 0; + + if (ep == NULL || req == NULL || mEp->ep.desc == NULL) + return -EINVAL; + + if (mEp->type == USB_ENDPOINT_XFER_CONTROL) { + if (req->length) + mEp = (ci->ep0_dir == RX) ? + ci->ep0out : ci->ep0in; + if (!list_empty(&mEp->qh.queue)) { + _ep_nuke(mEp); + retval = -EOVERFLOW; + dev_warn(mEp->ci->dev, "endpoint ctrl %X nuked\n", + _usb_addr(mEp)); + } + } + + /* first nuke then test link, e.g. previous status has not sent */ + if (!list_empty(&mReq->queue)) { + retval = -EBUSY; + dev_err(mEp->ci->dev, "request already in queue\n"); + goto done; + } + + if (req->length > 4 * CI13XXX_PAGE_SIZE) { + req->length = 4 * CI13XXX_PAGE_SIZE; + retval = -EMSGSIZE; + dev_warn(mEp->ci->dev, "request length truncated\n"); + } + + dbg_queue(_usb_addr(mEp), req, retval); + + /* push request */ + mReq->req.status = -EINPROGRESS; + mReq->req.actual = 0; + + retval = _hardware_enqueue(mEp, mReq); + + if (retval == -EALREADY) { + dbg_event(_usb_addr(mEp), "QUEUE", retval); + retval = 0; + } + if (!retval) + list_add_tail(&mReq->queue, &mEp->qh.queue); + + done: + return retval; +} + + + +/** * isr_get_status_response: get_status request response * @ci: ci struct * @setup: setup request packet @@ -694,9 +756,7 @@ __acquires(mEp->lock) } /* else do nothing; reserved for future use */ - spin_unlock(mEp->lock); - retval = usb_ep_queue(&mEp->ep, req, gfp_flags); - spin_lock(mEp->lock); + retval = _ep_queue(&mEp->ep, req, gfp_flags); if (retval) goto err_free_buf; @@ -743,8 +803,6 @@ isr_setup_status_complete(struct usb_ep *ep, struct usb_request *req) * This function returns an error code */ static int isr_setup_status_phase(struct ci13xxx *ci) -__releases(mEp->lock) -__acquires(mEp->lock) { int retval; struct ci13xxx_ep *mEp; @@ -753,9 +811,7 @@ __acquires(mEp->lock) ci->status->context = ci; ci->status->complete = isr_setup_status_complete; - spin_unlock(mEp->lock); - retval = usb_ep_queue(&mEp->ep, ci->status, GFP_ATOMIC); - spin_lock(mEp->lock); + retval = _ep_queue(&mEp->ep, ci->status, GFP_ATOMIC); return retval; } @@ -1152,8 +1208,6 @@ static int ep_queue(struct usb_ep *ep, struct usb_request *req, gfp_t __maybe_unused gfp_flags) { struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); - struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req); - struct ci13xxx *ci = mEp->ci; int retval = 0; unsigned long flags; @@ -1162,47 +1216,8 @@ static int ep_queue(struct usb_ep *ep, struct usb_request *req, spin_lock_irqsave(mEp->lock, flags); - if (mEp->type == USB_ENDPOINT_XFER_CONTROL) { - if (req->length) - mEp = (ci->ep0_dir == RX) ? - ci->ep0out : ci->ep0in; - if (!list_empty(&mEp->qh.queue)) { - _ep_nuke(mEp); - retval = -EOVERFLOW; - dev_warn(mEp->ci->dev, "endpoint ctrl %X nuked\n", - _usb_addr(mEp)); - } - } - - /* first nuke then test link, e.g. previous status has not sent */ - if (!list_empty(&mReq->queue)) { - retval = -EBUSY; - dev_err(mEp->ci->dev, "request already in queue\n"); - goto done; - } - - if (req->length > 4 * CI13XXX_PAGE_SIZE) { - req->length = 4 * CI13XXX_PAGE_SIZE; - retval = -EMSGSIZE; - dev_warn(mEp->ci->dev, "request length truncated\n"); - } - - dbg_queue(_usb_addr(mEp), req, retval); + retval = _ep_queue(ep, req, gfp_flags); - /* push request */ - mReq->req.status = -EINPROGRESS; - mReq->req.actual = 0; - - retval = _hardware_enqueue(mEp, mReq); - - if (retval == -EALREADY) { - dbg_event(_usb_addr(mEp), "QUEUE", retval); - retval = 0; - } - if (!retval) - list_add_tail(&mReq->queue, &mEp->qh.queue); - - done: spin_unlock_irqrestore(mEp->lock, flags); return retval; }