Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 27 Mar 2009 11:27:40 -0700
From:      Andrew Thompson <thompsa@FreeBSD.org>
To:        usb <usb@freebsd.org>
Cc:        current@freebsd.org
Subject:   Proposed USB data buffer changes
Message-ID:  <20090327182740.GB26662@citylink.fud.org.nz>

next in thread | raw e-mail | index | archive | help
Hi,


I want the USB peripheral driver API to be solid before 8.0 so things dont bite
us down the line. I have discussed this privately with Hans already and want to
put it out for public consumption.


With the new USB code the buffer management has been merged into the
xfer structure and this dictates the layout of the usb drivers and how
locking is performed.

This uses a state machine (my attempt to show below)

 |-< |-<     XFER      <-| <-|
 |   |                   |   |
--------- callback_fn ---------
 |   |                   |   |
 |   -> SETUP (copyin) >-|   |
 |                           |
 ->   COMPLETE (copyout)   >-|

It can take an external buffer instead of the copyin/out but it doesnt really
simplify things at all.

The problems I see with this approach are

 1. It is in contrast to other major operating systems, making porting
    drivers harder. Windows, Linux and oldUSB all use a URB style of data
    handling. 

 2. It greatly complicates locking as the xfer lock can not be dropped
    until the xfer is resubmitted. This requirement to hold the lock
    creates a big problem for get/put of data to another layer (eg TTY),
    to avoid lock order reversals the drivers are generally written to
    share the lock with the lower/upper layer (eg TTY).

 3. In the general case data can not be directly queued on the xfer (must be
    "picked" up by the state machine callback). This limits the options for
    designing a driver and may require the driver to implement a queue.

I think its vital that we separate out the data buffers from the xfer
(its actually a pipe in usb speak). It should draw from the Linux API which is
simple and I believe works quite well. The data buffer is represented as a usb
URB which is allocated either at attach or on the fly and then queued on the
xfer (pipe) for processing. An arbitrary number of URB buffers can be on the
queue.

As the buffer would only have a single reference it would not need explicit
locking, the callback would not need the xfer lock to be held at all and this
would make it _much_ easier to handoff the data without LOR.

This reduction in locking means that the driver and the xfer do not need to
share a lock either, something that is mandatory now. The xfer can have a
private lock for enqueue/start/stop.

Example functions could be,

 usb_alloc_urb - Creates a URB representing data and housekeeping, the data
                 section can be allocated or passed in from say a mbuf.
		 This can also perform the DMA foo.

 usb_submit_urb - Queues the URB on the usb pipe.

I dont think this would take much work. The xfer callbacks would be changed to
take a URB and a few changes to queuing. It was mentioned the reason for this
approach was to preallocate and do DMA setup on attach but this can still
easily be done with the above. 

Comments?


cheers,
Andrew



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20090327182740.GB26662>