xhci: Link PM and bug fixes for 3.5.

Hi Greg,
 
 Here's the final Link Power Management patches, along with a couple of bug
 fixes that have been sitting in my queue.  I've fixed all the comments that
 Alan and Andiry had on the Link PM patches, so I think they're ready to go.
 
 Sarah Sharp
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.11 (GNU/Linux)
 
 iQIcBAABAgAGBQJPttDmAAoJEBMGWMLi1Gc5IJgP/jPNhCjHWr+YqsmcvJdlHxkE
 1TrMCScAhAk7OkAaZ+4xpFsD4G3bN5+SS4U6x3hEdhqgJIWbtDazOBctfVKezJQ1
 uywnJNW08aW6GWYCTtoDVHY/ofLjpRnSRC21RXW4zKW8U4dHp1UcoCfkLRpqbb1C
 /GYuLb03Ipl25+wDDDQAmFIs5IlEGHfE7a1r27I43MHIHvg6iw7rzgJPI5HKEIH2
 3Usw4+DL1aMAlU1YKRwiwVoOVnmujzlb4a0ONhuBUdHKCGbfi6/Tce6lH0ElXavH
 mJgv5S9Ro2H/rMtYFq1ZoR9NxeizqtKT2Dv0KOsWiFwZBOfhjvmDel62N+7w1akt
 EWgahjASunwS56LBMg5ni0eK0VOt1kHQl3yeF6HmSdRftljN5Fke2r4BDA83sfl/
 VggQPPoLNdHou9LRO+XLOKe3sW5+nIH/b+SJUvWYktCSN9wMPCH5wbXNp8WIh/7p
 MvD2Kj7iqgF2PPzqpYGIwTHNwh5YdmnyYeCkr/IaoCBmUV0qD8HConsRN6USVIRI
 aBCZR4APWlaTzhu/eP5inuuGwNBGTVi3aJKe/WgN2aG2TsYnAzKhmvbELpYaheZj
 /Fe2itLuejVSjVsQI6KfhneCZyM45M7Ip8FTcEE1/z4R3cTEc5vE1adjFGWIzHRo
 bHPQ0JRfpamuJkxaSTOY
 =ixwg
 -----END PGP SIGNATURE-----

Merge tag 'for-usb-next-2012-05-18' of git://git.kernel.org/pub/scm/linux/kernel/git/sarah/xhci into usb-next

xhci: Link PM and bug fixes for 3.5.

Hi Greg,

Here's the final Link Power Management patches, along with a couple of bug
fixes that have been sitting in my queue.  I've fixed all the comments that
Alan and Andiry had on the Link PM patches, so I think they're ready to go.

Sarah Sharp
This commit is contained in:
Greg Kroah-Hartman 2012-05-18 16:32:52 -07:00
commit f06b9f3ced
70 changed files with 1512 additions and 13 deletions

View File

@ -439,6 +439,7 @@ static struct usb_driver ath3k_driver = {
.probe = ath3k_probe,
.disconnect = ath3k_disconnect,
.id_table = ath3k_table,
.disable_hub_initiated_lpm = 1,
};
module_usb_driver(ath3k_driver);

View File

@ -279,6 +279,7 @@ static struct usb_driver bcm203x_driver = {
.probe = bcm203x_probe,
.disconnect = bcm203x_disconnect,
.id_table = bcm203x_table,
.disable_hub_initiated_lpm = 1,
};
module_usb_driver(bcm203x_driver);

View File

@ -749,6 +749,7 @@ static struct usb_driver bfusb_driver = {
.probe = bfusb_probe,
.disconnect = bfusb_disconnect,
.id_table = bfusb_table,
.disable_hub_initiated_lpm = 1,
};
module_usb_driver(bfusb_driver);

View File

@ -508,6 +508,7 @@ static struct usb_driver bpa10x_driver = {
.probe = bpa10x_probe,
.disconnect = bpa10x_disconnect,
.id_table = bpa10x_table,
.disable_hub_initiated_lpm = 1,
};
module_usb_driver(bpa10x_driver);

View File

@ -1218,6 +1218,7 @@ static struct usb_driver btusb_driver = {
#endif
.id_table = btusb_table,
.supports_autosuspend = 1,
.disable_hub_initiated_lpm = 1,
};
module_usb_driver(btusb_driver);

View File

@ -148,6 +148,7 @@ static struct usb_driver gigaset_usb_driver = {
.reset_resume = gigaset_post_reset,
.pre_reset = gigaset_pre_reset,
.post_reset = gigaset_post_reset,
.disable_hub_initiated_lpm = 1,
};
/* get message text for usb_submit_urb return code

View File

@ -124,6 +124,7 @@ static struct usb_driver gigaset_usb_driver = {
.reset_resume = gigaset_resume,
.pre_reset = gigaset_pre_reset,
.post_reset = gigaset_resume,
.disable_hub_initiated_lpm = 1,
};
struct usb_cardstate {

View File

@ -2151,6 +2151,7 @@ static struct usb_driver hfcsusb_drv = {
.id_table = hfcsusb_idtab,
.probe = hfcsusb_probe,
.disconnect = hfcsusb_disconnect,
.disable_hub_initiated_lpm = 1,
};
module_usb_driver(hfcsusb_drv);

View File

@ -1568,6 +1568,7 @@ static struct usb_driver hfc_drv = {
.id_table = hfcusb_idtab,
.probe = hfc_usb_probe,
.disconnect = hfc_usb_disconnect,
.disable_hub_initiated_lpm = 1,
};
static void __exit

View File

@ -182,6 +182,7 @@ static struct usb_driver st5481_usb_driver = {
.probe = probe_st5481,
.disconnect = disconnect_st5481,
.id_table = st5481_ids,
.disable_hub_initiated_lpm = 1,
};
static int __init st5481_usb_init(void)

View File

@ -1647,6 +1647,7 @@ static struct usb_driver asix_driver = {
.resume = usbnet_resume,
.disconnect = usbnet_disconnect,
.supports_autosuspend = 1,
.disable_hub_initiated_lpm = 1,
};
module_usb_driver(asix_driver);

View File

@ -952,6 +952,7 @@ static struct usb_driver catc_driver = {
.probe = catc_probe,
.disconnect = catc_disconnect,
.id_table = catc_id_table,
.disable_hub_initiated_lpm = 1,
};
module_usb_driver(catc_driver);

View File

@ -457,6 +457,7 @@ static struct usb_driver usbpn_driver = {
.probe = usbpn_probe,
.disconnect = usbpn_disconnect,
.id_table = usbpn_ids,
.disable_hub_initiated_lpm = 1,
};
module_usb_driver(usbpn_driver);

View File

@ -368,6 +368,7 @@ static struct usb_driver eem_driver = {
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
.disable_hub_initiated_lpm = 1,
};
module_usb_driver(eem_driver);

View File

@ -633,6 +633,7 @@ static struct usb_driver cdc_driver = {
.resume = usbnet_resume,
.reset_resume = usbnet_resume,
.supports_autosuspend = 1,
.disable_hub_initiated_lpm = 1,
};
module_usb_driver(cdc_driver);

View File

@ -1212,6 +1212,7 @@ static struct usb_driver cdc_ncm_driver = {
.resume = usbnet_resume,
.reset_resume = usbnet_resume,
.supports_autosuspend = 1,
.disable_hub_initiated_lpm = 1,
};
static const struct ethtool_ops cdc_ncm_ethtool_ops = {

View File

@ -336,6 +336,7 @@ static struct usb_driver cdc_subset_driver = {
.resume = usbnet_resume,
.disconnect = usbnet_disconnect,
.id_table = products,
.disable_hub_initiated_lpm = 1,
};
module_usb_driver(cdc_subset_driver);

View File

@ -327,6 +327,7 @@ static struct usb_driver cx82310_driver = {
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
.disable_hub_initiated_lpm = 1,
};
module_usb_driver(cx82310_driver);

View File

@ -670,6 +670,7 @@ static struct usb_driver dm9601_driver = {
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
.disable_hub_initiated_lpm = 1,
};
module_usb_driver(dm9601_driver);

View File

@ -225,6 +225,7 @@ static struct usb_driver gl620a_driver = {
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
.disable_hub_initiated_lpm = 1,
};
module_usb_driver(gl620a_driver);

View File

@ -3291,6 +3291,7 @@ static struct usb_driver hso_driver = {
.resume = hso_resume,
.reset_resume = hso_resume,
.supports_autosuspend = 1,
.disable_hub_initiated_lpm = 1,
};
static int __init hso_init(void)

View File

@ -236,6 +236,7 @@ static struct usb_driver int51x1_driver = {
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
.disable_hub_initiated_lpm = 1,
};
module_usb_driver(int51x1_driver);

View File

@ -554,6 +554,7 @@ static struct usb_driver ipheth_driver = {
.probe = ipheth_probe,
.disconnect = ipheth_disconnect,
.id_table = ipheth_table,
.disable_hub_initiated_lpm = 1,
};
module_usb_driver(ipheth_driver);

View File

@ -372,7 +372,8 @@ static struct usb_driver kalmia_driver = {
.probe = usbnet_probe,
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume
.resume = usbnet_resume,
.disable_hub_initiated_lpm = 1,
};
module_usb_driver(kalmia_driver);

View File

@ -179,6 +179,7 @@ static struct usb_driver kaweth_driver = {
.resume = kaweth_resume,
.id_table = usb_klsi_table,
.supports_autosuspend = 1,
.disable_hub_initiated_lpm = 1,
};
typedef __u8 eth_addr_t[6];

View File

@ -344,6 +344,7 @@ static struct usb_driver lg_vl600_driver = {
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
.disable_hub_initiated_lpm = 1,
};
module_usb_driver(lg_vl600_driver);

View File

@ -690,6 +690,7 @@ static struct usb_driver mcs7830_driver = {
.suspend = usbnet_suspend,
.resume = usbnet_resume,
.reset_resume = mcs7830_reset_resume,
.disable_hub_initiated_lpm = 1,
};
module_usb_driver(mcs7830_driver);

View File

@ -587,6 +587,7 @@ static struct usb_driver net1080_driver = {
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
.disable_hub_initiated_lpm = 1,
};
module_usb_driver(net1080_driver);

View File

@ -1489,6 +1489,7 @@ static struct usb_driver pegasus_driver = {
.id_table = pegasus_ids,
.suspend = pegasus_suspend,
.resume = pegasus_resume,
.disable_hub_initiated_lpm = 1,
};
static void __init parse_id(char *id)

View File

@ -152,6 +152,7 @@ static struct usb_driver plusb_driver = {
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
.disable_hub_initiated_lpm = 1,
};
module_usb_driver(plusb_driver);

View File

@ -525,6 +525,7 @@ static struct usb_driver qmi_wwan_driver = {
.resume = qmi_wwan_resume,
.reset_resume = qmi_wwan_resume,
.supports_autosuspend = 1,
.disable_hub_initiated_lpm = 1,
};
static int __init qmi_wwan_init(void)

View File

@ -633,6 +633,7 @@ static struct usb_driver rndis_driver = {
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
.disable_hub_initiated_lpm = 1,
};
module_usb_driver(rndis_driver);

View File

@ -948,7 +948,8 @@ static struct usb_driver rtl8150_driver = {
.disconnect = rtl8150_disconnect,
.id_table = rtl8150_table,
.suspend = rtl8150_suspend,
.resume = rtl8150_resume
.resume = rtl8150_resume,
.disable_hub_initiated_lpm = 1,
};
module_usb_driver(rtl8150_driver);

View File

@ -982,6 +982,7 @@ static struct usb_driver sierra_net_driver = {
.suspend = usbnet_suspend,
.resume = usbnet_resume,
.no_dynamic_id = 1,
.disable_hub_initiated_lpm = 1,
};
module_usb_driver(sierra_net_driver);

View File

@ -1250,6 +1250,7 @@ static struct usb_driver smsc75xx_driver = {
.suspend = usbnet_suspend,
.resume = usbnet_resume,
.disconnect = usbnet_disconnect,
.disable_hub_initiated_lpm = 1,
};
module_usb_driver(smsc75xx_driver);

View File

@ -1297,6 +1297,7 @@ static struct usb_driver smsc95xx_driver = {
.suspend = usbnet_suspend,
.resume = usbnet_resume,
.disconnect = usbnet_disconnect,
.disable_hub_initiated_lpm = 1,
};
module_usb_driver(smsc95xx_driver);

View File

@ -377,6 +377,7 @@ static struct usb_driver zaurus_driver = {
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
.disable_hub_initiated_lpm = 1,
};
module_usb_driver(zaurus_driver);

View File

@ -2486,6 +2486,7 @@ static struct usb_driver at76_driver = {
.probe = at76_probe,
.disconnect = at76_disconnect,
.id_table = dev_table,
.disable_hub_initiated_lpm = 1,
};
static int __init at76_mod_init(void)

View File

@ -405,6 +405,7 @@ static struct usb_driver ath6kl_usb_driver = {
.probe = ath6kl_usb_probe,
.disconnect = ath6kl_usb_remove,
.id_table = ath6kl_usb_ids,
.disable_hub_initiated_lpm = 1,
};
static int ath6kl_usb_init(void)

View File

@ -1356,6 +1356,7 @@ static struct usb_driver ath9k_hif_usb_driver = {
#endif
.id_table = ath9k_hif_usb_ids,
.soft_unbind = 1,
.disable_hub_initiated_lpm = 1,
};
int ath9k_hif_usb_init(void)

View File

@ -1159,6 +1159,7 @@ static struct usb_driver carl9170_driver = {
.resume = carl9170_usb_resume,
.reset_resume = carl9170_usb_resume,
#endif /* CONFIG_PM */
.disable_hub_initiated_lpm = 1,
};
module_usb_driver(carl9170_driver);

View File

@ -1605,6 +1605,7 @@ static struct usb_driver brcmf_usbdrvr = {
.suspend = brcmf_usb_suspend,
.resume = brcmf_usb_resume,
.supports_autosuspend = 1
.disable_hub_initiated_lpm = 1,
};
void brcmf_usb_exit(void)

View File

@ -1180,6 +1180,7 @@ static struct usb_driver if_usb_driver = {
.suspend = if_usb_suspend,
.resume = if_usb_resume,
.reset_resume = if_usb_resume,
.disable_hub_initiated_lpm = 1,
};
module_usb_driver(if_usb_driver);

View File

@ -920,6 +920,7 @@ static struct usb_driver if_usb_driver = {
.id_table = if_usb_table,
.suspend = if_usb_suspend,
.resume = if_usb_resume,
.disable_hub_initiated_lpm = 1,
};
module_usb_driver(if_usb_driver);

View File

@ -1752,6 +1752,7 @@ static struct usb_driver orinoco_driver = {
.probe = ezusb_probe,
.disconnect = ezusb_disconnect,
.id_table = ezusb_table,
.disable_hub_initiated_lpm = 1,
};
module_usb_driver(orinoco_driver);

View File

@ -1081,6 +1081,7 @@ static struct usb_driver p54u_driver = {
.reset_resume = p54u_resume,
#endif /* CONFIG_PM */
.soft_unbind = 1,
.disable_hub_initiated_lpm = 1,
};
module_usb_driver(p54u_driver);

View File

@ -3776,6 +3776,7 @@ static struct usb_driver rndis_wlan_driver = {
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
.disable_hub_initiated_lpm = 1,
};
module_usb_driver(rndis_wlan_driver);

View File

@ -1980,6 +1980,7 @@ static struct usb_driver rt2500usb_driver = {
.disconnect = rt2x00usb_disconnect,
.suspend = rt2x00usb_suspend,
.resume = rt2x00usb_resume,
.disable_hub_initiated_lpm = 1,
};
module_usb_driver(rt2500usb_driver);

View File

@ -1293,6 +1293,7 @@ static struct usb_driver rt2800usb_driver = {
.disconnect = rt2x00usb_disconnect,
.suspend = rt2x00usb_suspend,
.resume = rt2x00usb_resume,
.disable_hub_initiated_lpm = 1,
};
module_usb_driver(rt2800usb_driver);

View File

@ -2526,6 +2526,7 @@ static struct usb_driver rt73usb_driver = {
.disconnect = rt2x00usb_disconnect,
.suspend = rt2x00usb_suspend,
.resume = rt2x00usb_resume,
.disable_hub_initiated_lpm = 1,
};
module_usb_driver(rt73usb_driver);

View File

@ -1662,6 +1662,7 @@ static struct usb_driver rtl8187_driver = {
.id_table = rtl8187_table,
.probe = rtl8187_probe,
.disconnect = __devexit_p(rtl8187_disconnect),
.disable_hub_initiated_lpm = 1,
};
module_usb_driver(rtl8187_driver);

View File

@ -372,6 +372,7 @@ static struct usb_driver rtl8192cu_driver = {
#ifdef CONFIG_AUTOSUSPEND
.supports_autosuspend = 1,
#endif
.disable_hub_initiated_lpm = 1,
};
module_usb_driver(rtl8192cu_driver);

View File

@ -1905,6 +1905,7 @@ static struct usb_driver zd1201_usb = {
.id_table = zd1201_table,
.suspend = zd1201_suspend,
.resume = zd1201_resume,
.disable_hub_initiated_lpm = 1,
};
module_usb_driver(zd1201_usb);

View File

@ -1542,6 +1542,7 @@ static struct usb_driver driver = {
.disconnect = disconnect,
.pre_reset = pre_reset,
.post_reset = post_reset,
.disable_hub_initiated_lpm = 1,
};
struct workqueue_struct *zd_workqueue;

View File

@ -1664,6 +1664,7 @@ static struct usb_driver acm_driver = {
#ifdef CONFIG_PM
.supports_autosuspend = 1,
#endif
.disable_hub_initiated_lpm = 1,
};
/*

View File

@ -1034,6 +1034,7 @@ static struct usb_driver wdm_driver = {
.post_reset = wdm_post_reset,
.id_table = wdm_ids,
.supports_autosuspend = 1,
.disable_hub_initiated_lpm = 1,
};
module_usb_driver(wdm_driver);

View File

@ -288,6 +288,7 @@ static int usb_probe_interface(struct device *dev)
struct usb_device *udev = interface_to_usbdev(intf);
const struct usb_device_id *id;
int error = -ENODEV;
int lpm_disable_error;
dev_dbg(dev, "%s\n", __func__);
@ -324,6 +325,25 @@ static int usb_probe_interface(struct device *dev)
if (driver->supports_autosuspend)
pm_runtime_enable(dev);
/* If the new driver doesn't allow hub-initiated LPM, and we can't
* disable hub-initiated LPM, then fail the probe.
*
* Otherwise, leaving LPM enabled should be harmless, because the
* endpoint intervals should remain the same, and the U1/U2 timeouts
* should remain the same.
*
* If we need to install alt setting 0 before probe, or another alt
* setting during probe, that should also be fine. usb_set_interface()
* will attempt to disable LPM, and fail if it can't disable it.
*/
lpm_disable_error = usb_unlocked_disable_lpm(udev);
if (lpm_disable_error && driver->disable_hub_initiated_lpm) {
dev_err(&intf->dev, "%s Failed to disable LPM for driver %s\n.",
__func__, driver->name);
error = lpm_disable_error;
goto err;
}
/* Carry out a deferred switch to altsetting 0 */
if (intf->needs_altsetting0) {
error = usb_set_interface(udev, intf->altsetting[0].
@ -338,6 +358,11 @@ static int usb_probe_interface(struct device *dev)
goto err;
intf->condition = USB_INTERFACE_BOUND;
/* If the LPM disable succeeded, balance the ref counts. */
if (!lpm_disable_error)
usb_unlocked_enable_lpm(udev);
usb_autosuspend_device(udev);
return error;
@ -361,7 +386,7 @@ static int usb_unbind_interface(struct device *dev)
struct usb_driver *driver = to_usb_driver(dev->driver);
struct usb_interface *intf = to_usb_interface(dev);
struct usb_device *udev;
int error, r;
int error, r, lpm_disable_error;
intf->condition = USB_INTERFACE_UNBINDING;
@ -369,6 +394,13 @@ static int usb_unbind_interface(struct device *dev)
udev = interface_to_usbdev(intf);
error = usb_autoresume_device(udev);
/* Hub-initiated LPM policy may change, so attempt to disable LPM until
* the driver is unbound. If LPM isn't disabled, that's fine because it
* wouldn't be enabled unless all the bound interfaces supported
* hub-initiated LPM.
*/
lpm_disable_error = usb_unlocked_disable_lpm(udev);
/* Terminate all URBs for this interface unless the driver
* supports "soft" unbinding.
*/
@ -402,6 +434,10 @@ static int usb_unbind_interface(struct device *dev)
intf->condition = USB_INTERFACE_UNBOUND;
intf->needs_remote_wakeup = 0;
/* Attempt to re-enable USB3 LPM, if the disable succeeded. */
if (!lpm_disable_error)
usb_unlocked_enable_lpm(udev);
/* Unbound interfaces are always runtime-PM-disabled and -suspended */
if (driver->supports_autosuspend)
pm_runtime_disable(dev);
@ -442,17 +478,29 @@ int usb_driver_claim_interface(struct usb_driver *driver,
struct usb_interface *iface, void *priv)
{
struct device *dev = &iface->dev;
struct usb_device *udev;
int retval = 0;
int lpm_disable_error;
if (dev->driver)
return -EBUSY;
udev = interface_to_usbdev(iface);
dev->driver = &driver->drvwrap.driver;
usb_set_intfdata(iface, priv);
iface->needs_binding = 0;
iface->condition = USB_INTERFACE_BOUND;
/* Disable LPM until this driver is bound. */
lpm_disable_error = usb_unlocked_disable_lpm(udev);
if (lpm_disable_error && driver->disable_hub_initiated_lpm) {
dev_err(&iface->dev, "%s Failed to disable LPM for driver %s\n.",
__func__, driver->name);
return -ENOMEM;
}
/* Claimed interfaces are initially inactive (suspended) and
* runtime-PM-enabled, but only if the driver has autosuspend
* support. Otherwise they are marked active, to prevent the
@ -471,6 +519,10 @@ int usb_driver_claim_interface(struct usb_driver *driver,
if (device_is_registered(dev))
retval = device_bind_driver(dev);
/* Attempt to re-enable USB3 LPM, if the disable was successful. */
if (!lpm_disable_error)
usb_unlocked_enable_lpm(udev);
return retval;
}
EXPORT_SYMBOL_GPL(usb_driver_claim_interface);

View File

@ -997,6 +997,15 @@ static int register_root_hub(struct usb_hcd *hcd)
dev_name(&usb_dev->dev), retval);
return (retval < 0) ? retval : -EMSGSIZE;
}
if (usb_dev->speed == USB_SPEED_SUPER) {
retval = usb_get_bos_descriptor(usb_dev);
if (retval < 0) {
mutex_unlock(&usb_bus_list_lock);
dev_dbg(parent_dev, "can't read %s bos descriptor %d\n",
dev_name(&usb_dev->dev), retval);
return retval;
}
}
retval = usb_new_device (usb_dev);
if (retval) {

View File

@ -177,6 +177,228 @@ static struct usb_hub *hdev_to_hub(struct usb_device *hdev)
return usb_get_intfdata(hdev->actconfig->interface[0]);
}
static int usb_device_supports_lpm(struct usb_device *udev)
{
/* USB 2.1 (and greater) devices indicate LPM support through
* their USB 2.0 Extended Capabilities BOS descriptor.
*/
if (udev->speed == USB_SPEED_HIGH) {
if (udev->bos->ext_cap &&
(USB_LPM_SUPPORT &
le32_to_cpu(udev->bos->ext_cap->bmAttributes)))
return 1;
return 0;
}
/* All USB 3.0 must support LPM, but we need their max exit latency
* information from the SuperSpeed Extended Capabilities BOS descriptor.
*/
if (!udev->bos->ss_cap) {
dev_warn(&udev->dev, "No LPM exit latency info found. "
"Power management will be impacted.\n");
return 0;
}
if (udev->parent->lpm_capable)
return 1;
dev_warn(&udev->dev, "Parent hub missing LPM exit latency info. "
"Power management will be impacted.\n");
return 0;
}
/*
* Set the Maximum Exit Latency (MEL) for the host to initiate a transition from
* either U1 or U2.
*/
static void usb_set_lpm_mel(struct usb_device *udev,
struct usb3_lpm_parameters *udev_lpm_params,
unsigned int udev_exit_latency,
struct usb_hub *hub,
struct usb3_lpm_parameters *hub_lpm_params,
unsigned int hub_exit_latency)
{
unsigned int total_mel;
unsigned int device_mel;
unsigned int hub_mel;
/*
* Calculate the time it takes to transition all links from the roothub
* to the parent hub into U0. The parent hub must then decode the
* packet (hub header decode latency) to figure out which port it was
* bound for.
*
* The Hub Header decode latency is expressed in 0.1us intervals (0x1
* means 0.1us). Multiply that by 100 to get nanoseconds.
*/
total_mel = hub_lpm_params->mel +
(hub->descriptor->u.ss.bHubHdrDecLat * 100);
/*
* How long will it take to transition the downstream hub's port into
* U0? The greater of either the hub exit latency or the device exit
* latency.
*
* The BOS U1/U2 exit latencies are expressed in 1us intervals.
* Multiply that by 1000 to get nanoseconds.
*/
device_mel = udev_exit_latency * 1000;
hub_mel = hub_exit_latency * 1000;
if (device_mel > hub_mel)
total_mel += device_mel;
else
total_mel += hub_mel;
udev_lpm_params->mel = total_mel;
}
/*
* Set the maximum Device to Host Exit Latency (PEL) for the device to initiate
* a transition from either U1 or U2.
*/
static void usb_set_lpm_pel(struct usb_device *udev,
struct usb3_lpm_parameters *udev_lpm_params,
unsigned int udev_exit_latency,
struct usb_hub *hub,
struct usb3_lpm_parameters *hub_lpm_params,
unsigned int hub_exit_latency,
unsigned int port_to_port_exit_latency)
{
unsigned int first_link_pel;
unsigned int hub_pel;
/*
* First, the device sends an LFPS to transition the link between the
* device and the parent hub into U0. The exit latency is the bigger of
* the device exit latency or the hub exit latency.
*/
if (udev_exit_latency > hub_exit_latency)
first_link_pel = udev_exit_latency * 1000;
else
first_link_pel = hub_exit_latency * 1000;
/*
* When the hub starts to receive the LFPS, there is a slight delay for
* it to figure out that one of the ports is sending an LFPS. Then it
* will forward the LFPS to its upstream link. The exit latency is the
* delay, plus the PEL that we calculated for this hub.
*/
hub_pel = port_to_port_exit_latency * 1000 + hub_lpm_params->pel;
/*
* According to figure C-7 in the USB 3.0 spec, the PEL for this device
* is the greater of the two exit latencies.
*/
if (first_link_pel > hub_pel)
udev_lpm_params->pel = first_link_pel;
else
udev_lpm_params->pel = hub_pel;
}
/*
* Set the System Exit Latency (SEL) to indicate the total worst-case time from
* when a device initiates a transition to U0, until when it will receive the
* first packet from the host controller.
*
* Section C.1.5.1 describes the four components to this:
* - t1: device PEL
* - t2: time for the ERDY to make it from the device to the host.
* - t3: a host-specific delay to process the ERDY.
* - t4: time for the packet to make it from the host to the device.
*
* t3 is specific to both the xHCI host and the platform the host is integrated
* into. The Intel HW folks have said it's negligible, FIXME if a different
* vendor says otherwise.
*/
static void usb_set_lpm_sel(struct usb_device *udev,
struct usb3_lpm_parameters *udev_lpm_params)
{
struct usb_device *parent;
unsigned int num_hubs;
unsigned int total_sel;
/* t1 = device PEL */
total_sel = udev_lpm_params->pel;
/* How many external hubs are in between the device & the root port. */
for (parent = udev->parent, num_hubs = 0; parent->parent;
parent = parent->parent)
num_hubs++;
/* t2 = 2.1us + 250ns * (num_hubs - 1) */
if (num_hubs > 0)
total_sel += 2100 + 250 * (num_hubs - 1);
/* t4 = 250ns * num_hubs */
total_sel += 250 * num_hubs;
udev_lpm_params->sel = total_sel;
}
static void usb_set_lpm_parameters(struct usb_device *udev)
{
struct usb_hub *hub;
unsigned int port_to_port_delay;
unsigned int udev_u1_del;
unsigned int udev_u2_del;
unsigned int hub_u1_del;
unsigned int hub_u2_del;
if (!udev->lpm_capable || udev->speed != USB_SPEED_SUPER)
return;
hub = hdev_to_hub(udev->parent);
/* It doesn't take time to transition the roothub into U0, since it
* doesn't have an upstream link.
*/
if (!hub)
return;
udev_u1_del = udev->bos->ss_cap->bU1devExitLat;
udev_u2_del = udev->bos->ss_cap->bU2DevExitLat;
hub_u1_del = udev->parent->bos->ss_cap->bU1devExitLat;
hub_u2_del = udev->parent->bos->ss_cap->bU2DevExitLat;
usb_set_lpm_mel(udev, &udev->u1_params, udev_u1_del,
hub, &udev->parent->u1_params, hub_u1_del);
usb_set_lpm_mel(udev, &udev->u2_params, udev_u2_del,
hub, &udev->parent->u2_params, hub_u2_del);
/*
* Appendix C, section C.2.2.2, says that there is a slight delay from
* when the parent hub notices the downstream port is trying to
* transition to U0 to when the hub initiates a U0 transition on its
* upstream port. The section says the delays are tPort2PortU1EL and
* tPort2PortU2EL, but it doesn't define what they are.
*
* The hub chapter, sections 10.4.2.4 and 10.4.2.5 seem to be talking
* about the same delays. Use the maximum delay calculations from those
* sections. For U1, it's tHubPort2PortExitLat, which is 1us max. For
* U2, it's tHubPort2PortExitLat + U2DevExitLat - U1DevExitLat. I
* assume the device exit latencies they are talking about are the hub
* exit latencies.
*
* What do we do if the U2 exit latency is less than the U1 exit
* latency? It's possible, although not likely...
*/
port_to_port_delay = 1;
usb_set_lpm_pel(udev, &udev->u1_params, udev_u1_del,
hub, &udev->parent->u1_params, hub_u1_del,
port_to_port_delay);
if (hub_u2_del > hub_u1_del)
port_to_port_delay = 1 + hub_u2_del - hub_u1_del;
else
port_to_port_delay = 1 + hub_u1_del;
usb_set_lpm_pel(udev, &udev->u2_params, udev_u2_del,
hub, &udev->parent->u2_params, hub_u2_del,
port_to_port_delay);
/* Now that we've got PEL, calculate SEL. */
usb_set_lpm_sel(udev, &udev->u1_params);
usb_set_lpm_sel(udev, &udev->u2_params);
}
/* USB 2.0 spec Section 11.24.4.5 */
static int get_hub_descriptor(struct usb_device *hdev, void *data)
{
@ -2480,6 +2702,12 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
if (udev->usb2_hw_lpm_enabled == 1)
usb_set_usb2_hardware_lpm(udev, 0);
if (usb_unlocked_disable_lpm(udev)) {
dev_err(&udev->dev, "%s Failed to disable LPM before suspend\n.",
__func__);
return -ENOMEM;
}
/* see 7.1.7.6 */
if (hub_is_superspeed(hub->hdev))
status = set_port_feature(hub->hdev,
@ -2499,6 +2727,13 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
NULL, 0,
USB_CTRL_SET_TIMEOUT);
/* Try to enable USB2 hardware LPM again */
if (udev->usb2_hw_lpm_capable == 1)
usb_set_usb2_hardware_lpm(udev, 1);
/* Try to enable USB3 LPM again */
usb_unlocked_enable_lpm(udev);
/* System sleep transitions should never fail */
if (!PMSG_IS_AUTO(msg))
status = 0;
@ -2696,6 +2931,9 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)
/* Try to enable USB2 hardware LPM */
if (udev->usb2_hw_lpm_capable == 1)
usb_set_usb2_hardware_lpm(udev, 1);
/* Try to enable USB3 LPM */
usb_unlocked_enable_lpm(udev);
}
return status;
@ -2824,11 +3062,425 @@ void usb_root_hub_lost_power(struct usb_device *rhdev)
}
EXPORT_SYMBOL_GPL(usb_root_hub_lost_power);
static const char * const usb3_lpm_names[] = {
"U0",
"U1",
"U2",
"U3",
};
/*
* Send a Set SEL control transfer to the device, prior to enabling
* device-initiated U1 or U2. This lets the device know the exit latencies from
* the time the device initiates a U1 or U2 exit, to the time it will receive a
* packet from the host.
*
* This function will fail if the SEL or PEL values for udev are greater than
* the maximum allowed values for the link state to be enabled.
*/
static int usb_req_set_sel(struct usb_device *udev, enum usb3_link_state state)
{
struct usb_set_sel_req *sel_values;
unsigned long long u1_sel;
unsigned long long u1_pel;
unsigned long long u2_sel;
unsigned long long u2_pel;
int ret;
/* Convert SEL and PEL stored in ns to us */
u1_sel = DIV_ROUND_UP(udev->u1_params.sel, 1000);
u1_pel = DIV_ROUND_UP(udev->u1_params.pel, 1000);
u2_sel = DIV_ROUND_UP(udev->u2_params.sel, 1000);
u2_pel = DIV_ROUND_UP(udev->u2_params.pel, 1000);
/*
* Make sure that the calculated SEL and PEL values for the link
* state we're enabling aren't bigger than the max SEL/PEL
* value that will fit in the SET SEL control transfer.
* Otherwise the device would get an incorrect idea of the exit
* latency for the link state, and could start a device-initiated
* U1/U2 when the exit latencies are too high.
*/
if ((state == USB3_LPM_U1 &&
(u1_sel > USB3_LPM_MAX_U1_SEL_PEL ||
u1_pel > USB3_LPM_MAX_U1_SEL_PEL)) ||
(state == USB3_LPM_U2 &&
(u2_sel > USB3_LPM_MAX_U2_SEL_PEL ||
u2_pel > USB3_LPM_MAX_U2_SEL_PEL))) {
dev_dbg(&udev->dev, "Device-initiated %s disabled due "
"to long SEL %llu ms or PEL %llu ms\n",
usb3_lpm_names[state], u1_sel, u1_pel);
return -EINVAL;
}
/*
* If we're enabling device-initiated LPM for one link state,
* but the other link state has a too high SEL or PEL value,
* just set those values to the max in the Set SEL request.
*/
if (u1_sel > USB3_LPM_MAX_U1_SEL_PEL)
u1_sel = USB3_LPM_MAX_U1_SEL_PEL;
if (u1_pel > USB3_LPM_MAX_U1_SEL_PEL)
u1_pel = USB3_LPM_MAX_U1_SEL_PEL;
if (u2_sel > USB3_LPM_MAX_U2_SEL_PEL)
u2_sel = USB3_LPM_MAX_U2_SEL_PEL;
if (u2_pel > USB3_LPM_MAX_U2_SEL_PEL)
u2_pel = USB3_LPM_MAX_U2_SEL_PEL;
/*
* usb_enable_lpm() can be called as part of a failed device reset,
* which may be initiated by an error path of a mass storage driver.
* Therefore, use GFP_NOIO.
*/
sel_values = kmalloc(sizeof *(sel_values), GFP_NOIO);
if (!sel_values)
return -ENOMEM;
sel_values->u1_sel = u1_sel;
sel_values->u1_pel = u1_pel;
sel_values->u2_sel = cpu_to_le16(u2_sel);
sel_values->u2_pel = cpu_to_le16(u2_pel);
ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
USB_REQ_SET_SEL,
USB_RECIP_DEVICE,
0, 0,
sel_values, sizeof *(sel_values),
USB_CTRL_SET_TIMEOUT);
kfree(sel_values);
return ret;
}
/*
* Enable or disable device-initiated U1 or U2 transitions.
*/
static int usb_set_device_initiated_lpm(struct usb_device *udev,
enum usb3_link_state state, bool enable)
{
int ret;
int feature;
switch (state) {
case USB3_LPM_U1:
feature = USB_DEVICE_U1_ENABLE;
break;
case USB3_LPM_U2:
feature = USB_DEVICE_U2_ENABLE;
break;
default:
dev_warn(&udev->dev, "%s: Can't %s non-U1 or U2 state.\n",
__func__, enable ? "enable" : "disable");
return -EINVAL;
}
if (udev->state != USB_STATE_CONFIGURED) {
dev_dbg(&udev->dev, "%s: Can't %s %s state "
"for unconfigured device.\n",
__func__, enable ? "enable" : "disable",
usb3_lpm_names[state]);
return 0;
}
if (enable) {
/*
* First, let the device know about the exit latencies
* associated with the link state we're about to enable.
*/
ret = usb_req_set_sel(udev, state);
if (ret < 0) {
dev_warn(&udev->dev, "Set SEL for device-initiated "
"%s failed.\n", usb3_lpm_names[state]);
return -EBUSY;
}
/*
* Now send the control transfer to enable device-initiated LPM
* for either U1 or U2.
*/
ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
USB_REQ_SET_FEATURE,
USB_RECIP_DEVICE,
feature,
0, NULL, 0,
USB_CTRL_SET_TIMEOUT);
} else {
ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
USB_REQ_CLEAR_FEATURE,
USB_RECIP_DEVICE,
feature,
0, NULL, 0,
USB_CTRL_SET_TIMEOUT);
}
if (ret < 0) {
dev_warn(&udev->dev, "%s of device-initiated %s failed.\n",
enable ? "Enable" : "Disable",
usb3_lpm_names[state]);
return -EBUSY;
}
return 0;
}
static int usb_set_lpm_timeout(struct usb_device *udev,
enum usb3_link_state state, int timeout)
{
int ret;
int feature;
switch (state) {
case USB3_LPM_U1:
feature = USB_PORT_FEAT_U1_TIMEOUT;
break;
case USB3_LPM_U2:
feature = USB_PORT_FEAT_U2_TIMEOUT;
break;
default:
dev_warn(&udev->dev, "%s: Can't set timeout for non-U1 or U2 state.\n",
__func__);
return -EINVAL;
}
if (state == USB3_LPM_U1 && timeout > USB3_LPM_U1_MAX_TIMEOUT &&
timeout != USB3_LPM_DEVICE_INITIATED) {
dev_warn(&udev->dev, "Failed to set %s timeout to 0x%x, "
"which is a reserved value.\n",
usb3_lpm_names[state], timeout);
return -EINVAL;
}
ret = set_port_feature(udev->parent,
USB_PORT_LPM_TIMEOUT(timeout) | udev->portnum,
feature);
if (ret < 0) {
dev_warn(&udev->dev, "Failed to set %s timeout to 0x%x,"
"error code %i\n", usb3_lpm_names[state],
timeout, ret);
return -EBUSY;
}
if (state == USB3_LPM_U1)
udev->u1_params.timeout = timeout;
else
udev->u2_params.timeout = timeout;
return 0;
}
/*
* Enable the hub-initiated U1/U2 idle timeouts, and enable device-initiated
* U1/U2 entry.
*
* We will attempt to enable U1 or U2, but there are no guarantees that the
* control transfers to set the hub timeout or enable device-initiated U1/U2
* will be successful.
*
* If we cannot set the parent hub U1/U2 timeout, we attempt to let the xHCI
* driver know about it. If that call fails, it should be harmless, and just
* take up more slightly more bus bandwidth for unnecessary U1/U2 exit latency.
*/
static void usb_enable_link_state(struct usb_hcd *hcd, struct usb_device *udev,
enum usb3_link_state state)
{
int timeout;
/* We allow the host controller to set the U1/U2 timeout internally
* first, so that it can change its schedule to account for the
* additional latency to send data to a device in a lower power
* link state.
*/
timeout = hcd->driver->enable_usb3_lpm_timeout(hcd, udev, state);
/* xHCI host controller doesn't want to enable this LPM state. */
if (timeout == 0)
return;
if (timeout < 0) {
dev_warn(&udev->dev, "Could not enable %s link state, "
"xHCI error %i.\n", usb3_lpm_names[state],
timeout);
return;
}
if (usb_set_lpm_timeout(udev, state, timeout))
/* If we can't set the parent hub U1/U2 timeout,
* device-initiated LPM won't be allowed either, so let the xHCI
* host know that this link state won't be enabled.
*/
hcd->driver->disable_usb3_lpm_timeout(hcd, udev, state);
/* Only a configured device will accept the Set Feature U1/U2_ENABLE */
else if (udev->actconfig)
usb_set_device_initiated_lpm(udev, state, true);
}
/*
* Disable the hub-initiated U1/U2 idle timeouts, and disable device-initiated
* U1/U2 entry.
*
* If this function returns -EBUSY, the parent hub will still allow U1/U2 entry.
* If zero is returned, the parent will not allow the link to go into U1/U2.
*
* If zero is returned, device-initiated U1/U2 entry may still be enabled, but
* it won't have an effect on the bus link state because the parent hub will
* still disallow device-initiated U1/U2 entry.
*
* If zero is returned, the xHCI host controller may still think U1/U2 entry is
* possible. The result will be slightly more bus bandwidth will be taken up
* (to account for U1/U2 exit latency), but it should be harmless.
*/
static int usb_disable_link_state(struct usb_hcd *hcd, struct usb_device *udev,
enum usb3_link_state state)
{
int feature;
switch (state) {
case USB3_LPM_U1:
feature = USB_PORT_FEAT_U1_TIMEOUT;
break;
case USB3_LPM_U2:
feature = USB_PORT_FEAT_U2_TIMEOUT;
break;
default:
dev_warn(&udev->dev, "%s: Can't disable non-U1 or U2 state.\n",
__func__);
return -EINVAL;
}
if (usb_set_lpm_timeout(udev, state, 0))
return -EBUSY;
usb_set_device_initiated_lpm(udev, state, false);
if (hcd->driver->disable_usb3_lpm_timeout(hcd, udev, state))
dev_warn(&udev->dev, "Could not disable xHCI %s timeout, "
"bus schedule bandwidth may be impacted.\n",
usb3_lpm_names[state]);
return 0;
}
/*
* Disable hub-initiated and device-initiated U1 and U2 entry.
* Caller must own the bandwidth_mutex.
*
* This will call usb_enable_lpm() on failure, which will decrement
* lpm_disable_count, and will re-enable LPM if lpm_disable_count reaches zero.
*/
int usb_disable_lpm(struct usb_device *udev)
{
struct usb_hcd *hcd;
if (!udev || !udev->parent ||
udev->speed != USB_SPEED_SUPER ||
!udev->lpm_capable)
return 0;
hcd = bus_to_hcd(udev->bus);
if (!hcd || !hcd->driver->disable_usb3_lpm_timeout)
return 0;
udev->lpm_disable_count++;
if ((udev->u1_params.timeout == 0 && udev->u1_params.timeout == 0))
return 0;
/* If LPM is enabled, attempt to disable it. */
if (usb_disable_link_state(hcd, udev, USB3_LPM_U1))
goto enable_lpm;
if (usb_disable_link_state(hcd, udev, USB3_LPM_U2))
goto enable_lpm;
return 0;
enable_lpm:
usb_enable_lpm(udev);
return -EBUSY;
}
EXPORT_SYMBOL_GPL(usb_disable_lpm);
/* Grab the bandwidth_mutex before calling usb_disable_lpm() */
int usb_unlocked_disable_lpm(struct usb_device *udev)
{
struct usb_hcd *hcd = bus_to_hcd(udev->bus);
int ret;
if (!hcd)
return -EINVAL;
mutex_lock(hcd->bandwidth_mutex);
ret = usb_disable_lpm(udev);
mutex_unlock(hcd->bandwidth_mutex);
return ret;
}
EXPORT_SYMBOL_GPL(usb_unlocked_disable_lpm);
/*
* Attempt to enable device-initiated and hub-initiated U1 and U2 entry. The
* xHCI host policy may prevent U1 or U2 from being enabled.
*
* Other callers may have disabled link PM, so U1 and U2 entry will be disabled
* until the lpm_disable_count drops to zero. Caller must own the
* bandwidth_mutex.
*/
void usb_enable_lpm(struct usb_device *udev)
{
struct usb_hcd *hcd;
if (!udev || !udev->parent ||
udev->speed != USB_SPEED_SUPER ||
!udev->lpm_capable)
return;
udev->lpm_disable_count--;
hcd = bus_to_hcd(udev->bus);
/* Double check that we can both enable and disable LPM.
* Device must be configured to accept set feature U1/U2 timeout.
*/
if (!hcd || !hcd->driver->enable_usb3_lpm_timeout ||
!hcd->driver->disable_usb3_lpm_timeout)
return;
if (udev->lpm_disable_count > 0)
return;
usb_enable_link_state(hcd, udev, USB3_LPM_U1);
usb_enable_link_state(hcd, udev, USB3_LPM_U2);
}
EXPORT_SYMBOL_GPL(usb_enable_lpm);
/* Grab the bandwidth_mutex before calling usb_enable_lpm() */
void usb_unlocked_enable_lpm(struct usb_device *udev)
{
struct usb_hcd *hcd = bus_to_hcd(udev->bus);
if (!hcd)
return;
mutex_lock(hcd->bandwidth_mutex);
usb_enable_lpm(udev);
mutex_unlock(hcd->bandwidth_mutex);
}
EXPORT_SYMBOL_GPL(usb_unlocked_enable_lpm);
#else /* CONFIG_PM */
#define hub_suspend NULL
#define hub_resume NULL
#define hub_reset_resume NULL
int usb_disable_lpm(struct usb_device *udev)
{
return 0;
}
void usb_enable_lpm(struct usb_device *udev) { }
int usb_unlocked_disable_lpm(struct usb_device *udev)
{
return 0;
}
void usb_unlocked_enable_lpm(struct usb_device *udev) { }
#endif
@ -3208,9 +3860,8 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
if (udev->wusb == 0 && le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0201) {
retval = usb_get_bos_descriptor(udev);
if (!retval) {
if (udev->bos->ext_cap && (USB_LPM_SUPPORT &
le32_to_cpu(udev->bos->ext_cap->bmAttributes)))
udev->lpm_capable = 1;
udev->lpm_capable = usb_device_supports_lpm(udev);
usb_set_lpm_parameters(udev);
}
}
@ -4042,11 +4693,22 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
goto done;
mutex_lock(hcd->bandwidth_mutex);
/* Disable LPM while we reset the device and reinstall the alt settings.
* Device-initiated LPM settings, and system exit latency settings are
* cleared when the device is reset, so we have to set them up again.
*/
ret = usb_disable_lpm(udev);
if (ret) {
dev_err(&udev->dev, "%s Failed to disable LPM\n.", __func__);
mutex_unlock(hcd->bandwidth_mutex);
goto done;
}
ret = usb_hcd_alloc_bandwidth(udev, udev->actconfig, NULL, NULL);
if (ret < 0) {
dev_warn(&udev->dev,
"Busted HC? Not enough HCD resources for "
"old configuration.\n");
usb_enable_lpm(udev);
mutex_unlock(hcd->bandwidth_mutex);
goto re_enumerate;
}
@ -4058,6 +4720,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
dev_err(&udev->dev,
"can't restore configuration #%d (error=%d)\n",
udev->actconfig->desc.bConfigurationValue, ret);
usb_enable_lpm(udev);
mutex_unlock(hcd->bandwidth_mutex);
goto re_enumerate;
}
@ -4096,10 +4759,13 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
desc->bInterfaceNumber,
desc->bAlternateSetting,
ret);
usb_unlocked_enable_lpm(udev);
goto re_enumerate;
}
}
/* Now that the alt settings are re-installed, enable LPM. */
usb_unlocked_enable_lpm(udev);
done:
return 0;

View File

@ -1308,10 +1308,19 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
* Remove the current alt setting and add the new alt setting.
*/
mutex_lock(hcd->bandwidth_mutex);
/* Disable LPM, and re-enable it once the new alt setting is installed,
* so that the xHCI driver can recalculate the U1/U2 timeouts.
*/
if (usb_disable_lpm(dev)) {
dev_err(&iface->dev, "%s Failed to disable LPM\n.", __func__);
mutex_unlock(hcd->bandwidth_mutex);
return -ENOMEM;
}
ret = usb_hcd_alloc_bandwidth(dev, NULL, iface->cur_altsetting, alt);
if (ret < 0) {
dev_info(&dev->dev, "Not enough bandwidth for altsetting %d\n",
alternate);
usb_enable_lpm(dev);
mutex_unlock(hcd->bandwidth_mutex);
return ret;
}
@ -1334,6 +1343,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
} else if (ret < 0) {
/* Re-instate the old alt setting */
usb_hcd_alloc_bandwidth(dev, NULL, alt, iface->cur_altsetting);
usb_enable_lpm(dev);
mutex_unlock(hcd->bandwidth_mutex);
return ret;
}
@ -1354,6 +1364,9 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
iface->cur_altsetting = alt;
/* Now that the interface is installed, re-enable LPM. */
usb_unlocked_enable_lpm(dev);
/* If the interface only has one altsetting and the device didn't
* accept the request, we attempt to carry out the equivalent action
* by manually clearing the HALT feature for each endpoint in the
@ -1437,6 +1450,14 @@ int usb_reset_configuration(struct usb_device *dev)
config = dev->actconfig;
retval = 0;
mutex_lock(hcd->bandwidth_mutex);
/* Disable LPM, and re-enable it once the configuration is reset, so
* that the xHCI driver can recalculate the U1/U2 timeouts.
*/
if (usb_disable_lpm(dev)) {
dev_err(&dev->dev, "%s Failed to disable LPM\n.", __func__);
mutex_unlock(hcd->bandwidth_mutex);
return -ENOMEM;
}
/* Make sure we have enough bandwidth for each alternate setting 0 */
for (i = 0; i < config->desc.bNumInterfaces; i++) {
struct usb_interface *intf = config->interface[i];
@ -1465,6 +1486,7 @@ int usb_reset_configuration(struct usb_device *dev)
usb_hcd_alloc_bandwidth(dev, NULL,
alt, intf->cur_altsetting);
}
usb_enable_lpm(dev);
mutex_unlock(hcd->bandwidth_mutex);
return retval;
}
@ -1502,6 +1524,8 @@ int usb_reset_configuration(struct usb_device *dev)
create_intf_ep_devs(intf);
}
}
/* Now that the interfaces are installed, re-enable LPM. */
usb_unlocked_enable_lpm(dev);
return 0;
}
EXPORT_SYMBOL_GPL(usb_reset_configuration);
@ -1763,8 +1787,18 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
* this call fails, the device state is unchanged.
*/
mutex_lock(hcd->bandwidth_mutex);
/* Disable LPM, and re-enable it once the new configuration is
* installed, so that the xHCI driver can recalculate the U1/U2
* timeouts.
*/
if (usb_disable_lpm(dev)) {
dev_err(&dev->dev, "%s Failed to disable LPM\n.", __func__);
mutex_unlock(hcd->bandwidth_mutex);
return -ENOMEM;
}
ret = usb_hcd_alloc_bandwidth(dev, cp, NULL, NULL);
if (ret < 0) {
usb_enable_lpm(dev);
mutex_unlock(hcd->bandwidth_mutex);
usb_autosuspend_device(dev);
goto free_interfaces;
@ -1784,6 +1818,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
if (!cp) {
usb_set_device_state(dev, USB_STATE_ADDRESS);
usb_hcd_alloc_bandwidth(dev, NULL, NULL, NULL);
usb_enable_lpm(dev);
mutex_unlock(hcd->bandwidth_mutex);
usb_autosuspend_device(dev);
goto free_interfaces;
@ -1838,6 +1873,9 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
!(dev->quirks & USB_QUIRK_CONFIG_INTF_STRINGS))
cp->string = usb_cache_string(dev, cp->desc.iConfiguration);
/* Now that the interfaces are installed, re-enable LPM. */
usb_unlocked_enable_lpm(dev);
/* Now that all the interfaces are set up, register them
* to trigger binding of drivers to interfaces. probe()
* routines may install different altsettings and may

View File

@ -475,6 +475,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
struct xhci_bus_state *bus_state;
u16 link_state = 0;
u16 wake_mask = 0;
u16 timeout = 0;
max_ports = xhci_get_ports(hcd, &port_array);
bus_state = &xhci->bus_state[hcd_index(hcd)];
@ -623,6 +624,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
link_state = (wIndex & 0xff00) >> 3;
if (wValue == USB_PORT_FEAT_REMOTE_WAKE_MASK)
wake_mask = wIndex & 0xff00;
/* The MSB of wIndex is the U1/U2 timeout */
timeout = (wIndex & 0xff00) >> 8;
wIndex &= 0xff;
if (!wIndex || wIndex > max_ports)
goto error;
@ -747,6 +750,22 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
temp = xhci_readl(xhci, port_array[wIndex]);
break;
case USB_PORT_FEAT_U1_TIMEOUT:
if (hcd->speed != HCD_USB3)
goto error;
temp = xhci_readl(xhci, port_array[wIndex] + 1);
temp &= ~PORT_U1_TIMEOUT_MASK;
temp |= PORT_U1_TIMEOUT(timeout);
xhci_writel(xhci, temp, port_array[wIndex] + 1);
break;
case USB_PORT_FEAT_U2_TIMEOUT:
if (hcd->speed != HCD_USB3)
goto error;
temp = xhci_readl(xhci, port_array[wIndex] + 1);
temp &= ~PORT_U2_TIMEOUT_MASK;
temp |= PORT_U2_TIMEOUT(timeout);
xhci_writel(xhci, temp, port_array[wIndex] + 1);
break;
default:
goto error;
}

View File

@ -1791,6 +1791,14 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
{
struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
struct dev_info *dev_info, *next;
struct list_head *tt_list_head;
struct list_head *tt;
struct list_head *endpoints;
struct list_head *ep, *q;
struct xhci_tt_bw_info *tt_info;
struct xhci_interval_bw_table *bwt;
struct xhci_virt_ep *virt_ep;
unsigned long flags;
int size;
int i;
@ -1807,6 +1815,9 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
xhci->event_ring = NULL;
xhci_dbg(xhci, "Freed event ring\n");
if (xhci->lpm_command)
xhci_free_command(xhci, xhci->lpm_command);
xhci->cmd_ring_reserved_trbs = 0;
if (xhci->cmd_ring)
xhci_ring_free(xhci, xhci->cmd_ring);
xhci->cmd_ring = NULL;
@ -1849,8 +1860,26 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
}
spin_unlock_irqrestore(&xhci->lock, flags);
bwt = &xhci->rh_bw->bw_table;
for (i = 0; i < XHCI_MAX_INTERVAL; i++) {
endpoints = &bwt->interval_bw[i].endpoints;
list_for_each_safe(ep, q, endpoints) {
virt_ep = list_entry(ep, struct xhci_virt_ep, bw_endpoint_list);
list_del(&virt_ep->bw_endpoint_list);
kfree(virt_ep);
}
}
tt_list_head = &xhci->rh_bw->tts;
list_for_each_safe(tt, q, tt_list_head) {
tt_info = list_entry(tt, struct xhci_tt_bw_info, tt_list);
list_del(tt);
kfree(tt_info);
}
xhci->num_usb2_ports = 0;
xhci->num_usb3_ports = 0;
xhci->num_active_eps = 0;
kfree(xhci->usb2_ports);
kfree(xhci->usb3_ports);
kfree(xhci->port_array);
@ -2350,6 +2379,16 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring);
xhci_dbg_cmd_ptrs(xhci);
xhci->lpm_command = xhci_alloc_command(xhci, true, true, flags);
if (!xhci->lpm_command)
goto fail;
/* Reserve one command ring TRB for disabling LPM.
* Since the USB core grabs the shared usb_bus bandwidth mutex before
* disabling LPM, we only need to reserve one TRB for all devices.
*/
xhci->cmd_ring_reserved_trbs++;
val = xhci_readl(xhci, &xhci->cap_regs->db_off);
val &= DBOFF_MASK;
xhci_dbg(xhci, "// Doorbell array is located at offset 0x%x"

View File

@ -72,6 +72,7 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
xhci_dbg(xhci, "QUIRK: Fresco Logic revision %u "
"has broken MSI implementation\n",
pdev->revision);
xhci->quirks |= XHCI_TRUST_TX_LENGTH;
}
if (pdev->vendor == PCI_VENDOR_ID_NEC)
@ -83,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;
@ -169,6 +174,13 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
if (retval)
goto put_usb3_hcd;
/* Roothub already marked as USB 3.0 speed */
/* We know the LPM timeout algorithms for this host, let the USB core
* enable and disable LPM for devices under the USB 3.0 roothub.
*/
if (xhci->quirks & XHCI_LPM_SUPPORT)
hcd_to_bus(xhci->shared_hcd)->root_hub->lpm_capable = 1;
return 0;
put_usb3_hcd:
@ -292,6 +304,8 @@ static const struct hc_driver xhci_pci_hc_driver = {
*/
.update_device = xhci_update_device,
.set_usb2_hw_lpm = xhci_set_usb2_hardware_lpm,
.enable_usb3_lpm_timeout = xhci_enable_usb3_lpm_timeout,
.disable_usb3_lpm_timeout = xhci_disable_usb3_lpm_timeout,
};
/*-------------------------------------------------------------------------*/

View File

@ -1787,8 +1787,12 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
/* handle completion code */
switch (trb_comp_code) {
case COMP_SUCCESS:
frame->status = 0;
break;
if (TRB_LEN(le32_to_cpu(event->transfer_len)) == 0) {
frame->status = 0;
break;
}
if ((xhci->quirks & XHCI_TRUST_TX_LENGTH))
trb_comp_code = COMP_SHORT_TX;
case COMP_SHORT_TX:
frame->status = td->urb->transfer_flags & URB_SHORT_NOT_OK ?
-EREMOTEIO : 0;
@ -1885,13 +1889,16 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td,
switch (trb_comp_code) {
case COMP_SUCCESS:
/* Double check that the HW transferred everything. */
if (event_trb != td->last_trb) {
if (event_trb != td->last_trb ||
TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) {
xhci_warn(xhci, "WARN Successful completion "
"on short TX\n");
if (td->urb->transfer_flags & URB_SHORT_NOT_OK)
*status = -EREMOTEIO;
else
*status = 0;
if ((xhci->quirks & XHCI_TRUST_TX_LENGTH))
trb_comp_code = COMP_SHORT_TX;
} else {
*status = 0;
}
@ -2050,6 +2057,13 @@ static int handle_tx_event(struct xhci_hcd *xhci,
* transfer type
*/
case COMP_SUCCESS:
if (TRB_LEN(le32_to_cpu(event->transfer_len)) == 0)
break;
if (xhci->quirks & XHCI_TRUST_TX_LENGTH)
trb_comp_code = COMP_SHORT_TX;
else
xhci_warn(xhci, "WARN Successful completion on short TX: "
"needs XHCI_TRUST_TX_LENGTH quirk?\n");
case COMP_SHORT_TX:
break;
case COMP_STOP:
@ -3595,12 +3609,12 @@ int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
/* Queue an evaluate context command TRB */
int xhci_queue_evaluate_context(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
u32 slot_id)
u32 slot_id, bool command_must_succeed)
{
return queue_command(xhci, lower_32_bits(in_ctx_ptr),
upper_32_bits(in_ctx_ptr), 0,
TRB_TYPE(TRB_EVAL_CONTEXT) | SLOT_ID_FOR_TRB(slot_id),
false);
command_must_succeed);
}
/*

View File

@ -2446,7 +2446,7 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci,
udev->slot_id, must_succeed);
else
ret = xhci_queue_evaluate_context(xhci, in_ctx->dma,
udev->slot_id);
udev->slot_id, must_succeed);
if (ret < 0) {
if (command)
list_del(&command->cmd_list);
@ -3837,6 +3837,458 @@ int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,
return 0;
}
/*---------------------- 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)
{
unsigned long long sel;
unsigned long long pel;
unsigned int max_sel_pel;
char *state_name;
switch (state) {
case USB3_LPM_U1:
/* Convert SEL and PEL stored in nanoseconds to microseconds */
sel = DIV_ROUND_UP(udev->u1_params.sel, 1000);
pel = DIV_ROUND_UP(udev->u1_params.pel, 1000);
max_sel_pel = USB3_LPM_MAX_U1_SEL_PEL;
state_name = "U1";
break;
case USB3_LPM_U2:
sel = DIV_ROUND_UP(udev->u2_params.sel, 1000);
pel = DIV_ROUND_UP(udev->u2_params.pel, 1000);
max_sel_pel = USB3_LPM_MAX_U2_SEL_PEL;
state_name = "U2";
break;
default:
dev_warn(&udev->dev, "%s: Can't get timeout for non-U1 or U2 state.\n",
__func__);
return -EINVAL;
}
if (sel <= max_sel_pel && pel <= max_sel_pel)
return USB3_LPM_DEVICE_INITIATED;
if (sel > max_sel_pel)
dev_dbg(&udev->dev, "Device-initiated %s disabled "
"due to long SEL %llu ms\n",
state_name, sel);
else
dev_dbg(&udev->dev, "Device-initiated %s disabled "
"due to long PEL %llu\n ms",
state_name, pel);
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;
}
static int xhci_update_timeout_for_endpoint(struct xhci_hcd *xhci,
struct usb_device *udev,
struct usb_endpoint_descriptor *desc,
enum usb3_link_state state,
u16 *timeout)
{
u16 alt_timeout;
alt_timeout = xhci_call_host_update_timeout_for_endpoint(xhci, udev,
desc, state, timeout);
/* If we found we can't enable hub-initiated LPM, or
* the U1 or U2 exit latency was too high to allow
* device-initiated LPM as well, just stop searching.
*/
if (alt_timeout == USB3_LPM_DISABLED ||
alt_timeout == USB3_LPM_DEVICE_INITIATED) {
*timeout = alt_timeout;
return -E2BIG;
}
if (alt_timeout > *timeout)
*timeout = alt_timeout;
return 0;
}
static int xhci_update_timeout_for_interface(struct xhci_hcd *xhci,
struct usb_device *udev,
struct usb_host_interface *alt,
enum usb3_link_state state,
u16 *timeout)
{
int j;
for (j = 0; j < alt->desc.bNumEndpoints; j++) {
if (xhci_update_timeout_for_endpoint(xhci, udev,
&alt->endpoint[j].desc, state, timeout))
return -E2BIG;
continue;
}
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;
}
/* Returns the U1 or U2 timeout that should be enabled.
* If the tier check or timeout setting functions return with a non-zero exit
* code, that means the timeout value has been finalized and we shouldn't look
* at any more endpoints.
*/
static u16 xhci_calculate_lpm_timeout(struct usb_hcd *hcd,
struct usb_device *udev, enum usb3_link_state state)
{
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
struct usb_host_config *config;
char *state_name;
int i;
u16 timeout = USB3_LPM_DISABLED;
if (state == USB3_LPM_U1)
state_name = "U1";
else if (state == USB3_LPM_U2)
state_name = "U2";
else {
dev_warn(&udev->dev, "Can't enable unknown link state %i\n",
state);
return timeout;
}
if (xhci_check_tier_policy(xhci, udev, state) < 0)
return timeout;
/* Gather some information about the currently installed configuration
* and alternate interface settings.
*/
if (xhci_update_timeout_for_endpoint(xhci, udev, &udev->ep0.desc,
state, &timeout))
return timeout;
config = udev->actconfig;
if (!config)
return timeout;
for (i = 0; i < USB_MAXINTERFACES; i++) {
struct usb_driver *driver;
struct usb_interface *intf = config->interface[i];
if (!intf)
continue;
/* Check if any currently bound drivers want hub-initiated LPM
* disabled.
*/
if (intf->dev.driver) {
driver = to_usb_driver(intf->dev.driver);
if (driver && driver->disable_hub_initiated_lpm) {
dev_dbg(&udev->dev, "Hub-initiated %s disabled "
"at request of driver %s\n",
state_name, driver->name);
return xhci_get_timeout_no_hub_lpm(udev, state);
}
}
/* Not sure how this could happen... */
if (!intf->cur_altsetting)
continue;
if (xhci_update_timeout_for_interface(xhci, udev,
intf->cur_altsetting,
state, &timeout))
return timeout;
}
return timeout;
}
/*
* Issue an Evaluate Context command to change the Maximum Exit Latency in the
* slot context. If that succeeds, store the new MEL in the xhci_virt_device.
*/
static int xhci_change_max_exit_latency(struct xhci_hcd *xhci,
struct usb_device *udev, u16 max_exit_latency)
{
struct xhci_virt_device *virt_dev;
struct xhci_command *command;
struct xhci_input_control_ctx *ctrl_ctx;
struct xhci_slot_ctx *slot_ctx;
unsigned long flags;
int ret;
spin_lock_irqsave(&xhci->lock, flags);
if (max_exit_latency == xhci->devs[udev->slot_id]->current_mel) {
spin_unlock_irqrestore(&xhci->lock, flags);
return 0;
}
/* Attempt to issue an Evaluate Context command to change the MEL. */
virt_dev = xhci->devs[udev->slot_id];
command = xhci->lpm_command;
xhci_slot_copy(xhci, command->in_ctx, virt_dev->out_ctx);
spin_unlock_irqrestore(&xhci->lock, flags);
ctrl_ctx = xhci_get_input_control_ctx(xhci, command->in_ctx);
ctrl_ctx->add_flags |= cpu_to_le32(SLOT_FLAG);
slot_ctx = xhci_get_slot_ctx(xhci, command->in_ctx);
slot_ctx->dev_info2 &= cpu_to_le32(~((u32) MAX_EXIT));
slot_ctx->dev_info2 |= cpu_to_le32(max_exit_latency);
xhci_dbg(xhci, "Set up evaluate context for LPM MEL change.\n");
xhci_dbg(xhci, "Slot %u Input Context:\n", udev->slot_id);
xhci_dbg_ctx(xhci, command->in_ctx, 0);
/* Issue and wait for the evaluate context command. */
ret = xhci_configure_endpoint(xhci, udev, command,
true, true);
xhci_dbg(xhci, "Slot %u Output Context:\n", udev->slot_id);
xhci_dbg_ctx(xhci, virt_dev->out_ctx, 0);
if (!ret) {
spin_lock_irqsave(&xhci->lock, flags);
virt_dev->current_mel = max_exit_latency;
spin_unlock_irqrestore(&xhci->lock, flags);
}
return ret;
}
static int calculate_max_exit_latency(struct usb_device *udev,
enum usb3_link_state state_changed,
u16 hub_encoded_timeout)
{
unsigned long long u1_mel_us = 0;
unsigned long long u2_mel_us = 0;
unsigned long long mel_us = 0;
bool disabling_u1;
bool disabling_u2;
bool enabling_u1;
bool enabling_u2;
disabling_u1 = (state_changed == USB3_LPM_U1 &&
hub_encoded_timeout == USB3_LPM_DISABLED);
disabling_u2 = (state_changed == USB3_LPM_U2 &&
hub_encoded_timeout == USB3_LPM_DISABLED);
enabling_u1 = (state_changed == USB3_LPM_U1 &&
hub_encoded_timeout != USB3_LPM_DISABLED);
enabling_u2 = (state_changed == USB3_LPM_U2 &&
hub_encoded_timeout != USB3_LPM_DISABLED);
/* If U1 was already enabled and we're not disabling it,
* or we're going to enable U1, account for the U1 max exit latency.
*/
if ((udev->u1_params.timeout != USB3_LPM_DISABLED && !disabling_u1) ||
enabling_u1)
u1_mel_us = DIV_ROUND_UP(udev->u1_params.mel, 1000);
if ((udev->u2_params.timeout != USB3_LPM_DISABLED && !disabling_u2) ||
enabling_u2)
u2_mel_us = DIV_ROUND_UP(udev->u2_params.mel, 1000);
if (u1_mel_us > u2_mel_us)
mel_us = u1_mel_us;
else
mel_us = u2_mel_us;
/* xHCI host controller max exit latency field is only 16 bits wide. */
if (mel_us > MAX_EXIT) {
dev_warn(&udev->dev, "Link PM max exit latency of %lluus "
"is too big.\n", mel_us);
return -E2BIG;
}
return mel_us;
}
/* Returns the USB3 hub-encoded value for the U1/U2 timeout. */
int xhci_enable_usb3_lpm_timeout(struct usb_hcd *hcd,
struct usb_device *udev, enum usb3_link_state state)
{
struct xhci_hcd *xhci;
u16 hub_encoded_timeout;
int mel;
int ret;
xhci = hcd_to_xhci(hcd);
/* The LPM timeout values are pretty host-controller specific, so don't
* enable hub-initiated timeouts unless the vendor has provided
* information about their timeout algorithm.
*/
if (!xhci || !(xhci->quirks & XHCI_LPM_SUPPORT) ||
!xhci->devs[udev->slot_id])
return USB3_LPM_DISABLED;
hub_encoded_timeout = xhci_calculate_lpm_timeout(hcd, udev, state);
mel = calculate_max_exit_latency(udev, state, hub_encoded_timeout);
if (mel < 0) {
/* Max Exit Latency is too big, disable LPM. */
hub_encoded_timeout = USB3_LPM_DISABLED;
mel = 0;
}
ret = xhci_change_max_exit_latency(xhci, udev, mel);
if (ret)
return ret;
return hub_encoded_timeout;
}
int xhci_disable_usb3_lpm_timeout(struct usb_hcd *hcd,
struct usb_device *udev, enum usb3_link_state state)
{
struct xhci_hcd *xhci;
u16 mel;
int ret;
xhci = hcd_to_xhci(hcd);
if (!xhci || !(xhci->quirks & XHCI_LPM_SUPPORT) ||
!xhci->devs[udev->slot_id])
return 0;
mel = calculate_max_exit_latency(udev, state, USB3_LPM_DISABLED);
ret = xhci_change_max_exit_latency(xhci, udev, mel);
if (ret)
return ret;
return 0;
}
/*-------------------------------------------------------------------------*/
int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev)
{
struct xhci_hcd *xhci = hcd_to_xhci(hcd);

View File

@ -362,8 +362,10 @@ struct xhci_op_regs {
* Timeout can be up to 127us. 0xFF means an infinite timeout.
*/
#define PORT_U1_TIMEOUT(p) ((p) & 0xff)
#define PORT_U1_TIMEOUT_MASK 0xff
/* Inactivity timer value for transitions into U2 */
#define PORT_U2_TIMEOUT(p) (((p) & 0xff) << 8)
#define PORT_U2_TIMEOUT_MASK (0xff << 8)
/* Bits 24:31 for port testing */
/* USB2 Protocol PORTSPMSC */
@ -914,6 +916,8 @@ struct xhci_virt_device {
u8 real_port;
struct xhci_interval_bw_table *bw_table;
struct xhci_tt_bw_info *tt_info;
/* The current max exit latency for the enabled USB3 link states. */
u16 current_mel;
};
/*
@ -1424,6 +1428,8 @@ struct xhci_hcd {
/* slot enabling and address device helpers */
struct completion addr_dev;
int slot_id;
/* For USB 3.0 LPM enable/disable. */
struct xhci_command *lpm_command;
/* Internal mirror of the HW's dcbaa */
struct xhci_virt_device *devs[MAX_HC_SLOTS];
/* For keeping track of bandwidth domains per roothub. */
@ -1481,6 +1487,9 @@ struct xhci_hcd {
#define XHCI_RESET_ON_RESUME (1 << 7)
#define XHCI_SW_BW_CHECKING (1 << 8)
#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 */
@ -1754,7 +1763,7 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags,
int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
u32 slot_id, bool command_must_succeed);
int xhci_queue_evaluate_context(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
u32 slot_id);
u32 slot_id, bool command_must_succeed);
int xhci_queue_reset_ep(struct xhci_hcd *xhci, int slot_id,
unsigned int ep_index);
int xhci_queue_reset_device(struct xhci_hcd *xhci, u32 slot_id);
@ -1778,6 +1787,10 @@ void xhci_ring_ep_doorbell(struct xhci_hcd *xhci, unsigned int slot_id,
/* xHCI roothub code */
void xhci_set_link_state(struct xhci_hcd *xhci, __le32 __iomem **port_array,
int port_id, u32 link_state);
int xhci_enable_usb3_lpm_timeout(struct usb_hcd *hcd,
struct usb_device *udev, enum usb3_link_state state);
int xhci_disable_usb3_lpm_timeout(struct usb_hcd *hcd,
struct usb_device *udev, enum usb3_link_state state);
void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array,
int port_id, u32 port_bit);
int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex,

View File

@ -378,6 +378,45 @@ enum usb_device_removable {
USB_DEVICE_FIXED,
};
/*
* USB 3.0 Link Power Management (LPM) parameters.
*
* PEL and SEL are USB 3.0 Link PM latencies for device-initiated LPM exit.
* MEL is the USB 3.0 Link PM latency for host-initiated LPM exit.
* All three are stored in nanoseconds.
*/
struct usb3_lpm_parameters {
/*
* Maximum exit latency (MEL) for the host to send a packet to the
* device (either a Ping for isoc endpoints, or a data packet for
* interrupt endpoints), the hubs to decode the packet, and for all hubs
* in the path to transition the links to U0.
*/
unsigned int mel;
/*
* Maximum exit latency for a device-initiated LPM transition to bring
* all links into U0. Abbreviated as "PEL" in section 9.4.12 of the USB
* 3.0 spec, with no explanation of what "P" stands for. "Path"?
*/
unsigned int pel;
/*
* The System Exit Latency (SEL) includes PEL, and three other
* latencies. After a device initiates a U0 transition, it will take
* some time from when the device sends the ERDY to when it will finally
* receive the data packet. Basically, SEL should be the worse-case
* latency from when a device starts initiating a U0 transition to when
* it will get data.
*/
unsigned int sel;
/*
* The idle timeout value that is currently programmed into the parent
* hub for this device. When the timer counts to zero, the parent hub
* will initiate an LPM transition to either U1 or U2.
*/
int timeout;
};
/**
* struct usb_device - kernel's representation of a USB device
* @devnum: device number; address on a USB bus
@ -435,6 +474,12 @@ enum usb_device_removable {
* specific data for the device.
* @slot_id: Slot ID assigned by xHCI
* @removable: Device can be physically removed from this port
* @u1_params: exit latencies for USB3 U1 LPM state, and hub-initiated timeout.
* @u2_params: exit latencies for USB3 U2 LPM state, and hub-initiated timeout.
* @lpm_disable_count: Ref count used by usb_disable_lpm() and usb_enable_lpm()
* to keep track of the number of functions that require USB 3.0 Link Power
* Management to be disabled for this usb_device. This count should only
* be manipulated by those functions, with the bandwidth_mutex is held.
*
* Notes:
* Usbcore drivers should not set usbdev->state directly. Instead use
@ -481,6 +526,7 @@ struct usb_device {
unsigned lpm_capable:1;
unsigned usb2_hw_lpm_capable:1;
unsigned usb2_hw_lpm_enabled:1;
unsigned usb3_lpm_enabled:1;
int string_langid;
/* static strings from the device */
@ -507,6 +553,10 @@ struct usb_device {
struct wusb_dev *wusb_dev;
int slot_id;
enum usb_device_removable removable;
struct usb3_lpm_parameters u1_params;
struct usb3_lpm_parameters u2_params;
unsigned lpm_disable_count;
unsigned hub_initiated_lpm_disable_count;
};
#define to_usb_device(d) container_of(d, struct usb_device, dev)
@ -542,6 +592,12 @@ extern void usb_autopm_put_interface_async(struct usb_interface *intf);
extern void usb_autopm_get_interface_no_resume(struct usb_interface *intf);
extern void usb_autopm_put_interface_no_suspend(struct usb_interface *intf);
extern int usb_disable_lpm(struct usb_device *udev);
extern void usb_enable_lpm(struct usb_device *udev);
/* Same as above, but these functions lock/unlock the bandwidth_mutex. */
extern int usb_unlocked_disable_lpm(struct usb_device *udev);
extern void usb_unlocked_enable_lpm(struct usb_device *udev);
static inline void usb_mark_last_busy(struct usb_device *udev)
{
pm_runtime_mark_last_busy(&udev->dev);
@ -842,6 +898,9 @@ struct usbdrv_wrap {
* for interfaces bound to this driver.
* @soft_unbind: if set to 1, the USB core will not kill URBs and disable
* endpoints before calling the driver's disconnect method.
* @disable_hub_initiated_lpm: if set to 0, the USB core will not allow hubs
* to initiate lower power link state transitions when an idle timeout
* occurs. Device-initiated USB 3.0 link PM will still be allowed.
*
* USB interface drivers must provide a name, probe() and disconnect()
* methods, and an id_table. Other driver fields are optional.
@ -882,6 +941,7 @@ struct usb_driver {
struct usbdrv_wrap drvwrap;
unsigned int no_dynamic_id:1;
unsigned int supports_autosuspend:1;
unsigned int disable_hub_initiated_lpm:1;
unsigned int soft_unbind:1;
};
#define to_usb_driver(d) container_of(d, struct usb_driver, drvwrap.driver)

View File

@ -76,6 +76,8 @@
#define USB_PORT_FEAT_C_BH_PORT_RESET 29
#define USB_PORT_FEAT_FORCE_LINKPM_ACCEPT 30
#define USB_PORT_LPM_TIMEOUT(p) (((p) & 0xff) << 8)
/* USB 3.0 hub remote wake mask bits, see table 10-14 */
#define USB_PORT_FEAT_REMOTE_WAKE_CONNECT (1 << 8)
#define USB_PORT_FEAT_REMOTE_WAKE_DISCONNECT (1 << 9)

View File

@ -392,6 +392,11 @@ struct usb_endpoint_descriptor {
#define USB_ENDPOINT_XFER_INT 3
#define USB_ENDPOINT_MAX_ADJUSTABLE 0x80
/* The USB 3.0 spec redefines bits 5:4 of bmAttributes as interrupt ep type. */
#define USB_ENDPOINT_INTRTYPE 0x30
#define USB_ENDPOINT_INTR_PERIODIC (0 << 4)
#define USB_ENDPOINT_INTR_NOTIFICATION (1 << 4)
#define USB_ENDPOINT_SYNCTYPE 0x0c
#define USB_ENDPOINT_SYNC_NONE (0 << 2)
#define USB_ENDPOINT_SYNC_ASYNC (1 << 2)
@ -594,6 +599,12 @@ static inline int usb_endpoint_maxp(const struct usb_endpoint_descriptor *epd)
return __le16_to_cpu(epd->wMaxPacketSize);
}
static inline int usb_endpoint_interrupt_type(
const struct usb_endpoint_descriptor *epd)
{
return epd->bmAttributes & USB_ENDPOINT_INTRTYPE;
}
/*-------------------------------------------------------------------------*/
/* USB_DT_SS_ENDPOINT_COMP: SuperSpeed Endpoint Companion descriptor */
@ -935,6 +946,51 @@ enum usb_device_state {
*/
};
enum usb3_link_state {
USB3_LPM_U0 = 0,
USB3_LPM_U1,
USB3_LPM_U2,
USB3_LPM_U3
};
/*
* A U1 timeout of 0x0 means the parent hub will reject any transitions to U1.
* 0xff means the parent hub will accept transitions to U1, but will not
* initiate a transition.
*
* A U1 timeout of 0x1 to 0x7F also causes the hub to initiate a transition to
* U1 after that many microseconds. Timeouts of 0x80 to 0xFE are reserved
* values.
*
* A U2 timeout of 0x0 means the parent hub will reject any transitions to U2.
* 0xff means the parent hub will accept transitions to U2, but will not
* initiate a transition.
*
* A U2 timeout of 0x1 to 0xFE also causes the hub to initiate a transition to
* U2 after N*256 microseconds. Therefore a U2 timeout value of 0x1 means a U2
* idle timer of 256 microseconds, 0x2 means 512 microseconds, 0xFE means
* 65.024ms.
*/
#define USB3_LPM_DISABLED 0x0
#define USB3_LPM_U1_MAX_TIMEOUT 0x7F
#define USB3_LPM_U2_MAX_TIMEOUT 0xFE
#define USB3_LPM_DEVICE_INITIATED 0xFF
struct usb_set_sel_req {
__u8 u1_sel;
__u8 u1_pel;
__le16 u2_sel;
__le16 u2_pel;
} __attribute__ ((packed));
/*
* The Set System Exit Latency control transfer provides one byte each for
* U1 SEL and U1 PEL, so the max exit latency is 0xFF. U2 SEL and U2 PEL each
* are two bytes long.
*/
#define USB3_LPM_MAX_U1_SEL_PEL 0xFF
#define USB3_LPM_MAX_U2_SEL_PEL 0xFFFF
/*-------------------------------------------------------------------------*/
/*

View File

@ -344,6 +344,15 @@ struct hc_driver {
*/
int (*update_device)(struct usb_hcd *, struct usb_device *);
int (*set_usb2_hw_lpm)(struct usb_hcd *, struct usb_device *, int);
/* USB 3.0 Link Power Management */
/* Returns the USB3 hub-encoded value for the U1/U2 timeout. */
int (*enable_usb3_lpm_timeout)(struct usb_hcd *,
struct usb_device *, enum usb3_link_state state);
/* The xHCI host controller can still fail the command to
* disable the LPM timeouts, so this can return an error code.
*/
int (*disable_usb3_lpm_timeout)(struct usb_hcd *,
struct usb_device *, enum usb3_link_state state);
};
extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);