[Bug 257082] Sound with Scarlett Solo 3rd intermittently cuts off for very short periods of milliseconds.

From: <bugzilla-noreply_at_freebsd.org>
Date: Sun, 11 Jul 2021 15:57:24 UTC
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=257082

--- Comment #16 from Hodong <hodong@nimfsoft.com> ---
(In reply to Hans Petter Selasky from comment #14)

I applied your patch to FreeBSD-13 and I'm listening to music and still having
the same problem.

An error occurred in xhci.c when applying your patch, so I applied it manually.
Perhaps only the line number is different.

diff --git a/sys/dev/usb/controller/xhci.c b/sys/dev/usb/controller/xhci.c
index 10e37c97c..690091fce 100644
--- a/sys/dev/usb/controller/xhci.c
+++ b/sys/dev/usb/controller/xhci.c
@@ -133,8 +133,8 @@ struct xhci_std_temp {
        uint32_t                offset;
        uint32_t                max_packet_size;
        uint32_t                average;
+       uint32_t                isoc_frame;
        uint16_t                isoc_delta;
-       uint16_t                isoc_frame;
        uint8_t                 shortpkt;
        uint8_t                 multishort;
        uint8_t                 last_frame;
@@ -644,6 +644,9 @@ xhci_init(struct xhci_softc *sc, device_t self, uint8_t
dma32)

        DPRINTF("HCS2=0x%08x\n", temp);

+       /* get isochronous scheduling threshold */
+       sc->sc_ist = XHCI_HCS2_IST(temp);
+
        /* get number of scratchpads */
        sc->sc_noscratch = XHCI_HCS2_SPB_MAX(temp);

@@ -2075,58 +2078,57 @@ xhci_setup_generic_chain(struct usb_xfer *xfer)

                x = XREAD4(temp.sc, runt, XHCI_MFINDEX);

-               DPRINTF("MFINDEX=0x%08x\n", x);
+               DPRINTF("MFINDEX=0x%08x IST=0x%x\n", x, temp.sc->sc_ist);

                switch (usbd_get_speed(xfer->xroot->udev)) {
                case USB_SPEED_FULL:
                        shift = 3;
                        temp.isoc_delta = 8;    /* 1ms */
-                       x += temp.isoc_delta - 1;
-                       x &= ~(temp.isoc_delta - 1);
                        break;
                default:
                        shift = usbd_xfer_get_fps_shift(xfer);
                        temp.isoc_delta = 1U << shift;
-                       x += temp.isoc_delta - 1;
-                       x &= ~(temp.isoc_delta - 1);
-                       /* simple frame load balancing */
-                       x += xfer->endpoint->usb_uframe;
                        break;
                }

-               y = XHCI_MFINDEX_GET(x - xfer->endpoint->isoc_next);
+               /* Compute isochronous scheduling threshold. */
+               if (temp.sc->sc_ist & 8)
+                       y = (temp.sc->sc_ist & 7) << 3;
+               else
+                       y = (temp.sc->sc_ist & 7);

-               if ((xfer->endpoint->is_synced == 0) ||
-                   (y < (xfer->nframes << shift)) ||
-                   (XHCI_MFINDEX_GET(-y) >= (128 * 8))) {
+               /* Range check the IST. */
+               if (y < 8) {
+                       y = 0;
+               } else if (y > 15) {
+                       DPRINTFN(3, "IST(%d) is too big!\n", temp.sc->sc_ist);
                        /*
-                        * If there is data underflow or the pipe
-                        * queue is empty we schedule the transfer a
-                        * few frames ahead of the current frame
-                        * position. Else two isochronous transfers
-                        * might overlap.
+                        * The USB stack minimum isochronous transfer
+                        * size is typically 2x2 ms of payload. If the
+                        * IST makes is above 15 microframes, we have
+                        * an effective scheduling delay of more than
+                        * or equal to 2 milliseconds, which is too
+                        * much.
                         */
-                       xfer->endpoint->isoc_next = XHCI_MFINDEX_GET(x + (3 *
8));
-                       xfer->endpoint->is_synced = 1;
-                       temp.do_isoc_sync = 1;
-
-                       DPRINTFN(3, "start next=%d\n",
xfer->endpoint->isoc_next);
+               } else {
+                       /*
+                        * Subtract one millisecond, because the
+                        * generic code adds that to the latency.
+                        */
+                       y -= 8;
                }

-               /* compute isochronous completion time */
-
-               y = XHCI_MFINDEX_GET(xfer->endpoint->isoc_next - (x & ~7));
+               if (usbd_xfer_get_isochronous_start_frame(
+                   xfer, x, y, 8, XHCI_MFINDEX_GET(-1), &temp.isoc_frame)) {
+                       /* Start isochronous transfer at specified time. */
+                       temp.do_isoc_sync = 1;

-               xfer->isoc_time_complete =
-                   usb_isoc_time_expand(&temp.sc->sc_bus, x / 8) +
-                   (y / 8) + (((xfer->nframes << shift) + 7) / 8);
+                       DPRINTFN(3, "start next=%d\n", temp.isoc_frame);
+               }

                x = 0;
-               temp.isoc_frame = xfer->endpoint->isoc_next;
                temp.trb_type = XHCI_TRB_TYPE_ISOCH;

-               xfer->endpoint->isoc_next += xfer->nframes << shift;
-
        } else if (xfer->flags_int.control_xfr) {
                /* check if we should prepend a setup message */

@@ -3063,15 +3065,7 @@ xhci_device_done(struct usb_xfer *xfer, usb_error_t
error)
 static void
 xhci_device_generic_open(struct usb_xfer *xfer)
 {
-       if (xfer->flags_int.isochronous_xfr) {
-               switch (xfer->xroot->udev->speed) {
-               case USB_SPEED_FULL:
-                       break;
-               default:
-                       usb_hs_bandwidth_alloc(xfer);
-                       break;
-               }
-       }
+       DPRINTF("\n");
 }

 static void
@@ -3080,16 +3074,6 @@ xhci_device_generic_close(struct usb_xfer *xfer)
        DPRINTF("\n");

        xhci_device_done(xfer, USB_ERR_CANCELLED);
-
-       if (xfer->flags_int.isochronous_xfr) {
-               switch (xfer->xroot->udev->speed) {
-               case USB_SPEED_FULL:
-                       break;
-               default:
-                       usb_hs_bandwidth_free(xfer);
-                       break;
-               }
-       }
 }

 static void

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

Before installing the kernel, I gave the following commands:

cd /boot
git init
git add .
git commit -m initial

So I can see that the kernel is properly installed.

-----------------------------------------------
/boot % git status
On branch master
Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   entropy
        deleted:    kernel.old/.freebsd-update
        modified:   kernel/ehci.ko
        modified:   kernel/kernel
        modified:   kernel/ohci.ko
        modified:   kernel/uhci.ko
        modified:   kernel/usb.ko
        modified:   kernel/xhci.ko

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        kernel.old/if_igb.ko
        kernel.old/if_ixlv.ko

no changes added to commit (use "git add" and/or "git commit -a")
-----------------------------------------------

The xhci.c of FreeBSD-13 and FreeBSD-14-CURRENT is different. So when I have
time later, I'll install FreeBSD-14-CURRENT and listen to music with Scarlett
Solo.
Thank you so much.

-- 
You are receiving this mail because:
You are the assignee for the bug.