usb: define USB_SPEED_SUPER_PLUS speed for SuperSpeedPlus USB3.1 devices
authorMathias Nyman <mathias.nyman@linux.intel.com>
Thu, 10 Dec 2015 07:59:25 +0000 (09:59 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 7 Sep 2016 06:32:39 +0000 (08:32 +0200)
commit 8a1b2725a60d3267135c15e80984b4406054f650 upstream.

Add a new USB_SPEED_SUPER_PLUS device speed, and make sure usb core can
handle the new speed.
In most cases the behaviour is the same as with USB_SPEED_SUPER SuperSpeed
devices. In a few places we add a "Plus" string to inform the user of the
new speed.

Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/common/common.c
drivers/usb/core/config.c
drivers/usb/core/devices.c
drivers/usb/core/hcd-pci.c
drivers/usb/core/hcd.c
drivers/usb/core/hub.c
drivers/usb/core/urb.c
drivers/usb/core/usb.h
include/uapi/linux/usb/ch9.h

index 673d53038ed221c3b2e0c7c0d78d9309d307420a..a00bfb93acc36d56cdbc0487a56218a5a8ee45e6 100644 (file)
@@ -50,6 +50,7 @@ static const char *const speed_names[] = {
        [USB_SPEED_HIGH] = "high-speed",
        [USB_SPEED_WIRELESS] = "wireless",
        [USB_SPEED_SUPER] = "super-speed",
+       [USB_SPEED_SUPER_PLUS] = "super-speed-plus",
 };
 
 const char *usb_speed_string(enum usb_device_speed speed)
index 5050760f5e17cf3872952ae5fa6a40d01aab394b..bbcf4009f99eaa5c0d6119e3c7016ca640cf7da2 100644 (file)
@@ -191,6 +191,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
        if (usb_endpoint_xfer_int(d)) {
                i = 1;
                switch (to_usb_device(ddev)->speed) {
+               case USB_SPEED_SUPER_PLUS:
                case USB_SPEED_SUPER:
                case USB_SPEED_HIGH:
                        /* Many device manufacturers are using full-speed
@@ -274,7 +275,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
        }
 
        /* Parse a possible SuperSpeed endpoint companion descriptor */
-       if (to_usb_device(ddev)->speed == USB_SPEED_SUPER)
+       if (to_usb_device(ddev)->speed >= USB_SPEED_SUPER)
                usb_parse_ss_endpoint_companion(ddev, cfgno,
                                inum, asnum, endpoint, buffer, size);
 
index 2a3bbdf7eb9407568c71c0896615d30fb48ea9cb..332ed277a06ceb866dffb8e784ec06d92348dc85 100644 (file)
@@ -221,7 +221,7 @@ static char *usb_dump_endpoint_descriptor(int speed, char *start, char *end,
                break;
        case USB_ENDPOINT_XFER_INT:
                type = "Int.";
-               if (speed == USB_SPEED_HIGH || speed == USB_SPEED_SUPER)
+               if (speed == USB_SPEED_HIGH || speed >= USB_SPEED_SUPER)
                        interval = 1 << (desc->bInterval - 1);
                else
                        interval = desc->bInterval;
@@ -230,7 +230,7 @@ static char *usb_dump_endpoint_descriptor(int speed, char *start, char *end,
                return start;
        }
        interval *= (speed == USB_SPEED_HIGH ||
-                    speed == USB_SPEED_SUPER) ? 125 : 1000;
+                    speed >= USB_SPEED_SUPER) ? 125 : 1000;
        if (interval % 1000)
                unit = 'u';
        else {
@@ -322,7 +322,7 @@ static char *usb_dump_config_descriptor(char *start, char *end,
 
        if (start > end)
                return start;
-       if (speed == USB_SPEED_SUPER)
+       if (speed >= USB_SPEED_SUPER)
                mul = 8;
        else
                mul = 2;
@@ -534,6 +534,8 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes,
                speed = "480"; break;
        case USB_SPEED_SUPER:
                speed = "5000"; break;
+       case USB_SPEED_SUPER_PLUS:
+               speed = "10000"; break;
        default:
                speed = "??";
        }
@@ -553,7 +555,7 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes,
 
                /* super/high speed reserves 80%, full/low reserves 90% */
                if (usbdev->speed == USB_SPEED_HIGH ||
-                   usbdev->speed == USB_SPEED_SUPER)
+                   usbdev->speed >= USB_SPEED_SUPER)
                        max = 800;
                else
                        max = FRAME_TIME_MAX_USECS_ALLOC;
index b8b580e5ae6e369f2bf1033e3dc054817b51f125..40378487e023c4e41e4b5de99de4feb343548deb 100644 (file)
@@ -206,7 +206,7 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
         * The xHCI driver has its own irq management
         * make sure irq setup is not touched for xhci in generic hcd code
         */
-       if ((driver->flags & HCD_MASK) != HCD_USB3) {
+       if ((driver->flags & HCD_MASK) < HCD_USB3) {
                if (!dev->irq) {
                        dev_err(&dev->dev,
                        "Found HC with no IRQ. Check BIOS/PCI %s setup!\n",
index 1c102d60cd9f4afe861a6933e9495662d74de4f5..f44ce09367bc185a514b12fd32c5a604a36e07cc 100644 (file)
@@ -1078,7 +1078,7 @@ static int register_root_hub(struct usb_hcd *hcd)
                retval = usb_get_bos_descriptor(usb_dev);
                if (!retval) {
                        usb_dev->lpm_capable = usb_device_supports_lpm(usb_dev);
-               } else if (usb_dev->speed == USB_SPEED_SUPER) {
+               } else if (usb_dev->speed >= USB_SPEED_SUPER) {
                        mutex_unlock(&usb_bus_list_lock);
                        dev_dbg(parent_dev, "can't read %s bos descriptor %d\n",
                                        dev_name(&usb_dev->dev), retval);
@@ -2112,7 +2112,7 @@ int usb_alloc_streams(struct usb_interface *interface,
        hcd = bus_to_hcd(dev->bus);
        if (!hcd->driver->alloc_streams || !hcd->driver->free_streams)
                return -EINVAL;
-       if (dev->speed != USB_SPEED_SUPER)
+       if (dev->speed < USB_SPEED_SUPER)
                return -EINVAL;
        if (dev->state < USB_STATE_CONFIGURED)
                return -ENODEV;
@@ -2160,7 +2160,7 @@ int usb_free_streams(struct usb_interface *interface,
 
        dev = interface_to_usbdev(interface);
        hcd = bus_to_hcd(dev->bus);
-       if (dev->speed != USB_SPEED_SUPER)
+       if (dev->speed < USB_SPEED_SUPER)
                return -EINVAL;
 
        /* Double-free is not allowed */
index 84df093639acb18c37e7b8b45bb878d0aca2bf5a..34762c6e61501deba8265a0300eace1a00af7317 100644 (file)
@@ -298,7 +298,7 @@ static void usb_set_lpm_parameters(struct usb_device *udev)
        unsigned int hub_u1_del;
        unsigned int hub_u2_del;
 
-       if (!udev->lpm_capable || udev->speed != USB_SPEED_SUPER)
+       if (!udev->lpm_capable || udev->speed < USB_SPEED_SUPER)
                return;
 
        hub = usb_hub_to_struct_hub(udev->parent);
@@ -2645,7 +2645,7 @@ static unsigned hub_is_wusb(struct usb_hub *hub)
  */
 static bool use_new_scheme(struct usb_device *udev, int retry)
 {
-       if (udev->speed == USB_SPEED_SUPER)
+       if (udev->speed >= USB_SPEED_SUPER)
                return false;
 
        return USE_NEW_SCHEME(retry);
@@ -3985,7 +3985,7 @@ int usb_disable_lpm(struct usb_device *udev)
        struct usb_hcd *hcd;
 
        if (!udev || !udev->parent ||
-                       udev->speed != USB_SPEED_SUPER ||
+                       udev->speed < USB_SPEED_SUPER ||
                        !udev->lpm_capable ||
                        udev->state < USB_STATE_DEFAULT)
                return 0;
@@ -4042,7 +4042,7 @@ void usb_enable_lpm(struct usb_device *udev)
        struct usb_hcd *hcd;
 
        if (!udev || !udev->parent ||
-                       udev->speed != USB_SPEED_SUPER ||
+                       udev->speed < USB_SPEED_SUPER ||
                        !udev->lpm_capable ||
                        udev->state < USB_STATE_DEFAULT)
                return;
@@ -4308,7 +4308,9 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
 
        retval = -ENODEV;
 
-       if (oldspeed != USB_SPEED_UNKNOWN && oldspeed != udev->speed) {
+       /* Don't allow speed changes at reset, except usb 3.0 to faster */
+       if (oldspeed != USB_SPEED_UNKNOWN && oldspeed != udev->speed &&
+           !(oldspeed == USB_SPEED_SUPER && udev->speed > oldspeed)) {
                dev_dbg(&udev->dev, "device reset changed speed!\n");
                goto fail;
        }
@@ -4320,6 +4322,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
         * reported as 0xff in the device descriptor). WUSB1.0[4.8.1].
         */
        switch (udev->speed) {
+       case USB_SPEED_SUPER_PLUS:
        case USB_SPEED_SUPER:
        case USB_SPEED_WIRELESS:        /* fixed at 512 */
                udev->ep0.desc.wMaxPacketSize = cpu_to_le16(512);
@@ -4346,7 +4349,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
        else
                speed = usb_speed_string(udev->speed);
 
-       if (udev->speed != USB_SPEED_SUPER)
+       if (udev->speed < USB_SPEED_SUPER)
                dev_info(&udev->dev,
                                "%s %s USB device number %d using %s\n",
                                (udev->config) ? "reset" : "new", speed,
@@ -4476,11 +4479,12 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
                                                        devnum, retval);
                                goto fail;
                        }
-                       if (udev->speed == USB_SPEED_SUPER) {
+                       if (udev->speed >= USB_SPEED_SUPER) {
                                devnum = udev->devnum;
                                dev_info(&udev->dev,
-                                               "%s SuperSpeed USB device number %d using %s\n",
+                                               "%s SuperSpeed%s USB device number %d using %s\n",
                                                (udev->config) ? "reset" : "new",
+                                        (udev->speed == USB_SPEED_SUPER_PLUS) ? "Plus" : "",
                                                devnum, udev->bus->controller->driver->name);
                        }
 
@@ -4519,7 +4523,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
         * got from those devices show they aren't superspeed devices. Warm
         * reset the port attached by the devices can fix them.
         */
-       if ((udev->speed == USB_SPEED_SUPER) &&
+       if ((udev->speed >= USB_SPEED_SUPER) &&
                        (le16_to_cpu(udev->descriptor.bcdUSB) < 0x0300)) {
                dev_err(&udev->dev, "got a wrong device descriptor, "
                                "warm reset device\n");
@@ -4530,7 +4534,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
        }
 
        if (udev->descriptor.bMaxPacketSize0 == 0xff ||
-                       udev->speed == USB_SPEED_SUPER)
+                       udev->speed >= USB_SPEED_SUPER)
                i = 512;
        else
                i = udev->descriptor.bMaxPacketSize0;
@@ -4740,7 +4744,7 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus,
                udev->level = hdev->level + 1;
                udev->wusb = hub_is_wusb(hub);
 
-               /* Only USB 3.0 devices are connected to SuperSpeed hubs. */
+               /* Devices connected to SuperSpeed hubs are USB 3.0 or later */
                if (hub_is_superspeed(hub->hdev))
                        udev->speed = USB_SPEED_SUPER;
                else
index 3d274778caaf8f9f473aacc89b1be6c20de19ab2..c601e25b609fb58e6842c18e62e5c484c98182ae 100644 (file)
@@ -401,7 +401,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
                /* SuperSpeed isoc endpoints have up to 16 bursts of up to
                 * 3 packets each
                 */
-               if (dev->speed == USB_SPEED_SUPER) {
+               if (dev->speed >= USB_SPEED_SUPER) {
                        int     burst = 1 + ep->ss_ep_comp.bMaxBurst;
                        int     mult = USB_SS_MULT(ep->ss_ep_comp.bmAttributes);
                        max *= burst;
@@ -499,6 +499,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
                }
                /* too big? */
                switch (dev->speed) {
+               case USB_SPEED_SUPER_PLUS:
                case USB_SPEED_SUPER:   /* units are 125us */
                        /* Handle up to 2^(16-1) microframes */
                        if (urb->interval > (1 << 15))
index 05b5e17abf92fc158530d13f3e2ae8edf9923c5a..53318126ed91b24603934030702a0dae178cc5d1 100644 (file)
@@ -45,7 +45,7 @@ static inline unsigned usb_get_max_power(struct usb_device *udev,
                struct usb_host_config *c)
 {
        /* SuperSpeed power is in 8 mA units; others are in 2 mA units */
-       unsigned mul = (udev->speed == USB_SPEED_SUPER ? 8 : 2);
+       unsigned mul = (udev->speed >= USB_SPEED_SUPER ? 8 : 2);
 
        return c->desc.bMaxPower * mul;
 }
index 4338eb7b09b3ad705f766fa1c3e1f8a100ae049e..779a62aafafe6a2d19b3c25bd9ddbef7617b0f7f 100644 (file)
@@ -954,6 +954,7 @@ enum usb_device_speed {
        USB_SPEED_HIGH,                         /* usb 2.0 */
        USB_SPEED_WIRELESS,                     /* wireless (usb 2.5) */
        USB_SPEED_SUPER,                        /* usb 3.0 */
+       USB_SPEED_SUPER_PLUS,                   /* usb 3.1 */
 };