aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/core/driver.c14
-rw-r--r--drivers/usb/core/hub.c9
-rw-r--r--drivers/usb/core/usb.h5
-rw-r--r--drivers/usb/host/xhci-hub.c9
-rw-r--r--drivers/usb/host/xhci-pci.c1
-rw-r--r--drivers/usb/host/xhci.c74
-rw-r--r--drivers/usb/host/xhci.h4
-rw-r--r--include/linux/usb.h4
-rw-r--r--include/linux/usb/hcd.h1
9 files changed, 120 insertions, 1 deletions
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 14b83f2a4e87..adf5ca8a2396 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -1700,6 +1700,20 @@ int usb_runtime_idle(struct device *dev)
1700 return 0; 1700 return 0;
1701} 1701}
1702 1702
1703int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable)
1704{
1705 struct usb_hcd *hcd = bus_to_hcd(udev->bus);
1706 int ret = -EPERM;
1707
1708 if (hcd->driver->set_usb2_hw_lpm) {
1709 ret = hcd->driver->set_usb2_hw_lpm(hcd, udev, enable);
1710 if (!ret)
1711 udev->usb2_hw_lpm_enabled = enable;
1712 }
1713
1714 return ret;
1715}
1716
1703#endif /* CONFIG_USB_SUSPEND */ 1717#endif /* CONFIG_USB_SUSPEND */
1704 1718
1705struct bus_type usb_bus_type = { 1719struct bus_type usb_bus_type = {
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 4ffc3d1bd9e7..d6cc83249341 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -2392,6 +2392,10 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
2392 } 2392 }
2393 } 2393 }
2394 2394
2395 /* disable USB2 hardware LPM */
2396 if (udev->usb2_hw_lpm_enabled == 1)
2397 usb_set_usb2_hardware_lpm(udev, 0);
2398
2395 /* see 7.1.7.6 */ 2399 /* see 7.1.7.6 */
2396 if (hub_is_superspeed(hub->hdev)) 2400 if (hub_is_superspeed(hub->hdev))
2397 status = set_port_feature(hub->hdev, 2401 status = set_port_feature(hub->hdev,
@@ -2603,7 +2607,12 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)
2603 if (status < 0) { 2607 if (status < 0) {
2604 dev_dbg(&udev->dev, "can't resume, status %d\n", status); 2608 dev_dbg(&udev->dev, "can't resume, status %d\n", status);
2605 hub_port_logical_disconnect(hub, port1); 2609 hub_port_logical_disconnect(hub, port1);
2610 } else {
2611 /* Try to enable USB2 hardware LPM */
2612 if (udev->usb2_hw_lpm_capable == 1)
2613 usb_set_usb2_hardware_lpm(udev, 1);
2606 } 2614 }
2615
2607 return status; 2616 return status;
2608} 2617}
2609 2618
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index 0d023cd2c149..3888778582c4 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -82,6 +82,7 @@ extern int usb_remote_wakeup(struct usb_device *dev);
82extern int usb_runtime_suspend(struct device *dev); 82extern int usb_runtime_suspend(struct device *dev);
83extern int usb_runtime_resume(struct device *dev); 83extern int usb_runtime_resume(struct device *dev);
84extern int usb_runtime_idle(struct device *dev); 84extern int usb_runtime_idle(struct device *dev);
85extern int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable);
85 86
86#else 87#else
87 88
@@ -96,6 +97,10 @@ static inline int usb_remote_wakeup(struct usb_device *udev)
96 return 0; 97 return 0;
97} 98}
98 99
100static inline int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable)
101{
102 return 0;
103}
99#endif 104#endif
100 105
101extern struct bus_type usb_bus_type; 106extern struct bus_type usb_bus_type;
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index d7be6d7324d3..9f844d45c667 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -574,10 +574,19 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
574 switch (wValue) { 574 switch (wValue) {
575 case USB_PORT_FEAT_SUSPEND: 575 case USB_PORT_FEAT_SUSPEND:
576 temp = xhci_readl(xhci, port_array[wIndex]); 576 temp = xhci_readl(xhci, port_array[wIndex]);
577 if ((temp & PORT_PLS_MASK) != XDEV_U0) {
578 /* Resume the port to U0 first */
579 xhci_set_link_state(xhci, port_array, wIndex,
580 XDEV_U0);
581 spin_unlock_irqrestore(&xhci->lock, flags);
582 msleep(10);
583 spin_lock_irqsave(&xhci->lock, flags);
584 }
577 /* In spec software should not attempt to suspend 585 /* In spec software should not attempt to suspend
578 * a port unless the port reports that it is in the 586 * a port unless the port reports that it is in the
579 * enabled (PED = ‘1’,PLS < ‘3’) state. 587 * enabled (PED = ‘1’,PLS < ‘3’) state.
580 */ 588 */
589 temp = xhci_readl(xhci, port_array[wIndex]);
581 if ((temp & PORT_PE) == 0 || (temp & PORT_RESET) 590 if ((temp & PORT_PE) == 0 || (temp & PORT_RESET)
582 || (temp & PORT_PLS_MASK) >= XDEV_U3) { 591 || (temp & PORT_PLS_MASK) >= XDEV_U3) {
583 xhci_warn(xhci, "USB core suspending device " 592 xhci_warn(xhci, "USB core suspending device "
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index 213a7d73b118..e66e2b03fbbe 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -349,6 +349,7 @@ static const struct hc_driver xhci_pci_hc_driver = {
349 * call back when device connected and addressed 349 * call back when device connected and addressed
350 */ 350 */
351 .update_device = xhci_update_device, 351 .update_device = xhci_update_device,
352 .set_usb2_hw_lpm = xhci_set_usb2_hardware_lpm,
352}; 353};
353 354
354/*-------------------------------------------------------------------------*/ 355/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index b0649a4bd315..4648cc0c5721 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -3286,6 +3286,11 @@ void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
3286 del_timer_sync(&virt_dev->eps[i].stop_cmd_timer); 3286 del_timer_sync(&virt_dev->eps[i].stop_cmd_timer);
3287 } 3287 }
3288 3288
3289 if (udev->usb2_hw_lpm_enabled) {
3290 xhci_set_usb2_hardware_lpm(hcd, udev, 0);
3291 udev->usb2_hw_lpm_enabled = 0;
3292 }
3293
3289 spin_lock_irqsave(&xhci->lock, flags); 3294 spin_lock_irqsave(&xhci->lock, flags);
3290 /* Don't disable the slot if the host controller is dead. */ 3295 /* Don't disable the slot if the host controller is dead. */
3291 state = xhci_readl(xhci, &xhci->op_regs->status); 3296 state = xhci_readl(xhci, &xhci->op_regs->status);
@@ -3699,20 +3704,87 @@ finish:
3699 return ret; 3704 return ret;
3700} 3705}
3701 3706
3707int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,
3708 struct usb_device *udev, int enable)
3709{
3710 struct xhci_hcd *xhci = hcd_to_xhci(hcd);
3711 __le32 __iomem **port_array;
3712 __le32 __iomem *pm_addr;
3713 u32 temp;
3714 unsigned int port_num;
3715 unsigned long flags;
3716 int u2del, hird;
3717
3718 if (hcd->speed == HCD_USB3 || !xhci->hw_lpm_support ||
3719 !udev->lpm_capable)
3720 return -EPERM;
3721
3722 if (!udev->parent || udev->parent->parent ||
3723 udev->descriptor.bDeviceClass == USB_CLASS_HUB)
3724 return -EPERM;
3725
3726 if (udev->usb2_hw_lpm_capable != 1)
3727 return -EPERM;
3728
3729 spin_lock_irqsave(&xhci->lock, flags);
3730
3731 port_array = xhci->usb2_ports;
3732 port_num = udev->portnum - 1;
3733 pm_addr = port_array[port_num] + 1;
3734 temp = xhci_readl(xhci, pm_addr);
3735
3736 xhci_dbg(xhci, "%s port %d USB2 hardware LPM\n",
3737 enable ? "enable" : "disable", port_num);
3738
3739 u2del = HCS_U2_LATENCY(xhci->hcs_params3);
3740 if (le32_to_cpu(udev->bos->ext_cap->bmAttributes) & (1 << 2))
3741 hird = xhci_calculate_hird_besl(u2del, 1);
3742 else
3743 hird = xhci_calculate_hird_besl(u2del, 0);
3744
3745 if (enable) {
3746 temp &= ~PORT_HIRD_MASK;
3747 temp |= PORT_HIRD(hird) | PORT_RWE;
3748 xhci_writel(xhci, temp, pm_addr);
3749 temp = xhci_readl(xhci, pm_addr);
3750 temp |= PORT_HLE;
3751 xhci_writel(xhci, temp, pm_addr);
3752 } else {
3753 temp &= ~(PORT_HLE | PORT_RWE | PORT_HIRD_MASK);
3754 xhci_writel(xhci, temp, pm_addr);
3755 }
3756
3757 spin_unlock_irqrestore(&xhci->lock, flags);
3758 return 0;
3759}
3760
3702int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev) 3761int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev)
3703{ 3762{
3704 struct xhci_hcd *xhci = hcd_to_xhci(hcd); 3763 struct xhci_hcd *xhci = hcd_to_xhci(hcd);
3705 int ret; 3764 int ret;
3706 3765
3707 ret = xhci_usb2_software_lpm_test(hcd, udev); 3766 ret = xhci_usb2_software_lpm_test(hcd, udev);
3708 if (!ret) 3767 if (!ret) {
3709 xhci_dbg(xhci, "software LPM test succeed\n"); 3768 xhci_dbg(xhci, "software LPM test succeed\n");
3769 if (xhci->hw_lpm_support == 1) {
3770 udev->usb2_hw_lpm_capable = 1;
3771 ret = xhci_set_usb2_hardware_lpm(hcd, udev, 1);
3772 if (!ret)
3773 udev->usb2_hw_lpm_enabled = 1;
3774 }
3775 }
3710 3776
3711 return 0; 3777 return 0;
3712} 3778}
3713 3779
3714#else 3780#else
3715 3781
3782int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,
3783 struct usb_device *udev, int enable)
3784{
3785 return 0;
3786}
3787
3716int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev) 3788int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev)
3717{ 3789{
3718 return 0; 3790 return 0;
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index b24c4fce457e..e738466703a5 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -367,7 +367,9 @@ struct xhci_op_regs {
367#define PORT_L1S_SUCCESS 1 367#define PORT_L1S_SUCCESS 1
368#define PORT_RWE (1 << 3) 368#define PORT_RWE (1 << 3)
369#define PORT_HIRD(p) (((p) & 0xf) << 4) 369#define PORT_HIRD(p) (((p) & 0xf) << 4)
370#define PORT_HIRD_MASK (0xf << 4)
370#define PORT_L1DS(p) (((p) & 0xff) << 8) 371#define PORT_L1DS(p) (((p) & 0xff) << 8)
372#define PORT_HLE (1 << 16)
371 373
372/** 374/**
373 * struct xhci_intr_reg - Interrupt Register Set 375 * struct xhci_intr_reg - Interrupt Register Set
@@ -1677,6 +1679,8 @@ int xhci_free_streams(struct usb_hcd *hcd, struct usb_device *udev,
1677 gfp_t mem_flags); 1679 gfp_t mem_flags);
1678int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev); 1680int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev);
1679int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev); 1681int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev);
1682int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,
1683 struct usb_device *udev, int enable);
1680int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev, 1684int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev,
1681 struct usb_tt *tt, gfp_t mem_flags); 1685 struct usb_tt *tt, gfp_t mem_flags);
1682int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags); 1686int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags);
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 1d00d9bc5d65..6f49a1b39fa6 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -411,6 +411,8 @@ struct usb_tt;
411 * @authenticated: Crypto authentication passed 411 * @authenticated: Crypto authentication passed
412 * @wusb: device is Wireless USB 412 * @wusb: device is Wireless USB
413 * @lpm_capable: device supports LPM 413 * @lpm_capable: device supports LPM
414 * @usb2_hw_lpm_capable: device can perform USB2 hardware LPM
415 * @usb2_hw_lpm_enabled: USB2 hardware LPM enabled
414 * @string_langid: language ID for strings 416 * @string_langid: language ID for strings
415 * @product: iProduct string, if present (static) 417 * @product: iProduct string, if present (static)
416 * @manufacturer: iManufacturer string, if present (static) 418 * @manufacturer: iManufacturer string, if present (static)
@@ -474,6 +476,8 @@ struct usb_device {
474 unsigned authenticated:1; 476 unsigned authenticated:1;
475 unsigned wusb:1; 477 unsigned wusb:1;
476 unsigned lpm_capable:1; 478 unsigned lpm_capable:1;
479 unsigned usb2_hw_lpm_capable:1;
480 unsigned usb2_hw_lpm_enabled:1;
477 int string_langid; 481 int string_langid;
478 482
479 /* static strings from the device */ 483 /* static strings from the device */
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index 0097136ba45d..a4cd6c58870a 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -343,6 +343,7 @@ struct hc_driver {
343 * address is set 343 * address is set
344 */ 344 */
345 int (*update_device)(struct usb_hcd *, struct usb_device *); 345 int (*update_device)(struct usb_hcd *, struct usb_device *);
346 int (*set_usb2_hw_lpm)(struct usb_hcd *, struct usb_device *, int);
346}; 347};
347 348
348extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb); 349extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);