Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 303999
b: refs/heads/master
c: e3567d2
h: refs/heads/master
i:
  303997: 0ce5fca
  303995: 451229c
  303991: 50ee40a
  303983: 0257a0d
  303967: db07ea6
  303935: 9a32d3d
  303871: b70ed04
v: v3
  • Loading branch information
Sarah Sharp committed May 18, 2012
1 parent a92fad3 commit fb42631
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 3b3db026414bba1c8f45c49d5eeaefd48d66e1ae
refs/heads/master: e3567d2c15a7a8e2f992a5f7c7683453ca406d82
4 changes: 4 additions & 0 deletions trunk/drivers/usb/host/xhci-pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
/* AMD PLL quirk */
if (pdev->vendor == PCI_VENDOR_ID_AMD && usb_amd_find_chipset_info())
xhci->quirks |= XHCI_AMD_PLL_FIX;
if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
xhci->quirks |= XHCI_LPM_SUPPORT;
xhci->quirks |= XHCI_INTEL_HOST;
}
if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
pdev->device == PCI_DEVICE_ID_INTEL_PANTHERPOINT_XHCI) {
xhci->quirks |= XHCI_SPURIOUS_SUCCESS;
Expand Down
133 changes: 133 additions & 0 deletions trunk/drivers/usb/host/xhci.c
Original file line number Diff line number Diff line change
Expand Up @@ -3839,6 +3839,13 @@ int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,

/*---------------------- USB 3.0 Link PM functions ------------------------*/

/* Service interval in nanoseconds = 2^(bInterval - 1) * 125us * 1000ns / 1us */
static unsigned long long xhci_service_interval_to_ns(
struct usb_endpoint_descriptor *desc)
{
return (1 << (desc->bInterval - 1)) * 125 * 1000;
}

static u16 xhci_get_timeout_no_hub_lpm(struct usb_device *udev,
enum usb3_link_state state)
{
Expand Down Expand Up @@ -3881,12 +3888,112 @@ static u16 xhci_get_timeout_no_hub_lpm(struct usb_device *udev,
return USB3_LPM_DISABLED;
}

/* Returns the hub-encoded U1 timeout value.
* The U1 timeout should be the maximum of the following values:
* - For control endpoints, U1 system exit latency (SEL) * 3
* - For bulk endpoints, U1 SEL * 5
* - For interrupt endpoints:
* - Notification EPs, U1 SEL * 3
* - Periodic EPs, max(105% of bInterval, U1 SEL * 2)
* - For isochronous endpoints, max(105% of bInterval, U1 SEL * 2)
*/
static u16 xhci_calculate_intel_u1_timeout(struct usb_device *udev,
struct usb_endpoint_descriptor *desc)
{
unsigned long long timeout_ns;
int ep_type;
int intr_type;

ep_type = usb_endpoint_type(desc);
switch (ep_type) {
case USB_ENDPOINT_XFER_CONTROL:
timeout_ns = udev->u1_params.sel * 3;
break;
case USB_ENDPOINT_XFER_BULK:
timeout_ns = udev->u1_params.sel * 5;
break;
case USB_ENDPOINT_XFER_INT:
intr_type = usb_endpoint_interrupt_type(desc);
if (intr_type == USB_ENDPOINT_INTR_NOTIFICATION) {
timeout_ns = udev->u1_params.sel * 3;
break;
}
/* Otherwise the calculation is the same as isoc eps */
case USB_ENDPOINT_XFER_ISOC:
timeout_ns = xhci_service_interval_to_ns(desc);
timeout_ns = DIV_ROUND_UP(timeout_ns * 105, 100);
if (timeout_ns < udev->u1_params.sel * 2)
timeout_ns = udev->u1_params.sel * 2;
break;
default:
return 0;
}

/* The U1 timeout is encoded in 1us intervals. */
timeout_ns = DIV_ROUND_UP(timeout_ns, 1000);
/* Don't return a timeout of zero, because that's USB3_LPM_DISABLED. */
if (timeout_ns == USB3_LPM_DISABLED)
timeout_ns++;

/* If the necessary timeout value is bigger than what we can set in the
* USB 3.0 hub, we have to disable hub-initiated U1.
*/
if (timeout_ns <= USB3_LPM_U1_MAX_TIMEOUT)
return timeout_ns;
dev_dbg(&udev->dev, "Hub-initiated U1 disabled "
"due to long timeout %llu ms\n", timeout_ns);
return xhci_get_timeout_no_hub_lpm(udev, USB3_LPM_U1);
}

/* Returns the hub-encoded U2 timeout value.
* The U2 timeout should be the maximum of:
* - 10 ms (to avoid the bandwidth impact on the scheduler)
* - largest bInterval of any active periodic endpoint (to avoid going
* into lower power link states between intervals).
* - the U2 Exit Latency of the device
*/
static u16 xhci_calculate_intel_u2_timeout(struct usb_device *udev,
struct usb_endpoint_descriptor *desc)
{
unsigned long long timeout_ns;
unsigned long long u2_del_ns;

timeout_ns = 10 * 1000 * 1000;

if ((usb_endpoint_xfer_int(desc) || usb_endpoint_xfer_isoc(desc)) &&
(xhci_service_interval_to_ns(desc) > timeout_ns))
timeout_ns = xhci_service_interval_to_ns(desc);

u2_del_ns = udev->bos->ss_cap->bU2DevExitLat * 1000;
if (u2_del_ns > timeout_ns)
timeout_ns = u2_del_ns;

/* The U2 timeout is encoded in 256us intervals */
timeout_ns = DIV_ROUND_UP(timeout_ns, 256 * 1000);
/* If the necessary timeout value is bigger than what we can set in the
* USB 3.0 hub, we have to disable hub-initiated U2.
*/
if (timeout_ns <= USB3_LPM_U2_MAX_TIMEOUT)
return timeout_ns;
dev_dbg(&udev->dev, "Hub-initiated U2 disabled "
"due to long timeout %llu ms\n", timeout_ns);
return xhci_get_timeout_no_hub_lpm(udev, USB3_LPM_U2);
}

static u16 xhci_call_host_update_timeout_for_endpoint(struct xhci_hcd *xhci,
struct usb_device *udev,
struct usb_endpoint_descriptor *desc,
enum usb3_link_state state,
u16 *timeout)
{
if (state == USB3_LPM_U1) {
if (xhci->quirks & XHCI_INTEL_HOST)
return xhci_calculate_intel_u1_timeout(udev, desc);
} else {
if (xhci->quirks & XHCI_INTEL_HOST)
return xhci_calculate_intel_u2_timeout(udev, desc);
}

return USB3_LPM_DISABLED;
}

Expand Down Expand Up @@ -3932,10 +4039,36 @@ static int xhci_update_timeout_for_interface(struct xhci_hcd *xhci,
return 0;
}

static int xhci_check_intel_tier_policy(struct usb_device *udev,
enum usb3_link_state state)
{
struct usb_device *parent;
unsigned int num_hubs;

if (state == USB3_LPM_U2)
return 0;

/* Don't enable U1 if the device is on a 2nd tier hub or lower. */
for (parent = udev->parent, num_hubs = 0; parent->parent;
parent = parent->parent)
num_hubs++;

if (num_hubs < 2)
return 0;

dev_dbg(&udev->dev, "Disabling U1 link state for device"
" below second-tier hub.\n");
dev_dbg(&udev->dev, "Plug device into first-tier hub "
"to decrease power consumption.\n");
return -E2BIG;
}

static int xhci_check_tier_policy(struct xhci_hcd *xhci,
struct usb_device *udev,
enum usb3_link_state state)
{
if (xhci->quirks & XHCI_INTEL_HOST)
return xhci_check_intel_tier_policy(udev, state);
return -EINVAL;
}

Expand Down
1 change: 1 addition & 0 deletions trunk/drivers/usb/host/xhci.h
Original file line number Diff line number Diff line change
Expand Up @@ -1489,6 +1489,7 @@ struct xhci_hcd {
#define XHCI_AMD_0x96_HOST (1 << 9)
#define XHCI_TRUST_TX_LENGTH (1 << 10)
#define XHCI_LPM_SUPPORT (1 << 11)
#define XHCI_INTEL_HOST (1 << 12)
unsigned int num_active_eps;
unsigned int limit_active_eps;
/* There are two roothubs to keep track of bus suspend info for */
Expand Down

0 comments on commit fb42631

Please sign in to comment.