On Sun, 27 Nov 2005, Steve Calfee wrote:

> >When a control request arrives on ep0 and the gadget has to do a lot of
> >processing before completing the data or status stages of the request,
> >there's a possibility that the host might time out and send another
> >request to ep0.  If this happens, there's ambiguity about which request
> >the data or status stage corresponds to. The host will think it goes with
> >the second request, but the gadget driver may still be working on the
> >first.
> >
> Hi Alan, How could this ever happen? The device is supposed to reply with
> NAKs when it is not ready to respond to IN or OUT requests. NAKs are not
> supposed to timeout, or at least it should be a hugely long timeout of
> minutes, and then the host should reset the device.

It's not true that NAKs aren't supposed to time out.  The USB spec lists a
timeout value of 50 ms for standard control requests requiring no data
transfer and 5 seconds for requests that do send data (see 9.2.6.1 and
9.2.6.4).  Unfortunately sometimes the processing may take longer.  Linux
generally uses timeouts of 5 seconds.


Your comments are true. I have never seen evidence of the 50ms enforced by a host, but those failures are pretty rare, and I have not searched the Linux hcd code for this. After the long timeout, the appropriate action is for the host to reset the device, because it is probably dead.


> >To some extent the gadget driver can avoid this problem by keeping track
> >of setup requests as they arrive.  Assign a tag number to each one, for
> >example, and don't send a reply if the current tag is different from the > >reply's tag. But there's still a race between the setup routine changing
> >the current tag and the reply routine checking it.
> >
>
> How could it tag a setup request? Only one, by definition can be active at a
> time.

That's the whole point.  If a driver uses multiple threads, only the
thread that gets the setup notification will realize that a new request
has become active.  Somehow it has to tell the other threads that the
request they are working on is now stale.

As for how to tag a setup request... it's easy.  In the ep0-setup routine:

        reply_tag = ++private_data->ep0_tag;
        start_processing_request(reply_tag);

At the end of request processing, when the reply is about to be sent:

        if (reply_tag == private_data->ep0_tag)
                send_reply();

If a new request arrives before the processing routine has managed to call
send_reply, then the stale reply won't get sent.


You could do that, but why? If the device is hung, reset it, don't complicate the higher level setup protocol.

The spec does address "slow" setup responses, by saying the device should work around them:
<quote>
9.2.6 Request Processing
With the exception of SetAddress() requests (see Section 9.4.6), a device may begin processing of a request as soon as the device returns the ACK following the Setup. The device is expected to &#8220;complete&#8221; processing of the request before it allows the Status stage to complete successfully. Some requests initiate operations that take many milliseconds to complete. For requests such as this, the device class is required to define a method other than Status stage completion to indicate that the operation has completed. For example, a reset on a hub port takes at least 10 ms to complete. The SetPortFeature(PORT_RESET) (see Chapter 11) request &#8220;completes&#8221; when the reset on the port is initiated. Completion of the reset operation is signaled when the port&#8217;s status change is set to indicate that the port is now enabled. This technique prevents the host from having to constantly poll for a completion when it is known that the request will take
a relatively long period of time.
</quote>

>  If it sees a second SETUP it should STALL the ep0.

You probably mean, if the gadget driver sees a second setup before it has
finished processing the first.  Bear in mind that the gadget driver may
think it has finished processing a request before the reply actually gets
sent, because of buffering and protocol delays.


Yes, that is what I mean, but 50 ms is a really long time for buffering delays.


Besides, why should it STALL ep0?  Why not simply complete the new
request?  STALL is supposed to be used only when a request can't be
handled for some reason.

<quote>
9.2.7 Request Error
When a request is received by a device that is not defined for the device, is inappropriate for the current setting of the device, or has values that are not compatible with the request, then a Request Error exists. The device deals with the Request Error by returning a STALL PID in response to the next Data stage transaction or in the Status stage of the message. It is preferred that the STALL PID be returned at the next
Data stage transaction, as this avoids unnecessary bus activity.
</quote>


I would interpret a second SETUP as an inappropriate request if a previous SETUP has not concluded.


> This confirmed endpoint zero protocol process is so important that the USB > spec requires an additional zero length IN/OUT in the opposite direction as > the SETUP data packets. This is done so the highest level driver (not just > the host controller hardware) will confirm that the entire transaction is > complete and has gotten to the driver. If you look with a protocol analyser
> this last zero length packet is almost never able to be sent in the last
> frame of the setup data transactions, because it has to go all the way to
> the top of the driver stack to get confirmation that the transaction was
> received by the receiving end.

Are you talking about (non-zero length) IN transfers or OUT transfers?
For IN transfers this extra packet is sent by the host controller hardware
with no intervention from the upper layers and no delay.  For OUT
transfers it is sent by the gadget, and the gadget layer is involved.
Hence it can be delayed, and it is precisely this delay which concerns me.


For an IN status response, it could be queued by the host, because it is the device confirming that the data it just got in the setup/OUT sequence was received and understood.

A HCD could queue the final zero length OUT, after the setup and IN transfers but it would be bad. The whole point in the USB protocol for that last zero length packet going in the reverse direction is so the receiving end of the data acknowledges that the highest level driver has seen and understood the data. If you just put it in with the setup transaction, it is totally redundant with all the other ack and data recovery protocols. The zero length packet acknowledge is there for the receiving end high level driver to acknowledge a setup packet was received and understood, not as part of the low level error recovery as is handled by say the OHCI hardware.


> By design of the protocol, races should never happen, or if detected, either
> a STALL should be sent or the host should reset the device.

Where in the USB spec does it say that a STALL should be sent or the host
should reset the device if a control request times out?  Either action
seems pretty drastic to me.  A new setup packet should be the only reset
needed.



<quote>
9.4 Standard Device Requests
<snip>
If an unsupported or invalid request is made to a USB device, the device responds by returning STALL in the Data or Status stage of the request. If the device detects the error in the Setup stage, it is preferred that the device returns STALL at the earlier of the Data or Status stage. Receipt of an unsupported or invalid request does NOT cause the optional Halt feature on the control pipe to be set. If for any reason, the device becomes unable to communicate via its Default Control Pipe due to an error condition, the device must be
reset to clear the condition and restart the Default Control Pipe.
</quote>


It took me some time to find the appropriate sections of the USB 2.0 spec.

Regards, Steve




-------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc. Do you grep through log files
for problems?  Stop!  Download the new AJAX search engine that makes
searching your log files as easy as surfing the  web.  DOWNLOAD SPLUNK!
http://ads.osdn.com/?ad_id=7637&alloc_id=16865&op=click
_______________________________________________
linux-usb-devel@lists.sourceforge.net
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to