diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-09-16 23:42:46 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-09-16 23:42:46 -0400 |
commit | 2bcb132c693566bcb8208cc7ce66b72a4f852ecf (patch) | |
tree | 6fc4f05ce18140d86aa78a10380a610734aeaef9 /drivers/usb/host | |
parent | 67e6da702753dac8f0540209dded80a0c4e60d81 (diff) | |
parent | 5698bd757d55b1bb87edd1a9744ab09c142abfc2 (diff) |
Merge 3.6-rc6 into usb-next
This resolves the merge problems with:
drivers/usb/dwc3/gadget.c
drivers/usb/musb/tusb6010.c
that had been seen in linux-next.
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/host')
-rw-r--r-- | drivers/usb/host/ehci-q.c | 12 | ||||
-rw-r--r-- | drivers/usb/host/ohci-at91.c | 10 | ||||
-rw-r--r-- | drivers/usb/host/pci-quirks.c | 42 | ||||
-rw-r--r-- | drivers/usb/host/pci-quirks.h | 1 | ||||
-rw-r--r-- | drivers/usb/host/xhci-hub.c | 42 | ||||
-rw-r--r-- | drivers/usb/host/xhci-plat.c | 2 | ||||
-rw-r--r-- | drivers/usb/host/xhci.c | 123 | ||||
-rw-r--r-- | drivers/usb/host/xhci.h | 6 |
8 files changed, 227 insertions, 11 deletions
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 9bc39ca460c8..4b66374bdc8e 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c | |||
@@ -128,9 +128,17 @@ qh_refresh (struct ehci_hcd *ehci, struct ehci_qh *qh) | |||
128 | else { | 128 | else { |
129 | qtd = list_entry (qh->qtd_list.next, | 129 | qtd = list_entry (qh->qtd_list.next, |
130 | struct ehci_qtd, qtd_list); | 130 | struct ehci_qtd, qtd_list); |
131 | /* first qtd may already be partially processed */ | 131 | /* |
132 | if (cpu_to_hc32(ehci, qtd->qtd_dma) == qh->hw->hw_current) | 132 | * first qtd may already be partially processed. |
133 | * If we come here during unlink, the QH overlay region | ||
134 | * might have reference to the just unlinked qtd. The | ||
135 | * qtd is updated in qh_completions(). Update the QH | ||
136 | * overlay here. | ||
137 | */ | ||
138 | if (cpu_to_hc32(ehci, qtd->qtd_dma) == qh->hw->hw_current) { | ||
139 | qh->hw->hw_qtd_next = qtd->hw_next; | ||
133 | qtd = NULL; | 140 | qtd = NULL; |
141 | } | ||
134 | } | 142 | } |
135 | 143 | ||
136 | if (qtd) | 144 | if (qtd) |
diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index a665b3eaa746..aaa8d2bce217 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c | |||
@@ -570,6 +570,16 @@ static int __devinit ohci_hcd_at91_drv_probe(struct platform_device *pdev) | |||
570 | 570 | ||
571 | if (pdata) { | 571 | if (pdata) { |
572 | at91_for_each_port(i) { | 572 | at91_for_each_port(i) { |
573 | /* | ||
574 | * do not configure PIO if not in relation with | ||
575 | * real USB port on board | ||
576 | */ | ||
577 | if (i >= pdata->ports) { | ||
578 | pdata->vbus_pin[i] = -EINVAL; | ||
579 | pdata->overcurrent_pin[i] = -EINVAL; | ||
580 | break; | ||
581 | } | ||
582 | |||
573 | if (!gpio_is_valid(pdata->vbus_pin[i])) | 583 | if (!gpio_is_valid(pdata->vbus_pin[i])) |
574 | continue; | 584 | continue; |
575 | gpio = pdata->vbus_pin[i]; | 585 | gpio = pdata->vbus_pin[i]; |
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index c5e9e4a76f14..966d1484ee79 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c | |||
@@ -75,7 +75,9 @@ | |||
75 | #define NB_PIF0_PWRDOWN_1 0x01100013 | 75 | #define NB_PIF0_PWRDOWN_1 0x01100013 |
76 | 76 | ||
77 | #define USB_INTEL_XUSB2PR 0xD0 | 77 | #define USB_INTEL_XUSB2PR 0xD0 |
78 | #define USB_INTEL_USB2PRM 0xD4 | ||
78 | #define USB_INTEL_USB3_PSSEN 0xD8 | 79 | #define USB_INTEL_USB3_PSSEN 0xD8 |
80 | #define USB_INTEL_USB3PRM 0xDC | ||
79 | 81 | ||
80 | static struct amd_chipset_info { | 82 | static struct amd_chipset_info { |
81 | struct pci_dev *nb_dev; | 83 | struct pci_dev *nb_dev; |
@@ -772,10 +774,18 @@ void usb_enable_xhci_ports(struct pci_dev *xhci_pdev) | |||
772 | return; | 774 | return; |
773 | } | 775 | } |
774 | 776 | ||
775 | ports_available = 0xffffffff; | 777 | /* Read USB3PRM, the USB 3.0 Port Routing Mask Register |
778 | * Indicate the ports that can be changed from OS. | ||
779 | */ | ||
780 | pci_read_config_dword(xhci_pdev, USB_INTEL_USB3PRM, | ||
781 | &ports_available); | ||
782 | |||
783 | dev_dbg(&xhci_pdev->dev, "Configurable ports to enable SuperSpeed: 0x%x\n", | ||
784 | ports_available); | ||
785 | |||
776 | /* Write USB3_PSSEN, the USB 3.0 Port SuperSpeed Enable | 786 | /* Write USB3_PSSEN, the USB 3.0 Port SuperSpeed Enable |
777 | * Register, to turn on SuperSpeed terminations for all | 787 | * Register, to turn on SuperSpeed terminations for the |
778 | * available ports. | 788 | * switchable ports. |
779 | */ | 789 | */ |
780 | pci_write_config_dword(xhci_pdev, USB_INTEL_USB3_PSSEN, | 790 | pci_write_config_dword(xhci_pdev, USB_INTEL_USB3_PSSEN, |
781 | cpu_to_le32(ports_available)); | 791 | cpu_to_le32(ports_available)); |
@@ -785,7 +795,16 @@ void usb_enable_xhci_ports(struct pci_dev *xhci_pdev) | |||
785 | dev_dbg(&xhci_pdev->dev, "USB 3.0 ports that are now enabled " | 795 | dev_dbg(&xhci_pdev->dev, "USB 3.0 ports that are now enabled " |
786 | "under xHCI: 0x%x\n", ports_available); | 796 | "under xHCI: 0x%x\n", ports_available); |
787 | 797 | ||
788 | ports_available = 0xffffffff; | 798 | /* Read XUSB2PRM, xHCI USB 2.0 Port Routing Mask Register |
799 | * Indicate the USB 2.0 ports to be controlled by the xHCI host. | ||
800 | */ | ||
801 | |||
802 | pci_read_config_dword(xhci_pdev, USB_INTEL_USB2PRM, | ||
803 | &ports_available); | ||
804 | |||
805 | dev_dbg(&xhci_pdev->dev, "Configurable USB 2.0 ports to hand over to xCHI: 0x%x\n", | ||
806 | ports_available); | ||
807 | |||
789 | /* Write XUSB2PR, the xHC USB 2.0 Port Routing Register, to | 808 | /* Write XUSB2PR, the xHC USB 2.0 Port Routing Register, to |
790 | * switch the USB 2.0 power and data lines over to the xHCI | 809 | * switch the USB 2.0 power and data lines over to the xHCI |
791 | * host. | 810 | * host. |
@@ -822,12 +841,12 @@ static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev) | |||
822 | void __iomem *op_reg_base; | 841 | void __iomem *op_reg_base; |
823 | u32 val; | 842 | u32 val; |
824 | int timeout; | 843 | int timeout; |
844 | int len = pci_resource_len(pdev, 0); | ||
825 | 845 | ||
826 | if (!mmio_resource_enabled(pdev, 0)) | 846 | if (!mmio_resource_enabled(pdev, 0)) |
827 | return; | 847 | return; |
828 | 848 | ||
829 | base = ioremap_nocache(pci_resource_start(pdev, 0), | 849 | base = ioremap_nocache(pci_resource_start(pdev, 0), len); |
830 | pci_resource_len(pdev, 0)); | ||
831 | if (base == NULL) | 850 | if (base == NULL) |
832 | return; | 851 | return; |
833 | 852 | ||
@@ -837,9 +856,17 @@ static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev) | |||
837 | */ | 856 | */ |
838 | ext_cap_offset = xhci_find_next_cap_offset(base, XHCI_HCC_PARAMS_OFFSET); | 857 | ext_cap_offset = xhci_find_next_cap_offset(base, XHCI_HCC_PARAMS_OFFSET); |
839 | do { | 858 | do { |
859 | if ((ext_cap_offset + sizeof(val)) > len) { | ||
860 | /* We're reading garbage from the controller */ | ||
861 | dev_warn(&pdev->dev, | ||
862 | "xHCI controller failing to respond"); | ||
863 | return; | ||
864 | } | ||
865 | |||
840 | if (!ext_cap_offset) | 866 | if (!ext_cap_offset) |
841 | /* We've reached the end of the extended capabilities */ | 867 | /* We've reached the end of the extended capabilities */ |
842 | goto hc_init; | 868 | goto hc_init; |
869 | |||
843 | val = readl(base + ext_cap_offset); | 870 | val = readl(base + ext_cap_offset); |
844 | if (XHCI_EXT_CAPS_ID(val) == XHCI_EXT_CAPS_LEGACY) | 871 | if (XHCI_EXT_CAPS_ID(val) == XHCI_EXT_CAPS_LEGACY) |
845 | break; | 872 | break; |
@@ -870,9 +897,10 @@ static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev) | |||
870 | /* Disable any BIOS SMIs and clear all SMI events*/ | 897 | /* Disable any BIOS SMIs and clear all SMI events*/ |
871 | writel(val, base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET); | 898 | writel(val, base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET); |
872 | 899 | ||
900 | hc_init: | ||
873 | if (usb_is_intel_switchable_xhci(pdev)) | 901 | if (usb_is_intel_switchable_xhci(pdev)) |
874 | usb_enable_xhci_ports(pdev); | 902 | usb_enable_xhci_ports(pdev); |
875 | hc_init: | 903 | |
876 | op_reg_base = base + XHCI_HC_LENGTH(readl(base)); | 904 | op_reg_base = base + XHCI_HC_LENGTH(readl(base)); |
877 | 905 | ||
878 | /* Wait for the host controller to be ready before writing any | 906 | /* Wait for the host controller to be ready before writing any |
diff --git a/drivers/usb/host/pci-quirks.h b/drivers/usb/host/pci-quirks.h index ef004a5de20f..7f69a39163ce 100644 --- a/drivers/usb/host/pci-quirks.h +++ b/drivers/usb/host/pci-quirks.h | |||
@@ -15,6 +15,7 @@ void usb_disable_xhci_ports(struct pci_dev *xhci_pdev); | |||
15 | static inline void usb_amd_quirk_pll_disable(void) {} | 15 | static inline void usb_amd_quirk_pll_disable(void) {} |
16 | static inline void usb_amd_quirk_pll_enable(void) {} | 16 | static inline void usb_amd_quirk_pll_enable(void) {} |
17 | static inline void usb_amd_dev_put(void) {} | 17 | static inline void usb_amd_dev_put(void) {} |
18 | static inline void usb_disable_xhci_ports(struct pci_dev *xhci_pdev) {} | ||
18 | #endif /* CONFIG_PCI */ | 19 | #endif /* CONFIG_PCI */ |
19 | 20 | ||
20 | #endif /* __LINUX_USB_PCI_QUIRKS_H */ | 21 | #endif /* __LINUX_USB_PCI_QUIRKS_H */ |
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 5896f0588d41..aa90ad4d4fd5 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c | |||
@@ -493,11 +493,48 @@ static void xhci_hub_report_link_state(u32 *status, u32 status_reg) | |||
493 | * when this bit is set. | 493 | * when this bit is set. |
494 | */ | 494 | */ |
495 | pls |= USB_PORT_STAT_CONNECTION; | 495 | pls |= USB_PORT_STAT_CONNECTION; |
496 | } else { | ||
497 | /* | ||
498 | * If CAS bit isn't set but the Port is already at | ||
499 | * Compliance Mode, fake a connection so the USB core | ||
500 | * notices the Compliance state and resets the port. | ||
501 | * This resolves an issue generated by the SN65LVPE502CP | ||
502 | * in which sometimes the port enters compliance mode | ||
503 | * caused by a delay on the host-device negotiation. | ||
504 | */ | ||
505 | if (pls == USB_SS_PORT_LS_COMP_MOD) | ||
506 | pls |= USB_PORT_STAT_CONNECTION; | ||
496 | } | 507 | } |
508 | |||
497 | /* update status field */ | 509 | /* update status field */ |
498 | *status |= pls; | 510 | *status |= pls; |
499 | } | 511 | } |
500 | 512 | ||
513 | /* | ||
514 | * Function for Compliance Mode Quirk. | ||
515 | * | ||
516 | * This Function verifies if all xhc USB3 ports have entered U0, if so, | ||
517 | * the compliance mode timer is deleted. A port won't enter | ||
518 | * compliance mode if it has previously entered U0. | ||
519 | */ | ||
520 | void xhci_del_comp_mod_timer(struct xhci_hcd *xhci, u32 status, u16 wIndex) | ||
521 | { | ||
522 | u32 all_ports_seen_u0 = ((1 << xhci->num_usb3_ports)-1); | ||
523 | bool port_in_u0 = ((status & PORT_PLS_MASK) == XDEV_U0); | ||
524 | |||
525 | if (!(xhci->quirks & XHCI_COMP_MODE_QUIRK)) | ||
526 | return; | ||
527 | |||
528 | if ((xhci->port_status_u0 != all_ports_seen_u0) && port_in_u0) { | ||
529 | xhci->port_status_u0 |= 1 << wIndex; | ||
530 | if (xhci->port_status_u0 == all_ports_seen_u0) { | ||
531 | del_timer_sync(&xhci->comp_mode_recovery_timer); | ||
532 | xhci_dbg(xhci, "All USB3 ports have entered U0 already!\n"); | ||
533 | xhci_dbg(xhci, "Compliance Mode Recovery Timer Deleted.\n"); | ||
534 | } | ||
535 | } | ||
536 | } | ||
537 | |||
501 | int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | 538 | int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, |
502 | u16 wIndex, char *buf, u16 wLength) | 539 | u16 wIndex, char *buf, u16 wLength) |
503 | { | 540 | { |
@@ -651,6 +688,11 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | |||
651 | /* Update Port Link State for super speed ports*/ | 688 | /* Update Port Link State for super speed ports*/ |
652 | if (hcd->speed == HCD_USB3) { | 689 | if (hcd->speed == HCD_USB3) { |
653 | xhci_hub_report_link_state(&status, temp); | 690 | xhci_hub_report_link_state(&status, temp); |
691 | /* | ||
692 | * Verify if all USB3 Ports Have entered U0 already. | ||
693 | * Delete Compliance Mode Timer if so. | ||
694 | */ | ||
695 | xhci_del_comp_mod_timer(xhci, temp, wIndex); | ||
654 | } | 696 | } |
655 | if (bus_state->port_c_suspend & (1 << wIndex)) | 697 | if (bus_state->port_c_suspend & (1 << wIndex)) |
656 | status |= 1 << USB_PORT_FEAT_C_SUSPEND; | 698 | status |= 1 << USB_PORT_FEAT_C_SUSPEND; |
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index 689bc18b051d..df90fe51b4aa 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c | |||
@@ -118,7 +118,7 @@ static int xhci_plat_probe(struct platform_device *pdev) | |||
118 | goto put_hcd; | 118 | goto put_hcd; |
119 | } | 119 | } |
120 | 120 | ||
121 | hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); | 121 | hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); |
122 | if (!hcd->regs) { | 122 | if (!hcd->regs) { |
123 | dev_dbg(&pdev->dev, "error mapping memory\n"); | 123 | dev_dbg(&pdev->dev, "error mapping memory\n"); |
124 | ret = -EFAULT; | 124 | ret = -EFAULT; |
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 66bc5c3985fb..a4b0ce13fa0c 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/module.h> | 26 | #include <linux/module.h> |
27 | #include <linux/moduleparam.h> | 27 | #include <linux/moduleparam.h> |
28 | #include <linux/slab.h> | 28 | #include <linux/slab.h> |
29 | #include <linux/dmi.h> | ||
29 | 30 | ||
30 | #include "xhci.h" | 31 | #include "xhci.h" |
31 | 32 | ||
@@ -399,6 +400,95 @@ static void xhci_msix_sync_irqs(struct xhci_hcd *xhci) | |||
399 | 400 | ||
400 | #endif | 401 | #endif |
401 | 402 | ||
403 | static void compliance_mode_recovery(unsigned long arg) | ||
404 | { | ||
405 | struct xhci_hcd *xhci; | ||
406 | struct usb_hcd *hcd; | ||
407 | u32 temp; | ||
408 | int i; | ||
409 | |||
410 | xhci = (struct xhci_hcd *)arg; | ||
411 | |||
412 | for (i = 0; i < xhci->num_usb3_ports; i++) { | ||
413 | temp = xhci_readl(xhci, xhci->usb3_ports[i]); | ||
414 | if ((temp & PORT_PLS_MASK) == USB_SS_PORT_LS_COMP_MOD) { | ||
415 | /* | ||
416 | * Compliance Mode Detected. Letting USB Core | ||
417 | * handle the Warm Reset | ||
418 | */ | ||
419 | xhci_dbg(xhci, "Compliance Mode Detected->Port %d!\n", | ||
420 | i + 1); | ||
421 | xhci_dbg(xhci, "Attempting Recovery routine!\n"); | ||
422 | hcd = xhci->shared_hcd; | ||
423 | |||
424 | if (hcd->state == HC_STATE_SUSPENDED) | ||
425 | usb_hcd_resume_root_hub(hcd); | ||
426 | |||
427 | usb_hcd_poll_rh_status(hcd); | ||
428 | } | ||
429 | } | ||
430 | |||
431 | if (xhci->port_status_u0 != ((1 << xhci->num_usb3_ports)-1)) | ||
432 | mod_timer(&xhci->comp_mode_recovery_timer, | ||
433 | jiffies + msecs_to_jiffies(COMP_MODE_RCVRY_MSECS)); | ||
434 | } | ||
435 | |||
436 | /* | ||
437 | * Quirk to work around issue generated by the SN65LVPE502CP USB3.0 re-driver | ||
438 | * that causes ports behind that hardware to enter compliance mode sometimes. | ||
439 | * The quirk creates a timer that polls every 2 seconds the link state of | ||
440 | * each host controller's port and recovers it by issuing a Warm reset | ||
441 | * if Compliance mode is detected, otherwise the port will become "dead" (no | ||
442 | * device connections or disconnections will be detected anymore). Becasue no | ||
443 | * status event is generated when entering compliance mode (per xhci spec), | ||
444 | * this quirk is needed on systems that have the failing hardware installed. | ||
445 | */ | ||
446 | static void compliance_mode_recovery_timer_init(struct xhci_hcd *xhci) | ||
447 | { | ||
448 | xhci->port_status_u0 = 0; | ||
449 | init_timer(&xhci->comp_mode_recovery_timer); | ||
450 | |||
451 | xhci->comp_mode_recovery_timer.data = (unsigned long) xhci; | ||
452 | xhci->comp_mode_recovery_timer.function = compliance_mode_recovery; | ||
453 | xhci->comp_mode_recovery_timer.expires = jiffies + | ||
454 | msecs_to_jiffies(COMP_MODE_RCVRY_MSECS); | ||
455 | |||
456 | set_timer_slack(&xhci->comp_mode_recovery_timer, | ||
457 | msecs_to_jiffies(COMP_MODE_RCVRY_MSECS)); | ||
458 | add_timer(&xhci->comp_mode_recovery_timer); | ||
459 | xhci_dbg(xhci, "Compliance Mode Recovery Timer Initialized.\n"); | ||
460 | } | ||
461 | |||
462 | /* | ||
463 | * This function identifies the systems that have installed the SN65LVPE502CP | ||
464 | * USB3.0 re-driver and that need the Compliance Mode Quirk. | ||
465 | * Systems: | ||
466 | * Vendor: Hewlett-Packard -> System Models: Z420, Z620 and Z820 | ||
467 | */ | ||
468 | static bool compliance_mode_recovery_timer_quirk_check(void) | ||
469 | { | ||
470 | const char *dmi_product_name, *dmi_sys_vendor; | ||
471 | |||
472 | dmi_product_name = dmi_get_system_info(DMI_PRODUCT_NAME); | ||
473 | dmi_sys_vendor = dmi_get_system_info(DMI_SYS_VENDOR); | ||
474 | |||
475 | if (!(strstr(dmi_sys_vendor, "Hewlett-Packard"))) | ||
476 | return false; | ||
477 | |||
478 | if (strstr(dmi_product_name, "Z420") || | ||
479 | strstr(dmi_product_name, "Z620") || | ||
480 | strstr(dmi_product_name, "Z820")) | ||
481 | return true; | ||
482 | |||
483 | return false; | ||
484 | } | ||
485 | |||
486 | static int xhci_all_ports_seen_u0(struct xhci_hcd *xhci) | ||
487 | { | ||
488 | return (xhci->port_status_u0 == ((1 << xhci->num_usb3_ports)-1)); | ||
489 | } | ||
490 | |||
491 | |||
402 | /* | 492 | /* |
403 | * Initialize memory for HCD and xHC (one-time init). | 493 | * Initialize memory for HCD and xHC (one-time init). |
404 | * | 494 | * |
@@ -422,6 +512,12 @@ int xhci_init(struct usb_hcd *hcd) | |||
422 | retval = xhci_mem_init(xhci, GFP_KERNEL); | 512 | retval = xhci_mem_init(xhci, GFP_KERNEL); |
423 | xhci_dbg(xhci, "Finished xhci_init\n"); | 513 | xhci_dbg(xhci, "Finished xhci_init\n"); |
424 | 514 | ||
515 | /* Initializing Compliance Mode Recovery Data If Needed */ | ||
516 | if (compliance_mode_recovery_timer_quirk_check()) { | ||
517 | xhci->quirks |= XHCI_COMP_MODE_QUIRK; | ||
518 | compliance_mode_recovery_timer_init(xhci); | ||
519 | } | ||
520 | |||
425 | return retval; | 521 | return retval; |
426 | } | 522 | } |
427 | 523 | ||
@@ -631,6 +727,11 @@ void xhci_stop(struct usb_hcd *hcd) | |||
631 | del_timer_sync(&xhci->event_ring_timer); | 727 | del_timer_sync(&xhci->event_ring_timer); |
632 | #endif | 728 | #endif |
633 | 729 | ||
730 | /* Deleting Compliance Mode Recovery Timer */ | ||
731 | if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) && | ||
732 | (!(xhci_all_ports_seen_u0(xhci)))) | ||
733 | del_timer_sync(&xhci->comp_mode_recovery_timer); | ||
734 | |||
634 | if (xhci->quirks & XHCI_AMD_PLL_FIX) | 735 | if (xhci->quirks & XHCI_AMD_PLL_FIX) |
635 | usb_amd_dev_put(); | 736 | usb_amd_dev_put(); |
636 | 737 | ||
@@ -661,7 +762,7 @@ void xhci_shutdown(struct usb_hcd *hcd) | |||
661 | { | 762 | { |
662 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); | 763 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); |
663 | 764 | ||
664 | if (xhci->quirks && XHCI_SPURIOUS_REBOOT) | 765 | if (xhci->quirks & XHCI_SPURIOUS_REBOOT) |
665 | usb_disable_xhci_ports(to_pci_dev(hcd->self.controller)); | 766 | usb_disable_xhci_ports(to_pci_dev(hcd->self.controller)); |
666 | 767 | ||
667 | spin_lock_irq(&xhci->lock); | 768 | spin_lock_irq(&xhci->lock); |
@@ -808,6 +909,16 @@ int xhci_suspend(struct xhci_hcd *xhci) | |||
808 | } | 909 | } |
809 | spin_unlock_irq(&xhci->lock); | 910 | spin_unlock_irq(&xhci->lock); |
810 | 911 | ||
912 | /* | ||
913 | * Deleting Compliance Mode Recovery Timer because the xHCI Host | ||
914 | * is about to be suspended. | ||
915 | */ | ||
916 | if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) && | ||
917 | (!(xhci_all_ports_seen_u0(xhci)))) { | ||
918 | del_timer_sync(&xhci->comp_mode_recovery_timer); | ||
919 | xhci_dbg(xhci, "Compliance Mode Recovery Timer Deleted!\n"); | ||
920 | } | ||
921 | |||
811 | /* step 5: remove core well power */ | 922 | /* step 5: remove core well power */ |
812 | /* synchronize irq when using MSI-X */ | 923 | /* synchronize irq when using MSI-X */ |
813 | xhci_msix_sync_irqs(xhci); | 924 | xhci_msix_sync_irqs(xhci); |
@@ -940,6 +1051,16 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) | |||
940 | usb_hcd_resume_root_hub(hcd); | 1051 | usb_hcd_resume_root_hub(hcd); |
941 | usb_hcd_resume_root_hub(xhci->shared_hcd); | 1052 | usb_hcd_resume_root_hub(xhci->shared_hcd); |
942 | } | 1053 | } |
1054 | |||
1055 | /* | ||
1056 | * If system is subject to the Quirk, Compliance Mode Timer needs to | ||
1057 | * be re-initialized Always after a system resume. Ports are subject | ||
1058 | * to suffer the Compliance Mode issue again. It doesn't matter if | ||
1059 | * ports have entered previously to U0 before system's suspension. | ||
1060 | */ | ||
1061 | if (xhci->quirks & XHCI_COMP_MODE_QUIRK) | ||
1062 | compliance_mode_recovery_timer_init(xhci); | ||
1063 | |||
943 | return retval; | 1064 | return retval; |
944 | } | 1065 | } |
945 | #endif /* CONFIG_PM */ | 1066 | #endif /* CONFIG_PM */ |
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index e81ccfa3552f..e44e2d3c83b0 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h | |||
@@ -1510,6 +1510,7 @@ struct xhci_hcd { | |||
1510 | #define XHCI_LPM_SUPPORT (1 << 11) | 1510 | #define XHCI_LPM_SUPPORT (1 << 11) |
1511 | #define XHCI_INTEL_HOST (1 << 12) | 1511 | #define XHCI_INTEL_HOST (1 << 12) |
1512 | #define XHCI_SPURIOUS_REBOOT (1 << 13) | 1512 | #define XHCI_SPURIOUS_REBOOT (1 << 13) |
1513 | #define XHCI_COMP_MODE_QUIRK (1 << 14) | ||
1513 | unsigned int num_active_eps; | 1514 | unsigned int num_active_eps; |
1514 | unsigned int limit_active_eps; | 1515 | unsigned int limit_active_eps; |
1515 | /* There are two roothubs to keep track of bus suspend info for */ | 1516 | /* There are two roothubs to keep track of bus suspend info for */ |
@@ -1526,6 +1527,11 @@ struct xhci_hcd { | |||
1526 | unsigned sw_lpm_support:1; | 1527 | unsigned sw_lpm_support:1; |
1527 | /* support xHCI 1.0 spec USB2 hardware LPM */ | 1528 | /* support xHCI 1.0 spec USB2 hardware LPM */ |
1528 | unsigned hw_lpm_support:1; | 1529 | unsigned hw_lpm_support:1; |
1530 | /* Compliance Mode Recovery Data */ | ||
1531 | struct timer_list comp_mode_recovery_timer; | ||
1532 | u32 port_status_u0; | ||
1533 | /* Compliance Mode Timer Triggered every 2 seconds */ | ||
1534 | #define COMP_MODE_RCVRY_MSECS 2000 | ||
1529 | }; | 1535 | }; |
1530 | 1536 | ||
1531 | /* convert between an HCD pointer and the corresponding EHCI_HCD */ | 1537 | /* convert between an HCD pointer and the corresponding EHCI_HCD */ |