Index: usb/ehci.c =================================================================== RCS file: /cvsroot/src/sys/dev/usb/ehci.c,v retrieving revision 1.254.8.5 diff -p -u -r1.254.8.5 ehci.c --- usb/ehci.c 27 Sep 2018 14:52:26 -0000 1.254.8.5 +++ usb/ehci.c 27 Sep 2018 23:17:40 -0000 @@ -75,6 +75,7 @@ __KERNEL_RCSID(0, "$NetBSD: ehci.c,v 1.2 #include #include #include +#include #include @@ -446,8 +447,9 @@ ehci_init(ehci_softc_t *sc) } if (sc->sc_ncomp > 0) { KASSERT(!(sc->sc_flags & EHCIF_ETTF)); - aprint_normal("%s: %d companion controller%s, %d port%s%s", - device_xname(sc->sc_dev), sc->sc_ncomp, + aprint_normal_dev(sc->sc_dev, + "%d companion controller%s, %d port%s%s", + sc->sc_ncomp, sc->sc_ncomp!=1 ? "s" : "", EHCI_HCS_N_PCC(sparams), EHCI_HCS_N_PCC(sparams)!=1 ? "s" : "", @@ -459,6 +461,11 @@ ehci_init(ehci_softc_t *sc) device_xname(sc->sc_comps[i])); } aprint_normal("\n"); + + mutex_init(&sc->sc_complock, MUTEX_DEFAULT, IPL_USB); + callout_init(&sc->sc_compcallout, CALLOUT_MPSAFE); + cv_init(&sc->sc_compcv, "ehciccv"); + sc->sc_comp_state = CO_EARLY; } sc->sc_noport = EHCI_HCS_N_PORTS(sparams); sc->sc_hasppc = EHCI_HCS_PPC(sparams); @@ -1337,6 +1344,19 @@ ehci_detach(struct ehci_softc *sc, int f if (rv != 0) return rv; + if (sc->sc_ncomp > 0) { + mutex_enter(&sc->sc_complock); + /* XXX try to halt callout instead of waiting */ + while (sc->sc_comp_state == CO_SCHED) + cv_wait(&sc->sc_compcv, &sc->sc_complock); + mutex_exit(&sc->sc_complock); + + callout_halt(&sc->sc_compcallout, NULL); + callout_destroy(&sc->sc_compcallout); + cv_destroy(&sc->sc_compcv); + mutex_destroy(&sc->sc_complock); + } + callout_halt(&sc->sc_tmo_intrlist, NULL); callout_destroy(&sc->sc_tmo_intrlist); @@ -2597,6 +2617,72 @@ ehci_roothub_ctrl(struct usbd_bus *bus, return totlen; } +/* + * Handle ehci hand-off in early boot vs RB_ASKNAME/RB_SINGLE. + * + * This pile of garbage below works around the following problem without + * holding boots with no hand-over devices present, while penalising + * boots where the first ehci probe hands off devices with a 5 second + * delay, if RB_ASKNAME/RB_SINGLE is set. This is typically not a problem + * for RB_SINGLE, but the same basic issue exists. + * + * The way ehci hand-off works, the companion controller does not get the + * device until after its' initial bus explore, so the reference dropped + * after the first explore is not enough. 5 seconds should be enough, + * and EHCI_DISOWN_DELAY_SECONDS can be set to another value. + * + * There are 3 states. CO_EARLY is set during attach. CO_SCHED is set + * if the callback is scheduled. CO_DONE is set when the callout has + * called config_pending_decr(). + * + * There's a mutex, a cv and a callout here, and we delay detach if the + * callout has been set. + */ +#ifndef EHCI_DISOWN_DELAY_SECONDS +#define EHCI_DISOWN_DELAY_SECONDS 5 +#endif +static int ehci_disown_delay_seconds = EHCI_DISOWN_DELAY_SECONDS; + +static void +ehci_disown_callback(void *arg) +{ + ehci_softc_t *sc = arg; + + config_pending_decr(sc->sc_dev); + + mutex_enter(&sc->sc_complock); + KASSERT(sc->sc_comp_state == CO_SCHED); + sc->sc_comp_state = CO_DONE; + cv_signal(&sc->sc_compcv); + mutex_exit(&sc->sc_complock); +} + +static void +ehci_disown_sched_callback(ehci_softc_t *sc) +{ + extern bool root_is_mounted; + + mutex_enter(&sc->sc_complock); + + if (root_is_mounted || + (boothowto & (RB_ASKNAME|RB_SINGLE)) == 0 || + sc->sc_comp_state != CO_EARLY) { + mutex_exit(&sc->sc_complock); + return; + } + + callout_reset(&sc->sc_compcallout, ehci_disown_delay_seconds * hz, + ehci_disown_callback, &sc->sc_dev); + sc->sc_comp_state = CO_SCHED; + + mutex_exit(&sc->sc_complock); + + config_pending_incr(sc->sc_dev); + aprint_normal("delaying %s by %u seconds due to USB owner change.", + (boothowto & RB_ASKNAME) == 0 ? "ask root" : "single user", + ehci_disown_delay_seconds); +} + Static void ehci_disown(ehci_softc_t *sc, int index, int lowspeed) { @@ -2606,13 +2692,11 @@ ehci_disown(ehci_softc_t *sc, int index, EHCIHIST_FUNC(); EHCIHIST_CALLED(); DPRINTF("index=%jd lowspeed=%jd", index, lowspeed, 0, 0); -#ifdef DIAGNOSTIC if (sc->sc_npcomp != 0) { int i = (index-1) / sc->sc_npcomp; - if (i >= sc->sc_ncomp) - printf("%s: strange port\n", - device_xname(sc->sc_dev)); - else + if (i < sc->sc_ncomp) { + ehci_disown_sched_callback(sc); +#ifdef DIAGNOSTIC printf("%s: handing over %s speed device on " "port %d to %s\n", device_xname(sc->sc_dev), @@ -2620,10 +2704,16 @@ ehci_disown(ehci_softc_t *sc, int index, index, sc->sc_comps[i] ? device_xname(sc->sc_comps[i]) : "companion controller"); + } else { + printf("%s: strange port\n", + device_xname(sc->sc_dev)); +#endif + } } else { +#ifdef DIAGNOSTIC printf("%s: npcomp == 0\n", device_xname(sc->sc_dev)); - } #endif + } port = EHCI_PORTSC(index); v = EOREAD4(sc, port) &~ EHCI_PS_CLEAR; EOWRITE4(sc, port, v | EHCI_PS_PO); Index: usb/ehcivar.h =================================================================== RCS file: /cvsroot/src/sys/dev/usb/ehcivar.h,v retrieving revision 1.43.10.1 diff -p -u -r1.43.10.1 ehcivar.h --- usb/ehcivar.h 25 Aug 2018 11:29:52 -0000 1.43.10.1 +++ usb/ehcivar.h 27 Sep 2018 23:17:40 -0000 @@ -185,6 +185,16 @@ typedef struct ehci_softc { u_int sc_npcomp; device_t sc_comps[EHCI_COMPANION_MAX]; + /* This chunk to handle early RB_ASKNAME hand over. */ + callout_t sc_compcallout; + kmutex_t sc_complock; + kcondvar_t sc_compcv; + enum { + CO_EARLY, + CO_SCHED, + CO_DONE, + } sc_comp_state; + usb_dma_t sc_fldma; ehci_link_t *sc_flist; u_int sc_flsize; Index: usb/xhci.c =================================================================== RCS file: /cvsroot/src/sys/dev/usb/xhci.c,v retrieving revision 1.72.2.8 diff -p -u -r1.72.2.8 xhci.c --- usb/xhci.c 27 Sep 2018 14:52:26 -0000 1.72.2.8 +++ usb/xhci.c 27 Sep 2018 23:17:40 -0000 @@ -3979,7 +3979,7 @@ xhci_device_bulk_start(struct usbd_xfer xhci_db_write_4(sc, XHCI_DOORBELL(xs->xs_idx), dci); - if (xfer->ux_timeout && !xhci_polling_p(sc)) { + if (xfer->ux_timeout && !polling) { callout_reset(&xfer->ux_callout, mstohz(xfer->ux_timeout), xhci_timeout, xfer); } @@ -4055,6 +4055,7 @@ xhci_device_intr_start(struct usbd_xfer struct xhci_ring * const tr = &xs->xs_ep[dci].xe_tr; struct xhci_xfer * const xx = XHCI_XFER2XXFER(xfer); const uint32_t len = xfer->ux_length; + const bool polling = xhci_polling_p(sc); usb_dma_t * const dma = &xfer->ux_dmabuf; uint64_t parameter; uint32_t status; @@ -4082,9 +4083,11 @@ xhci_device_intr_start(struct usbd_xfer xhci_trb_put(&xx->xx_trb[i++], parameter, status, control); xfer->ux_status = USBD_IN_PROGRESS; - mutex_enter(&tr->xr_lock); + if (!polling) + mutex_enter(&tr->xr_lock); xhci_ring_put(sc, tr, xfer, xx->xx_trb, i); - mutex_exit(&tr->xr_lock); + if (!polling) + mutex_exit(&tr->xr_lock); xhci_db_write_4(sc, XHCI_DOORBELL(xs->xs_idx), dci);