Commit 6b403b02 authored by Sarah Sharp's avatar Sarah Sharp Committed by Greg Kroah-Hartman

USB: Add SuperSpeed to the list of USB device speeds.

Modify the USB core to handle the new USB 3.0 speed, "SuperSpeed".  This
is 5.0 Gbps (wire speed).  There are probably more places that check for
speed that I've missed.

SuperSpeed devices have a 512 byte endpoint 0 max packet size.  This shows
up as a bMaxPacketSize0 set to 0x09 (see table 9-8 of the USB 3.0 bus
spec).

xHCI spec says that the xHC can handle intervals up to 2^15 microframes.  That
might change when real silicon becomes available.

Add FIXME note for SuperSpeed isochronous endpoints.  They can transmit up
to 16 packets in one "burst" before they wait for an acknowledgment of the
packets.  They can do up to 3 bursts per microframe (determined by the
mult value in the endpoint companion descriptor).  The xHCI driver doesn't
have support for isoc yet, so fix this later.
Signed-off-by: default avatarSarah Sharp <sarah.a.sharp@linux.intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 7f84eef0
...@@ -92,6 +92,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, ...@@ -92,6 +92,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
if (usb_endpoint_xfer_int(d)) { if (usb_endpoint_xfer_int(d)) {
i = 1; i = 1;
switch (to_usb_device(ddev)->speed) { switch (to_usb_device(ddev)->speed) {
case USB_SPEED_SUPER:
case USB_SPEED_HIGH: case USB_SPEED_HIGH:
/* Many device manufacturers are using full-speed /* Many device manufacturers are using full-speed
* bInterval values in high-speed interrupt endpoint * bInterval values in high-speed interrupt endpoint
......
...@@ -1870,8 +1870,20 @@ int usb_add_hcd(struct usb_hcd *hcd, ...@@ -1870,8 +1870,20 @@ int usb_add_hcd(struct usb_hcd *hcd,
retval = -ENOMEM; retval = -ENOMEM;
goto err_allocate_root_hub; goto err_allocate_root_hub;
} }
rhdev->speed = (hcd->driver->flags & HCD_USB2) ? USB_SPEED_HIGH :
USB_SPEED_FULL; switch (hcd->driver->flags & HCD_MASK) {
case HCD_USB11:
rhdev->speed = USB_SPEED_FULL;
break;
case HCD_USB2:
rhdev->speed = USB_SPEED_HIGH;
break;
case HCD_USB3:
rhdev->speed = USB_SPEED_SUPER;
break;
default:
goto err_allocate_root_hub;
}
hcd->self.root_hub = rhdev; hcd->self.root_hub = rhdev;
/* wakeup flag init defaults to "everything works" for root hubs, /* wakeup flag init defaults to "everything works" for root hubs,
......
...@@ -174,6 +174,7 @@ struct hc_driver { ...@@ -174,6 +174,7 @@ struct hc_driver {
#define HCD_USB11 0x0010 /* USB 1.1 */ #define HCD_USB11 0x0010 /* USB 1.1 */
#define HCD_USB2 0x0020 /* USB 2.0 */ #define HCD_USB2 0x0020 /* USB 2.0 */
#define HCD_USB3 0x0040 /* USB 3.0 */ #define HCD_USB3 0x0040 /* USB 3.0 */
#define HCD_MASK 0x0070
/* called to init HCD and root hub */ /* called to init HCD and root hub */
int (*reset) (struct usb_hcd *hcd); int (*reset) (struct usb_hcd *hcd);
......
...@@ -2471,6 +2471,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, ...@@ -2471,6 +2471,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]. * reported as 0xff in the device descriptor). WUSB1.0[4.8.1].
*/ */
switch (udev->speed) { switch (udev->speed) {
case USB_SPEED_SUPER:
case USB_SPEED_VARIABLE: /* fixed at 512 */ case USB_SPEED_VARIABLE: /* fixed at 512 */
udev->ep0.desc.wMaxPacketSize = cpu_to_le16(512); udev->ep0.desc.wMaxPacketSize = cpu_to_le16(512);
break; break;
...@@ -2496,6 +2497,9 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, ...@@ -2496,6 +2497,9 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
case USB_SPEED_LOW: speed = "low"; break; case USB_SPEED_LOW: speed = "low"; break;
case USB_SPEED_FULL: speed = "full"; break; case USB_SPEED_FULL: speed = "full"; break;
case USB_SPEED_HIGH: speed = "high"; break; case USB_SPEED_HIGH: speed = "high"; break;
case USB_SPEED_SUPER:
speed = "super";
break;
case USB_SPEED_VARIABLE: case USB_SPEED_VARIABLE:
speed = "variable"; speed = "variable";
type = "Wireless "; type = "Wireless ";
...@@ -2634,8 +2638,11 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, ...@@ -2634,8 +2638,11 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
if (retval) if (retval)
goto fail; goto fail;
i = udev->descriptor.bMaxPacketSize0 == 0xff? /* wusb device? */ if (udev->descriptor.bMaxPacketSize0 == 0xff ||
512 : udev->descriptor.bMaxPacketSize0; udev->speed == USB_SPEED_SUPER)
i = 512;
else
i = udev->descriptor.bMaxPacketSize0;
if (le16_to_cpu(udev->ep0.desc.wMaxPacketSize) != i) { if (le16_to_cpu(udev->ep0.desc.wMaxPacketSize) != i) {
if (udev->speed != USB_SPEED_FULL || if (udev->speed != USB_SPEED_FULL ||
!(i == 8 || i == 16 || i == 32 || i == 64)) { !(i == 8 || i == 16 || i == 32 || i == 64)) {
......
...@@ -351,6 +351,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) ...@@ -351,6 +351,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
if (xfertype == USB_ENDPOINT_XFER_ISOC) { if (xfertype == USB_ENDPOINT_XFER_ISOC) {
int n, len; int n, len;
/* FIXME SuperSpeed isoc endpoints have up to 16 bursts */
/* "high bandwidth" mode, 1-3 packets/uframe? */ /* "high bandwidth" mode, 1-3 packets/uframe? */
if (dev->speed == USB_SPEED_HIGH) { if (dev->speed == USB_SPEED_HIGH) {
int mult = 1 + ((max >> 11) & 0x03); int mult = 1 + ((max >> 11) & 0x03);
...@@ -426,6 +427,11 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) ...@@ -426,6 +427,11 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
return -EINVAL; return -EINVAL;
/* too big? */ /* too big? */
switch (dev->speed) { switch (dev->speed) {
case USB_SPEED_SUPER: /* units are 125us */
/* Handle up to 2^(16-1) microframes */
if (urb->interval > (1 << 15))
return -EINVAL;
max = 1 << 15;
case USB_SPEED_HIGH: /* units are microframes */ case USB_SPEED_HIGH: /* units are microframes */
/* NOTE usb handles 2^15 */ /* NOTE usb handles 2^15 */
if (urb->interval > (1024 * 8)) if (urb->interval > (1024 * 8))
......
...@@ -752,6 +752,7 @@ enum usb_device_speed { ...@@ -752,6 +752,7 @@ enum usb_device_speed {
USB_SPEED_LOW, USB_SPEED_FULL, /* usb 1.1 */ USB_SPEED_LOW, USB_SPEED_FULL, /* usb 1.1 */
USB_SPEED_HIGH, /* usb 2.0 */ USB_SPEED_HIGH, /* usb 2.0 */
USB_SPEED_VARIABLE, /* wireless (usb 2.5) */ USB_SPEED_VARIABLE, /* wireless (usb 2.5) */
USB_SPEED_SUPER, /* usb 3.0 */
}; };
enum usb_device_state { enum usb_device_state {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment