lkml.org 
[lkml]   [2020]   [May]   [1]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.4 32/70] drivers: usb: core: Dont disable irqs in usb_sg_wait() during URB submit.
    Date
    From: David Mosberger <davidm@egauge.net>

    commit 98b74b0ee57af1bcb6e8b2e76e707a71c5ef8ec9 upstream.

    usb_submit_urb() may take quite long to execute. For example, a
    single sg list may have 30 or more entries, possibly leading to that
    many calls to DMA-map pages. This can cause interrupt latency of
    several hundred micro-seconds.

    Avoid the problem by releasing the io->lock spinlock and re-enabling
    interrupts before calling usb_submit_urb(). This opens races with
    usb_sg_cancel() and sg_complete(). Handle those races by using
    usb_block_urb() to stop URBs from being submitted after
    usb_sg_cancel() or sg_complete() with error.

    Note that usb_unlink_urb() is guaranteed to return -ENODEV if
    !io->urbs[i]->dev and since the -ENODEV case is already handled,
    we don't have to check for !io->urbs[i]->dev explicitly.

    Before this change, reading 512MB from an ext3 filesystem on a USB
    memory stick showed a throughput of 12 MB/s with about 500 missed
    deadlines.

    With this change, reading the same file gave the same throughput but
    only one or two missed deadlines.

    Signed-off-by: David Mosberger <davidm@egauge.net>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    drivers/usb/core/message.c | 15 +++++++--------
    1 file changed, 7 insertions(+), 8 deletions(-)

    --- a/drivers/usb/core/message.c
    +++ b/drivers/usb/core/message.c
    @@ -306,9 +306,10 @@ static void sg_complete(struct urb *urb)
    */
    spin_unlock(&io->lock);
    for (i = 0, found = 0; i < io->entries; i++) {
    - if (!io->urbs[i] || !io->urbs[i]->dev)
    + if (!io->urbs[i])
    continue;
    if (found) {
    + usb_block_urb(io->urbs[i]);
    retval = usb_unlink_urb(io->urbs[i]);
    if (retval != -EINPROGRESS &&
    retval != -ENODEV &&
    @@ -519,12 +520,10 @@ void usb_sg_wait(struct usb_sg_request *
    int retval;

    io->urbs[i]->dev = io->dev;
    - retval = usb_submit_urb(io->urbs[i], GFP_ATOMIC);
    -
    - /* after we submit, let completions or cancellations fire;
    - * we handshake using io->status.
    - */
    spin_unlock_irq(&io->lock);
    +
    + retval = usb_submit_urb(io->urbs[i], GFP_NOIO);
    +
    switch (retval) {
    /* maybe we retrying will recover */
    case -ENXIO: /* hc didn't queue this one */
    @@ -594,8 +593,8 @@ void usb_sg_cancel(struct usb_sg_request
    for (i = 0; i < io->entries; i++) {
    int retval;

    - if (!io->urbs[i]->dev)
    - continue;
    + usb_block_urb(io->urbs[i]);
    +
    retval = usb_unlink_urb(io->urbs[i]);
    if (retval != -EINPROGRESS
    && retval != -ENODEV

    \
     
     \ /
      Last update: 2020-05-01 15:26    [W:3.691 / U:0.004 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site