David:
I think you misunderstood some of what I wrote (and I'm probably misunderstanding some of what you wrote too). A large part of the problem seems to be that Oliver and I used "unlink" to mean "remove from the hardware schedule before the hardware is through with it" -- maybe you say "dequeue" to mean that. You take "unlink" to mean "eventually call the completion handler with urb->status equal to -ENOENT or -ECONNRESET, regardless of what the lower level driver or the hardware does".
Well, the routines called "unlink" are at the higher level, and the ones called "dequeue" touch the hardware schedule, so I'll stick with my terminology.
Though given context, "unlink" is un-ambiguous: if you're talking about behavior inside the HCD, it's "dequeue"; behavior inside usbcore is just as clearly "unlink" (or maybe "giveback", etc.). Which is why I didn't use "dequeue", even though the code does.
Bearing that in mind...
On Fri, 18 Jul 2003, David Brownell wrote:
Alan Stern wrote:
On Fri, 18 Jul 2003, Oliver Neukum wrote:
It seems to me that you are racing against HC hardware.
Yes, certainly.
But not at that level, and URBs aren't hardware data structures either.
It should be clear that _dequeueing_ an URB races against hardware completion of that URB. That's what I meant before. You probably meant that hcd_unlink_urb() is protected from racing against anything by urb->lock, which is true. So _unlinking_ is a different story.
Well, I did carefully qualify my comment to be talking about the interface between usbcore and the hcd.
There's also a distinction between starting the unlink (which includes calling dequeue) and the asynchronous completion of that urb (which has _nothing_ special for the case that the completion was caused by unlinking, or even by dequeueing).
You cannot unlink an URB that is being executed, can you?
With UHCI you can. What will happen is that the HCD will finish executing the current TD, but on its next loop through the hardware schedule the QH will no longer be in the chain. As a result, you end up with an invalid USB transaction: the initial packets go out on the bus but the final ones don't.
All HCs have a similar answer to this question: (a) take all the relevant data structures off the hardware schedule; then (b) make sure they're off (by waiting for the next frame, or in the case of EHCI for an explicit IAA handshake); (c) run through and handle the work, reporting both hardware and software/unlink completions; and finally (d) relink the data structures if necessary.
But the current arrangement doesn't make use of the hardware completion
information -- what gets reported to the driver is only that the URB was
unlinked (status == -ECONNRESET). The driver isn't told whether or not
the hardware managed to complete the data transfer. Not with UHCI, anyway.
The USB device driver is told (at least by EHCI and OHCI) how many bytes transferred before the completion was triggered. Nothing else seems necessary.
Are you asking to get multiple fault reports -- both for the software-induced faults (ECONNRESET, ESHUTDOWN, ENOENT), and for any preceding hardware fault (normal completion, ETIMEDOUT, and so on)? I don't like such models at all. They lead to much confusion, even in the rare cases they can be justified.
At the same time you must retain EINPROGRESS in the status field until some time _after_ io is completed, because you need to evaluate the result of the transfer.
See above. The status can be set to -ECONNRESET because the transfer doesn't finish. Or maybe the race goes the other way and the transfer does finish; nevertheless the URB is marked as having been unlinked. The driver does not check the hardware status field to see whether the transfer completed successfully before the unlink occurred.
As pointed out earlier on this thread, the HCD glue does check urb->status before proceeding.
No; what I pointed out earlier was that the HCD glue checks urb->status before allowing an unlink. It doesn't check urb->status before proceeding to the callback handler (i.e., after calling the low-level dequeue routine).
Why would it check? The HCD isn't allowed to change that status any longer...
Since the communication between layers is asynchronous, the urb can't be (synchronously) unlinked before that status is changed. So the status is decided before the HCD gets kicked to accelerate any unlinking. That prevents all kinds of nastiness.
Is there any reason why the status couldn't be changed if the low-level HC driver detects that the hardware did manage to complete the transfer before it could be dequeued? When that happens, why not report that the URB succeeded and the unlink failed -- which is what really did occur -- rather than the other way around as we do now?
You're forgetting the asynchrony involved. Whatever component decided to initiate the unlink has already gone and done things relying on knowledge that the urb will get an "unlinked" callback. And it wasn't speculative execution...
Plus, the HCD _does_ report the actual bytes transferred, which already gives enough status for the device driver if it wants to implement almost any "second-guess that unlink" logic.
IMHO the only way to learn whether an URB can be unlinked is to try it.
Is there any point in the code that tries to determine whether an URB can be unlinked without actually trying it?
If you have to ask that, you haven't looked at the code that actually calls into the HCD to make it unlink. There's some code there that does exactly that -- and I've mentioned it before on this thread, come to think of it.
Here's where the difference in word usage is really acute. There's no way to learn whether an URB can be _dequeued_ without trying, and nowhere does the code attempt to do so. But hcd_unlink_urb() does make several checks (the most significant of which is whether urb->status == -EINPROGRESS) before allowing an _unlink_.
OK, I see what you're describing. But I don't see why it could ever matter. It's not going to affect the transfer length reported, and it's not (see discussion above) going to affect urb->status.
If the dequeue fails because the HCD is waiting to report the completion (which should be an SMP-only path), it's no big deal. And we know it's safe, because of how the giveback paths work.
- Dave
In the hope of clearer communication in the future...
Alan Stern
------------------------------------------------------- This SF.net email is sponsored by: VM Ware With VMware you can run multiple operating systems on a single machine. WITHOUT REBOOTING! Mix Linux / Windows / Novell virtual machines at the same time. Free trial click here: http://www.vmware.com/wl/offer/345/0 _______________________________________________ [EMAIL PROTECTED] To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel