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 “complete”
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 “completes” when the reset on the port is
initiated. Completion of the reset operation is
signaled when the port’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