Skip to content

Commit

Permalink
xHCI/USB: Make xHCI driver have a BOS descriptor.
Browse files Browse the repository at this point in the history
To add USB 3.0 link power management (LPM), we need to know what the U1
and U2 exit latencies are for the xHCI host controller.  External USB 3.0
hubs report these values through the SuperSpeed Capabilities descriptor in
the BOS descriptor.  Make the USB 3.0 roothub for the xHCI host behave
like an external hub and return the BOS descriptors.

The U1 and U2 exit latencies will vary across each host controller, so we
need to dynamically fill those values in by reading the exit latencies out
of the xHC registers.  Make the roothub code in the USB core handle
hub_control() returning the length of the data copied.

Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Acked-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
  • Loading branch information
Sarah Sharp authored and Greg Kroah-Hartman committed Oct 18, 2011
1 parent fa3ae0c commit 48e8236
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 2 deletions.
18 changes: 16 additions & 2 deletions drivers/usb/core/hcd.c
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,11 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
struct usb_ctrlrequest *cmd;
u16 typeReq, wValue, wIndex, wLength;
u8 *ubuf = urb->transfer_buffer;
u8 tbuf [sizeof (struct usb_hub_descriptor)]
/*
* tbuf should be as big as the BOS descriptor and
* the USB hub descriptor.
*/
u8 tbuf[USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE]
__attribute__((aligned(4)));
const u8 *bufp = tbuf;
unsigned len = 0;
Expand Down Expand Up @@ -562,6 +566,8 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
else /* unsupported IDs --> "protocol stall" */
goto error;
break;
case USB_DT_BOS << 8:
goto nongeneric;
default:
goto error;
}
Expand Down Expand Up @@ -596,6 +602,7 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
/* CLASS REQUESTS (and errors) */

default:
nongeneric:
/* non-generic request */
switch (typeReq) {
case GetHubStatus:
Expand All @@ -605,6 +612,9 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
case GetHubDescriptor:
len = sizeof (struct usb_hub_descriptor);
break;
case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
/* len is returned by hub_control */
break;
}
status = hcd->driver->hub_control (hcd,
typeReq, wValue, wIndex,
Expand All @@ -615,7 +625,7 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
status = -EPIPE;
}

if (status) {
if (status < 0) {
len = 0;
if (status != -EPIPE) {
dev_dbg (hcd->self.controller,
Expand All @@ -624,6 +634,10 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
typeReq, wValue, wIndex,
wLength, status);
}
} else if (status > 0) {
/* hub_control may return the length of data copied. */
len = status;
status = 0;
}
if (len) {
if (urb->transfer_buffer_length < len)
Expand Down
34 changes: 34 additions & 0 deletions drivers/usb/host/xhci-hub.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,25 @@
#define PORT_RWC_BITS (PORT_CSC | PORT_PEC | PORT_WRC | PORT_OCC | \
PORT_RC | PORT_PLC | PORT_PE)

/* usb 1.1 root hub device descriptor */
static u8 usb_bos_descriptor [] = {
USB_DT_BOS_SIZE, /* __u8 bLength, 5 bytes */
USB_DT_BOS, /* __u8 bDescriptorType */
0x0F, 0x00, /* __le16 wTotalLength, 15 bytes */
0x1, /* __u8 bNumDeviceCaps */
/* First device capability */
USB_DT_USB_SS_CAP_SIZE, /* __u8 bLength, 10 bytes */
USB_DT_DEVICE_CAPABILITY, /* Device Capability */
USB_SS_CAP_TYPE, /* bDevCapabilityType, SUPERSPEED_USB */
0x00, /* bmAttributes, LTM off by default */
USB_5GBPS_OPERATION, 0x00, /* wSpeedsSupported, 5Gbps only */
0x03, /* bFunctionalitySupport,
USB 3.0 speed only */
0x00, /* bU1DevExitLat, set later. */
0x00, 0x00 /* __le16 bU2DevExitLat, set later. */
};


static void xhci_common_hub_descriptor(struct xhci_hcd *xhci,
struct usb_hub_descriptor *desc, int ports)
{
Expand Down Expand Up @@ -455,6 +474,21 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
xhci_hub_descriptor(hcd, xhci,
(struct usb_hub_descriptor *) buf);
break;
case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
if ((wValue & 0xff00) != (USB_DT_BOS << 8))
goto error;

if (hcd->speed != HCD_USB3)
goto error;

memcpy(buf, &usb_bos_descriptor,
USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE);
temp = xhci_readl(xhci, &xhci->cap_regs->hcs_params3);
buf[12] = HCS_U1_LATENCY(temp);
put_unaligned_le16(HCS_U2_LATENCY(temp), &buf[13]);

spin_unlock_irqrestore(&xhci->lock, flags);
return USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE;
case GetPortStatus:
if (!wIndex || wIndex > max_ports)
goto error;
Expand Down

0 comments on commit 48e8236

Please sign in to comment.