diff options
| author | riastradh <riastradh@NetBSD.org> | 2023-04-07 09:39:48 +0000 |
|---|---|---|
| committer | riastradh <riastradh@NetBSD.org> | 2023-04-07 09:39:48 +0000 |
| commit | e90e1bf9689ce97054b975996c7c9fb857034144 (patch) | |
| tree | abe6f693334cc7dd3d40abe02d05c04fd63c230c /sys/dev/usb | |
| parent | 2e4048e4471cb61dc77d61e87ddf3b8d77033211 (diff) | |
xhci(4): Defer root intr xfers while polling.
Root intr xfers require taking adaptive locks, which is forbidden
while polling.
This is not great -- any USB transfer completion callbacks might try
to take adaptive locks, not just uhub_intr, and that will always
causes trouble. We get lucky with ukbd_intr because it's not
MP-safe, so it relies only on the kernel lock (a spin lock) anyway.
But this change brings xhci in line with ehci.
PR kern/57326
XXX pullup-8
XXX pullup-9
XXX pullup-10
Diffstat (limited to 'sys/dev/usb')
| -rw-r--r-- | sys/dev/usb/xhci.c | 28 | ||||
| -rw-r--r-- | sys/dev/usb/xhcivar.h | 4 |
2 files changed, 25 insertions, 7 deletions
diff --git a/sys/dev/usb/xhci.c b/sys/dev/usb/xhci.c index 6379e436d0c..c64b51580fb 100644 --- a/sys/dev/usb/xhci.c +++ b/sys/dev/usb/xhci.c @@ -1,4 +1,4 @@ -/* $NetBSD: xhci.c,v 1.175 2022/10/11 11:01:17 msaitoh Exp $ */ +/* $NetBSD: xhci.c,v 1.176 2023/04/07 09:39:48 riastradh Exp $ */ /* * Copyright (c) 2013 Jonathan A. Kollasch @@ -34,7 +34,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: xhci.c,v 1.175 2022/10/11 11:01:17 msaitoh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: xhci.c,v 1.176 2023/04/07 09:39:48 riastradh Exp $"); #ifdef _KERNEL_OPT #include "opt_usb.h" @@ -2351,11 +2351,15 @@ xhci_rhpsc(struct xhci_softc * const sc, u_int ctlrport) KASSERT(xfer->ux_status == USBD_IN_PROGRESS); uint8_t *p = xfer->ux_buf; - memset(p, 0, xfer->ux_length); + if (!xhci_polling_p(sc) || !sc->sc_intrxfer_deferred[bn]) + memset(p, 0, xfer->ux_length); p[rhp / NBBY] |= 1 << (rhp % NBBY); xfer->ux_actlen = xfer->ux_length; xfer->ux_status = USBD_NORMAL_COMPLETION; - usb_transfer_complete(xfer); + if (xhci_polling_p(sc)) + sc->sc_intrxfer_deferred[bn] = true; + else + usb_transfer_complete(xfer); } /* Process Transfer Events */ @@ -2619,7 +2623,7 @@ xhci_softintr(void *v) struct xhci_softc * const sc = XHCI_BUS2SC(bus); struct xhci_ring * const er = sc->sc_er; struct xhci_trb *trb; - int i, j, k; + int i, j, k, bn; XHCIHIST_FUNC(); @@ -2630,6 +2634,20 @@ xhci_softintr(void *v) XHCIHIST_CALLARGS("er: xr_ep %jd xr_cs %jd", i, j, 0, 0); + /* + * Handle deferred root intr xfer, in case we just switched off + * polling. It's not safe to complete root intr xfers while + * polling -- too much kernel machinery gets involved. + */ + if (!xhci_polling_p(sc)) { + for (bn = 0; bn < 2; bn++) { + if (__predict_false(sc->sc_intrxfer_deferred[bn])) { + sc->sc_intrxfer_deferred[bn] = false; + usb_transfer_complete(sc->sc_intrxfer[bn]); + } + } + } + while (1) { usb_syncmem(&er->xr_dma, XHCI_TRB_SIZE * i, XHCI_TRB_SIZE, BUS_DMASYNC_POSTREAD); diff --git a/sys/dev/usb/xhcivar.h b/sys/dev/usb/xhcivar.h index 20ae5405933..54681d6dcef 100644 --- a/sys/dev/usb/xhcivar.h +++ b/sys/dev/usb/xhcivar.h @@ -1,4 +1,4 @@ -/* $NetBSD: xhcivar.h,v 1.22 2022/10/11 09:18:22 msaitoh Exp $ */ +/* $NetBSD: xhcivar.h,v 1.23 2023/04/07 09:39:48 riastradh Exp $ */ /* * Copyright (c) 2013 Jonathan A. Kollasch @@ -121,7 +121,7 @@ struct xhci_softc { int *sc_rhportmap[2]; int sc_rhportcount[2]; struct usbd_xfer *sc_intrxfer[2]; - + bool sc_intrxfer_deferred[2]; struct xhci_slot * sc_slots; |
