xHCI 3.6 bug fixes.
Hi Greg, Here's seven bugfixes for 3.6. All of them are marked for stable, and most are vendor-specific fixes. Details: -------- - Commits052c7f9
and2963657
fix a couple stupid mistakes I made in a Intel xHCI bug fix patch I pushed just before I left for vacation. - Commits29d2145
anda96874a
fix issues with the Intel Panther Point EHCI to xHCI port switchover. - Commit71c731a
adds the work-around for the TI redriver "dead port" issue. - Commit319acdf
adds a fix for non-PCI xHCI platform drivers. - Commite955a1c
works around the UEFI issue with the xHCI host sometimes returning 0xff's in the MMIO on boot. Sarah Sharp -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQIcBAABAgAGBQJQR/DPAAoJEBMGWMLi1Gc5OeIP/2MsrUYUXi8TXHmyYrSYryVb +fIHky+qmAP6OTHgNm6J2hyfUYWCOZ1yBg61xXyDSLyX9lF21dA37Q5BEhtEL2VC /mxrXr2/iH72JpTuiptXuaxsolGlMy1V+M0CRkKc++1xbh9gqm9n+4h/VcXdKxjG hrYECWTKECAlsE8GMFSxN+m237WDSOq8+j39RlEY8Qp2+z3XGSiYVDX71gfH4OSG Cra8Lwg9u/IHJunNw6QsLtcPN/SHLLX431VQzwxDMeOyJHmD63+dPn0F18Dsf5Bj R030ovh4OZl9cPa5RrlT3U1Pucl16wySOzpE8KWgSlcX//2zY5f6ljo7xIDRQ3AV EGxvJ5w6VexJWvQL3bMBpcc8uqLnIxG+xI0k1zRikQ9CJ8qfbcJj/TnE/CW2e51A ICY47UkvCZf3hPEh6aEGYJxzwbPEcuVwtJ5G9TIxurc3fYlWal11kvxw30vQpHw4 A2WFVPjWFPvVeWEsIJ8n3y/zjyqM/T6vF24jzTW+uiTUuzm6UjSkXV07lE/3DSNo yCvGEXfgDncvUdFsUItey4RmRc7TZs+a68Ym3id27+HFWqjkjokCotsYSV1Xoi6I cRDrdCugfVW6zB1JH1Ys7YDN9nGPv13db1NEn11kT1NOyAflrbPRvHWcKdO6J4hN tz99e1nKL7QDnfxUQRmJ =124d -----END PGP SIGNATURE----- Merge tag 'for-usb-linus-2012-09-05' of git://git.kernel.org/pub/scm/linux/kernel/git/sarah/xhci into usb-linus xHCI 3.6 bug fixes. Hi Greg, Here's seven bugfixes for 3.6. All of them are marked for stable, and most are vendor-specific fixes. Details: -------- - Commits052c7f9
and2963657
fix a couple stupid mistakes I made in a Intel xHCI bug fix patch I pushed just before I left for vacation. - Commits29d2145
anda96874a
fix issues with the Intel Panther Point EHCI to xHCI port switchover. - Commit71c731a
adds the work-around for the TI redriver "dead port" issue. - Commit319acdf
adds a fix for non-PCI xHCI platform drivers. - Commite955a1c
works around the UEFI issue with the xHCI host sometimes returning 0xff's in the MMIO on boot. Sarah Sharp
This commit is contained in:
commit
7f7cd3cac9
@ -75,7 +75,9 @@
|
|||||||
#define NB_PIF0_PWRDOWN_1 0x01100013
|
#define NB_PIF0_PWRDOWN_1 0x01100013
|
||||||
|
|
||||||
#define USB_INTEL_XUSB2PR 0xD0
|
#define USB_INTEL_XUSB2PR 0xD0
|
||||||
|
#define USB_INTEL_USB2PRM 0xD4
|
||||||
#define USB_INTEL_USB3_PSSEN 0xD8
|
#define USB_INTEL_USB3_PSSEN 0xD8
|
||||||
|
#define USB_INTEL_USB3PRM 0xDC
|
||||||
|
|
||||||
static struct amd_chipset_info {
|
static struct amd_chipset_info {
|
||||||
struct pci_dev *nb_dev;
|
struct pci_dev *nb_dev;
|
||||||
@ -772,10 +774,18 @@ void usb_enable_xhci_ports(struct pci_dev *xhci_pdev)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ports_available = 0xffffffff;
|
/* Read USB3PRM, the USB 3.0 Port Routing Mask Register
|
||||||
|
* Indicate the ports that can be changed from OS.
|
||||||
|
*/
|
||||||
|
pci_read_config_dword(xhci_pdev, USB_INTEL_USB3PRM,
|
||||||
|
&ports_available);
|
||||||
|
|
||||||
|
dev_dbg(&xhci_pdev->dev, "Configurable ports to enable SuperSpeed: 0x%x\n",
|
||||||
|
ports_available);
|
||||||
|
|
||||||
/* Write USB3_PSSEN, the USB 3.0 Port SuperSpeed Enable
|
/* Write USB3_PSSEN, the USB 3.0 Port SuperSpeed Enable
|
||||||
* Register, to turn on SuperSpeed terminations for all
|
* Register, to turn on SuperSpeed terminations for the
|
||||||
* available ports.
|
* switchable ports.
|
||||||
*/
|
*/
|
||||||
pci_write_config_dword(xhci_pdev, USB_INTEL_USB3_PSSEN,
|
pci_write_config_dword(xhci_pdev, USB_INTEL_USB3_PSSEN,
|
||||||
cpu_to_le32(ports_available));
|
cpu_to_le32(ports_available));
|
||||||
@ -785,7 +795,16 @@ void usb_enable_xhci_ports(struct pci_dev *xhci_pdev)
|
|||||||
dev_dbg(&xhci_pdev->dev, "USB 3.0 ports that are now enabled "
|
dev_dbg(&xhci_pdev->dev, "USB 3.0 ports that are now enabled "
|
||||||
"under xHCI: 0x%x\n", ports_available);
|
"under xHCI: 0x%x\n", ports_available);
|
||||||
|
|
||||||
ports_available = 0xffffffff;
|
/* Read XUSB2PRM, xHCI USB 2.0 Port Routing Mask Register
|
||||||
|
* Indicate the USB 2.0 ports to be controlled by the xHCI host.
|
||||||
|
*/
|
||||||
|
|
||||||
|
pci_read_config_dword(xhci_pdev, USB_INTEL_USB2PRM,
|
||||||
|
&ports_available);
|
||||||
|
|
||||||
|
dev_dbg(&xhci_pdev->dev, "Configurable USB 2.0 ports to hand over to xCHI: 0x%x\n",
|
||||||
|
ports_available);
|
||||||
|
|
||||||
/* Write XUSB2PR, the xHC USB 2.0 Port Routing Register, to
|
/* Write XUSB2PR, the xHC USB 2.0 Port Routing Register, to
|
||||||
* switch the USB 2.0 power and data lines over to the xHCI
|
* switch the USB 2.0 power and data lines over to the xHCI
|
||||||
* host.
|
* host.
|
||||||
@ -822,12 +841,12 @@ static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev)
|
|||||||
void __iomem *op_reg_base;
|
void __iomem *op_reg_base;
|
||||||
u32 val;
|
u32 val;
|
||||||
int timeout;
|
int timeout;
|
||||||
|
int len = pci_resource_len(pdev, 0);
|
||||||
|
|
||||||
if (!mmio_resource_enabled(pdev, 0))
|
if (!mmio_resource_enabled(pdev, 0))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
base = ioremap_nocache(pci_resource_start(pdev, 0),
|
base = ioremap_nocache(pci_resource_start(pdev, 0), len);
|
||||||
pci_resource_len(pdev, 0));
|
|
||||||
if (base == NULL)
|
if (base == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -837,9 +856,17 @@ static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev)
|
|||||||
*/
|
*/
|
||||||
ext_cap_offset = xhci_find_next_cap_offset(base, XHCI_HCC_PARAMS_OFFSET);
|
ext_cap_offset = xhci_find_next_cap_offset(base, XHCI_HCC_PARAMS_OFFSET);
|
||||||
do {
|
do {
|
||||||
|
if ((ext_cap_offset + sizeof(val)) > len) {
|
||||||
|
/* We're reading garbage from the controller */
|
||||||
|
dev_warn(&pdev->dev,
|
||||||
|
"xHCI controller failing to respond");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!ext_cap_offset)
|
if (!ext_cap_offset)
|
||||||
/* We've reached the end of the extended capabilities */
|
/* We've reached the end of the extended capabilities */
|
||||||
goto hc_init;
|
goto hc_init;
|
||||||
|
|
||||||
val = readl(base + ext_cap_offset);
|
val = readl(base + ext_cap_offset);
|
||||||
if (XHCI_EXT_CAPS_ID(val) == XHCI_EXT_CAPS_LEGACY)
|
if (XHCI_EXT_CAPS_ID(val) == XHCI_EXT_CAPS_LEGACY)
|
||||||
break;
|
break;
|
||||||
@ -870,9 +897,10 @@ static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev)
|
|||||||
/* Disable any BIOS SMIs and clear all SMI events*/
|
/* Disable any BIOS SMIs and clear all SMI events*/
|
||||||
writel(val, base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET);
|
writel(val, base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET);
|
||||||
|
|
||||||
|
hc_init:
|
||||||
if (usb_is_intel_switchable_xhci(pdev))
|
if (usb_is_intel_switchable_xhci(pdev))
|
||||||
usb_enable_xhci_ports(pdev);
|
usb_enable_xhci_ports(pdev);
|
||||||
hc_init:
|
|
||||||
op_reg_base = base + XHCI_HC_LENGTH(readl(base));
|
op_reg_base = base + XHCI_HC_LENGTH(readl(base));
|
||||||
|
|
||||||
/* Wait for the host controller to be ready before writing any
|
/* Wait for the host controller to be ready before writing any
|
||||||
|
@ -15,6 +15,7 @@ void usb_disable_xhci_ports(struct pci_dev *xhci_pdev);
|
|||||||
static inline void usb_amd_quirk_pll_disable(void) {}
|
static inline void usb_amd_quirk_pll_disable(void) {}
|
||||||
static inline void usb_amd_quirk_pll_enable(void) {}
|
static inline void usb_amd_quirk_pll_enable(void) {}
|
||||||
static inline void usb_amd_dev_put(void) {}
|
static inline void usb_amd_dev_put(void) {}
|
||||||
|
static inline void usb_disable_xhci_ports(struct pci_dev *xhci_pdev) {}
|
||||||
#endif /* CONFIG_PCI */
|
#endif /* CONFIG_PCI */
|
||||||
|
|
||||||
#endif /* __LINUX_USB_PCI_QUIRKS_H */
|
#endif /* __LINUX_USB_PCI_QUIRKS_H */
|
||||||
|
@ -493,11 +493,48 @@ static void xhci_hub_report_link_state(u32 *status, u32 status_reg)
|
|||||||
* when this bit is set.
|
* when this bit is set.
|
||||||
*/
|
*/
|
||||||
pls |= USB_PORT_STAT_CONNECTION;
|
pls |= USB_PORT_STAT_CONNECTION;
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* If CAS bit isn't set but the Port is already at
|
||||||
|
* Compliance Mode, fake a connection so the USB core
|
||||||
|
* notices the Compliance state and resets the port.
|
||||||
|
* This resolves an issue generated by the SN65LVPE502CP
|
||||||
|
* in which sometimes the port enters compliance mode
|
||||||
|
* caused by a delay on the host-device negotiation.
|
||||||
|
*/
|
||||||
|
if (pls == USB_SS_PORT_LS_COMP_MOD)
|
||||||
|
pls |= USB_PORT_STAT_CONNECTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* update status field */
|
/* update status field */
|
||||||
*status |= pls;
|
*status |= pls;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Function for Compliance Mode Quirk.
|
||||||
|
*
|
||||||
|
* This Function verifies if all xhc USB3 ports have entered U0, if so,
|
||||||
|
* the compliance mode timer is deleted. A port won't enter
|
||||||
|
* compliance mode if it has previously entered U0.
|
||||||
|
*/
|
||||||
|
void xhci_del_comp_mod_timer(struct xhci_hcd *xhci, u32 status, u16 wIndex)
|
||||||
|
{
|
||||||
|
u32 all_ports_seen_u0 = ((1 << xhci->num_usb3_ports)-1);
|
||||||
|
bool port_in_u0 = ((status & PORT_PLS_MASK) == XDEV_U0);
|
||||||
|
|
||||||
|
if (!(xhci->quirks & XHCI_COMP_MODE_QUIRK))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ((xhci->port_status_u0 != all_ports_seen_u0) && port_in_u0) {
|
||||||
|
xhci->port_status_u0 |= 1 << wIndex;
|
||||||
|
if (xhci->port_status_u0 == all_ports_seen_u0) {
|
||||||
|
del_timer_sync(&xhci->comp_mode_recovery_timer);
|
||||||
|
xhci_dbg(xhci, "All USB3 ports have entered U0 already!\n");
|
||||||
|
xhci_dbg(xhci, "Compliance Mode Recovery Timer Deleted.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
||||||
u16 wIndex, char *buf, u16 wLength)
|
u16 wIndex, char *buf, u16 wLength)
|
||||||
{
|
{
|
||||||
@ -651,6 +688,11 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||||||
/* Update Port Link State for super speed ports*/
|
/* Update Port Link State for super speed ports*/
|
||||||
if (hcd->speed == HCD_USB3) {
|
if (hcd->speed == HCD_USB3) {
|
||||||
xhci_hub_report_link_state(&status, temp);
|
xhci_hub_report_link_state(&status, temp);
|
||||||
|
/*
|
||||||
|
* Verify if all USB3 Ports Have entered U0 already.
|
||||||
|
* Delete Compliance Mode Timer if so.
|
||||||
|
*/
|
||||||
|
xhci_del_comp_mod_timer(xhci, temp, wIndex);
|
||||||
}
|
}
|
||||||
if (bus_state->port_c_suspend & (1 << wIndex))
|
if (bus_state->port_c_suspend & (1 << wIndex))
|
||||||
status |= 1 << USB_PORT_FEAT_C_SUSPEND;
|
status |= 1 << USB_PORT_FEAT_C_SUSPEND;
|
||||||
|
@ -118,7 +118,7 @@ static int xhci_plat_probe(struct platform_device *pdev)
|
|||||||
goto put_hcd;
|
goto put_hcd;
|
||||||
}
|
}
|
||||||
|
|
||||||
hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
|
hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
|
||||||
if (!hcd->regs) {
|
if (!hcd->regs) {
|
||||||
dev_dbg(&pdev->dev, "error mapping memory\n");
|
dev_dbg(&pdev->dev, "error mapping memory\n");
|
||||||
ret = -EFAULT;
|
ret = -EFAULT;
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/moduleparam.h>
|
#include <linux/moduleparam.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
#include <linux/dmi.h>
|
||||||
|
|
||||||
#include "xhci.h"
|
#include "xhci.h"
|
||||||
|
|
||||||
@ -398,6 +399,95 @@ static void xhci_msix_sync_irqs(struct xhci_hcd *xhci)
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static void compliance_mode_recovery(unsigned long arg)
|
||||||
|
{
|
||||||
|
struct xhci_hcd *xhci;
|
||||||
|
struct usb_hcd *hcd;
|
||||||
|
u32 temp;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
xhci = (struct xhci_hcd *)arg;
|
||||||
|
|
||||||
|
for (i = 0; i < xhci->num_usb3_ports; i++) {
|
||||||
|
temp = xhci_readl(xhci, xhci->usb3_ports[i]);
|
||||||
|
if ((temp & PORT_PLS_MASK) == USB_SS_PORT_LS_COMP_MOD) {
|
||||||
|
/*
|
||||||
|
* Compliance Mode Detected. Letting USB Core
|
||||||
|
* handle the Warm Reset
|
||||||
|
*/
|
||||||
|
xhci_dbg(xhci, "Compliance Mode Detected->Port %d!\n",
|
||||||
|
i + 1);
|
||||||
|
xhci_dbg(xhci, "Attempting Recovery routine!\n");
|
||||||
|
hcd = xhci->shared_hcd;
|
||||||
|
|
||||||
|
if (hcd->state == HC_STATE_SUSPENDED)
|
||||||
|
usb_hcd_resume_root_hub(hcd);
|
||||||
|
|
||||||
|
usb_hcd_poll_rh_status(hcd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xhci->port_status_u0 != ((1 << xhci->num_usb3_ports)-1))
|
||||||
|
mod_timer(&xhci->comp_mode_recovery_timer,
|
||||||
|
jiffies + msecs_to_jiffies(COMP_MODE_RCVRY_MSECS));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Quirk to work around issue generated by the SN65LVPE502CP USB3.0 re-driver
|
||||||
|
* that causes ports behind that hardware to enter compliance mode sometimes.
|
||||||
|
* The quirk creates a timer that polls every 2 seconds the link state of
|
||||||
|
* each host controller's port and recovers it by issuing a Warm reset
|
||||||
|
* if Compliance mode is detected, otherwise the port will become "dead" (no
|
||||||
|
* device connections or disconnections will be detected anymore). Becasue no
|
||||||
|
* status event is generated when entering compliance mode (per xhci spec),
|
||||||
|
* this quirk is needed on systems that have the failing hardware installed.
|
||||||
|
*/
|
||||||
|
static void compliance_mode_recovery_timer_init(struct xhci_hcd *xhci)
|
||||||
|
{
|
||||||
|
xhci->port_status_u0 = 0;
|
||||||
|
init_timer(&xhci->comp_mode_recovery_timer);
|
||||||
|
|
||||||
|
xhci->comp_mode_recovery_timer.data = (unsigned long) xhci;
|
||||||
|
xhci->comp_mode_recovery_timer.function = compliance_mode_recovery;
|
||||||
|
xhci->comp_mode_recovery_timer.expires = jiffies +
|
||||||
|
msecs_to_jiffies(COMP_MODE_RCVRY_MSECS);
|
||||||
|
|
||||||
|
set_timer_slack(&xhci->comp_mode_recovery_timer,
|
||||||
|
msecs_to_jiffies(COMP_MODE_RCVRY_MSECS));
|
||||||
|
add_timer(&xhci->comp_mode_recovery_timer);
|
||||||
|
xhci_dbg(xhci, "Compliance Mode Recovery Timer Initialized.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function identifies the systems that have installed the SN65LVPE502CP
|
||||||
|
* USB3.0 re-driver and that need the Compliance Mode Quirk.
|
||||||
|
* Systems:
|
||||||
|
* Vendor: Hewlett-Packard -> System Models: Z420, Z620 and Z820
|
||||||
|
*/
|
||||||
|
static bool compliance_mode_recovery_timer_quirk_check(void)
|
||||||
|
{
|
||||||
|
const char *dmi_product_name, *dmi_sys_vendor;
|
||||||
|
|
||||||
|
dmi_product_name = dmi_get_system_info(DMI_PRODUCT_NAME);
|
||||||
|
dmi_sys_vendor = dmi_get_system_info(DMI_SYS_VENDOR);
|
||||||
|
|
||||||
|
if (!(strstr(dmi_sys_vendor, "Hewlett-Packard")))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (strstr(dmi_product_name, "Z420") ||
|
||||||
|
strstr(dmi_product_name, "Z620") ||
|
||||||
|
strstr(dmi_product_name, "Z820"))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int xhci_all_ports_seen_u0(struct xhci_hcd *xhci)
|
||||||
|
{
|
||||||
|
return (xhci->port_status_u0 == ((1 << xhci->num_usb3_ports)-1));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize memory for HCD and xHC (one-time init).
|
* Initialize memory for HCD and xHC (one-time init).
|
||||||
*
|
*
|
||||||
@ -421,6 +511,12 @@ int xhci_init(struct usb_hcd *hcd)
|
|||||||
retval = xhci_mem_init(xhci, GFP_KERNEL);
|
retval = xhci_mem_init(xhci, GFP_KERNEL);
|
||||||
xhci_dbg(xhci, "Finished xhci_init\n");
|
xhci_dbg(xhci, "Finished xhci_init\n");
|
||||||
|
|
||||||
|
/* Initializing Compliance Mode Recovery Data If Needed */
|
||||||
|
if (compliance_mode_recovery_timer_quirk_check()) {
|
||||||
|
xhci->quirks |= XHCI_COMP_MODE_QUIRK;
|
||||||
|
compliance_mode_recovery_timer_init(xhci);
|
||||||
|
}
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -629,6 +725,11 @@ void xhci_stop(struct usb_hcd *hcd)
|
|||||||
del_timer_sync(&xhci->event_ring_timer);
|
del_timer_sync(&xhci->event_ring_timer);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Deleting Compliance Mode Recovery Timer */
|
||||||
|
if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) &&
|
||||||
|
(!(xhci_all_ports_seen_u0(xhci))))
|
||||||
|
del_timer_sync(&xhci->comp_mode_recovery_timer);
|
||||||
|
|
||||||
if (xhci->quirks & XHCI_AMD_PLL_FIX)
|
if (xhci->quirks & XHCI_AMD_PLL_FIX)
|
||||||
usb_amd_dev_put();
|
usb_amd_dev_put();
|
||||||
|
|
||||||
@ -659,7 +760,7 @@ void xhci_shutdown(struct usb_hcd *hcd)
|
|||||||
{
|
{
|
||||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||||
|
|
||||||
if (xhci->quirks && XHCI_SPURIOUS_REBOOT)
|
if (xhci->quirks & XHCI_SPURIOUS_REBOOT)
|
||||||
usb_disable_xhci_ports(to_pci_dev(hcd->self.controller));
|
usb_disable_xhci_ports(to_pci_dev(hcd->self.controller));
|
||||||
|
|
||||||
spin_lock_irq(&xhci->lock);
|
spin_lock_irq(&xhci->lock);
|
||||||
@ -806,6 +907,16 @@ int xhci_suspend(struct xhci_hcd *xhci)
|
|||||||
}
|
}
|
||||||
spin_unlock_irq(&xhci->lock);
|
spin_unlock_irq(&xhci->lock);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Deleting Compliance Mode Recovery Timer because the xHCI Host
|
||||||
|
* is about to be suspended.
|
||||||
|
*/
|
||||||
|
if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) &&
|
||||||
|
(!(xhci_all_ports_seen_u0(xhci)))) {
|
||||||
|
del_timer_sync(&xhci->comp_mode_recovery_timer);
|
||||||
|
xhci_dbg(xhci, "Compliance Mode Recovery Timer Deleted!\n");
|
||||||
|
}
|
||||||
|
|
||||||
/* step 5: remove core well power */
|
/* step 5: remove core well power */
|
||||||
/* synchronize irq when using MSI-X */
|
/* synchronize irq when using MSI-X */
|
||||||
xhci_msix_sync_irqs(xhci);
|
xhci_msix_sync_irqs(xhci);
|
||||||
@ -938,6 +1049,16 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
|
|||||||
usb_hcd_resume_root_hub(hcd);
|
usb_hcd_resume_root_hub(hcd);
|
||||||
usb_hcd_resume_root_hub(xhci->shared_hcd);
|
usb_hcd_resume_root_hub(xhci->shared_hcd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If system is subject to the Quirk, Compliance Mode Timer needs to
|
||||||
|
* be re-initialized Always after a system resume. Ports are subject
|
||||||
|
* to suffer the Compliance Mode issue again. It doesn't matter if
|
||||||
|
* ports have entered previously to U0 before system's suspension.
|
||||||
|
*/
|
||||||
|
if (xhci->quirks & XHCI_COMP_MODE_QUIRK)
|
||||||
|
compliance_mode_recovery_timer_init(xhci);
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_PM */
|
#endif /* CONFIG_PM */
|
||||||
|
@ -1495,6 +1495,7 @@ struct xhci_hcd {
|
|||||||
#define XHCI_LPM_SUPPORT (1 << 11)
|
#define XHCI_LPM_SUPPORT (1 << 11)
|
||||||
#define XHCI_INTEL_HOST (1 << 12)
|
#define XHCI_INTEL_HOST (1 << 12)
|
||||||
#define XHCI_SPURIOUS_REBOOT (1 << 13)
|
#define XHCI_SPURIOUS_REBOOT (1 << 13)
|
||||||
|
#define XHCI_COMP_MODE_QUIRK (1 << 14)
|
||||||
unsigned int num_active_eps;
|
unsigned int num_active_eps;
|
||||||
unsigned int limit_active_eps;
|
unsigned int limit_active_eps;
|
||||||
/* There are two roothubs to keep track of bus suspend info for */
|
/* There are two roothubs to keep track of bus suspend info for */
|
||||||
@ -1511,6 +1512,11 @@ struct xhci_hcd {
|
|||||||
unsigned sw_lpm_support:1;
|
unsigned sw_lpm_support:1;
|
||||||
/* support xHCI 1.0 spec USB2 hardware LPM */
|
/* support xHCI 1.0 spec USB2 hardware LPM */
|
||||||
unsigned hw_lpm_support:1;
|
unsigned hw_lpm_support:1;
|
||||||
|
/* Compliance Mode Recovery Data */
|
||||||
|
struct timer_list comp_mode_recovery_timer;
|
||||||
|
u32 port_status_u0;
|
||||||
|
/* Compliance Mode Timer Triggered every 2 seconds */
|
||||||
|
#define COMP_MODE_RCVRY_MSECS 2000
|
||||||
};
|
};
|
||||||
|
|
||||||
/* convert between an HCD pointer and the corresponding EHCI_HCD */
|
/* convert between an HCD pointer and the corresponding EHCI_HCD */
|
||||||
|
Loading…
Reference in New Issue
Block a user