Module Name: src
Committed By: mlelstv
Date: Mon Jun 5 03:44:48 UTC 2023
Modified Files:
src/sys/dev/usb: xhci.c xhcireg.h
Log Message:
- 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.
To generate a diff of this commit:
cvs rdiff -u -r1.178 -r1.179 src/sys/dev/usb/xhci.c
cvs rdiff -u -r1.22 -r1.23 src/sys/dev/usb/xhcireg.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/dev/usb/xhci.c
diff -u src/sys/dev/usb/xhci.c:1.178 src/sys/dev/usb/xhci.c:1.179
--- src/sys/dev/usb/xhci.c:1.178 Thu Apr 27 06:30:09 2023
+++ src/sys/dev/usb/xhci.c Mon Jun 5 03:44:47 2023
@@ -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);
- 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;
+ usbd_desc_iter_t iter;
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;
}
+ return NULL;
+}
- 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) {
- }
- 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);
+/* 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;
- /* XXX if LEC = 1, set ESIT instead */
- cp[0] |= XHCI_EPCTX_0_MULT_SET(0);
} else {
- /* use ival */
+ 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;
}
-#endif
- } else {
- /* USB 2.0 9.6.6 */
- cp[1] |= XHCI_EPCTX_1_MAXP_SIZE_SET(UE_GET_SIZE(mps));
+ mps = UE_GET_SIZE(mps);
- /* 6.2.3.4 */
- if (speed == USB_SPEED_HIGH &&
- (xfertype == UE_ISOCHRONOUS || xfertype == UE_INTERRUPT)) {
- maxb = UE_GET_TRANS(mps);
- } else {
- /* LS/FS or HS CTRL or HS BULK */
+ 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)
+ if (mep > XHCI_EPCTX_MEP_SS_INTR)
+ mep = XHCI_EPCTX_MEP_SS_INTR;
+ if (xfertype == UE_ISOCHRONOUS) {
+ if (speed == USB_SPEED_SUPER ||
+ XHCI_HCC2_LEC(sc->sc_hcc2) == 0) {
+ if (mep > XHCI_EPCTX_MEP_SS_ISOC)
+ mep = XHCI_EPCTX_MEP_SS_ISOC;
+ } else {
+ if (mep > XHCI_EPCTX_MEP_SS_ISOC_LEC)
+ mep = XHCI_EPCTX_MEP_SS_ISOC_LEC;
+ }
}
- cp[1] |= XHCI_EPCTX_1_MAXB_SET(maxb);
+ break;
}
+
xpipe->xp_maxb = maxb + 1;
xpipe->xp_mult = mult + 1;
+
+ cp[0] |= XHCI_EPCTX_0_MAX_ESIT_PAYLOAD_HI_SET(mep >> 16);
+ cp[0] |= XHCI_EPCTX_0_IVAL_SET(ival);
+ cp[0] |= XHCI_EPCTX_0_MULT_SET(mult);
+ cp[1] |= XHCI_EPCTX_1_MAXP_SIZE_SET(mps);
+ cp[1] |= XHCI_EPCTX_1_MAXB_SET(maxb);
+ cp[4] |= XHCI_EPCTX_4_MAX_ESIT_PAYLOAD_SET(mep & 0xffff);
+ cp[4] |= XHCI_EPCTX_4_AVG_TRB_LEN_SET(atl);
}
/*
- * Convert endpoint bInterval value to endpoint context interval value
- * for Interrupt pipe.
+ * Convert usbdi bInterval value to xhci endpoint context interval value
+ * for periodic pipe.
* xHCI 6.2.3.6 Table 65, USB 2.0 9.6.6
*/
static uint32_t
-xhci_bival2ival(uint32_t ival, uint32_t speed)
+xhci_bival2ival(uint32_t ival, uint32_t speed, uint32_t xfertype)
{
- if (speed == USB_SPEED_LOW || speed == USB_SPEED_FULL) {
- int i;
+ if (xfertype != UE_INTERRUPT && xfertype != UE_ISOCHRONOUS)
+ return 0;
+
+ if (xfertype == UE_INTERRUPT &&
+ (speed == USB_SPEED_LOW || speed == USB_SPEED_FULL)) {
+ u_int i;
/*
* round ival down to "the nearest base 2 multiple of
@@ -3931,9 +4003,22 @@ xhci_bival2ival(uint32_t ival, uint32_t
break;
}
ival = i;
+
+ /* 3 - 10 */
+ ival = (ival < 3) ? 3 : ival;
+ } else if (speed == USB_SPEED_FULL) {
+ /* FS isoc */
+ ival += 3; /* 1ms -> 125us */
+ ival--; /* Interval = bInterval-1 */
+ /* 3 - 18 */
+ ival = (ival > 18) ? 18 : ival;
+ ival = (ival < 3) ? 3 : ival;
} else {
- /* Interval = bInterval-1 for SS/HS */
- ival--;
+ /* SS/HS intr/isoc */
+ if (ival > 0)
+ ival--; /* Interval = bInterval-1 */
+ /* 0 - 15 */
+ ival = (ival > 15) ? 15 : ival;
}
return ival;
Index: src/sys/dev/usb/xhcireg.h
diff -u src/sys/dev/usb/xhcireg.h:1.22 src/sys/dev/usb/xhcireg.h:1.23
--- src/sys/dev/usb/xhcireg.h:1.22 Sat Apr 16 18:15:22 2022
+++ src/sys/dev/usb/xhcireg.h Mon Jun 5 03:44:47 2023
@@ -1,4 +1,4 @@
-/* $NetBSD: xhcireg.h,v 1.22 2022/04/16 18:15:22 andvar Exp $ */
+/* $NetBSD: xhcireg.h,v 1.23 2023/06/05 03:44:47 mlelstv Exp $ */
/*-
* Copyright (c) 2010 Hans Petter Selasky. All rights reserved.
@@ -105,7 +105,7 @@
#define XHCI_HCC2_CMC(x) __SHIFTOUT((x), __BIT(1)) /* CEC MaxExLatTooLg */
#define XHCI_HCC2_FSC(x) __SHIFTOUT((x), __BIT(2)) /* Foce Save Context */
#define XHCI_HCC2_CTC(x) __SHIFTOUT((x), __BIT(3)) /* Compliance Transc */
-#define XHCI_HCC2_LEC(x) __SHIFTOUT((x), __BIT(4)) /* Large ESIT Paylod */
+#define XHCI_HCC2_LEC(x) __SHIFTOUT((x), __BIT(4)) /* Large ESIT Payload */
#define XHCI_HCC2_CIC(x) __SHIFTOUT((x), __BIT(5)) /* Configuration Inf */
#define XHCI_HCC2_ETC(x) __SHIFTOUT((x), __BIT(6)) /* Extended TBC */
#define XHCI_HCC2_ETC_TSC(x) __SHIFTOUT((x), __BIT(7)) /* ExtTBC TRB Status */
@@ -648,6 +648,13 @@ struct xhci_trb {
#define XHCI_EPCTX_4_MAX_ESIT_PAYLOAD_MASK __BITS(16, 31)
#define XHCI_EPCTX_4_MAX_ESIT_PAYLOAD_SET(x) __SHIFTIN((x), XHCI_EPCTX_4_MAX_ESIT_PAYLOAD_MASK)
#define XHCI_EPCTX_4_MAX_ESIT_PAYLOAD_GET(x) __SHIFTOUT((x), XHCI_EPCTX_4_MAX_ESIT_PAYLOAD_MASK)
+#define XHCI_EPCTX_MEP_FS_INTR 64U
+#define XHCI_EPCTX_MEP_FS_ISOC (1*1024U)
+#define XHCI_EPCTX_MEP_HS_INTR (3*1024U)
+#define XHCI_EPCTX_MEP_HS_ISOC (3*1024U)
+#define XHCI_EPCTX_MEP_SS_INTR (3*1024U)
+#define XHCI_EPCTX_MEP_SS_ISOC (48*1024U)
+#define XHCI_EPCTX_MEP_SS_ISOC_LEC (16*1024*1024U - 1)
#define XHCI_INCTX_NON_CTRL_MASK 0xFFFFFFFCU