Michael Grzeschik <m.grzeschik@xxxxxxxxxxxxxx> writes: > There is no need to call ep_queue unlocked inside the own driver. We > move its functionionality into an unlocked version. > > This patch removes potential unlocked timeslots inside > isr_setup_status_phase and isr_get_status_response, in which the lock > got released just before acquired again inside usb_ep_queue. > > Cc: stable <stable@xxxxxxxxxxxxxxx> Other patches in this set are less questionable, but this is certainly not stable material. See Documentation/stable_kernel_rules.txt > Signed-off-by: Michael Grzeschik <m.grzeschik@xxxxxxxxxxxxxx> > Signed-off-by: Marc Kleine-Budde <mkl@xxxxxxxxxxxxxx> > --- > drivers/usb/chipidea/udc.c | 118 ++++++++++++++++++++++++++------------------- > 1 file changed, 68 insertions(+), 50 deletions(-) > > diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c > index e7c84ab..61afd71 100644 > --- a/drivers/usb/chipidea/udc.c > +++ b/drivers/usb/chipidea/udc.c > @@ -671,6 +671,71 @@ 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)); > + } > + } > + > + if (usb_endpoint_xfer_isoc(mEp->ep.desc)) { > + if (mReq->req.length > mEp->ep.maxpacket) > + return -EMSGSIZE; > + } > + > + /* 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) { > + retval = -EMSGSIZE; > + dev_err(mEp->ci->dev, "request bigger than one td\n"); > + goto done; > + } > + > + 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 > @@ -717,9 +782,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; > > @@ -766,8 +829,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; > @@ -776,9 +837,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; > } > @@ -1177,8 +1236,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; > > @@ -1187,47 +1244,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) { > - retval = -EMSGSIZE; > - dev_err(mEp->ci->dev, "request bigger than one td\n"); > - goto done; > - } > - > - 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; > } > -- > 1.8.2.rc2 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html