diff options
author | Andiry Xu <andiry.xu@amd.com> | 2011-09-23 14:19:51 -0700 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2011-09-26 15:51:10 -0700 |
commit | 9574323c39d1f8359a04843075d89c9f32d8b7e6 (patch) | |
tree | 38514abe7e4485face5fa1fb081c4a51a6f300c7 /drivers/usb/host/xhci-mem.c | |
parent | fc71ff7583b14347fa1cb592b698f088ecff36e3 (diff) |
xHCI: test USB2 software LPM
This patch tests USB2 software LPM for a USB2 LPM-capable device.
When a lpm-capable device is addressed, if the host also supports software
LPM, apply a test by putting the device into L1 state and resume it to see
if the device can do L1 suspend/resume successfully.
If the device fails to enter L1 or resume from L1 state, it may not
function normally and usbcore may disconnect and re-enumerate it. In this
case, store the device's Vid and Pid information, make sure the host will
not test LPM for it twice.
The test result is per device/host. Some devices claim to be lpm-capable,
but fail to enter L1 or resume. So the test is necessary.
The xHCI 1.0 errata has modified the USB2.0 LPM implementation. It redefines
the HIRD field to BESL, and adds another register Port Hardware LPM Control
(PORTHLPMC). However, this should not affect the LPM behavior on xHC which
does not implement 1.0 errata.
USB2.0 LPM errata defines a new bit BESL in the device's USB 2.0 extension
descriptor. If the device reports it uses BESL, driver should use BESL
instead of HIRD for it.
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/xhci-mem.c')
-rw-r--r-- | drivers/usb/host/xhci-mem.c | 11 |
1 files changed, 11 insertions, 0 deletions
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 9c7ddf0f3a4..3ec2ac9636f 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -1685,6 +1685,8 @@ void xhci_free_command(struct xhci_hcd *xhci, 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; + unsigned long flags; int size; int i; @@ -1742,6 +1744,13 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) scratchpad_free(xhci); + spin_lock_irqsave(&xhci->lock, flags); + list_for_each_entry_safe(dev_info, next, &xhci->lpm_failed_devs, list) { + list_del(&dev_info->list); + kfree(dev_info); + } + spin_unlock_irqrestore(&xhci->lock, flags); + xhci->num_usb2_ports = 0; xhci->num_usb3_ports = 0; kfree(xhci->usb2_ports); @@ -2328,6 +2337,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) if (xhci_setup_port_arrays(xhci, flags)) goto fail; + INIT_LIST_HEAD(&xhci->lpm_failed_devs); + return 0; fail: |