As best case, a host controller should support U0 to U1 switching for the devices connected below any tier of hub level supported by usb specification. Therefore xhci_check_default_tier_policy always returns success. A host should be able to issue LGO_Ux after the timeout calculated as per definition of system exit latency defined in C.1.5.2. Therefore xhci_calculate_default_ux_timeout returns ux_params.sel as the default implementation. Use default calculation in absence of any vendor specific limitations. Signed-off-by: Pratyush Anand <pratyush.anand@xxxxxx> --- drivers/usb/host/xhci.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 6cc58fe..930c01f 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -4140,6 +4140,53 @@ static u16 xhci_get_timeout_no_hub_lpm(struct usb_device *udev, return USB3_LPM_DISABLED; } +/* Returns the default hub-encoded U1 timeout value. + */ +static u16 xhci_calculate_default_u1_timeout(struct usb_device *udev, + struct usb_endpoint_descriptor *desc) +{ + unsigned long long timeout_ns; + + timeout_ns = udev->u1_params.sel; + + /* The U1 timeout is encoded in 1us intervals. */ + timeout_ns = DIV_ROUND_UP_ULL(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 default hub-encoded U2 timeout value. + */ +static u16 xhci_calculate_default_u2_timeout(struct usb_device *udev, + struct usb_endpoint_descriptor *desc) +{ + unsigned long long timeout_ns; + + timeout_ns = udev->u2_params.sel; + + /* The U2 timeout is encoded in 256us intervals */ + timeout_ns = DIV_ROUND_UP_ULL(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); +} + + /* 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 @@ -4241,9 +4288,13 @@ static u16 xhci_call_host_update_timeout_for_endpoint(struct xhci_hcd *xhci, if (state == USB3_LPM_U1) { if (xhci->quirks & XHCI_INTEL_HOST) return xhci_calculate_intel_u1_timeout(udev, desc); + else + return xhci_calculate_default_u1_timeout(udev, desc); } else { if (xhci->quirks & XHCI_INTEL_HOST) return xhci_calculate_intel_u2_timeout(udev, desc); + else + return xhci_calculate_default_u2_timeout(udev, desc); } return USB3_LPM_DISABLED; @@ -4291,6 +4342,14 @@ static int xhci_update_timeout_for_interface(struct xhci_hcd *xhci, return 0; } +static int xhci_check_default_tier_policy(struct usb_device *udev, + enum usb3_link_state state) +{ + /* Keeep Ux enabled for all devices */ + + return 0; +} + static int xhci_check_intel_tier_policy(struct usb_device *udev, enum usb3_link_state state) { @@ -4321,6 +4380,8 @@ static int xhci_check_tier_policy(struct xhci_hcd *xhci, { if (xhci->quirks & XHCI_INTEL_HOST) return xhci_check_intel_tier_policy(udev, state); + else + return xhci_check_default_tier_policy(udev, state); return -EINVAL; } -- 1.8.1.2 -- 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