USB: make urb scatter-gather support more generic
authorDavid Vrabel <david.vrabel@csr.com>
Mon, 24 Aug 2009 13:44:30 +0000 (14:44 +0100)
committerGreg Kroah-Hartman <gregkh@suse.de>
Fri, 11 Dec 2009 19:55:14 +0000 (11:55 -0800)
The WHCI HCD will also support urbs with scatter-gather lists.  Add a
usb_bus field to indicated how many sg list elements are supported by
the HCD.  Use this to decide whether to pass the scatter-list to the HCD
or not.

Make the usb-storage driver use this new field.

Signed-off-by: David Vrabel <david.vrabel@csr.com>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Cc: Matthew Dharm <mdharm-usb@one-eyed-alien.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/usb/core/message.c
drivers/usb/host/xhci-pci.c
drivers/usb/storage/usb.c
include/linux/usb.h

index e80f1af..8d874ca 100644 (file)
@@ -393,13 +393,7 @@ int usb_sg_init(struct usb_sg_request *io, struct usb_device *dev,
        if (io->entries <= 0)
                return io->entries;
 
-       /* If we're running on an xHCI host controller, queue the whole scatter
-        * gather list with one call to urb_enqueue().  This is only for bulk,
-        * as that endpoint type does not care how the data gets broken up
-        * across frames.
-        */
-       if (usb_pipebulk(pipe) &&
-                       bus_to_hcd(dev->bus)->driver->flags & HCD_USB3) {
+       if (dev->bus->sg_tablesize > 0) {
                io->urbs = kmalloc(sizeof *io->urbs, mem_flags);
                use_sg = true;
        } else {
index 06595ec..e097008 100644 (file)
@@ -54,6 +54,8 @@ static int xhci_pci_setup(struct usb_hcd *hcd)
        struct pci_dev          *pdev = to_pci_dev(hcd->self.controller);
        int                     retval;
 
+       hcd->self.sg_tablesize = TRBS_PER_SEGMENT - 1;
+
        xhci->cap_regs = hcd->regs;
        xhci->op_regs = hcd->regs +
                HC_LENGTH(xhci_readl(xhci, &xhci->cap_regs->hc_capbase));
index 01e43a1..1599d86 100644 (file)
@@ -843,6 +843,15 @@ static int usb_stor_scan_thread(void * __us)
        complete_and_exit(&us->scanning_done, 0);
 }
 
+static unsigned int usb_stor_sg_tablesize(struct usb_interface *intf)
+{
+       struct usb_device *usb_dev = interface_to_usbdev(intf);
+
+       if (usb_dev->bus->sg_tablesize) {
+               return usb_dev->bus->sg_tablesize;
+       }
+       return SG_ALL;
+}
 
 /* First part of general USB mass-storage probing */
 int usb_stor_probe1(struct us_data **pus,
@@ -871,6 +880,7 @@ int usb_stor_probe1(struct us_data **pus,
         * Allow 16-byte CDBs and thus > 2TB
         */
        host->max_cmd_len = 16;
+       host->sg_tablesize = usb_stor_sg_tablesize(intf);
        *pus = us = host_to_us(host);
        memset(us, 0, sizeof(struct us_data));
        mutex_init(&(us->dev_mutex));
index a34fa89..6e91ee4 100644 (file)
@@ -331,6 +331,7 @@ struct usb_bus {
        u8 otg_port;                    /* 0, or number of OTG/HNP port */
        unsigned is_b_host:1;           /* true during some HNP roleswitches */
        unsigned b_hnp_enable:1;        /* OTG: did A-Host enable HNP? */
+       unsigned sg_tablesize;          /* 0 or largest number of sg list entries */
 
        int devnum_next;                /* Next open device number in
                                         * round-robin allocation */