lkml.org 
[lkml]   [2012]   [May]   [26]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[ 42/55] xhci: Add new short TX quirk for Fresco Logic host.
    3.0-stable review patch.  If anyone has any objections, please let me know.

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

    From: Sarah Sharp <sarah.a.sharp@linux.intel.com>

    commit 1530bbc6272d9da1e39ef8e06190d42c13a02733 upstream.

    Sergio reported that when he recorded audio from a USB headset mic
    plugged into the USB 3.0 port on his ASUS N53SV-DH72, the audio sounded
    "robotic". When plugged into the USB 2.0 port under EHCI on the same
    laptop, the audio sounded fine. The device is:

    Bus 002 Device 004: ID 046d:0a0c Logitech, Inc. Clear Chat Comfort USB Headset

    The problem was tracked down to the Fresco Logic xHCI host controller
    not correctly reporting short transfers on isochronous IN endpoints.
    The driver would submit a 96 byte transfer, the device would only send
    88 or 90 bytes, and the xHCI host would report the transfer had a
    "successful" completion code, with an untransferred buffer length of 8
    or 6 bytes.

    The successful completion code and non-zero untransferred length is a
    contradiction. The xHCI host is supposed to only mark a transfer as
    successful if all the bytes are transferred. Otherwise, the transfer
    should be marked with a short packet completion code. Without the EHCI
    bus trace, we wouldn't know whether the xHCI driver should trust the
    completion code or the untransferred length. With it, we know to trust
    the untransferred length.

    Add a new xHCI quirk for the Fresco Logic host controller. If a
    transfer is reported as successful, but the untransferred length is
    non-zero, print a warning. For the Fresco Logic host, change the
    completion code to COMP_SHORT_TX and process the transfer like a short
    transfer.

    This should be backported to stable kernels that contain the commit
    f5182b4155b9d686c5540a6822486400e34ddd98 "xhci: Disable MSI for some
    Fresco Logic hosts." That commit was marked for stable kernels as old
    as 2.6.36.

    Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
    Reported-by: Sergio Correia <lists@uece.net>
    Tested-by: Sergio Correia <lists@uece.net>
    Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    drivers/usb/host/xhci-pci.c | 1 +
    drivers/usb/host/xhci-ring.c | 20 +++++++++++++++++---
    drivers/usb/host/xhci.h | 1 +
    3 files changed, 19 insertions(+), 3 deletions(-)

    --- a/drivers/usb/host/xhci-pci.c
    +++ b/drivers/usb/host/xhci-pci.c
    @@ -123,6 +123,7 @@ static int xhci_pci_setup(struct usb_hcd
    xhci_dbg(xhci, "QUIRK: Fresco Logic revision %u "
    "has broken MSI implementation\n",
    pdev->revision);
    + xhci->quirks |= XHCI_TRUST_TX_LENGTH;
    }

    if (pdev->vendor == PCI_VENDOR_ID_NEC)
    --- a/drivers/usb/host/xhci-ring.c
    +++ b/drivers/usb/host/xhci-ring.c
    @@ -1739,8 +1739,12 @@ static int process_isoc_td(struct xhci_h
    /* handle completion code */
    switch (trb_comp_code) {
    case COMP_SUCCESS:
    - frame->status = 0;
    - break;
    + if (TRB_LEN(le32_to_cpu(event->transfer_len)) == 0) {
    + frame->status = 0;
    + break;
    + }
    + if ((xhci->quirks & XHCI_TRUST_TX_LENGTH))
    + trb_comp_code = COMP_SHORT_TX;
    case COMP_SHORT_TX:
    frame->status = td->urb->transfer_flags & URB_SHORT_NOT_OK ?
    -EREMOTEIO : 0;
    @@ -1839,13 +1843,16 @@ static int process_bulk_intr_td(struct x
    switch (trb_comp_code) {
    case COMP_SUCCESS:
    /* Double check that the HW transferred everything. */
    - if (event_trb != td->last_trb) {
    + if (event_trb != td->last_trb ||
    + TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) {
    xhci_warn(xhci, "WARN Successful completion "
    "on short TX\n");
    if (td->urb->transfer_flags & URB_SHORT_NOT_OK)
    *status = -EREMOTEIO;
    else
    *status = 0;
    + if ((xhci->quirks & XHCI_TRUST_TX_LENGTH))
    + trb_comp_code = COMP_SHORT_TX;
    } else {
    *status = 0;
    }
    @@ -1986,6 +1993,13 @@ static int handle_tx_event(struct xhci_h
    * transfer type
    */
    case COMP_SUCCESS:
    + if (TRB_LEN(le32_to_cpu(event->transfer_len)) == 0)
    + break;
    + if (xhci->quirks & XHCI_TRUST_TX_LENGTH)
    + trb_comp_code = COMP_SHORT_TX;
    + else
    + xhci_warn(xhci, "WARN Successful completion on short TX: "
    + "needs XHCI_TRUST_TX_LENGTH quirk?\n");
    case COMP_SHORT_TX:
    break;
    case COMP_STOP:
    --- a/drivers/usb/host/xhci.h
    +++ b/drivers/usb/host/xhci.h
    @@ -1315,6 +1315,7 @@ struct xhci_hcd {
    #define XHCI_BROKEN_MSI (1 << 6)
    #define XHCI_RESET_ON_RESUME (1 << 7)
    #define XHCI_AMD_0x96_HOST (1 << 9)
    +#define XHCI_TRUST_TX_LENGTH (1 << 10)
    unsigned int num_active_eps;
    unsigned int limit_active_eps;
    /* There are two roothubs to keep track of bus suspend info for */



    \
     
     \ /
      Last update: 2012-05-27 03:41    [W:0.028 / U:0.104 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site