discuss-gnuradio
[Top][All Lists]
Advanced

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

Re: [Discuss-gnuradio] USB2 high speed vs. full speed.


From: Eric Blossom
Subject: Re: [Discuss-gnuradio] USB2 high speed vs. full speed.
Date: Sun, 13 Feb 2005 09:05:31 -0800
User-agent: Mutt/1.5.6i

On Sun, Feb 13, 2005 at 11:41:24PM +1030, Berndt Josef Wulf wrote:
> G'day,
> 
> The following are the reported devices and their configuration after loading 
> the firmware and fpga:
> 
> Reported devices by kernel during at bootup
> 
> hci0 at pci0 dev 29 function 7: Intel 82801DB USB EHCI Controller (rev. 0x01)
> ehci0: interrupting at irq 11
> ehci0: EHCI version 1.0
> ehci0: companion controllers, 2 ports each: uhci0 uhci1 uhci2
> usb3 at ehci0: USB revision 2.0
> uhub3 at usb3
> uhub3: Intel EHCI root hub, class 9/0, rev 2.00/1.00, addr 1
> uhub3: single transaction translator
> uhub3: 6 ports with 6 removable, self powered
> 
> NB: According to a GnuRadio Wiki article, the Intel 82801DB device is 
> acclaimed to be the best performer!
> 
> Reported configuration interrogated from userland
> 
> usbdevs -v
> [,,,]
> Controller /dev/usb3:
> addr 1: high speed, self powered, config 1, EHCI root hub(0x0000), 
> Intel(0x8086), rev 1.00
>  port 1 addr 2: high speed, self powered, config 1, USRP Rev 2(0x0002), Free 
> Software Folks(0xfffe), rev 1.02
>  port 2 powered
>  port 3 powered
>  port 4 powered
>  port 5 powered
>  port 6 powered
> 
> I was led to believe that the FX2 interface is suppose to be configured as a 
> fullspeed device. This doesn't appear to be the case as it is reports the 
> configuration of a high speed device.

"high speed" is the fast one (480 Mb/s).  Bad nomenclature.
"full speed" (12 Mb/s)
"low-speed" (1.5 Mb/s)

> A evaluation of the USRP USB interface only managed to push 4MB/sec data 
> bandwith which is below the expectation of a full speed USB device.

Yes.  This is not surprising given the NetBSD doesn't have a
non-default implementation of the fast usb code (fusb_*)

> test_usrp_standard_{tx,rx}  utilities report underruns and overruns 
> respectively until the decimation/interp value is adjusted to a value 
> accommodating this speed.

This is consistent...

> Not being an expert in USB software development this leads me to my question:
> 
> What is required to get the show running at the next level of speed? In which 
> aspects does the fusb_linux implementation differ from that of the generic 
> version considering that both make use of the libusb library.

The fundamental difference between fusb_generic and fusb_linux is that
the fusb_linux keeps multiple USB requests "in-flight" at the same
time.  That is, there are multiple outstanding read and write
requests.  fusb_generic uses the libusb usb_bulk_write / usb_bulk_read
functions which appear to make a single request and block until it's
completed.  fusb_linux cooperates with libusb, but goes "behind its
back" to get the speed.

> Currently, most example applications run with only a few overrun/underrun 
> messages chiefly caused due to activities of other applications running on 
> the same system, such as KMail checking for new mail etc., at the current 
> 4MB/sec limitation. "top" reports a CPU load of less than 10% for most 
> GnuRadio example programs run on this system.
> 
> Any help, pointers and tips are very much welcomed and appreciated.

The BSD libusb usb_bulk_write implementation is below.  It would
appear that there is no read-ahead or write-behind implemented in the
read and write system calls when applied to USB (probably the correct
default behavior).  The trick is to figure out how to get the kernel
to feed more than one write request to the driver at the same time.


int usb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, int size,
                   int timeout)
{
  int fd, ret, sent = 0;

  /* Ensure the endpoint address is correct */
  ep &= ~USB_ENDPOINT_IN;

  fd = ensure_ep_open(dev, ep, O_WRONLY);
  if (fd < 0) {
    if (usb_debug >= 2) {
#if __FreeBSD__
      fprintf (stderr, "usb_bulk_write: got negative open file descriptor for 
endpoint %d\n", UE_GET_ADDR(ep));
#else
      fprintf (stderr, "usb_bulk_write: got negative open file descriptor for 
endpoint %02d\n", UE_GET_ADDR(ep));
#endif
    }
    return fd;
  }

  ret = ioctl(fd, USB_SET_TIMEOUT, &timeout);
  if (ret < 0)
    USB_ERROR_STR(-errno, "error setting timeout: %s",
                  strerror(errno));

  do {
    ret = write(fd, bytes+sent, size-sent);
    if (ret < 0)
#if __FreeBSD__
      USB_ERROR_STR(-errno, "error writing to bulk endpoint %s.%d: %s",
                    dev->device->filename, UE_GET_ADDR(ep), strerror(errno));
#else
      USB_ERROR_STR(-errno, "error writing to bulk endpoint %s.%02d: %s",
                  dev->device->filename, UE_GET_ADDR(ep), strerror(errno));
#endif

    sent += ret;
  } while (ret > 0 && sent < size);

  return sent;
}


Not having looked at the BSD kernel in a long time, I don't have any
concrete suggestions.  However, I'd try these general approaches:

* Is there generic support for asynchronous reading and writing?  That
is, multiple reads and writes outstanding, where you are notified
somehow of their completion? (Signals, polling, etc).

* Is there a USB specific ioctl that allows you to submit an USB "URB"
(USB Request Block) asynchronously (this is the technique fusb_linux
uses.)

* Spend a bit of time looking at the USB driver source code and see how
it works.  There may be an ioctl that does what you want.

* Write a kernel driver that solves the problem.

One of these is bound to work.

If you've got a logic analyzer available, I can provide more tips for
seeing exactly what's going on.  Given the symptoms -- it works when
you slow down to 4MB/sec -- I'm quite confident that your throughput
problem is that the default libusb implementation issues a USB
request, then blocks for it to complete, then returns to user space.
There's no pipelining of requests.

Eric




reply via email to

[Prev in Thread] Current Thread [Next in Thread]