Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 74bb3508 authored by David Brownell's avatar David Brownell Committed by Greg Kroah-Hartman
Browse files

USB: musb_host, minor enqueue locking fix (v2)



Someone noted that the enqueue path used an unlocked access
for usb_host_endpoint->hcpriv ... fix that, by being safe
and always accessing it under spinlock protection.

Signed-off-by: default avatarDavid Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent e13c594f
Loading
Loading
Loading
Loading
+8 −9
Original line number Original line Diff line number Diff line
@@ -1841,7 +1841,7 @@ static int musb_urb_enqueue(
	unsigned long			flags;
	unsigned long			flags;
	struct musb			*musb = hcd_to_musb(hcd);
	struct musb			*musb = hcd_to_musb(hcd);
	struct usb_host_endpoint	*hep = urb->ep;
	struct usb_host_endpoint	*hep = urb->ep;
	struct musb_qh			*qh = hep->hcpriv;
	struct musb_qh			*qh;
	struct usb_endpoint_descriptor	*epd = &hep->desc;
	struct usb_endpoint_descriptor	*epd = &hep->desc;
	int				ret;
	int				ret;
	unsigned			type_reg;
	unsigned			type_reg;
@@ -1853,22 +1853,21 @@ static int musb_urb_enqueue(


	spin_lock_irqsave(&musb->lock, flags);
	spin_lock_irqsave(&musb->lock, flags);
	ret = usb_hcd_link_urb_to_ep(hcd, urb);
	ret = usb_hcd_link_urb_to_ep(hcd, urb);
	qh = ret ? NULL : hep->hcpriv;
	if (qh)
		urb->hcpriv = qh;
	spin_unlock_irqrestore(&musb->lock, flags);
	spin_unlock_irqrestore(&musb->lock, flags);
	if (ret)
		return ret;


	/* DMA mapping was already done, if needed, and this urb is on
	/* DMA mapping was already done, if needed, and this urb is on
	 * hep->urb_list ... so there's little to do unless hep wasn't
	 * hep->urb_list now ... so we're done, unless hep wasn't yet
	 * yet scheduled onto a live qh.
	 * scheduled onto a live qh.
	 *
	 *
	 * REVISIT best to keep hep->hcpriv valid until the endpoint gets
	 * REVISIT best to keep hep->hcpriv valid until the endpoint gets
	 * disabled, testing for empty qh->ring and avoiding qh setup costs
	 * disabled, testing for empty qh->ring and avoiding qh setup costs
	 * except for the first urb queued after a config change.
	 * except for the first urb queued after a config change.
	 */
	 */
	if (qh) {
	if (qh || ret)
		urb->hcpriv = qh;
		return ret;
		return 0;
	}


	/* Allocate and initialize qh, minimizing the work done each time
	/* Allocate and initialize qh, minimizing the work done each time
	 * hw_ep gets reprogrammed, or with irqs blocked.  Then schedule it.
	 * hw_ep gets reprogrammed, or with irqs blocked.  Then schedule it.