Re: usbtest and gadget zero with PLX 3380

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, Apr 23, 2012 at 12:27:57PM -0400, Alan Stern wrote:
> On Mon, 23 Apr 2012, Thomas Knauth wrote:
> 
> > >> Is this the intended behavior? Any writes/reads falling short of the
> > >> gadget zero buffer length, cause testusb to hang (USB activity LED on
> > >> the net3380 is on, during this time though).
> > >
> > > No it shouldn't hang, but I must say I don't like how g_zero works
> > > today. It relies a lot on the peripheral controller being able to abort
> > > a transfer which was started by mistake. If you look at how USB classes
> > > are built, they all have some way to tell the other end transfer is
> > > over.
> > >
> > > Either they will negotiate a transfer size (e.g. Mass Storage with CBW)
> > > or they will use a ZLP to notify about the end of the transfer; but
> > > g_zero/usbtest has neither.
> > 
> > This may actually be the explanation. The driver cannot tell whether
> > the request is finished or not if the size supplied to usbtest is a
> > multiple of the maximum packet size. Using, e.g., -s 511, works for
> > any value of -c. Using -s with g_zero buflen also works. Setting -s to
> > anything less than g_zero buflen being a multiple of the maximum
> > packet size, does not work. As far as I can tell from reading the
> > code, the driver does not know whether there will be more data for
> > this request, because req.actual < req.length (req.length defined by
> > g_zero buflen, req.actual defined by -s parameter to usbtest) and it
> > is not a short packet:
> > 
> > is_short = (count == 0) || ((count % ep->ep.maxpacket) != 0);
> > 
> > int retval = is_short || ((req->req.actual == req->req.length) &&
> > !req->req.zero);
> > 
> > I'm still unsure who is at fault here: the driver or g_zero/usbtest
> > and how best to fix this. Any suggestions?
> 
> Why is this a problem?  All that should happen is you transfer less
> data than g_zero expects.  Either way, the transfer should succeed.

ok, let's say usbtest is sending at 1024 byte chunks 5 times and g_zero
uses a 4096 byte buffer, this will mean UDC will start a 4k e.g. DMA
transfer and that single DMA transfer will receive the first 4 chunks
sent by usbtest.

Now g_zero blindly starts another 4k transfer, UDC's DMA is kicked, but
host only sends 1k. That transfer will never finish because 1024 is
aligned to wMaxPacketSize (so, not a short packet) and is not the end of
the transfer kicked to DMA (which was 4k). How do you make this work ?

If you look at most UDC's code, you will see there's a DMA abort or some
sort of transfer abort mechanism whenever actual == length, this is what
makes it magically work, but IMHO, that's not how USB is supposed to be
implemented. Look at all other classes, they have a way to negotiate
size of transfer (Mass Storage's CBW, Ethernet's MTU, MTP's handling of
ZLP and so on) so there will always be a way to finish the transfer. But
g_zero is special, because it relies on the UDC aborting a transfer
which was bigger than necessary.

-- 
balbi

Attachment: signature.asc
Description: Digital signature


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux