lkml.org 
[lkml]   [2021]   [Jan]   [26]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.10 140/199] xhci: make sure TRB is fully written before giving it to the controller
    Date
    From: Mathias Nyman <mathias.nyman@linux.intel.com>

    commit 576667bad341516edc4e18eb85acb0a2b4c9c9d9 upstream.

    Once the command ring doorbell is rung the xHC controller will parse all
    command TRBs on the command ring that have the cycle bit set properly.

    If the driver just started writing the next command TRB to the ring when
    hardware finished the previous TRB, then HW might fetch an incomplete TRB
    as long as its cycle bit set correctly.

    A command TRB is 16 bytes (128 bits) long.
    Driver writes the command TRB in four 32 bit chunks, with the chunk
    containing the cycle bit last. This does however not guarantee that
    chunks actually get written in that order.

    This was detected in stress testing when canceling URBs with several
    connected USB devices.
    Two consecutive "Set TR Dequeue pointer" commands got queued right
    after each other, and the second one was only partially written when
    the controller parsed it, causing the dequeue pointer to be set
    to bogus values. This was seen as error messages:

    "Mismatch between completed Set TR Deq Ptr command & xHCI internal state"

    Solution is to add a write memory barrier before writing the cycle bit.

    Cc: <stable@vger.kernel.org>
    Tested-by: Ross Zwisler <zwisler@google.com>
    Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
    Link: https://lore.kernel.org/r/20210115161907.2875631-2-mathias.nyman@linux.intel.com
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    drivers/usb/host/xhci-ring.c | 2 ++
    1 file changed, 2 insertions(+)

    --- a/drivers/usb/host/xhci-ring.c
    +++ b/drivers/usb/host/xhci-ring.c
    @@ -2930,6 +2930,8 @@ static void queue_trb(struct xhci_hcd *x
    trb->field[0] = cpu_to_le32(field1);
    trb->field[1] = cpu_to_le32(field2);
    trb->field[2] = cpu_to_le32(field3);
    + /* make sure TRB is fully written before giving it to the controller */
    + wmb();
    trb->field[3] = cpu_to_le32(field4);

    trace_xhci_queue_trb(ring, trb);

    \
     
     \ /
      Last update: 2021-01-26 10:56    [W:4.346 / U:0.196 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site