Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/usb - Fix clearing of EINT and other transient flags.



details:   https://anonhg.NetBSD.org/src/rev/94ced2f660e4
branches:  trunk
changeset: 376219:94ced2f660e4
user:      mlelstv <mlelstv%NetBSD.org@localhost>
date:      Mon Jun 05 03:44:47 2023 +0000

description:
- Fix clearing of EINT and other transient flags.

Patches from sc.dying in kern/56115:
- Set proper Max ESIT Payload value for interrupt/isoc endpoint context.
- Set proper Average TRB Length value.
- Not tested on superspeed/superspeedplus isochronous device.

- Add handling of some error paths for isochronous transfers.

diffstat:

 sys/dev/usb/xhci.c    |  283 ++++++++++++++++++++++++++++++++-----------------
 sys/dev/usb/xhcireg.h |   11 +-
 2 files changed, 193 insertions(+), 101 deletions(-)

diffs (truncated from 420 to 300 lines):

diff -r 0e5d1d5fc3f3 -r 94ced2f660e4 sys/dev/usb/xhci.c
--- a/sys/dev/usb/xhci.c        Sun Jun 04 23:42:38 2023 +0000
+++ b/sys/dev/usb/xhci.c        Mon Jun 05 03:44:47 2023 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: xhci.c,v 1.178 2023/04/27 06:30:09 skrll Exp $ */
+/*     $NetBSD: xhci.c,v 1.179 2023/06/05 03:44:47 mlelstv Exp $       */
 
 /*
  * Copyright (c) 2013 Jonathan A. Kollasch
@@ -34,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: xhci.c,v 1.178 2023/04/27 06:30:09 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: xhci.c,v 1.179 2023/06/05 03:44:47 mlelstv Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_usb.h"
@@ -192,7 +192,7 @@ static void xhci_setup_ctx(struct usbd_p
 static void xhci_setup_route(struct usbd_pipe *, uint32_t *);
 static void xhci_setup_tthub(struct usbd_pipe *, uint32_t *);
 static void xhci_setup_maxburst(struct usbd_pipe *, uint32_t *);
-static uint32_t xhci_bival2ival(uint32_t, uint32_t);
+static uint32_t xhci_bival2ival(uint32_t, uint32_t, uint32_t);
 
 static void xhci_noop(struct usbd_pipe *);
 
@@ -1765,7 +1765,7 @@ xhci_intr1(struct xhci_softc * const sc)
         * next shared interrupt. Also, to avoid race, EINT must be cleared
         * before XHCI_IMAN_INTR_PEND is cleared.
         */
-       xhci_op_write_4(sc, XHCI_USBSTS, usbsts & XHCI_STS_RSVDP0);
+       xhci_op_write_4(sc, XHCI_USBSTS, usbsts & ~XHCI_STS_RSVDP0);
 
 #ifdef XHCI_DEBUG
        usbsts = xhci_op_read_4(sc, XHCI_USBSTS);
@@ -2497,8 +2497,6 @@ xhci_event_transfer(struct xhci_softc * 
                        xfer->ux_frlengths[xx->xx_isoc_done] -=
                            XHCI_TRB_2_REM_GET(trb_2);
                        xfer->ux_actlen += xfer->ux_frlengths[xx->xx_isoc_done];
-                       if (++xx->xx_isoc_done < xfer->ux_nframes)
-                               return;
                } else
                if ((trb_3 & XHCI_TRB_3_ED_BIT) == 0) {
                        if (xfer->ux_actlen == 0)
@@ -2530,6 +2528,22 @@ xhci_event_transfer(struct xhci_softc * 
                break;
        }
 
+       if (xfertype == UE_ISOCHRONOUS) {
+               switch (trbcode) {
+               case XHCI_TRB_ERROR_SHORT_PKT:
+               case XHCI_TRB_ERROR_SUCCESS:
+                       break;
+               case XHCI_TRB_ERROR_MISSED_SERVICE:
+               case XHCI_TRB_ERROR_RING_UNDERRUN:
+               case XHCI_TRB_ERROR_RING_OVERRUN:
+               default:
+                       xfer->ux_frlengths[xx->xx_isoc_done] = 0;
+                       break;
+               }
+               if (++xx->xx_isoc_done < xfer->ux_nframes)
+                       return;
+       }
+
        if ((trb_3 & XHCI_TRB_3_ED_BIT) == 0 ||
            (trb_0 & 0x3) == 0x0) {
                /*
@@ -3552,9 +3566,7 @@ xhci_setup_ctx(struct usbd_pipe *pipe)
        const u_int dci = xhci_ep_get_dci(ed);
        const uint8_t xfertype = UE_GET_XFERTYPE(ed->bmAttributes);
        uint32_t *cp;
-       uint16_t mps = UGETW(ed->wMaxPacketSize);
        uint8_t speed = dev->ud_speed;
-       uint8_t ival = ed->bInterval;
 
        XHCIHIST_FUNC();
        XHCIHIST_CALLARGS("pipe %#jx: slot %ju dci %ju speed %ju",
@@ -3599,43 +3611,16 @@ xhci_setup_ctx(struct usbd_pipe *pipe)
        if (xfertype != UE_ISOCHRONOUS)
                cp[1] |= XHCI_EPCTX_1_CERR_SET(3);
 
-       if (xfertype == UE_CONTROL)
-               cp[4] = XHCI_EPCTX_4_AVG_TRB_LEN_SET(8); /* 6.2.3 */
-       else if (USB_IS_SS(speed))
-               cp[4] = XHCI_EPCTX_4_AVG_TRB_LEN_SET(mps);
-       else
-               cp[4] = XHCI_EPCTX_4_AVG_TRB_LEN_SET(UE_GET_SIZE(mps));
-
        xhci_setup_maxburst(pipe, cp);
 
-       switch (xfertype) {
-       case UE_CONTROL:
-               break;
-       case UE_BULK:
-               /* XXX Set MaxPStreams, HID, and LSA if streams enabled */
-               break;
-       case UE_INTERRUPT:
-               if (pipe->up_interval != USBD_DEFAULT_INTERVAL)
-                       ival = pipe->up_interval;
-
-               ival = xhci_bival2ival(ival, speed);
-               cp[0] |= XHCI_EPCTX_0_IVAL_SET(ival);
-               break;
-       case UE_ISOCHRONOUS:
-               if (pipe->up_interval != USBD_DEFAULT_INTERVAL)
-                       ival = pipe->up_interval;
-
-               /* xHCI 6.2.3.6 Table 65, USB 2.0 9.6.6 */
-               if (speed == USB_SPEED_FULL)
-                       ival += 3; /* 1ms -> 125us */
-               ival--;
-               cp[0] |= XHCI_EPCTX_0_IVAL_SET(ival);
-               break;
-       default:
-               break;
-       }
-       DPRINTFN(4, "setting ival %ju MaxBurst %#jx",
-           XHCI_EPCTX_0_IVAL_GET(cp[0]), XHCI_EPCTX_1_MAXB_GET(cp[1]), 0, 0);
+       DPRINTFN(4, "setting on dci %ju ival %ju mult %ju mps %#jx",
+           dci, XHCI_EPCTX_0_IVAL_GET(cp[0]), XHCI_EPCTX_0_MULT_GET(cp[0]),
+           XHCI_EPCTX_1_MAXP_SIZE_GET(cp[1]));
+       DPRINTFN(4, " maxburst %ju mep %#jx atl %#jx",
+           XHCI_EPCTX_1_MAXB_GET(cp[1]),
+           (XHCI_EPCTX_0_MAX_ESIT_PAYLOAD_HI_GET(cp[0]) << 16) +
+           XHCI_EPCTX_4_MAX_ESIT_PAYLOAD_GET(cp[4]),
+           XHCI_EPCTX_4_AVG_TRB_LEN_GET(cp[4]), 0);
 
        /* rewind TR dequeue pointer in xHC */
        /* can't use xhci_ep_get_dci() yet? */
@@ -3820,29 +3805,24 @@ xhci_setup_tthub(struct usbd_pipe *pipe,
            XHCI_SCTX_2_TT_PORT_NUM_SET(ttportnum);
 }
 
-/* set up params for periodic endpoint */
-static void
-xhci_setup_maxburst(struct usbd_pipe *pipe, uint32_t *cp)
+static const usb_endpoint_ss_comp_descriptor_t *
+xhci_get_essc_desc(struct usbd_pipe *pipe)
 {
-       struct xhci_pipe * const xpipe = (struct xhci_pipe *)pipe;
        struct usbd_device *dev = pipe->up_dev;
        usb_endpoint_descriptor_t * const ed = pipe->up_endpoint->ue_edesc;
-       const uint8_t xfertype = UE_GET_XFERTYPE(ed->bmAttributes);
+       const usb_cdc_descriptor_t *cdcd;
        usbd_desc_iter_t iter;
-       const usb_cdc_descriptor_t *cdcd;
-       uint32_t maxb = 0;
-       uint16_t mps = UGETW(ed->wMaxPacketSize);
-       uint8_t speed = dev->ud_speed;
-       uint8_t mult = 0;
        uint8_t ep;
 
        /* config desc is NULL when opening ep0 */
        if (dev == NULL || dev->ud_cdesc == NULL)
-               goto no_cdcd;
+               return NULL;
+
        cdcd = (const usb_cdc_descriptor_t *)usb_find_desc(dev,
            UDESC_INTERFACE, USBD_CDCSUBTYPE_ANY);
        if (cdcd == NULL)
-               goto no_cdcd;
+               return NULL;
+
        usb_desc_iter_init(dev, &iter);
        iter.cur = (const void *)cdcd;
 
@@ -3864,61 +3844,153 @@ xhci_setup_maxburst(struct usbd_pipe *pi
                }
        }
        if (cdcd != NULL && cdcd->bDescriptorType == UDESC_ENDPOINT_SS_COMP) {
-               const usb_endpoint_ss_comp_descriptor_t * esscd =
-                   (const usb_endpoint_ss_comp_descriptor_t *)cdcd;
-               maxb = esscd->bMaxBurst;
-               mult = UE_GET_SS_ISO_MULT(esscd->bmAttributes);
+               return (const usb_endpoint_ss_comp_descriptor_t *)cdcd;
        }
-
- no_cdcd:
-       /* 6.2.3.4,  4.8.2.4 */
-       if (USB_IS_SS(speed)) {
-               /* USB 3.1  9.6.6 */
-               cp[1] |= XHCI_EPCTX_1_MAXP_SIZE_SET(mps);
-               /* USB 3.1  9.6.7 */
-               cp[1] |= XHCI_EPCTX_1_MAXB_SET(maxb);
-#ifdef notyet
-               if (xfertype == UE_ISOCHRONOUS) {
+       return NULL;
+}
+
+/* set up params for periodic endpoint */
+static void
+xhci_setup_maxburst(struct usbd_pipe *pipe, uint32_t *cp)
+{
+       struct xhci_pipe * const xpipe = (struct xhci_pipe *)pipe;
+       struct xhci_softc * const sc = XHCI_PIPE2SC(pipe);
+       struct usbd_device * const dev = pipe->up_dev;
+       usb_endpoint_descriptor_t * const ed = pipe->up_endpoint->ue_edesc;
+       const uint8_t xfertype = UE_GET_XFERTYPE(ed->bmAttributes);
+       uint16_t mps = UGETW(ed->wMaxPacketSize);
+       uint8_t speed = dev->ud_speed;
+       uint32_t maxb, mep, atl;
+       uint8_t ival, mult;
+
+       const usb_endpoint_ss_comp_descriptor_t * esscd =
+           xhci_get_essc_desc(pipe);
+
+       /* USB 2.0  9.6.6, xHCI 4.8.2.4, 6.2.3.2 - 6.2.3.8 */
+       switch (xfertype) {
+       case UE_ISOCHRONOUS:
+       case UE_INTERRUPT:
+               if (USB_IS_SS(speed)) {
+                       maxb = esscd ? esscd->bMaxBurst : UE_GET_TRANS(mps);
+                       mep = esscd ? UGETW(esscd->wBytesPerInterval) :
+                           UE_GET_SIZE(mps) * (maxb + 1);
+                       if (esscd && xfertype == UE_ISOCHRONOUS &&
+                           XHCI_HCC2_LEC(sc->sc_hcc2) == 0) {
+                               mult = UE_GET_SS_ISO_MULT(esscd->bmAttributes);
+                               mult = (mult > 2) ? 2 : mult;
+                       } else
+                               mult = 0;
+
+               } else {
+                       switch (speed) {
+                       case USB_SPEED_HIGH:
+                               maxb = UE_GET_TRANS(mps);
+                               mep = UE_GET_SIZE(mps) * (maxb + 1);
+                               break;
+                       case USB_SPEED_FULL:
+                               maxb = 0;
+                               mep = UE_GET_SIZE(mps);
+                               break;
+                       default:
+                               maxb = 0;
+                               mep = 0;
+                               break;
+                       }
+                       mult = 0;
                }
-               if (XHCI_HCC2_LEC(sc->sc_hcc2) != 0) {
-                       /* use ESIT */
-                       cp[4] |= XHCI_EPCTX_4_MAX_ESIT_PAYLOAD_SET(x);
-                       cp[0] |= XHCI_EPCTX_0_MAX_ESIT_PAYLOAD_HI_SET(x);
-
-                       /* XXX if LEC = 1, set ESIT instead */
-                       cp[0] |= XHCI_EPCTX_0_MULT_SET(0);
-               } else {
-                       /* use ival */
+               mps = UE_GET_SIZE(mps);
+
+               if (pipe->up_interval == USBD_DEFAULT_INTERVAL)
+                       ival = ed->bInterval;
+               else
+                       ival = pipe->up_interval;
+
+               ival = xhci_bival2ival(ival, speed, xfertype);
+               atl = mep;
+               break;
+       case UE_CONTROL:
+       case UE_BULK:
+       default:
+               if (USB_IS_SS(speed)) {
+                       maxb = esscd ? esscd->bMaxBurst : 0;
+               } else
+                       maxb = 0;
+
+               mps = UE_GET_SIZE(mps);
+               mep = 0;
+               mult = 0;
+               ival = 0;
+               if (xfertype == UE_CONTROL)
+                       atl = 8;                /* 6.2.3 */
+               else
+                       atl = mps;
+               break;
+       }
+
+       switch (speed) {
+       case USB_SPEED_LOW:
+               break;
+       case USB_SPEED_FULL:
+               if (xfertype == UE_INTERRUPT)
+                       if (mep > XHCI_EPCTX_MEP_FS_INTR)
+                               mep = XHCI_EPCTX_MEP_FS_INTR;
+               if (xfertype == UE_ISOCHRONOUS)
+                       if (mep > XHCI_EPCTX_MEP_FS_ISOC)
+                               mep = XHCI_EPCTX_MEP_FS_ISOC;
+               break;
+       case USB_SPEED_HIGH:
+               if (xfertype == UE_INTERRUPT)
+                       if (mep > XHCI_EPCTX_MEP_HS_INTR)
+                               mep = XHCI_EPCTX_MEP_HS_INTR;
+               if (xfertype == UE_ISOCHRONOUS)
+                       if (mep > XHCI_EPCTX_MEP_HS_ISOC)
+                               mep = XHCI_EPCTX_MEP_HS_ISOC;
+               break;
+       case USB_SPEED_SUPER:
+       case USB_SPEED_SUPER_PLUS:
+       default:
+               if (xfertype == UE_INTERRUPT)



Home | Main Index | Thread Index | Old Index