Re: [RFC/PATCH v2] usb: host: xhci: issue 'Reset Endpoint' for !CONTROL EPs from finish_td()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

On Wed, Nov 12, 2014 at 03:03:10PM -0500, Alan Stern wrote:
> On Wed, 12 Nov 2014, Felipe Balbi wrote:
> 
> > If class driver wants to SetFeature(ENDPOINT_HALT) and
> > later tries to talk to the stalled endpoint, xhci will
> > move endpoint to EP_STATE_STALL and subsequent usb_submit_urb()
> > will not cause a USB token to be shifted into the data lines.
> > 
> > Because of that, peripheral will never have any means of
> > STALLing a follow up token.
> > 
> > This is a known error at least with g_zero + testusb -t 13
> > and can be easily reproduced.
> 
> Can you elaborate this description a bit more?  I don't understand what 
> the problem is.

Look at drivers/usb/misc/usbtest.c::test_halt(). Here's a dump of the
code:

static int verify_not_halted(struct usbtest_dev *tdev, int ep, struct urb *urb)
{
	int	retval;
	u16	status;

	/* shouldn't look or act halted */
	retval = usb_get_status(urb->dev, USB_RECIP_ENDPOINT, ep, &status);
	if (retval < 0) {
		ERROR(tdev, "ep %02x couldn't get no-halt status, %d\n",
				ep, retval);
		return retval;
	}
	if (status != 0) {
		ERROR(tdev, "ep %02x bogus status: %04x != 0\n", ep, status);
		return -EINVAL;
	}
	retval = simple_io(tdev, urb, 1, 0, 0, __func__);
	if (retval != 0)
		return -EINVAL;
	return 0;
}

static int verify_halted(struct usbtest_dev *tdev, int ep, struct urb *urb)
{
	int	retval;
	u16	status;

	/* should look and act halted */
	retval = usb_get_status(urb->dev, USB_RECIP_ENDPOINT, ep, &status);
	if (retval < 0) {
		ERROR(tdev, "ep %02x couldn't get halt status, %d\n",
				ep, retval);
		return retval;
	}
	if (status != 1) {
		ERROR(tdev, "ep %02x bogus status: %04x != 1\n", ep, status);
		return -EINVAL;
	}
	retval = simple_io(tdev, urb, 1, 0, -EPIPE, __func__);
	if (retval != -EPIPE)
		return -EINVAL;
	retval = simple_io(tdev, urb, 1, 0, -EPIPE, "verify_still_halted");
	if (retval != -EPIPE)
		return -EINVAL;
	return 0;
}

static int test_halt(struct usbtest_dev *tdev, int ep, struct urb *urb)
{
	int	retval;

	/* shouldn't look or act halted now */
	retval = verify_not_halted(tdev, ep, urb);
	if (retval < 0)
		return retval;

	/* set halt (protocol test only), verify it worked */
	retval = usb_control_msg(urb->dev, usb_sndctrlpipe(urb->dev, 0),
			USB_REQ_SET_FEATURE, USB_RECIP_ENDPOINT,
			USB_ENDPOINT_HALT, ep,
			NULL, 0, USB_CTRL_SET_TIMEOUT);
	if (retval < 0) {
		ERROR(tdev, "ep %02x couldn't set halt, %d\n", ep, retval);
		return retval;
	}
	retval = verify_halted(tdev, ep, urb);
	if (retval < 0) {
		int ret;

		/* clear halt anyways, else further tests will fail */
		ret = usb_clear_halt(urb->dev, urb->pipe);
		if (ret)
			ERROR(tdev, "ep %02x couldn't clear halt, %d\n",
			      ep, ret);

		return retval;
	}

	/* clear halt (tests API + protocol), verify it worked */
	retval = usb_clear_halt(urb->dev, urb->pipe);
	if (retval < 0) {
		ERROR(tdev, "ep %02x couldn't clear halt, %d\n", ep, retval);
		return retval;
	}
	retval = verify_not_halted(tdev, ep, urb);
	if (retval < 0)
		return retval;

	/* NOTE:  could also verify SET_INTERFACE clear halts ... */

	return 0;
}

Note, specially, what verify_halted() does. It will issue a GetStatus()
followed by two usb_submit_urb(). The first usb_submit_urb() will be
STALLed by the function (g_zero) and that will cause the endpoint to
move from EP_STATE_RUNNING to EP_STATE_HALTED. The following
usb_submit_urb() will trigger:

2815         case EP_STATE_HALTED:
2816                 xhci_dbg(xhci, "WARN halted endpoint, queueing URB anyway.\n");

But, because EP_HALTED flag is set, xhci_ring_ep_doorbell() will return
early:

316 void xhci_ring_ep_doorbell(struct xhci_hcd *xhci,
317                 unsigned int slot_id,
318                 unsigned int ep_index,
319                 unsigned int stream_id)
320 {
321         __le32 __iomem *db_addr = &xhci->dba->doorbell[slot_id];
322         struct xhci_virt_ep *ep = &xhci->devs[slot_id]->eps[ep_index];
323         unsigned int ep_state = ep->ep_state;
324 
325         /* Don't ring the doorbell for this endpoint if there are pending
326          * cancellations because we don't want to interrupt processing.
327          * We don't want to restart any stream rings if there's a set dequeue
328          * pointer command pending because the device can choose to start any
329          * stream once the endpoint is on the HW schedule.
330          */
331         if ((ep_state & EP_HALT_PENDING) || (ep_state & SET_DEQ_PENDING) ||
332             (ep_state & EP_HALTED))
333                 return;
334         writel(DB_VALUE(ep_index, stream_id), db_addr);
335         /* The CPU has better things to do at this point than wait for a
336          * write-posting flush.  It'll get there soon enough.
337          */
338 }

and the doorbell will never rung. But even if I drop EP_HALTED from the
check below and let EP doorbell be rung, nothing will happen because,
according to XHCI spec 1.0, we *must* first issue a Reset Endpoint
command to get Endpoint to move to EP_STATE_STOPPED, in which case,
ringing that EP's doorbell will actually cause a transfer to happen.

Right now, what happens is that second usb_submit_urb() does nothing and
the 10 second timer expires, causing the URB to be canceled and test
failing with -ETIMEDOUT.

> For instance, if an endpoint is halted then there's no reason for the
> controller to shift any USB tokens for it onto the data lines.  Doing
> so would just be a waste of bandwidth, since the response is bound to
> be another STALL.  And it doesn't matter that the peripheral has no
> means to STALL any follow-up iens, since the host controller already
> knows the endpoint is halted.

Now you're claiming that this is a bug on usbtest which has been in tree
for many, many years and is known to work with EHCI, MUSB and UHCI (at
least, probably dummy too), which is a different statement from previous
thread [1].

> Of course, control endpoints behave differently from other ones.  But 
> that's not what you're talking about here, since test 13 is for bulk or 
> interrupt endpoints.
> 
> The comment in the patch talks about moving the dequeue pointer past
> the STALLed TD and then clearing the halt condition.  Moving the
> dequeue pointer is fine -- there's no other way to take control of the
> TD back from the hardware -- but why would you want to clear the halt?  
> The HCD isn't supposed to do that; the class driver is.

See what usbtest does. It wants to make sure that, even if we issue
several URBs for that endpoint, the function will always STALL. Sure,
it's a waste of bandwidth, but what's the probability that any class
driver will actually do this outside of a test environment ? I think
it's not up to the HCD to device and it should, rather, let the function
respond with the expected STALL again which will, once more, move the
endpoint back into EP_STATE_HALT.

The only thing we should be discussing here, is proper placement for
xhci_cleanup_halted_endpoint().

[1] http://marc.info/?l=linux-usb&m=139033307026763&w=2

-- 
balbi

Attachment: signature.asc
Description: Digital signature


[Index of Archives]     [Linux Kernel]     [Kernel Development Newbies]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Hiking]     [Linux Kernel]     [Linux SCSI]