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