Alan Stern wrote:
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

Reply via email to