lkml.org 
[lkml]   [2015]   [Nov]   [9]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v3 04/12] usb: xhci: dbc: add support for Intel xHCI dbc quirk
    Date
    On Intel platform, if the debug target is connected with debug
    host, enabling DCE bit in command register leads to a hung bus
    state. In the hung state, the host system will not see a port
    connected status bit set. Hence debug target fails to be probed.

    The state could be resolved by performing a port reset to the
    debug port from the host xHCI. This patch introduces this work
    around.

    Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
    ---
    drivers/usb/early/xhci-dbc.c | 52 ++++++++++++++++++++++++++++++++++++++++++++
    include/linux/usb/xhci-dbc.h | 2 ++
    2 files changed, 54 insertions(+)

    diff --git a/drivers/usb/early/xhci-dbc.c b/drivers/usb/early/xhci-dbc.c
    index 22a1de9..6b23f09 100644
    --- a/drivers/usb/early/xhci-dbc.c
    +++ b/drivers/usb/early/xhci-dbc.c
    @@ -255,6 +255,8 @@ static void __iomem *xdbc_map_pci_mmio(u32 bus,
    xdbcp->bar = bar;
    xdbcp->xhci_base = base;
    xdbcp->xhci_length = sz64;
    + xdbcp->vendor = read_pci_config_16(bus, dev, func, PCI_VENDOR_ID);
    + xdbcp->device = read_pci_config_16(bus, dev, func, PCI_DEVICE_ID);

    if (length)
    *length = sz64;
    @@ -651,6 +653,52 @@ static int xdbc_mem_init(void)
    return 0;
    }

    +static void xdbc_reset_debug_port_callback(int cap_offset, void *data)
    +{
    + u8 major;
    + u32 val, port_offset, port_count;
    + u32 cap_length;
    + void __iomem *ops_reg;
    + void __iomem *portsc;
    + int i;
    +
    + val = readl(xdbcp->xhci_base + cap_offset);
    + major = (u8) XHCI_EXT_PORT_MAJOR(val);
    +
    + /* only reset super-speed port */
    + if (major != 0x3)
    + return;
    +
    + val = readl(xdbcp->xhci_base + cap_offset + 8);
    + port_offset = XHCI_EXT_PORT_OFF(val);
    + port_count = XHCI_EXT_PORT_COUNT(val);
    + xdbc_trace("Extcap Port offset %d count %d\n",
    + port_offset, port_count);
    +
    + cap_length = readl(xdbcp->xhci_base) & 0xff;
    + ops_reg = xdbcp->xhci_base + cap_length;
    +
    + port_offset--;
    + for (i = port_offset; i < (port_offset + port_count); i++) {
    + portsc = ops_reg + 0x400 + i * 0x10;
    + val = readl(portsc);
    + /* reset the port if CCS bit is cleared */
    + if (!(val & 0x1))
    + writel(val | (1 << 4), portsc);
    + }
    +}
    +
    +static void xdbc_reset_debug_port(void)
    +{
    + xdbc_walk_excap(xdbcp->bus,
    + xdbcp->dev,
    + xdbcp->func,
    + XHCI_EXT_CAPS_PROTOCOL,
    + false,
    + xdbc_reset_debug_port_callback,
    + NULL);
    +}
    +
    /*
    * xdbc_start: start DbC
    *
    @@ -669,6 +717,10 @@ static int xdbc_start(void)
    return -ENODEV;
    }

    + /* reset port to avoid bus hang */
    + if (xdbcp->vendor == PCI_VENDOR_ID_INTEL)
    + xdbc_reset_debug_port();
    +
    /* wait for port connection */
    if (handshake(&xdbcp->xdbc_reg->portsc, PORTSC_CCS,
    PORTSC_CCS, 5000000, 100) < 0) {
    diff --git a/include/linux/usb/xhci-dbc.h b/include/linux/usb/xhci-dbc.h
    index 153fb87..fc0ef9a 100644
    --- a/include/linux/usb/xhci-dbc.h
    +++ b/include/linux/usb/xhci-dbc.h
    @@ -128,6 +128,8 @@ struct xdbc_state {
    u32 dev;
    u32 func;
    u8 bar;
    + u16 vendor;
    + u16 device;
    void __iomem *xhci_base;
    size_t xhci_length;
    #define XDBC_PCI_MAX_BUSES 256
    --
    2.1.4


    \
     
     \ /
      Last update: 2015-11-09 09:01    [W:4.329 / U:0.152 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site