aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/xhci.c
diff options
context:
space:
mode:
authorSarah Sharp <sarah.a.sharp@linux.intel.com>2012-05-09 13:55:03 -0400
committerSarah Sharp <sarah.a.sharp@linux.intel.com>2012-05-18 18:42:03 -0400
commit3b3db026414bba1c8f45c49d5eeaefd48d66e1ae (patch)
tree7ecc41b7c5e440b5da8671caa6e33fcd5cac9b27 /drivers/usb/host/xhci.c
parent6538eafc7cb6b2d718d2539bef3158bfaad57468 (diff)
xhci: Add infrastructure for host-specific LPM policies.
The choice of U1 and U2 timeouts for USB 3.0 Link Power Management (LPM) is highly host controller specific. Here are a few examples of why it's host specific: 1. Setting the U1/U2 timeout too short may cause the link to go into U1/U2 in between service intervals, which some hosts may tolerate, and some may not. 2. The host controller has to modify its bus schedule in order to take into account the Maximum Exit Latency (MEL) to bring all the links from the host to the device into U0. If the MEL is too big, and it takes too long to bring the links into an active state, the host controller may not be able to service periodic endpoints in time. 3. Host controllers may also have scheduling limitations that force them to disable U1 or U2 if a USB device is behind too many tiers of hubs. We could take an educated guess at what U1/U2 timeouts may work for a particular host controller. However, that would result in a binary search on every new configuration or alt setting installation, with multiple failed Evaluate Context commands. Worse, the host may blindly accept the timeouts and just fail to update its schedule for U1/U2 exit latencies, which could result in randomly delayed periodic transfers. Since we don't want to cause jitter in periodic transfers, or delay config/alt setting changes too much, lay down a framework that xHCI vendors can extend in order to add their own U1/U2 timeout policies. To extend the framework, they will need to: - Modify the PCI init code to add a new xhci->quirk for their host, and set the XHCI_LPM_SUPPORT quirk flag. - Add their own vendor-specific hooks, like the ones that will be added in xhci_call_host_update_timeout_for_endpoint() and xhci_check_tier_policy() - Make the LPM enable/disable methods call those functions based on the xhci->quirk for their host. An example will be provided for the Intel xHCI host controller in the next patch. Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Diffstat (limited to 'drivers/usb/host/xhci.c')
-rw-r--r--drivers/usb/host/xhci.c319
1 files changed, 319 insertions, 0 deletions
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 05034f346fad..518d002d54cc 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -3837,6 +3837,325 @@ int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,
3837 return 0; 3837 return 0;
3838} 3838}
3839 3839
3840/*---------------------- USB 3.0 Link PM functions ------------------------*/
3841
3842static u16 xhci_get_timeout_no_hub_lpm(struct usb_device *udev,
3843 enum usb3_link_state state)
3844{
3845 unsigned long long sel;
3846 unsigned long long pel;
3847 unsigned int max_sel_pel;
3848 char *state_name;
3849
3850 switch (state) {
3851 case USB3_LPM_U1:
3852 /* Convert SEL and PEL stored in nanoseconds to microseconds */
3853 sel = DIV_ROUND_UP(udev->u1_params.sel, 1000);
3854 pel = DIV_ROUND_UP(udev->u1_params.pel, 1000);
3855 max_sel_pel = USB3_LPM_MAX_U1_SEL_PEL;
3856 state_name = "U1";
3857 break;
3858 case USB3_LPM_U2:
3859 sel = DIV_ROUND_UP(udev->u2_params.sel, 1000);
3860 pel = DIV_ROUND_UP(udev->u2_params.pel, 1000);
3861 max_sel_pel = USB3_LPM_MAX_U2_SEL_PEL;
3862 state_name = "U2";
3863 break;
3864 default:
3865 dev_warn(&udev->dev, "%s: Can't get timeout for non-U1 or U2 state.\n",
3866 __func__);
3867 return -EINVAL;
3868 }
3869
3870 if (sel <= max_sel_pel && pel <= max_sel_pel)
3871 return USB3_LPM_DEVICE_INITIATED;
3872
3873 if (sel > max_sel_pel)
3874 dev_dbg(&udev->dev, "Device-initiated %s disabled "
3875 "due to long SEL %llu ms\n",
3876 state_name, sel);
3877 else
3878 dev_dbg(&udev->dev, "Device-initiated %s disabled "
3879 "due to long PEL %llu\n ms",
3880 state_name, pel);
3881 return USB3_LPM_DISABLED;
3882}
3883
3884static u16 xhci_call_host_update_timeout_for_endpoint(struct xhci_hcd *xhci,
3885 struct usb_device *udev,
3886 struct usb_endpoint_descriptor *desc,
3887 enum usb3_link_state state,
3888 u16 *timeout)
3889{
3890 return USB3_LPM_DISABLED;
3891}
3892
3893static int xhci_update_timeout_for_endpoint(struct xhci_hcd *xhci,
3894 struct usb_device *udev,
3895 struct usb_endpoint_descriptor *desc,
3896 enum usb3_link_state state,
3897 u16 *timeout)
3898{
3899 u16 alt_timeout;
3900
3901 alt_timeout = xhci_call_host_update_timeout_for_endpoint(xhci, udev,
3902 desc, state, timeout);
3903
3904 /* If we found we can't enable hub-initiated LPM, or
3905 * the U1 or U2 exit latency was too high to allow
3906 * device-initiated LPM as well, just stop searching.
3907 */
3908 if (alt_timeout == USB3_LPM_DISABLED ||
3909 alt_timeout == USB3_LPM_DEVICE_INITIATED) {
3910 *timeout = alt_timeout;
3911 return -E2BIG;
3912 }
3913 if (alt_timeout > *timeout)
3914 *timeout = alt_timeout;
3915 return 0;
3916}
3917
3918static int xhci_update_timeout_for_interface(struct xhci_hcd *xhci,
3919 struct usb_device *udev,
3920 struct usb_host_interface *alt,
3921 enum usb3_link_state state,
3922 u16 *timeout)
3923{
3924 int j;
3925
3926 for (j = 0; j < alt->desc.bNumEndpoints; j++) {
3927 if (xhci_update_timeout_for_endpoint(xhci, udev,
3928 &alt->endpoint[j].desc, state, timeout))
3929 return -E2BIG;
3930 continue;
3931 }
3932 return 0;
3933}
3934
3935static int xhci_check_tier_policy(struct xhci_hcd *xhci,
3936 struct usb_device *udev,
3937 enum usb3_link_state state)
3938{
3939 return -EINVAL;
3940}
3941
3942/* Returns the U1 or U2 timeout that should be enabled.
3943 * If the tier check or timeout setting functions return with a non-zero exit
3944 * code, that means the timeout value has been finalized and we shouldn't look
3945 * at any more endpoints.
3946 */
3947static u16 xhci_calculate_lpm_timeout(struct usb_hcd *hcd,
3948 struct usb_device *udev, enum usb3_link_state state)
3949{
3950 struct xhci_hcd *xhci = hcd_to_xhci(hcd);
3951 struct usb_host_config *config;
3952 char *state_name;
3953 int i;
3954 u16 timeout = USB3_LPM_DISABLED;
3955
3956 if (state == USB3_LPM_U1)
3957 state_name = "U1";
3958 else if (state == USB3_LPM_U2)
3959 state_name = "U2";
3960 else {
3961 dev_warn(&udev->dev, "Can't enable unknown link state %i\n",
3962 state);
3963 return timeout;
3964 }
3965
3966 if (xhci_check_tier_policy(xhci, udev, state) < 0)
3967 return timeout;
3968
3969 /* Gather some information about the currently installed configuration
3970 * and alternate interface settings.
3971 */
3972 if (xhci_update_timeout_for_endpoint(xhci, udev, &udev->ep0.desc,
3973 state, &timeout))
3974 return timeout;
3975
3976 config = udev->actconfig;
3977 if (!config)
3978 return timeout;
3979
3980 for (i = 0; i < USB_MAXINTERFACES; i++) {
3981 struct usb_driver *driver;
3982 struct usb_interface *intf = config->interface[i];
3983
3984 if (!intf)
3985 continue;
3986
3987 /* Check if any currently bound drivers want hub-initiated LPM
3988 * disabled.
3989 */
3990 if (intf->dev.driver) {
3991 driver = to_usb_driver(intf->dev.driver);
3992 if (driver && driver->disable_hub_initiated_lpm) {
3993 dev_dbg(&udev->dev, "Hub-initiated %s disabled "
3994 "at request of driver %s\n",
3995 state_name, driver->name);
3996 return xhci_get_timeout_no_hub_lpm(udev, state);
3997 }
3998 }
3999
4000 /* Not sure how this could happen... */
4001 if (!intf->cur_altsetting)
4002 continue;
4003
4004 if (xhci_update_timeout_for_interface(xhci, udev,
4005 intf->cur_altsetting,
4006 state, &timeout))
4007 return timeout;
4008 }
4009 return timeout;
4010}
4011
4012/*
4013 * Issue an Evaluate Context command to change the Maximum Exit Latency in the
4014 * slot context. If that succeeds, store the new MEL in the xhci_virt_device.
4015 */
4016static int xhci_change_max_exit_latency(struct xhci_hcd *xhci,
4017 struct usb_device *udev, u16 max_exit_latency)
4018{
4019 struct xhci_virt_device *virt_dev;
4020 struct xhci_command *command;
4021 struct xhci_input_control_ctx *ctrl_ctx;
4022 struct xhci_slot_ctx *slot_ctx;
4023 unsigned long flags;
4024 int ret;
4025
4026 spin_lock_irqsave(&xhci->lock, flags);
4027 if (max_exit_latency == xhci->devs[udev->slot_id]->current_mel) {
4028 spin_unlock_irqrestore(&xhci->lock, flags);
4029 return 0;
4030 }
4031
4032 /* Attempt to issue an Evaluate Context command to change the MEL. */
4033 virt_dev = xhci->devs[udev->slot_id];
4034 command = xhci->lpm_command;
4035 xhci_slot_copy(xhci, command->in_ctx, virt_dev->out_ctx);
4036 spin_unlock_irqrestore(&xhci->lock, flags);
4037
4038 ctrl_ctx = xhci_get_input_control_ctx(xhci, command->in_ctx);
4039 ctrl_ctx->add_flags |= cpu_to_le32(SLOT_FLAG);
4040 slot_ctx = xhci_get_slot_ctx(xhci, command->in_ctx);
4041 slot_ctx->dev_info2 &= cpu_to_le32(~((u32) MAX_EXIT));
4042 slot_ctx->dev_info2 |= cpu_to_le32(max_exit_latency);
4043
4044 xhci_dbg(xhci, "Set up evaluate context for LPM MEL change.\n");
4045 xhci_dbg(xhci, "Slot %u Input Context:\n", udev->slot_id);
4046 xhci_dbg_ctx(xhci, command->in_ctx, 0);
4047
4048 /* Issue and wait for the evaluate context command. */
4049 ret = xhci_configure_endpoint(xhci, udev, command,
4050 true, true);
4051 xhci_dbg(xhci, "Slot %u Output Context:\n", udev->slot_id);
4052 xhci_dbg_ctx(xhci, virt_dev->out_ctx, 0);
4053
4054 if (!ret) {
4055 spin_lock_irqsave(&xhci->lock, flags);
4056 virt_dev->current_mel = max_exit_latency;
4057 spin_unlock_irqrestore(&xhci->lock, flags);
4058 }
4059 return ret;
4060}
4061
4062static int calculate_max_exit_latency(struct usb_device *udev,
4063 enum usb3_link_state state_changed,
4064 u16 hub_encoded_timeout)
4065{
4066 unsigned long long u1_mel_us = 0;
4067 unsigned long long u2_mel_us = 0;
4068 unsigned long long mel_us = 0;
4069 bool disabling_u1;
4070 bool disabling_u2;
4071 bool enabling_u1;
4072 bool enabling_u2;
4073
4074 disabling_u1 = (state_changed == USB3_LPM_U1 &&
4075 hub_encoded_timeout == USB3_LPM_DISABLED);
4076 disabling_u2 = (state_changed == USB3_LPM_U2 &&
4077 hub_encoded_timeout == USB3_LPM_DISABLED);
4078
4079 enabling_u1 = (state_changed == USB3_LPM_U1 &&
4080 hub_encoded_timeout != USB3_LPM_DISABLED);
4081 enabling_u2 = (state_changed == USB3_LPM_U2 &&
4082 hub_encoded_timeout != USB3_LPM_DISABLED);
4083
4084 /* If U1 was already enabled and we're not disabling it,
4085 * or we're going to enable U1, account for the U1 max exit latency.
4086 */
4087 if ((udev->u1_params.timeout != USB3_LPM_DISABLED && !disabling_u1) ||
4088 enabling_u1)
4089 u1_mel_us = DIV_ROUND_UP(udev->u1_params.mel, 1000);
4090 if ((udev->u2_params.timeout != USB3_LPM_DISABLED && !disabling_u2) ||
4091 enabling_u2)
4092 u2_mel_us = DIV_ROUND_UP(udev->u2_params.mel, 1000);
4093
4094 if (u1_mel_us > u2_mel_us)
4095 mel_us = u1_mel_us;
4096 else
4097 mel_us = u2_mel_us;
4098 /* xHCI host controller max exit latency field is only 16 bits wide. */
4099 if (mel_us > MAX_EXIT) {
4100 dev_warn(&udev->dev, "Link PM max exit latency of %lluus "
4101 "is too big.\n", mel_us);
4102 return -E2BIG;
4103 }
4104 return mel_us;
4105}
4106
4107/* Returns the USB3 hub-encoded value for the U1/U2 timeout. */
4108int xhci_enable_usb3_lpm_timeout(struct usb_hcd *hcd,
4109 struct usb_device *udev, enum usb3_link_state state)
4110{
4111 struct xhci_hcd *xhci;
4112 u16 hub_encoded_timeout;
4113 int mel;
4114 int ret;
4115
4116 xhci = hcd_to_xhci(hcd);
4117 /* The LPM timeout values are pretty host-controller specific, so don't
4118 * enable hub-initiated timeouts unless the vendor has provided
4119 * information about their timeout algorithm.
4120 */
4121 if (!xhci || !(xhci->quirks & XHCI_LPM_SUPPORT) ||
4122 !xhci->devs[udev->slot_id])
4123 return USB3_LPM_DISABLED;
4124
4125 hub_encoded_timeout = xhci_calculate_lpm_timeout(hcd, udev, state);
4126 mel = calculate_max_exit_latency(udev, state, hub_encoded_timeout);
4127 if (mel < 0) {
4128 /* Max Exit Latency is too big, disable LPM. */
4129 hub_encoded_timeout = USB3_LPM_DISABLED;
4130 mel = 0;
4131 }
4132
4133 ret = xhci_change_max_exit_latency(xhci, udev, mel);
4134 if (ret)
4135 return ret;
4136 return hub_encoded_timeout;
4137}
4138
4139int xhci_disable_usb3_lpm_timeout(struct usb_hcd *hcd,
4140 struct usb_device *udev, enum usb3_link_state state)
4141{
4142 struct xhci_hcd *xhci;
4143 u16 mel;
4144 int ret;
4145
4146 xhci = hcd_to_xhci(hcd);
4147 if (!xhci || !(xhci->quirks & XHCI_LPM_SUPPORT) ||
4148 !xhci->devs[udev->slot_id])
4149 return 0;
4150
4151 mel = calculate_max_exit_latency(udev, state, USB3_LPM_DISABLED);
4152 ret = xhci_change_max_exit_latency(xhci, udev, mel);
4153 if (ret)
4154 return ret;
4155 return 0;
4156}
4157/*-------------------------------------------------------------------------*/
4158
3840int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev) 4159int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev)
3841{ 4160{
3842 struct xhci_hcd *xhci = hcd_to_xhci(hcd); 4161 struct xhci_hcd *xhci = hcd_to_xhci(hcd);