Module Name:    src
Committed By:   martin
Date:           Fri Sep 28 08:33:43 UTC 2018

Modified Files:
        src/sys/dev/usb [netbsd-8]: ehci.c ehcivar.h xhci.c

Log Message:
Fixup for ticket #1037 - parts of the patch were accidently missing.


To generate a diff of this commit:
cvs rdiff -u -r1.254.8.5 -r1.254.8.6 src/sys/dev/usb/ehci.c
cvs rdiff -u -r1.43.10.1 -r1.43.10.2 src/sys/dev/usb/ehcivar.h
cvs rdiff -u -r1.72.2.8 -r1.72.2.9 src/sys/dev/usb/xhci.c

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/ehci.c
diff -u src/sys/dev/usb/ehci.c:1.254.8.5 src/sys/dev/usb/ehci.c:1.254.8.6
--- src/sys/dev/usb/ehci.c:1.254.8.5	Thu Sep 27 14:52:26 2018
+++ src/sys/dev/usb/ehci.c	Fri Sep 28 08:33:43 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: ehci.c,v 1.254.8.5 2018/09/27 14:52:26 martin Exp $ */
+/*	$NetBSD: ehci.c,v 1.254.8.6 2018/09/28 08:33:43 martin Exp $ */
 
 /*
  * Copyright (c) 2004-2012 The NetBSD Foundation, Inc.
@@ -53,7 +53,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ehci.c,v 1.254.8.5 2018/09/27 14:52:26 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ehci.c,v 1.254.8.6 2018/09/28 08:33:43 martin Exp $");
 
 #include "ohci.h"
 #include "uhci.h"
@@ -75,6 +75,7 @@ __KERNEL_RCSID(0, "$NetBSD: ehci.c,v 1.2
 #include <sys/select.h>
 #include <sys/sysctl.h>
 #include <sys/systm.h>
+#include <sys/reboot.h>
 
 #include <machine/endian.h>
 
@@ -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: src/sys/dev/usb/ehcivar.h
diff -u src/sys/dev/usb/ehcivar.h:1.43.10.1 src/sys/dev/usb/ehcivar.h:1.43.10.2
--- src/sys/dev/usb/ehcivar.h:1.43.10.1	Sat Aug 25 11:29:52 2018
+++ src/sys/dev/usb/ehcivar.h	Fri Sep 28 08:33:43 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: ehcivar.h,v 1.43.10.1 2018/08/25 11:29:52 martin Exp $ */
+/*	$NetBSD: ehcivar.h,v 1.43.10.2 2018/09/28 08:33:43 martin Exp $ */
 
 /*
  * Copyright (c) 2001 The NetBSD Foundation, Inc.
@@ -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: src/sys/dev/usb/xhci.c
diff -u src/sys/dev/usb/xhci.c:1.72.2.8 src/sys/dev/usb/xhci.c:1.72.2.9
--- src/sys/dev/usb/xhci.c:1.72.2.8	Thu Sep 27 14:52:26 2018
+++ src/sys/dev/usb/xhci.c	Fri Sep 28 08:33:43 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: xhci.c,v 1.72.2.8 2018/09/27 14:52:26 martin Exp $	*/
+/*	$NetBSD: xhci.c,v 1.72.2.9 2018/09/28 08:33:43 martin Exp $	*/
 
 /*
  * Copyright (c) 2013 Jonathan A. Kollasch
@@ -34,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: xhci.c,v 1.72.2.8 2018/09/27 14:52:26 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: xhci.c,v 1.72.2.9 2018/09/28 08:33:43 martin Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_usb.h"
@@ -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);
 

Reply via email to