lkml.org 
[lkml]   [2017]   [Sep]   [9]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Date
    Subject[PATCH 3.2 025/106] xhci: workaround for hosts missing CAS bit
    3.2.93-rc1 review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Mathias Nyman <mathias.nyman@linux.intel.com>

    commit 346e99736c3ce328fd42d678343b70243aca5f36 upstream.

    If a device is unplugged and replugged during Sx system suspend
    some Intel xHC hosts will overwrite the CAS (Cold attach status) flag
    and no device connection is noticed in resume.

    A device in this state can be identified in resume if its link state
    is in polling or compliance mode, and the current connect status is 0.
    A device in this state needs to be warm reset.

    Intel 100/c230 series PCH specification update Doc #332692-006 Errata #8

    Observed on Cherryview and Apollolake as they go into compliance mode
    if LFPS times out during polling, and re-plugged devices are not
    discovered at resume.

    Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    [bwh: Backported to 3.2: adjust context]
    Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
    ---
    drivers/usb/host/xhci-hub.c | 37 +++++++++++++++++++++++++++++++++++++
    drivers/usb/host/xhci-pci.c | 6 ++++++
    drivers/usb/host/xhci.h | 3 +++
    3 files changed, 46 insertions(+)

    --- a/drivers/usb/host/xhci-hub.c
    +++ b/drivers/usb/host/xhci-hub.c
    @@ -1036,6 +1036,35 @@ int xhci_bus_suspend(struct usb_hcd *hcd
    return 0;
    }

    +/*
    + * Workaround for missing Cold Attach Status (CAS) if device re-plugged in S3.
    + * warm reset a USB3 device stuck in polling or compliance mode after resume.
    + * See Intel 100/c230 series PCH specification update Doc #332692-006 Errata #8
    + */
    +static bool xhci_port_missing_cas_quirk(int port_index,
    + __le32 __iomem **port_array)
    +{
    + u32 portsc;
    +
    + portsc = readl(port_array[port_index]);
    +
    + /* if any of these are set we are not stuck */
    + if (portsc & (PORT_CONNECT | PORT_CAS))
    + return false;
    +
    + if (((portsc & PORT_PLS_MASK) != XDEV_POLLING) &&
    + ((portsc & PORT_PLS_MASK) != XDEV_COMP_MODE))
    + return false;
    +
    + /* clear wakeup/change bits, and do a warm port reset */
    + portsc &= ~(PORT_RWC_BITS | PORT_CEC | PORT_WAKE_BITS);
    + portsc |= PORT_WR;
    + writel(portsc, port_array[port_index]);
    + /* flush write */
    + readl(port_array[port_index]);
    + return true;
    +}
    +
    int xhci_bus_resume(struct usb_hcd *hcd)
    {
    struct xhci_hcd *xhci = hcd_to_xhci(hcd);
    @@ -1070,6 +1099,14 @@ int xhci_bus_resume(struct usb_hcd *hcd)
    int slot_id;

    temp = xhci_readl(xhci, port_array[port_index]);
    +
    + /* warm reset CAS limited ports stuck in polling/compliance */
    + if ((xhci->quirks & XHCI_MISSING_CAS) &&
    + (hcd->speed >= HCD_USB3) &&
    + xhci_port_missing_cas_quirk(port_index, port_array)) {
    + xhci_dbg(xhci, "reset stuck port %d\n", port_index);
    + continue;
    + }
    if (DEV_SUPERSPEED(temp))
    temp &= ~(PORT_RWC_BITS | PORT_CEC | PORT_WAKE_BITS);
    else
    --- a/drivers/usb/host/xhci-pci.c
    +++ b/drivers/usb/host/xhci-pci.c
    @@ -42,6 +42,7 @@
    #define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCI 0x9d2f
    #define PCI_DEVICE_ID_INTEL_BROXTON_M_XHCI 0x0aa8
    #define PCI_DEVICE_ID_INTEL_BROXTON_B_XHCI 0x1aa8
    +#define PCI_DEVICE_ID_INTEL_APL_XHCI 0x5aa8

    static const char hcd_name[] = "xhci_hcd";

    @@ -141,6 +142,11 @@ static void xhci_pci_quirks(struct devic
    pdev->device == PCI_DEVICE_ID_INTEL_BROXTON_B_XHCI)) {
    xhci->quirks |= XHCI_PME_STUCK_QUIRK;
    }
    + if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
    + (pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI ||
    + pdev->device == PCI_DEVICE_ID_INTEL_APL_XHCI))
    + xhci->quirks |= XHCI_MISSING_CAS;
    +
    if (pdev->vendor == PCI_VENDOR_ID_ETRON &&
    pdev->device == PCI_DEVICE_ID_ASROCK_P67) {
    xhci->quirks |= XHCI_RESET_ON_RESUME;
    --- a/drivers/usb/host/xhci.h
    +++ b/drivers/usb/host/xhci.h
    @@ -280,6 +280,8 @@ struct xhci_op_regs {
    #define XDEV_U0 (0x0 << 5)
    #define XDEV_U2 (0x2 << 5)
    #define XDEV_U3 (0x3 << 5)
    +#define XDEV_POLLING (0x7 << 5)
    +#define XDEV_COMP_MODE (0xa << 5)
    #define XDEV_RESUME (0xf << 5)
    /* true: port has power (see HCC_PPC) */
    #define PORT_POWER (1 << 9)
    @@ -1499,6 +1501,7 @@ struct xhci_hcd {
    #define XHCI_SLOW_SUSPEND (1 << 17)
    #define XHCI_SPURIOUS_WAKEUP (1 << 18)
    #define XHCI_PME_STUCK_QUIRK (1 << 20)
    +#define XHCI_MISSING_CAS (1 << 24)
    unsigned int num_active_eps;
    unsigned int limit_active_eps;
    /* There are two roothubs to keep track of bus suspend info for */
    \
     
     \ /
      Last update: 2017-09-10 00:42    [W:6.615 / U:0.060 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site