aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host
diff options
context:
space:
mode:
authorAndiry Xu <andiry.xu@amd.com>2011-09-23 17:19:52 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2011-09-26 18:51:10 -0400
commit65580b4321eb36f16ae8b5987bfa1bb948fc5112 (patch)
tree12735f923ad670c405efb5ab34c188dc06ad15f7 /drivers/usb/host
parent9574323c39d1f8359a04843075d89c9f32d8b7e6 (diff)
xHCI: set USB2 hardware LPM
If the device pass the USB2 software LPM and the host supports hardware LPM, enable hardware LPM for the device to let the host decide when to put the link into lower power state. If hardware LPM is enabled for a port and driver wants to put it into suspend, it must first disable hardware LPM, resume the port into U0, and then suspend the port. Signed-off-by: Andiry Xu <andiry.xu@amd.com> Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host')
-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
4 files changed, 87 insertions, 1 deletions
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);