Modified the xHCI roothub descriptor to return USB2.0 extension descriptor Best Effort Service Latency (BESL) and Deep Best Effort Service Latency (DBESL) values when set on the xHCI host. On link power management the BESL and DBESL values are used to estimate L1 exit latency for USB2.0 host and devices. Tools such as PowerTop and lsusb will use BESL and DBESL values to monitor LPM L1 exit latency. Additionally, by presenting the host controller BESL and DBESL values one could check if the BIOS or firmware is setting these values correctly. Currently the root hub device descriptor bcdUSB value is set to zero by the BIOS. Therefore to test this functionality with lsusb, I hard coded the usb2_rh_dev_descriptor (not include on patch) to: bcdUSB 0x01. Here is the result of lsusb: sudo lsusb -s 01:01 -v Binary Object Store Descriptor: bLength 5 bDescriptorType 15 wTotalLength 12 bNumDeviceCaps 1 USB 2.0 Extension Device Capability: bLength 7 bDescriptorType 16 bDevCapabilityType 2 bmAttributes 0x0000040e BESL Link Power Management (LPM) Supported BESL value 1024 us Device Status: 0x0001 Self Powered Signed-off-by: Alexandra Yates <alexandra.yates@xxxxxxxxxxxxxxx> --- drivers/usb/host/xhci-hub.c | 44 ++++++++++++++++++++++++++++++++++++++----- drivers/usb/host/xhci-mem.c | 5 ++++- drivers/usb/host/xhci.h | 1 + 3 files changed, 44 insertions(+), 6 deletions(-) diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 1d35459..431af44 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -30,7 +30,7 @@ PORT_RC | PORT_PLC | PORT_PE) /* USB 3.0 BOS descriptor and a capability descriptor, combined */ -static u8 usb_bos_descriptor [] = { +static u8 usb3_bos_descriptor[] = { USB_DT_BOS_SIZE, /* __u8 bLength, 5 bytes */ USB_DT_BOS, /* __u8 bDescriptorType */ 0x0F, 0x00, /* __le16 wTotalLength, 15 bytes */ @@ -47,6 +47,28 @@ static u8 usb_bos_descriptor [] = { 0x00, 0x00 /* __le16 bU2DevExitLat, set later. */ }; +/* USB 2.0 BOS descriptor and a capability descriptor, combined */ +static u8 usb2_bos_descriptor[] = { + USB_DT_BOS_SIZE, /* __u8 bLength, 5 bytes */ + USB_DT_BOS, /* __u8 bDescriptorType */ + 0x0c, 0x00, /* __le16 wTotalLength, 15 bytes */ + 0x1, /* __u8 bNumDeviceCaps */ + /* First device capability */ + USB_DT_USB_EXT_CAP_SIZE, /* 7 bits USB2 ext */ + USB_DT_DEVICE_CAPABILITY, /* Device Capability */ + USB_CAP_TYPE_EXT, /* DevCapability Type, USB2.0 ext */ + 0x00, /* bmAttributes first byte: bit1:LPM + Supported, bit2: BESL supported, + bit3:valid baseline BESL, bit4: + valid Deep BESL, bits5-7 */ + 0x00, /* bmAttributes - second byte: + 8-11bit:BESL and 12-16bit:DBESL*/ + 0x00, /* bmAttribute - third byte: reserved, + must be zero */ + 0x00, /* bmAttribute - fourth byte: reserved, + must be zero */ +}; + static void xhci_common_hub_descriptor(struct xhci_hcd *xhci, struct usb_hub_descriptor *desc, int ports) @@ -577,12 +599,24 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, if ((wValue & 0xff00) != (USB_DT_BOS << 8)) goto error; - if (hcd->speed != HCD_USB3) + if (hcd->speed == HCD_USB3) { + /* Set the U1 and U2 exit latencies. */ + memcpy(buf, &usb3_bos_descriptor, + USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE); + } else if (hcd->speed == HCD_USB2) { + memcpy(buf, &usb2_bos_descriptor, + USB_DT_BOS_SIZE + USB_DT_USB_EXT_CAP_SIZE); + + /* Set the BESL support bit in bmAttributes first + * byte */ + if (xhci->besl) { + buf[8] |= USB_BESL_SUPPORT; + buf[8] |= USB_BESL_BASELINE_VALID; + buf[9] = xhci->besl; + } + } else goto error; - /* Set the U1 and U2 exit latencies. */ - 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]); diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index df6978a..a31933f 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -2070,7 +2070,10 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports, /* cache usb2 port capabilities */ if (major_revision < 0x03 && xhci->num_ext_caps < max_caps) - xhci->ext_caps[xhci->num_ext_caps++] = temp; + xhci->ext_caps[xhci->num_ext_caps] = temp; + + if (xhci->ext_caps[xhci->num_ext_caps++] & XHCI_BLC) + xhci->besl = XHCI_DEFAULT_BESL; /* Check the host's USB2 LPM capability */ if ((xhci->hci_version == 0x96) && (major_revision != 0x03) && diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index c338741..8591a05 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1564,6 +1564,7 @@ struct xhci_hcd { /* Compliance Mode Recovery Data */ struct timer_list comp_mode_recovery_timer; u32 port_status_u0; + u8 besl; /* Compliance Mode Timer Triggered every 2 seconds */ #define COMP_MODE_RCVRY_MSECS 2000 }; -- 1.7.9.5 -- 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