On Fri, 2 Apr 2010, Sarah Sharp wrote: > Bulk endpoint streams were added in the USB 3.0 specification. Streams > allow a device driver to overload a bulk endpoint so that multiple > transfers can be queued at once. > > The device then decides which transfer it wants to work on first, and can > queue part of a transfer before it switches to a new stream. All this > switching is invisible to the device driver, which just gets a completion > for the URB. Drivers that use streams must be able to handle URBs > completing in a different order than they were submitted to the endpoint. > > This requires adding new API to set up xHCI data structures to support > multiple queues ("stream rings") per endpoint. Drivers will allocate a > number of stream IDs before enqueueing URBs to the bulk endpoints of the > device, and free the stream IDs in their disconnect function. See > Documentation/usb/bulk-streams.txt for details. > > The new mass storage device class, USB Attached SCSI Protocol (UASP), uses > these streams API. > > Signed-off-by: Sarah Sharp <sarah.a.sharp@xxxxxxxxxxxxxxx> > --- > drivers/usb/core/driver.c | 54 +++++++++++++++++++++++++++++++++++++++++++ > drivers/usb/core/hcd.h | 10 ++++++++ > drivers/usb/host/xhci-pci.c | 2 + > include/linux/usb.h | 10 ++++++++ > 4 files changed, 76 insertions(+), 0 deletions(-) > > diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c > index f3c2338..cc599da 100644 > --- a/drivers/usb/core/driver.c > +++ b/drivers/usb/core/driver.c > @@ -497,6 +497,60 @@ void usb_driver_release_interface(struct usb_driver *driver, > } > EXPORT_SYMBOL_GPL(usb_driver_release_interface); > > +/* Sets up a group of bulk endpoints to have num_streams stream IDs available. > + * Drivers may queue multiple transfers to different stream IDs, which may > + * complete in a different order than they were queued. > + */ > +int usb_alloc_streams(struct usb_interface *interface, > + struct usb_host_endpoint **eps, unsigned int num_eps, > + unsigned int num_streams, gfp_t mem_flags) > +{ > + struct usb_hcd *hcd; > + struct usb_device *dev; > + int i; > + > + dev = interface_to_usbdev(interface); > + hcd = bus_to_hcd(dev->bus); > + if (!hcd->driver->alloc_streams || !hcd->driver->free_streams) > + return -EINVAL; > + if (dev->speed != USB_SPEED_SUPER) > + return -EINVAL; > + > + /* Streams only apply to bulk endpoints. */ > + for (i = 0; i < num_eps; i++) > + if (!usb_endpoint_xfer_bulk(&eps[i]->desc)) > + return -EINVAL; > + > + return hcd->driver->alloc_streams(hcd, dev, eps, num_eps, > + num_streams, mem_flags); > +} > +EXPORT_SYMBOL_GPL(usb_alloc_streams); > + > +/* Reverts a group of bulk endpoints back to not using stream IDs. > + * Can fail if we are given bad arguments. > + */ > +void usb_free_streams(struct usb_interface *interface, > + struct usb_host_endpoint **eps, unsigned int num_eps, > + gfp_t mem_flags) > +{ > + struct usb_hcd *hcd; > + struct usb_device *dev; > + int i; > + > + dev = interface_to_usbdev(interface); > + hcd = bus_to_hcd(dev->bus); > + if (dev->speed != USB_SPEED_SUPER) > + return; > + > + /* Streams only apply to bulk endpoints. */ > + for (i = 0; i < num_eps; i++) > + if (!usb_endpoint_xfer_bulk(&eps[i]->desc)) > + return; > + > + hcd->driver->free_streams(hcd, dev, eps, num_eps, mem_flags); > +} > +EXPORT_SYMBOL_GPL(usb_free_streams); Don't these routines belong in hcd.c rather than driver.c? They are basically glue between the core and the HCDs, after all. Alan Stern -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html