diff options
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/core/hub.c | 87 | ||||
-rw-r--r-- | drivers/usb/core/message.c | 3 |
2 files changed, 84 insertions, 6 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 5c31d2c2f95a..b5bd6bd8fd12 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c | |||
@@ -2610,6 +2610,57 @@ static int check_port_resume_type(struct usb_device *udev, | |||
2610 | return status; | 2610 | return status; |
2611 | } | 2611 | } |
2612 | 2612 | ||
2613 | static bool usb_device_supports_ltm(struct usb_device *udev) | ||
2614 | { | ||
2615 | if (udev->speed != USB_SPEED_SUPER || !udev->bos || !udev->bos->ss_cap) | ||
2616 | return false; | ||
2617 | return udev->bos->ss_cap->bmAttributes & USB_LTM_SUPPORT; | ||
2618 | } | ||
2619 | |||
2620 | int usb_disable_ltm(struct usb_device *udev) | ||
2621 | { | ||
2622 | struct usb_hcd *hcd = bus_to_hcd(udev->bus); | ||
2623 | |||
2624 | /* Check if the roothub and device supports LTM. */ | ||
2625 | if (!usb_device_supports_ltm(hcd->self.root_hub) || | ||
2626 | !usb_device_supports_ltm(udev)) | ||
2627 | return 0; | ||
2628 | |||
2629 | /* Clear Feature LTM Enable can only be sent if the device is | ||
2630 | * configured. | ||
2631 | */ | ||
2632 | if (!udev->actconfig) | ||
2633 | return 0; | ||
2634 | |||
2635 | return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), | ||
2636 | USB_REQ_CLEAR_FEATURE, USB_RECIP_DEVICE, | ||
2637 | USB_DEVICE_LTM_ENABLE, 0, NULL, 0, | ||
2638 | USB_CTRL_SET_TIMEOUT); | ||
2639 | } | ||
2640 | EXPORT_SYMBOL_GPL(usb_disable_ltm); | ||
2641 | |||
2642 | void usb_enable_ltm(struct usb_device *udev) | ||
2643 | { | ||
2644 | struct usb_hcd *hcd = bus_to_hcd(udev->bus); | ||
2645 | |||
2646 | /* Check if the roothub and device supports LTM. */ | ||
2647 | if (!usb_device_supports_ltm(hcd->self.root_hub) || | ||
2648 | !usb_device_supports_ltm(udev)) | ||
2649 | return; | ||
2650 | |||
2651 | /* Set Feature LTM Enable can only be sent if the device is | ||
2652 | * configured. | ||
2653 | */ | ||
2654 | if (!udev->actconfig) | ||
2655 | return; | ||
2656 | |||
2657 | usb_control_msg(udev, usb_sndctrlpipe(udev, 0), | ||
2658 | USB_REQ_SET_FEATURE, USB_RECIP_DEVICE, | ||
2659 | USB_DEVICE_LTM_ENABLE, 0, NULL, 0, | ||
2660 | USB_CTRL_SET_TIMEOUT); | ||
2661 | } | ||
2662 | EXPORT_SYMBOL_GPL(usb_enable_ltm); | ||
2663 | |||
2613 | #ifdef CONFIG_USB_SUSPEND | 2664 | #ifdef CONFIG_USB_SUSPEND |
2614 | 2665 | ||
2615 | /* | 2666 | /* |
@@ -2705,6 +2756,11 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) | |||
2705 | if (udev->usb2_hw_lpm_enabled == 1) | 2756 | if (udev->usb2_hw_lpm_enabled == 1) |
2706 | usb_set_usb2_hardware_lpm(udev, 0); | 2757 | usb_set_usb2_hardware_lpm(udev, 0); |
2707 | 2758 | ||
2759 | if (usb_disable_ltm(udev)) { | ||
2760 | dev_err(&udev->dev, "%s Failed to disable LTM before suspend\n.", | ||
2761 | __func__); | ||
2762 | return -ENOMEM; | ||
2763 | } | ||
2708 | if (usb_unlocked_disable_lpm(udev)) { | 2764 | if (usb_unlocked_disable_lpm(udev)) { |
2709 | dev_err(&udev->dev, "%s Failed to disable LPM before suspend\n.", | 2765 | dev_err(&udev->dev, "%s Failed to disable LPM before suspend\n.", |
2710 | __func__); | 2766 | __func__); |
@@ -2734,7 +2790,8 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) | |||
2734 | if (udev->usb2_hw_lpm_capable == 1) | 2790 | if (udev->usb2_hw_lpm_capable == 1) |
2735 | usb_set_usb2_hardware_lpm(udev, 1); | 2791 | usb_set_usb2_hardware_lpm(udev, 1); |
2736 | 2792 | ||
2737 | /* Try to enable USB3 LPM again */ | 2793 | /* Try to enable USB3 LTM and LPM again */ |
2794 | usb_enable_ltm(udev); | ||
2738 | usb_unlocked_enable_lpm(udev); | 2795 | usb_unlocked_enable_lpm(udev); |
2739 | 2796 | ||
2740 | /* System sleep transitions should never fail */ | 2797 | /* System sleep transitions should never fail */ |
@@ -2935,7 +2992,8 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) | |||
2935 | if (udev->usb2_hw_lpm_capable == 1) | 2992 | if (udev->usb2_hw_lpm_capable == 1) |
2936 | usb_set_usb2_hardware_lpm(udev, 1); | 2993 | usb_set_usb2_hardware_lpm(udev, 1); |
2937 | 2994 | ||
2938 | /* Try to enable USB3 LPM */ | 2995 | /* Try to enable USB3 LTM and LPM */ |
2996 | usb_enable_ltm(udev); | ||
2939 | usb_unlocked_enable_lpm(udev); | 2997 | usb_unlocked_enable_lpm(udev); |
2940 | } | 2998 | } |
2941 | 2999 | ||
@@ -3488,6 +3546,15 @@ EXPORT_SYMBOL_GPL(usb_unlocked_disable_lpm); | |||
3488 | 3546 | ||
3489 | void usb_unlocked_enable_lpm(struct usb_device *udev) { } | 3547 | void usb_unlocked_enable_lpm(struct usb_device *udev) { } |
3490 | EXPORT_SYMBOL_GPL(usb_unlocked_enable_lpm); | 3548 | EXPORT_SYMBOL_GPL(usb_unlocked_enable_lpm); |
3549 | |||
3550 | int usb_disable_ltm(struct usb_device *udev) | ||
3551 | { | ||
3552 | return 0; | ||
3553 | } | ||
3554 | EXPORT_SYMBOL_GPL(usb_disable_ltm); | ||
3555 | |||
3556 | void usb_enable_ltm(struct usb_device *udev) { } | ||
3557 | EXPORT_SYMBOL_GPL(usb_enable_ltm); | ||
3491 | #endif | 3558 | #endif |
3492 | 3559 | ||
3493 | 3560 | ||
@@ -4673,15 +4740,22 @@ static int usb_reset_and_verify_device(struct usb_device *udev) | |||
4673 | } | 4740 | } |
4674 | parent_hub = hdev_to_hub(parent_hdev); | 4741 | parent_hub = hdev_to_hub(parent_hdev); |
4675 | 4742 | ||
4676 | /* Disable LPM while we reset the device and reinstall the alt settings. | 4743 | /* Disable LPM and LTM while we reset the device and reinstall the alt |
4677 | * Device-initiated LPM settings, and system exit latency settings are | 4744 | * settings. Device-initiated LPM settings, and system exit latency |
4678 | * cleared when the device is reset, so we have to set them up again. | 4745 | * settings are cleared when the device is reset, so we have to set |
4746 | * them up again. | ||
4679 | */ | 4747 | */ |
4680 | ret = usb_unlocked_disable_lpm(udev); | 4748 | ret = usb_unlocked_disable_lpm(udev); |
4681 | if (ret) { | 4749 | if (ret) { |
4682 | dev_err(&udev->dev, "%s Failed to disable LPM\n.", __func__); | 4750 | dev_err(&udev->dev, "%s Failed to disable LPM\n.", __func__); |
4683 | goto re_enumerate; | 4751 | goto re_enumerate; |
4684 | } | 4752 | } |
4753 | ret = usb_disable_ltm(udev); | ||
4754 | if (ret) { | ||
4755 | dev_err(&udev->dev, "%s Failed to disable LTM\n.", | ||
4756 | __func__); | ||
4757 | goto re_enumerate; | ||
4758 | } | ||
4685 | 4759 | ||
4686 | set_bit(port1, parent_hub->busy_bits); | 4760 | set_bit(port1, parent_hub->busy_bits); |
4687 | for (i = 0; i < SET_CONFIG_TRIES; ++i) { | 4761 | for (i = 0; i < SET_CONFIG_TRIES; ++i) { |
@@ -4769,8 +4843,9 @@ static int usb_reset_and_verify_device(struct usb_device *udev) | |||
4769 | } | 4843 | } |
4770 | 4844 | ||
4771 | done: | 4845 | done: |
4772 | /* Now that the alt settings are re-installed, enable LPM. */ | 4846 | /* Now that the alt settings are re-installed, enable LTM and LPM. */ |
4773 | usb_unlocked_enable_lpm(udev); | 4847 | usb_unlocked_enable_lpm(udev); |
4848 | usb_enable_ltm(udev); | ||
4774 | return 0; | 4849 | return 0; |
4775 | 4850 | ||
4776 | re_enumerate: | 4851 | re_enumerate: |
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index c0877b7f505a..0ab7da2283e3 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c | |||
@@ -1175,6 +1175,7 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0) | |||
1175 | dev->actconfig->interface[i] = NULL; | 1175 | dev->actconfig->interface[i] = NULL; |
1176 | } | 1176 | } |
1177 | usb_unlocked_disable_lpm(dev); | 1177 | usb_unlocked_disable_lpm(dev); |
1178 | usb_disable_ltm(dev); | ||
1178 | dev->actconfig = NULL; | 1179 | dev->actconfig = NULL; |
1179 | if (dev->state == USB_STATE_CONFIGURED) | 1180 | if (dev->state == USB_STATE_CONFIGURED) |
1180 | usb_set_device_state(dev, USB_STATE_ADDRESS); | 1181 | usb_set_device_state(dev, USB_STATE_ADDRESS); |
@@ -1879,6 +1880,8 @@ free_interfaces: | |||
1879 | 1880 | ||
1880 | /* Now that the interfaces are installed, re-enable LPM. */ | 1881 | /* Now that the interfaces are installed, re-enable LPM. */ |
1881 | usb_unlocked_enable_lpm(dev); | 1882 | usb_unlocked_enable_lpm(dev); |
1883 | /* Enable LTM if it was turned off by usb_disable_device. */ | ||
1884 | usb_enable_ltm(dev); | ||
1882 | 1885 | ||
1883 | /* Now that all the interfaces are set up, register them | 1886 | /* Now that all the interfaces are set up, register them |
1884 | * to trigger binding of drivers to interfaces. probe() | 1887 | * to trigger binding of drivers to interfaces. probe() |