Regressions List Tracking
 help / color / mirror / Atom feed
From: Chris Yokum <linux-usb@mail.totalphase.com>
To: stable@vger.kernel.org
Cc: regressions@lists.linux.dev
Subject: 6.5.0 broke XHCI URB submissions for count >512
Date: Fri, 1 Mar 2024 16:27:46 -0800 (PST)	[thread overview]
Message-ID: <949223224.833962.1709339266739.JavaMail.zimbra@totalphase.com> (raw)


[-- Attachment #1.1: Type: text/plain, Size: 1828 bytes --]



We have found a regression bug, where more than 512 URBs cannot be reliably submitted to XHCI. URBs beyond that return 0x00 instead of valid data in the buffer. 




Our software works reliably on kernel versions through 6.4.x and fails on versions 6.5, 6.6, 6.7, and 6.8.0-rc6. This was discovered when Ubuntu recently updated their latest kernel package to version 6.5. 




The issue is limited to the XHCI driver and appears to be isolated to this specific commit: 

[ https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/drivers/usb?h=v6.5&id=f5af638f0609af889f15c700c60b93c06cc76675 | https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/drivers/usb?h=v6.5&id=f5af638f0609af889f15c700c60b93c06cc76675 ] 




Attached is a test program that demonstrates the problem. We used a few different USB-to-Serial adapters with no driver installed as a convenient way to reproduce. We check the TRB debug information before and after to verify the actual number of allocated TRBs. 




With some adapters on unaffected kernels, the TRB map gets expanded correctly. This directly corresponds to correct functional behavior. On affected kernels, the TRB ring does not expand, and our functional tests also will fail. 




We don't know exactly why this happens. Some adapters do work correctly, so there seems to also be some subtle problem that was being masked by the liberal expansion of the TRB ring in older kernels. We also saw on one system that the TRB expansion did work correctly with one particular adapter. However, on all systems at least two adapters did exhibit the problem and fail. 




Would it be possible to resolve this regression for the 6.8 release and backport the fix to versions 6.5, 6.6, and 6.7? 

#regzbot ^introduced: f5af638f0609af889f15c700c60b93c06cc76675 

[-- Attachment #1.2: Type: text/html, Size: 20668 bytes --]

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: xhci_bug.c --]
[-- Type: text/x-csrc; name=xhci_bug.c, Size: 3923 bytes --]

// Test case for XHCI buffer expansion regression
//
// 1) Compile this program:  gcc -o xhci_bug xhci_bug.c
// 2) Plug in a supported USB to serial device
// 3) Get the bus and device numbers from lsusb:
//    Bus 003 Device 015: ID 0403:6001 Future Technology Devices International, Ltd FT232 Serial (UART) IC
// 4) Run as root:  ./xhci_bug ftdi_sio 3 15 4096

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/usbdevice_fs.h>

#define URB_SIZE 64

struct Device {
    const char *driver;
    int         ep;
    const char *ep_debug;
};

static struct Device devices[] = {
    { "ftdi_sio", 0x81, "ep02" },
    { "pl2303",   0x83, "ep06" },
    { "cp210x",   0x82, "ep04" },
    { },
};

int main (int argc, char *argv[])
{
    // Parse command line
    if (argc < 4) {
        char drivers[255] = { };
        for (int i = 0; devices[i].driver; ++i) {
            strcat(drivers, devices[i].driver);
            if (devices[i+1].driver) strcat(drivers, "|");
        }

        printf("usage: xhci_bug <%s> BUS DEV NUM_URBS\n", drivers);
        return 1;
    }

    const char *driver = argv[1];
    int bus = atoi(argv[2]);
    int dev = atoi(argv[3]);
    int num_urbs = atoi(argv[4]);

    if (num_urbs > 4096)
        num_urbs = 4096;

    // Find the driver
    struct Device *device = NULL;
    for (int i = 0; devices[i].driver; ++i) {
        if (strcmp(devices[i].driver, driver) == 0) {
            device = &devices[i];
            break;
        }
    }

    if (device == NULL) {
        printf("error: driver %s not found\n", driver);
        return 1;
    }

    // Remove the driver
    char cmd[1024];
    sprintf(cmd, "lsmod | grep %s -q && rmmod %s", driver, driver);
    system(cmd);

    // Get the debug path
    char debug[256] = { };

    sprintf(
        cmd,
        "find /sys/kernel/debug/usb/xhci -name 'name' | "
        "while IFS= read -r line; do "
        "dir=$(dirname $line); "
        "sys=/sys/bus/usb/devices/$(cat $dir/name); "
        "grep -q '^%d$' $sys/busnum && "
        "grep -q '^%d$' $sys/devnum && "
        "echo $dir; "
        "done",
        bus, dev
    );

    FILE *fp = popen(cmd, "r");
    char *p = fgets(debug, sizeof(debug), fp);
    pclose(fp);

    if (p == NULL) {
        printf("error: debug path not found\n");
        return 1;
    }

    debug[strlen(debug)-1] = '\0';

    // Print the number of TRBs
    printf("Before URB submission:\n");
    sprintf(cmd, "wc -l %s/%s/trbs", debug, device->ep_debug);
    system(cmd);
    printf("\n");

    // Open the device
    char path[256];
    sprintf(path, "/dev/bus/usb/%03d/%03d", bus, dev);

    int fd = open(path, O_RDWR);
    if (fd < 0)
        return 1;

    int rc;

    int cfg = 1;
    rc = ioctl(fd, USBDEVFS_SETCONFIGURATION, &cfg);
    if (rc < 0 && errno != EBUSY) {
        printf("error: unable to set configuration\n");
        close(fd);
        return 1;
    }

    int ifce = 0;
    rc = ioctl(fd, USBDEVFS_CLAIMINTERFACE, &ifce);
    if (rc < 0) {
        printf("error: unable to claim interface\n");
        close(fd);
        return 1;
    }

    // Submit URBs
    printf("Submitting %d URBs\n\n", num_urbs);

    for (int i = 0; i < num_urbs; ++i) {
        struct usbdevfs_urb *ioctl_urb = calloc(1, sizeof(*ioctl_urb));

        ioctl_urb->type          = USBDEVFS_URB_TYPE_BULK;
        ioctl_urb->endpoint      = device->ep;
        ioctl_urb->buffer        = calloc(1, URB_SIZE);
        ioctl_urb->buffer_length = URB_SIZE;

        rc = ioctl(fd, USBDEVFS_SUBMITURB, ioctl_urb);
        if (rc < 0) {
            printf("error: could not submit urb #%d\n", i);
            return 1;
        }
    }

    // Print the number of TRBs
    printf("After URB submission:\n");
    system(cmd);
    printf("\n");

    // Close the device
    close(fd);
    return 0;
}

             reply	other threads:[~2024-03-02  0:27 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-03-02  0:27 Chris Yokum [this message]
2024-03-02  6:53 ` 6.5.0 broke XHCI URB submissions for count >512 Linux regression tracking (Thorsten Leemhuis)
2024-03-02  7:14   ` Greg Kroah-Hartman
2024-03-02 15:55     ` Chris Yokum
2024-03-04 11:57       ` Mathias Nyman
2024-03-04 15:53         ` Mathias Nyman
2024-03-04 23:50           ` Chris Yokum
2024-03-11 17:03             ` Chris Yokum
2024-03-12  8:52               ` Mathias Nyman

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=949223224.833962.1709339266739.JavaMail.zimbra@totalphase.com \
    --to=linux-usb@mail.totalphase.com \
    --cc=regressions@lists.linux.dev \
    --cc=stable@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).