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".

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.

> >>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.

> >>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).

> > Part of this problem is caused already in the hcd glue layer.  
> > hcd_unlink_urb() sets urb->status to -ECONNRESET or -ENOENT _before_ 
> > calling the HC driver to dequeue the URB.
> > 
> > One could easily argue that this behavior is a bug.
> 
> Sounds like you want to try ... ;)

Not really.  I recognize that this is how the system is intended to work.

> It's just how unlinking is defined; not a bug.  At some point,
> some software component chooses what urb->status will be.
> 
> 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?

> >>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_.

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