tech-net archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

usbnet cleanups



FYI: I have a string of patches to simplify and tidy up usbnet(9) and
all the usbnet-based USB ethernet drivers.

I'm not done with it yet -- I'm trying to find a way to restore
synchronous hardware multicast filter updates, but it will require
some more surgery to the usbnet API and probably some testing with
actual devices.

Most of the changes are mechanical and don't affect any ordering of or
issuance of commands to hardware, so they're reasonably safe for me to
test only on my ure(4).  However, I plan to change the order of
hardware initialization and multicast filter update in the various
drivers' if_init routines so it can all be done uniformly in
usbnet_init_rx_tx which will also take care of coordinating with
if_mcast_op.  That kind of change will probably require testing on all
of the usbnet devices, but all I have is ure(4), so I might need help
with testing once the changes are ready.

The patch set so far is attached (goes on top of the change I posted
recently to break the usbnet multicast deadlock).  Let me know if you
have any comments!
From 0b390603949574411ba23b9b4c15bfb1e2727ef4 Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Fri, 24 Dec 2021 22:10:56 +0000
Subject: [PATCH 01/48] usbnet: Simplify usbnet_isdying.

usbnet_detach (or its caller) stops all users before it returns.

If un->un_pri is null at this point, there's a bug -- something
didn't wait for everything to finish before calling usbnet_detach.
---
 sys/dev/usb/usbnet.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/usb/usbnet.c b/sys/dev/usb/usbnet.c
index 9fa061b3cea0..9c694b588346 100644
--- a/sys/dev/usb/usbnet.c
+++ b/sys/dev/usb/usbnet.c
@@ -1322,7 +1322,7 @@ usbnet_havelink(struct usbnet *un)
 bool
 usbnet_isdying(struct usbnet *un)
 {
-	return un->un_pri == NULL || un->un_pri->unp_dying;
+	return un->un_pri->unp_dying;
 }
 
 

From 9b3cfdde5d79ff2f7c881638aa8dc45afd958b29 Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Fri, 24 Dec 2021 22:56:01 +0000
Subject: [PATCH 02/48] usbnet: Set and clear IFF_RUNNING slightly earlier and
 later.

- Set IFF_RUNNING before any calls to usbnet_rxeof are possible.
- Don't clear IFF_RUNNING until all transfers have been aborted.
---
 sys/dev/usb/usbnet.c | 23 ++++++++++++-----------
 1 file changed, 12 insertions(+), 11 deletions(-)

diff --git a/sys/dev/usb/usbnet.c b/sys/dev/usb/usbnet.c
index 9c694b588346..1f58ff87f1d3 100644
--- a/sys/dev/usb/usbnet.c
+++ b/sys/dev/usb/usbnet.c
@@ -850,9 +850,6 @@ usbnet_init_rx_tx(struct usbnet * const un)
 		goto out;
 	}
 
-	/* Start up the receive pipe(s). */
-	usbnet_rx_start_pipes(un);
-
 	/* Indicate we are up and running. */
 #if 0
 	/* XXX if_mcast_op() can call this without ifnet locked */
@@ -860,6 +857,9 @@ usbnet_init_rx_tx(struct usbnet * const un)
 #endif
 	ifp->if_flags |= IFF_RUNNING;
 
+	/* Start up the receive pipe(s). */
+	usbnet_rx_start_pipes(un);
+
 	callout_schedule(&unp->unp_stat_ch, hz);
 
 out:
@@ -1126,14 +1126,6 @@ usbnet_stop(struct usbnet *un, struct ifnet *ifp, int disable)
 
 	uno_stop(un, ifp, disable);
 
-	/*
-	 * XXXSMP Would like to
-	 *	KASSERT(IFNET_LOCKED(ifp))
-	 * here but the locking order is:
-	 *	ifnet -> core_lock -> rxlock -> txlock
-	 * and core_lock is already held.
-	 */
-	ifp->if_flags &= ~IFF_RUNNING;
 	unp->unp_timer = 0;
 
 	callout_halt(&unp->unp_stat_ch, &unp->unp_core_lock);
@@ -1150,6 +1142,15 @@ usbnet_stop(struct usbnet *un, struct ifnet *ifp, int disable)
 	/* Close pipes. */
 	usbnet_ep_close_pipes(un);
 
+	/*
+	 * XXXSMP Would like to
+	 *	KASSERT(IFNET_LOCKED(ifp))
+	 * here but the locking order is:
+	 *	ifnet -> core_lock -> rxlock -> txlock
+	 * and core_lock is already held.
+	 */
+	ifp->if_flags &= ~IFF_RUNNING;
+
 	usbnet_unbusy(un);
 }
 

From 4490b37114c567ad54a3ce933456372695219c11 Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Fri, 24 Dec 2021 22:59:10 +0000
Subject: [PATCH 03/48] usbnet: Take IFNET_LOCK around access to if_flags in
 usbnet_detach.

This is not stable without IFNET_LOCK.  Extraneous calls to
usbnet_stop arising from this race might be harmless, but let's
render it unnecessary to even think about that.
---
 sys/dev/usb/usbnet.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/sys/dev/usb/usbnet.c b/sys/dev/usb/usbnet.c
index 1f58ff87f1d3..d35385f1cdbd 100644
--- a/sys/dev/usb/usbnet.c
+++ b/sys/dev/usb/usbnet.c
@@ -1554,11 +1554,11 @@ usbnet_detach(device_t self, int flags)
 	unp->unp_dying = true;
 	mutex_exit(&unp->unp_core_lock);
 
+	IFNET_LOCK(ifp);
 	if (ifp->if_flags & IFF_RUNNING) {
-		IFNET_LOCK(ifp);
 		usbnet_if_stop(ifp, 1);
-		IFNET_UNLOCK(ifp);
 	}
+	IFNET_UNLOCK(ifp);
 
 	callout_halt(&unp->unp_stat_ch, NULL);
 	usb_rem_task_wait(un->un_udev, &unp->unp_ticktask, USB_TASKQ_DRIVER,

From 67361d5f71966183d532165d912f0b8f7d8f5101 Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Fri, 24 Dec 2021 23:01:27 +0000
Subject: [PATCH 04/48] usbnet: Ensure ifp->if_softc is initialized _before_
 publishing ifp.

Otherwise other parts of the system might start using ifp the moment
we if_register it, and trip over null if_softc.
---
 sys/dev/usb/usbnet.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/sys/dev/usb/usbnet.c b/sys/dev/usb/usbnet.c
index d35385f1cdbd..83fcf11b7ebc 100644
--- a/sys/dev/usb/usbnet.c
+++ b/sys/dev/usb/usbnet.c
@@ -80,6 +80,7 @@ struct usbnet_private {
 	bool			unp_dying;
 	bool			unp_stopping;
 	bool			unp_attached;
+	bool			unp_ifp_attached;
 	bool			unp_link;
 
 	int			unp_refcnt;
@@ -1492,7 +1493,9 @@ usbnet_attach_ifp(struct usbnet *un,
 	struct ifnet * const ifp = usbnet_ifp(un);
 
 	KASSERT(unp->unp_attached);
+	KASSERT(!unp->unp_ifp_attached);
 
+	ifp->if_softc = un;
 	strlcpy(ifp->if_xname, device_xname(un->un_dev), IFNAMSIZ);
 	ifp->if_flags = if_flags;
 	ifp->if_extflags = IFEF_MPSAFE | if_extflags;
@@ -1511,6 +1514,7 @@ usbnet_attach_ifp(struct usbnet *un,
 	if (ifp->_if_input == NULL)
 		ifp->if_percpuq = if_percpuq_create(ifp);
 	if_register(ifp);
+	unp->unp_ifp_attached = true;
 
 	/*
 	 * If ethernet address is all zero, skip ether_ifattach() and
@@ -1528,7 +1532,6 @@ usbnet_attach_ifp(struct usbnet *un,
 
 	/* Now ready, and attached. */
 	IFQ_SET_READY(&ifp->if_snd);
-	ifp->if_softc = un;
 
 	usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, un->un_udev, un->un_dev);
 
@@ -1584,7 +1587,7 @@ usbnet_detach(device_t self, int flags)
 		mii_detach(mii, MII_PHY_ANY, MII_OFFSET_ANY);
 		ifmedia_fini(&mii->mii_media);
 	}
-	if (ifp->if_softc) {
+	if (unp->unp_ifp_attached) {
 		if (!usbnet_empty_eaddr(un))
 			ether_ifdetach(ifp);
 		else

From 1c858f49341d18eb984005bd6ac3783154302997 Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Fri, 24 Dec 2021 23:08:03 +0000
Subject: [PATCH 05/48] usbnet: Ensure access to unp_timer is protected by
 unp_txlock.

---
 sys/dev/usb/usbnet.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/sys/dev/usb/usbnet.c b/sys/dev/usb/usbnet.c
index 83fcf11b7ebc..de231d9bd799 100644
--- a/sys/dev/usb/usbnet.c
+++ b/sys/dev/usb/usbnet.c
@@ -1127,7 +1127,9 @@ usbnet_stop(struct usbnet *un, struct ifnet *ifp, int disable)
 
 	uno_stop(un, ifp, disable);
 
+	mutex_enter(&unp->unp_txlock);
 	unp->unp_timer = 0;
+	mutex_exit(&unp->unp_txlock);
 
 	callout_halt(&unp->unp_stat_ch, &unp->unp_core_lock);
 	usb_rem_task_wait(un->un_udev, &unp->unp_ticktask, USB_TASKQ_DRIVER,
@@ -1239,7 +1241,10 @@ usbnet_tick_task(void *arg)
 	usbnet_busy(un);
 	mutex_exit(&unp->unp_core_lock);
 
-	if (unp->unp_timer != 0 && --unp->unp_timer == 0)
+	mutex_enter(&unp->unp_txlock);
+	const bool timeout = unp->unp_timer != 0 && --unp->unp_timer == 0;
+	mutex_exit(&unp->unp_txlock);
+	if (timeout)
 		usbnet_watchdog(ifp);
 
 	DPRINTFN(8, "mii %#jx ifp %#jx", (uintptr_t)mii, (uintptr_t)ifp, 0, 0);

From d58dd54b7d30ebd9f668610167061bedf002d63b Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Fri, 24 Dec 2021 23:34:52 +0000
Subject: [PATCH 06/48] usbnet: Assert IFNET_LOCKED on if_flags change
 callbacks.

- if_init
- if_stop
- ethersubr(9) ifflags_cb
---
 sys/dev/usb/usbnet.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/sys/dev/usb/usbnet.c b/sys/dev/usb/usbnet.c
index de231d9bd799..c2b0d55a6bc9 100644
--- a/sys/dev/usb/usbnet.c
+++ b/sys/dev/usb/usbnet.c
@@ -1006,6 +1006,8 @@ usbnet_ifflags_cb(struct ethercom *ec)
 	struct usbnet_private * const unp = un->un_pri;
 	int rv = 0;
 
+	KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname);
+
 	mutex_enter(&unp->unp_core_lock);
 
 	const u_short changed = ifp->if_flags ^ unp->unp_if_flags;
@@ -1163,6 +1165,8 @@ usbnet_if_stop(struct ifnet *ifp, int disable)
 	struct usbnet * const un = ifp->if_softc;
 	struct usbnet_private * const unp = un->un_pri;
 
+	KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname);
+
 	mutex_enter(&unp->unp_core_lock);
 	usbnet_stop(un, ifp, disable);
 	mutex_exit(&unp->unp_core_lock);
@@ -1272,6 +1276,8 @@ usbnet_if_init(struct ifnet *ifp)
 	USBNETHIST_FUNC(); USBNETHIST_CALLED();
 	struct usbnet * const un = ifp->if_softc;
 
+	KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname);
+
 	return uno_init(un, ifp);
 }
 

From da1ab5a96723fe5cc297d31d8085cd43f5d3687a Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Fri, 24 Dec 2021 23:52:41 +0000
Subject: [PATCH 07/48] usbnet: Assert IFNET_LOCKED in usbnet_init_rx_tx,
 usbnet_stop.

Exception: urndis(4) abuses this API to start this logic before the
ifp is actually initialized.  So for the sake of urndis(4), until
sense can be beaten into it, allow the !unp_ifp_attached case to run
without IFNET_LOCK.
---
 sys/dev/usb/usbnet.c | 17 ++++++++++-------
 1 file changed, 10 insertions(+), 7 deletions(-)

diff --git a/sys/dev/usb/usbnet.c b/sys/dev/usb/usbnet.c
index c2b0d55a6bc9..9b475f07ff88 100644
--- a/sys/dev/usb/usbnet.c
+++ b/sys/dev/usb/usbnet.c
@@ -151,6 +151,8 @@ fail:
 static void
 uno_stop(struct usbnet *un, struct ifnet *ifp, int disable)
 {
+	KASSERTMSG(!un->un_pri->unp_ifp_attached || IFNET_LOCKED(ifp),
+	    "%s", ifp->if_xname);
 	usbnet_isowned_core(un);
 	if (un->un_ops->uno_stop)
 		(*un->un_ops->uno_stop)(ifp, disable);
@@ -820,6 +822,9 @@ usbnet_init_rx_tx(struct usbnet * const un)
 	usbd_status err;
 	int error = 0;
 
+	KASSERTMSG(!unp->unp_ifp_attached || IFNET_LOCKED(ifp),
+	    "%s", ifp->if_xname);
+
 	usbnet_isowned_core(un);
 
 	if (unp->unp_dying) {
@@ -1117,6 +1122,8 @@ usbnet_stop(struct usbnet *un, struct ifnet *ifp, int disable)
 
 	USBNETHIST_FUNC(); USBNETHIST_CALLED();
 
+	KASSERTMSG(!unp->unp_ifp_attached || IFNET_LOCKED(ifp),
+	    "%s", ifp->if_xname);
 	usbnet_isowned_core(un);
 
 	usbnet_busy(un);
@@ -1147,13 +1154,9 @@ usbnet_stop(struct usbnet *un, struct ifnet *ifp, int disable)
 	/* Close pipes. */
 	usbnet_ep_close_pipes(un);
 
-	/*
-	 * XXXSMP Would like to
-	 *	KASSERT(IFNET_LOCKED(ifp))
-	 * here but the locking order is:
-	 *	ifnet -> core_lock -> rxlock -> txlock
-	 * and core_lock is already held.
-	 */
+	/* Everything is quesced now. */
+	KASSERTMSG(!unp->unp_ifp_attached || IFNET_LOCKED(ifp),
+	    "%s", ifp->if_xname);
 	ifp->if_flags &= ~IFF_RUNNING;
 
 	usbnet_unbusy(un);

From 6db5e6e0d96d1c6e57f3e6e76b207ab7c4d36ea2 Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Fri, 24 Dec 2021 22:50:37 +0000
Subject: [PATCH 08/48] usbnet: Don't check if_flags for IFF_RUNNING in
 usbnet_rxeof.

This can only run after we start the pipes in usbnet_init_rx_tx, and
before we abort the pipes in usbnet_stop, during which time if_flags
& IFF_RUNNING is stably set.
---
 sys/dev/usb/usbnet.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/sys/dev/usb/usbnet.c b/sys/dev/usb/usbnet.c
index 9b475f07ff88..7123c7c95879 100644
--- a/sys/dev/usb/usbnet.c
+++ b/sys/dev/usb/usbnet.c
@@ -337,7 +337,6 @@ usbnet_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
 	struct usbnet_chain * const c = priv;
 	struct usbnet * const un = c->unc_un;
 	struct usbnet_private * const unp = un->un_pri;
-	struct ifnet * const ifp = usbnet_ifp(un);
 	uint32_t total_len;
 
 	USBNETHIST_CALLARGSN(5, "%jd: enter: status %#jx xfer %#jx",
@@ -347,7 +346,7 @@ usbnet_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
 
 	if (unp->unp_dying || unp->unp_stopping ||
 	    status == USBD_INVAL || status == USBD_NOT_STARTED ||
-	    status == USBD_CANCELLED || !(ifp->if_flags & IFF_RUNNING))
+	    status == USBD_CANCELLED)
 		goto out;
 
 	if (status != USBD_NORMAL_COMPLETION) {

From c424f119686f6ea5c0e60fdd162149f321189e0b Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Fri, 24 Dec 2021 22:52:49 +0000
Subject: [PATCH 09/48] usbnet: Don't check if_flags for IFF_RUNNING in
 usbnet_pipe_intr.

The one user of this interface in tree, aue(4), doesn't care --
if_statinc is safe whether IFF_RUNNING or not.
---
 sys/dev/usb/usbnet.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/sys/dev/usb/usbnet.c b/sys/dev/usb/usbnet.c
index 7123c7c95879..846faf9f5404 100644
--- a/sys/dev/usb/usbnet.c
+++ b/sys/dev/usb/usbnet.c
@@ -443,11 +443,10 @@ usbnet_pipe_intr(struct usbd_xfer *xfer, void *priv, usbd_status status)
 	struct usbnet * const un = priv;
 	struct usbnet_private * const unp = un->un_pri;
 	struct usbnet_intr * const uni = un->un_intr;
-	struct ifnet * const ifp = usbnet_ifp(un);
 
 	if (uni == NULL || unp->unp_dying || unp->unp_stopping ||
 	    status == USBD_INVAL || status == USBD_NOT_STARTED ||
-	    status == USBD_CANCELLED || !(ifp->if_flags & IFF_RUNNING)) {
+	    status == USBD_CANCELLED) {
 		USBNETHIST_CALLARGS("%jd: uni %#jx d/s %#jx status %#jx",
 		    unp->unp_number, (uintptr_t)uni,
 		    (unp->unp_dying << 8) | unp->unp_stopping, status);

From 52ec9a399c17df3e1adc49041f733b7147e839e3 Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Sat, 25 Dec 2021 12:52:21 +0000
Subject: [PATCH 10/48] usbnet: Omit needless unp == NULL test in
 usbnet_tick_task.

The task is never scheduled until after un->un_pri is initialized,
and un->un_pri isn't nulled until after the callout and task are
quiescent.
---
 sys/dev/usb/usbnet.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/sys/dev/usb/usbnet.c b/sys/dev/usb/usbnet.c
index 846faf9f5404..e1dca2a3980e 100644
--- a/sys/dev/usb/usbnet.c
+++ b/sys/dev/usb/usbnet.c
@@ -1227,9 +1227,6 @@ usbnet_tick_task(void *arg)
 	struct usbnet * const un = arg;
 	struct usbnet_private * const unp = un->un_pri;
 
-	if (unp == NULL)
-		return;
-
 	USBNETHIST_CALLARGSN(8, "%jd: enter", unp->unp_number, 0, 0, 0);
 
 	mutex_enter(&unp->unp_core_lock);

From 9c9839af0364d4bfbb5888b07d654bddb2d5355d Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Sat, 25 Dec 2021 20:31:02 +0000
Subject: [PATCH 11/48] axen(4), mue(4), smsc(4): Omit irrelevant cases in
 ioctl.

SIOCSIFFLAGS and SIOCSETHERCAP always end up in ether_ioctl_reinit,
which triggers the same logic to reprogram the multicast filters
anyway.
---
 sys/dev/usb/if_axen.c | 2 --
 sys/dev/usb/if_mue.c  | 2 --
 sys/dev/usb/if_smsc.c | 2 --
 3 files changed, 6 deletions(-)

diff --git a/sys/dev/usb/if_axen.c b/sys/dev/usb/if_axen.c
index bf91d56b356d..fe433722d185 100644
--- a/sys/dev/usb/if_axen.c
+++ b/sys/dev/usb/if_axen.c
@@ -559,8 +559,6 @@ axen_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 	usbnet_busy(un);
 
 	switch (cmd) {
-	case SIOCSIFFLAGS:
-	case SIOCSETHERCAP:
 	case SIOCADDMULTI:
 	case SIOCDELMULTI:
 		axen_setiff_locked(un);
diff --git a/sys/dev/usb/if_mue.c b/sys/dev/usb/if_mue.c
index 559b9eff2569..16a52e4c6ed4 100644
--- a/sys/dev/usb/if_mue.c
+++ b/sys/dev/usb/if_mue.c
@@ -1273,8 +1273,6 @@ mue_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 	usbnet_busy(un);
 
 	switch (cmd) {
-	case SIOCSIFFLAGS:
-	case SIOCSETHERCAP:
 	case SIOCADDMULTI:
 	case SIOCDELMULTI:
 		mue_setiff_locked(un);
diff --git a/sys/dev/usb/if_smsc.c b/sys/dev/usb/if_smsc.c
index 6cf37e507d1c..12eaf3fa3cc6 100644
--- a/sys/dev/usb/if_smsc.c
+++ b/sys/dev/usb/if_smsc.c
@@ -757,8 +757,6 @@ smsc_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 	usbnet_busy(un);
 
 	switch (cmd) {
-	case SIOCSIFFLAGS:
-	case SIOCSETHERCAP:
 	case SIOCADDMULTI:
 	case SIOCDELMULTI:
 		smsc_setiff_locked(un);

From 878bba3c7c206ba7dc98a4da92535fac1fabedb0 Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Sun, 26 Dec 2021 00:52:09 +0000
Subject: [PATCH 12/48] usbnet: Remove usbnet_set_dying.

Not necessary for the one caller that did it (url(4)): usbnet_detach
handles failed attach just fine without it.
---
 sys/dev/usb/if_url.c | 8 +-------
 sys/dev/usb/usbnet.c | 6 ------
 sys/dev/usb/usbnet.h | 1 -
 3 files changed, 1 insertion(+), 14 deletions(-)

diff --git a/sys/dev/usb/if_url.c b/sys/dev/usb/if_url.c
index 764b9c654682..dbb57bf66ca7 100644
--- a/sys/dev/usb/if_url.c
+++ b/sys/dev/usb/if_url.c
@@ -256,18 +256,12 @@ url_attach(device_t parent, device_t self, void *aux)
 	usbnet_unlock_core(un);
 	if (err) {
 		aprint_error_dev(self, "read MAC address failed\n");
-		goto bad;
+		return;
 	}
 
 	/* initialize interface information */
 	usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST,
 	    0, &unm);
-
-	return;
-
- bad:
-	usbnet_set_dying(un, true);
-	return;
 }
 
 /* read/write memory */
diff --git a/sys/dev/usb/usbnet.c b/sys/dev/usb/usbnet.c
index e1dca2a3980e..a8f912b0ad54 100644
--- a/sys/dev/usb/usbnet.c
+++ b/sys/dev/usb/usbnet.c
@@ -1288,12 +1288,6 @@ usbnet_set_link(struct usbnet *un, bool link)
 	un->un_pri->unp_link = link;
 }
 
-void
-usbnet_set_dying(struct usbnet *un, bool link)
-{
-	un->un_pri->unp_dying = link;
-}
-
 struct ifnet *
 usbnet_ifp(struct usbnet *un)
 {
diff --git a/sys/dev/usb/usbnet.h b/sys/dev/usb/usbnet.h
index 15e9dfc7b351..1faa822887c5 100644
--- a/sys/dev/usb/usbnet.h
+++ b/sys/dev/usb/usbnet.h
@@ -284,7 +284,6 @@ struct usbnet {
 /* Various accessors. */
 
 void usbnet_set_link(struct usbnet *, bool);
-void usbnet_set_dying(struct usbnet *, bool);
 
 struct ifnet *usbnet_ifp(struct usbnet *);
 struct ethercom *usbnet_ec(struct usbnet *);

From 8e80685cb82740f96216a8e7e38b90a859a532fa Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Sun, 26 Dec 2021 01:17:06 +0000
Subject: [PATCH 13/48] usbnet: Fix ordering of actions in usbnet_stop.

Make sure all software activity is quiescent (callouts and tasks,
including ifmedia and mii callbacks -- anything that might trigger
register access) before asking the driver to stop the hardware.  This
way, the driver uno_stop routine is guaranteed exclusive access to
the registers.

This will also enable us to simplify the callouts and tasks so they
don't have to check the software state -- to be done in a separate
commit.
---
 sys/dev/usb/usbnet.c | 21 +++++++++++++++++----
 1 file changed, 17 insertions(+), 4 deletions(-)

diff --git a/sys/dev/usb/usbnet.c b/sys/dev/usb/usbnet.c
index a8f912b0ad54..1b516402527d 100644
--- a/sys/dev/usb/usbnet.c
+++ b/sys/dev/usb/usbnet.c
@@ -1132,16 +1132,29 @@ usbnet_stop(struct usbnet *un, struct ifnet *ifp, int disable)
 	mutex_exit(&unp->unp_txlock);
 	mutex_exit(&unp->unp_rxlock);
 
+	/*
+	 * Stop the timer first, then the task -- if the timer was
+	 * already firing, we stop the task or wait for it complete
+	 * only after if last fired.  Setting unp_stopping prevents the
+	 * timer task from being scheduled again.
+	 */
+	callout_halt(&unp->unp_stat_ch, &unp->unp_core_lock);
+	usb_rem_task_wait(un->un_udev, &unp->unp_ticktask, USB_TASKQ_DRIVER,
+	    &unp->unp_core_lock);
+
+	/*
+	 * Now that the software is quiescent, ask the driver to stop
+	 * the hardware.  The driver's uno_stop routine now has
+	 * exclusive access to any registers that might previously have
+	 * been used by to ifmedia, mii, or ioctl callbacks.
+	 */
 	uno_stop(un, ifp, disable);
 
+	/* Clear the watchdog timer.  */
 	mutex_enter(&unp->unp_txlock);
 	unp->unp_timer = 0;
 	mutex_exit(&unp->unp_txlock);
 
-	callout_halt(&unp->unp_stat_ch, &unp->unp_core_lock);
-	usb_rem_task_wait(un->un_udev, &unp->unp_ticktask, USB_TASKQ_DRIVER,
-	    &unp->unp_core_lock);
-
 	/* Stop transfers. */
 	usbnet_ep_stop_pipes(un);
 

From 6b410d0d925d0361ad8c8b828edf825fe1b775bb Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Sun, 26 Dec 2021 01:22:46 +0000
Subject: [PATCH 14/48] usbnet: Assert IFNET_LOCKED in usbnet_media_upd.

This ensures, if the device is being initialized or stopped,
usbnet_media_upd will not run until it's done, so the reset sequence
has exclusive access to the device registers used by mii.
---
 sys/dev/usb/usbnet.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/sys/dev/usb/usbnet.c b/sys/dev/usb/usbnet.c
index 1b516402527d..89041f6ec949 100644
--- a/sys/dev/usb/usbnet.c
+++ b/sys/dev/usb/usbnet.c
@@ -983,6 +983,9 @@ usbnet_media_upd(struct ifnet *ifp)
 	/* ifmedia layer ensures core_lock is held. */
 	usbnet_isowned_core(un);
 
+	/* ifmedia changes only with IFNET_LOCK held.  */
+	KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname);
+
 	if (unp->unp_dying)
 		return EIO;
 

From bd850aa336dc3b6b6d199a68d8b516815f3aa776 Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Sun, 26 Dec 2021 01:29:16 +0000
Subject: [PATCH 15/48] usbnet: Refuse to bring interfaces back up once dying.

Make this happen uniformly across all usbnet drivers, not on a
per-driver basis.

This ensures new activity on the interface can't happen by the time
we have stopped existing activity and waited for it to complete.
---
 sys/dev/usb/usbnet.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/sys/dev/usb/usbnet.c b/sys/dev/usb/usbnet.c
index 89041f6ec949..a831fc6eba62 100644
--- a/sys/dev/usb/usbnet.c
+++ b/sys/dev/usb/usbnet.c
@@ -1289,9 +1289,20 @@ usbnet_if_init(struct ifnet *ifp)
 {
 	USBNETHIST_FUNC(); USBNETHIST_CALLED();
 	struct usbnet * const un = ifp->if_softc;
+	bool dying;
 
 	KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname);
 
+	/*
+	 * Prevent anyone from bringing the interface back up once
+	 * we're detaching.
+	 */
+	mutex_enter(&un->un_pri->unp_core_lock);
+	dying = un->un_pri->unp_dying;
+	mutex_exit(&un->un_pri->unp_core_lock);
+	if (dying)
+		return EIO;
+
 	return uno_init(un, ifp);
 }
 
@@ -1572,10 +1583,18 @@ usbnet_detach(device_t self, int flags)
 	struct ifnet * const ifp = usbnet_ifp(un);
 	struct mii_data * const mii = usbnet_mii(un);
 
+	/*
+	 * Prevent new activity.  After we stop the interface, it
+	 * cannot be brought back up.
+	 */
 	mutex_enter(&unp->unp_core_lock);
 	unp->unp_dying = true;
 	mutex_exit(&unp->unp_core_lock);
 
+	/*
+	 * If we're still running on the network, stop and wait for all
+	 * asynchronous activity to finish.
+	 */
 	IFNET_LOCK(ifp);
 	if (ifp->if_flags & IFF_RUNNING) {
 		usbnet_if_stop(ifp, 1);

From 07e9df75ad90f906fbb3a3396207def648637404 Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Sun, 26 Dec 2021 01:32:42 +0000
Subject: [PATCH 16/48] usbnet: Omit needless callout_halt and
 usb_rem_task_wait.

The callout and tasks cannot be pending at this point -- it is a bug
if usbnet_if_stop failed to quiesce everything, so turn these into
KASSERTs.
---
 sys/dev/usb/usbnet.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/sys/dev/usb/usbnet.c b/sys/dev/usb/usbnet.c
index a831fc6eba62..630290b91626 100644
--- a/sys/dev/usb/usbnet.c
+++ b/sys/dev/usb/usbnet.c
@@ -1601,9 +1601,13 @@ usbnet_detach(device_t self, int flags)
 	}
 	IFNET_UNLOCK(ifp);
 
-	callout_halt(&unp->unp_stat_ch, NULL);
-	usb_rem_task_wait(un->un_udev, &unp->unp_ticktask, USB_TASKQ_DRIVER,
-	    NULL);
+	/*
+	 * The callout and tick task can't be scheduled anew at this
+	 * point, and usbnet_if_stop has waited for them to complete.
+	 */
+	KASSERT(!callout_pending(&unp->unp_stat_ch));
+	KASSERT(!usb_task_pending(un->un_udev, &unp->unp_ticktask));
+
 	usb_rem_task_wait(un->un_udev, &unp->unp_mcasttask, USB_TASKQ_DRIVER,
 	    NULL);
 

From ade3f86f732debdbd708baa53ee98a25d3495ce7 Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Sun, 26 Dec 2021 01:47:10 +0000
Subject: [PATCH 17/48] usbnet: Detach interface and mii before waiting for
 refcnt to drain.

All outstanding software activity under usbnet's control -- which is
all that participates in the refcnting -- should be quiesced by
stopping and detaching everything.
---
 sys/dev/usb/usbnet.c | 28 ++++++++++++++--------------
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/sys/dev/usb/usbnet.c b/sys/dev/usb/usbnet.c
index 630290b91626..f072bebc9e83 100644
--- a/sys/dev/usb/usbnet.c
+++ b/sys/dev/usb/usbnet.c
@@ -1611,20 +1611,6 @@ usbnet_detach(device_t self, int flags)
 	usb_rem_task_wait(un->un_udev, &unp->unp_mcasttask, USB_TASKQ_DRIVER,
 	    NULL);
 
-	mutex_enter(&unp->unp_core_lock);
-	unp->unp_refcnt--;
-	while (unp->unp_refcnt >= 0) {
-		/* Wait for processes to go away */
-		cv_wait(&unp->unp_detachcv, &unp->unp_core_lock);
-	}
-	mutex_exit(&unp->unp_core_lock);
-
-	usbnet_rx_list_free(un);
-	usbnet_tx_list_free(un);
-
-	callout_destroy(&unp->unp_stat_ch);
-	rnd_detach_source(&unp->unp_rndsrc);
-
 	if (mii) {
 		mii_detach(mii, MII_PHY_ANY, MII_OFFSET_ANY);
 		ifmedia_fini(&mii->mii_media);
@@ -1672,6 +1658,20 @@ usbnet_detach(device_t self, int flags)
 	usb_rem_task_wait(un->un_udev, &unp->unp_mcasttask, USB_TASKQ_DRIVER,
 	    NULL);
 
+	mutex_enter(&unp->unp_core_lock);
+	unp->unp_refcnt--;
+	while (unp->unp_refcnt >= 0) {
+		/* Wait for processes to go away */
+		cv_wait(&unp->unp_detachcv, &unp->unp_core_lock);
+	}
+	mutex_exit(&unp->unp_core_lock);
+
+	usbnet_rx_list_free(un);
+	usbnet_tx_list_free(un);
+
+	callout_destroy(&unp->unp_stat_ch);
+	rnd_detach_source(&unp->unp_rndsrc);
+
 	cv_destroy(&unp->unp_detachcv);
 	mutex_destroy(&unp->unp_core_lock);
 	mutex_destroy(&unp->unp_rxlock);

From ff4f846bf22cd9318d2c4ef138142cbae660a856 Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Sun, 26 Dec 2021 01:49:56 +0000
Subject: [PATCH 18/48] usbnet: Make detach order reverse attach order, for
 unp_stat_ch.

No functional change intended.
---
 sys/dev/usb/usbnet.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/sys/dev/usb/usbnet.c b/sys/dev/usb/usbnet.c
index f072bebc9e83..470db472a7c5 100644
--- a/sys/dev/usb/usbnet.c
+++ b/sys/dev/usb/usbnet.c
@@ -1669,7 +1669,6 @@ usbnet_detach(device_t self, int flags)
 	usbnet_rx_list_free(un);
 	usbnet_tx_list_free(un);
 
-	callout_destroy(&unp->unp_stat_ch);
 	rnd_detach_source(&unp->unp_rndsrc);
 
 	cv_destroy(&unp->unp_detachcv);
@@ -1677,6 +1676,8 @@ usbnet_detach(device_t self, int flags)
 	mutex_destroy(&unp->unp_rxlock);
 	mutex_destroy(&unp->unp_txlock);
 
+	callout_destroy(&unp->unp_stat_ch);
+
 	pmf_device_deregister(un->un_dev);
 
 	usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, un->un_udev, un->un_dev);

From 0af793b09552df9bb35f9798fc9ea974c21c751a Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Sun, 26 Dec 2021 01:50:32 +0000
Subject: [PATCH 19/48] usbnet: Don't issue a detach event if we never issued
 an attach one.

---
 sys/dev/usb/usbnet.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/sys/dev/usb/usbnet.c b/sys/dev/usb/usbnet.c
index 470db472a7c5..33c78dcc85d9 100644
--- a/sys/dev/usb/usbnet.c
+++ b/sys/dev/usb/usbnet.c
@@ -1680,7 +1680,14 @@ usbnet_detach(device_t self, int flags)
 
 	pmf_device_deregister(un->un_dev);
 
-	usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, un->un_udev, un->un_dev);
+	/*
+	 * Notify userland that we're going away, if we arrived in the
+	 * first place.
+	 */
+	if (unp->unp_ifp_attached) {
+		usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, un->un_udev,
+		    un->un_dev);
+	}
 
 	kmem_free(unp, sizeof(*unp));
 	un->un_pri = NULL;

From 680ec3df0983dd6bebf4fbc48b21acf9d438ad4f Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Sun, 26 Dec 2021 01:50:59 +0000
Subject: [PATCH 20/48] usbnet: Uncomment and fix assertion for ifp->if_flags
 |= IFF_RUNNING.

We always hold IFNET_LOCK for ioctls that end up here -- the ones
that don't hold it are only SIOCADDMULTI/SIOCDELMULTI, which don't
end up here.  However, urndis(4) throws a spanner in the works by
doing weird device initialization.
---
 sys/dev/usb/usbnet.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/sys/dev/usb/usbnet.c b/sys/dev/usb/usbnet.c
index 33c78dcc85d9..b3ad4ba90f01 100644
--- a/sys/dev/usb/usbnet.c
+++ b/sys/dev/usb/usbnet.c
@@ -855,10 +855,9 @@ usbnet_init_rx_tx(struct usbnet * const un)
 	}
 
 	/* Indicate we are up and running. */
-#if 0
-	/* XXX if_mcast_op() can call this without ifnet locked */
-	KASSERT(ifp->if_softc == NULL || IFNET_LOCKED(ifp));
-#endif
+	/* XXX urndis calls usbnet_init_rx_tx before usbnet_attach_ifp.  */
+	KASSERTMSG(!unp->unp_ifp_attached || IFNET_LOCKED(ifp),
+	    "%s", ifp->if_xname);
 	ifp->if_flags |= IFF_RUNNING;
 
 	/* Start up the receive pipe(s). */

From cac7009b221d01604551f01270a74948aeec04da Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Fri, 24 Dec 2021 22:07:39 +0000
Subject: [PATCH 21/48] usbnet: Omit needless tests in usbnet_tick.

It's harmless for us to schedule the tick task even if unp_dying or
unp_stopping is set by now, because usbnet_stop will just wait for it
to finish anyway, and the callout can't be scheduled again until the
interface is done stopping and is brought back up again.

No need for unp == NULL test -- un->un_pri is initialized well before
this callout can be scheduled, and is nulled out only at the end of
usbnet_detach, at which point we have already halted this callout.
---
 sys/dev/usb/usbnet.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/sys/dev/usb/usbnet.c b/sys/dev/usb/usbnet.c
index b3ad4ba90f01..183bd5af37c6 100644
--- a/sys/dev/usb/usbnet.c
+++ b/sys/dev/usb/usbnet.c
@@ -1203,10 +1203,8 @@ usbnet_tick(void *arg)
 
 	USBNETHIST_CALLARGSN(10, "%jd: enter", unp->unp_number, 0, 0, 0);
 
-	if (unp != NULL && !unp->unp_stopping && !unp->unp_dying) {
-		/* Perform periodic stuff in process context */
-		usb_add_task(un->un_udev, &unp->unp_ticktask, USB_TASKQ_DRIVER);
-	}
+	/* Perform periodic stuff in process context */
+	usb_add_task(un->un_udev, &unp->unp_ticktask, USB_TASKQ_DRIVER);
 }
 
 static void

From c30e16918cb8cac0fa7dfd4ed0fe2f89579eeac9 Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Sun, 26 Dec 2021 01:54:38 +0000
Subject: [PATCH 22/48] usbnet: Omit needless locking/busying/testing in
 usbnet_tick_task.

usbnet_stop waits for the task to complete before resetting the
hardware, and usbnet_detach waits for usbnet_stop to complete before
destroying anything, so there's no need for any of this.
---
 sys/dev/usb/usbnet.c | 15 +--------------
 1 file changed, 1 insertion(+), 14 deletions(-)

diff --git a/sys/dev/usb/usbnet.c b/sys/dev/usb/usbnet.c
index 183bd5af37c6..4568379f0db7 100644
--- a/sys/dev/usb/usbnet.c
+++ b/sys/dev/usb/usbnet.c
@@ -1239,22 +1239,10 @@ usbnet_tick_task(void *arg)
 	USBNETHIST_FUNC();
 	struct usbnet * const un = arg;
 	struct usbnet_private * const unp = un->un_pri;
-
-	USBNETHIST_CALLARGSN(8, "%jd: enter", unp->unp_number, 0, 0, 0);
-
-	mutex_enter(&unp->unp_core_lock);
-	if (unp->unp_stopping || unp->unp_dying) {
-		mutex_exit(&unp->unp_core_lock);
-		return;
-	}
-
 	struct ifnet * const ifp = usbnet_ifp(un);
 	struct mii_data * const mii = usbnet_mii(un);
 
-	KASSERT(ifp != NULL);	/* embedded member */
-
-	usbnet_busy(un);
-	mutex_exit(&unp->unp_core_lock);
+	USBNETHIST_CALLARGSN(8, "%jd: enter", unp->unp_number, 0, 0, 0);
 
 	mutex_enter(&unp->unp_txlock);
 	const bool timeout = unp->unp_timer != 0 && --unp->unp_timer == 0;
@@ -1275,7 +1263,6 @@ usbnet_tick_task(void *arg)
 	uno_tick(un);
 
 	mutex_enter(&unp->unp_core_lock);
-	usbnet_unbusy(un);
 	if (!unp->unp_stopping && !unp->unp_dying)
 		callout_schedule(&unp->unp_stat_ch, hz);
 	mutex_exit(&unp->unp_core_lock);

From 44b1379971bcc9ac4090000da3d08c6e5df8b0ba Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Sun, 26 Dec 2021 10:06:50 +0000
Subject: [PATCH 23/48] usbnet: Clear watchdog timer before stopping hardware.

No need to take the lock again -- which might not be necessary
because the callout and task have completed, but let's obviate the
need to think about that.
---
 sys/dev/usb/usbnet.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/sys/dev/usb/usbnet.c b/sys/dev/usb/usbnet.c
index 4568379f0db7..a84512b557e4 100644
--- a/sys/dev/usb/usbnet.c
+++ b/sys/dev/usb/usbnet.c
@@ -1128,9 +1128,14 @@ usbnet_stop(struct usbnet *un, struct ifnet *ifp, int disable)
 
 	usbnet_busy(un);
 
+	/*
+	 * Prevent new activity (rescheduling ticks, xfers, &c.) and
+	 * clear the watchdog timer.
+	 */
 	mutex_enter(&unp->unp_rxlock);
 	mutex_enter(&unp->unp_txlock);
 	unp->unp_stopping = true;
+	unp->unp_timer = 0;
 	mutex_exit(&unp->unp_txlock);
 	mutex_exit(&unp->unp_rxlock);
 
@@ -1152,11 +1157,6 @@ usbnet_stop(struct usbnet *un, struct ifnet *ifp, int disable)
 	 */
 	uno_stop(un, ifp, disable);
 
-	/* Clear the watchdog timer.  */
-	mutex_enter(&unp->unp_txlock);
-	unp->unp_timer = 0;
-	mutex_exit(&unp->unp_txlock);
-
 	/* Stop transfers. */
 	usbnet_ep_stop_pipes(un);
 

From 8e5914ebba29ca7c95176e1dbee2f277af32bcb5 Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Wed, 29 Dec 2021 22:34:05 +0000
Subject: [PATCH 24/48] usbnet: Avoid IFNET_LOCK on detach if we never attached
 the ifp.

---
 sys/dev/usb/usbnet.c | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/sys/dev/usb/usbnet.c b/sys/dev/usb/usbnet.c
index a84512b557e4..22b87068e38d 100644
--- a/sys/dev/usb/usbnet.c
+++ b/sys/dev/usb/usbnet.c
@@ -1578,12 +1578,17 @@ usbnet_detach(device_t self, int flags)
 	/*
 	 * If we're still running on the network, stop and wait for all
 	 * asynchronous activity to finish.
+	 *
+	 * If usbnet_attach_ifp never ran, IFNET_LOCK won't work, but
+	 * no activity is possible, so just skip this part.
 	 */
-	IFNET_LOCK(ifp);
-	if (ifp->if_flags & IFF_RUNNING) {
-		usbnet_if_stop(ifp, 1);
+	if (unp->unp_ifp_attached) {
+		IFNET_LOCK(ifp);
+		if (ifp->if_flags & IFF_RUNNING) {
+			usbnet_if_stop(ifp, 1);
+		}
+		IFNET_UNLOCK(ifp);
 	}
-	IFNET_UNLOCK(ifp);
 
 	/*
 	 * The callout and tick task can't be scheduled anew at this

From fef5253a148714d4d83e9bf4e26a67b95e048ed5 Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Thu, 30 Dec 2021 09:34:22 +0000
Subject: [PATCH 25/48] cue(4): Return real error code, not -1, on init when
 detaching.

---
 sys/dev/usb/if_cue.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/usb/if_cue.c b/sys/dev/usb/if_cue.c
index e730297a939d..587c430a5d15 100644
--- a/sys/dev/usb/if_cue.c
+++ b/sys/dev/usb/if_cue.c
@@ -622,7 +622,7 @@ cue_init_locked(struct ifnet *ifp)
 	DPRINTFN(10,("%s: %s: enter\n", device_xname(un->un_dev),__func__));
 
 	if (usbnet_isdying(un))
-		return -1;
+		return ENXIO;
 
 	/* Cancel pending I/O */
 	usbnet_stop(un, ifp, 1);

From ff74d323331239a1ad41d9ea17c777622497af26 Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Thu, 30 Dec 2021 09:48:31 +0000
Subject: [PATCH 26/48] usbnet: Don't waste time calling uno_stop if device is
 detaching.

The hardware is most likely gone, so trying to write to its registers
(and, in some cases, wait until a timeout for a device to reset) is a
waste of time.  Even if it was detached only in software with drvctl,
reattaching it will reset the device anyway.
---
 sys/dev/usb/usbnet.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/sys/dev/usb/usbnet.c b/sys/dev/usb/usbnet.c
index 22b87068e38d..e04c3589f2b5 100644
--- a/sys/dev/usb/usbnet.c
+++ b/sys/dev/usb/usbnet.c
@@ -1154,8 +1154,13 @@ usbnet_stop(struct usbnet *un, struct ifnet *ifp, int disable)
 	 * the hardware.  The driver's uno_stop routine now has
 	 * exclusive access to any registers that might previously have
 	 * been used by to ifmedia, mii, or ioctl callbacks.
+	 *
+	 * Don't bother if the device is being detached, though -- if
+	 * it's been unplugged then there's no point in trying to touch
+	 * the registers.
 	 */
-	uno_stop(un, ifp, disable);
+	if (!unp->unp_dying)
+		uno_stop(un, ifp, disable);
 
 	/* Stop transfers. */
 	usbnet_ep_stop_pipes(un);

From fba090856b71d66937aa74bc3cbc6736b1b5b62a Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Thu, 30 Dec 2021 09:51:35 +0000
Subject: [PATCH 27/48] usbnet: Impart blame on whose ifnet is unlocked in
 uno_init.

---
 sys/dev/usb/usbnet.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/usb/usbnet.c b/sys/dev/usb/usbnet.c
index e04c3589f2b5..b938c70a8202 100644
--- a/sys/dev/usb/usbnet.c
+++ b/sys/dev/usb/usbnet.c
@@ -181,7 +181,7 @@ uno_override_ioctl(struct usbnet *un, struct ifnet *ifp, u_long cmd, void *data)
 static int
 uno_init(struct usbnet *un, struct ifnet *ifp)
 {
-	KASSERT(IFNET_LOCKED(ifp));
+	KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname);
 	return (*un->un_ops->uno_init)(ifp);
 }
 

From 8d1cc47306dbb7f0b211e42b86c69dc474df3080 Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Thu, 30 Dec 2021 09:53:09 +0000
Subject: [PATCH 28/48] usbnet: Assert ioctl locking.

---
 sys/dev/usb/usbnet.c | 24 ++++++++++++++++++------
 1 file changed, 18 insertions(+), 6 deletions(-)

diff --git a/sys/dev/usb/usbnet.c b/sys/dev/usb/usbnet.c
index b938c70a8202..ace8f78da9d6 100644
--- a/sys/dev/usb/usbnet.c
+++ b/sys/dev/usb/usbnet.c
@@ -161,11 +161,15 @@ uno_stop(struct usbnet *un, struct ifnet *ifp, int disable)
 static int
 uno_ioctl(struct usbnet *un, struct ifnet *ifp, u_long cmd, void *data)
 {
-	/*
-	 * There are cases where IFNET_LOCK will not be held when we
-	 * are called (e.g. add/delete multicast address), so we can't
-	 * assert it.
-	 */
+
+	switch (cmd) {
+	case SIOCADDMULTI:
+	case SIOCDELMULTI:
+		break;
+	default:
+		KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname);
+	}
+
 	if (un->un_ops->uno_ioctl)
 		return (*un->un_ops->uno_ioctl)(ifp, cmd, data);
 	return 0;
@@ -174,7 +178,15 @@ uno_ioctl(struct usbnet *un, struct ifnet *ifp, u_long cmd, void *data)
 static int
 uno_override_ioctl(struct usbnet *un, struct ifnet *ifp, u_long cmd, void *data)
 {
-	/* See above. */
+
+	switch (cmd) {
+	case SIOCADDMULTI:
+	case SIOCDELMULTI:
+		break;
+	default:
+		KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname);
+	}
+
 	return (*un->un_ops->uno_override_ioctl)(ifp, cmd, data);
 }
 

From 0e006acd07faa0cdfd7a221d81912e0970ee89a6 Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Thu, 30 Dec 2021 10:17:02 +0000
Subject: [PATCH 29/48] usbnet: Enter uno_init with the core lock held.

This reduces code in all drivers except urndis(4) and aue(4).

However, it's still safe for urndis to drop the core lock because the
ifnet is locked, and the ifnet lock covers the DOWN->UP (uno_init)
and UP->DOWN (uno_stop) transitions.
---
 sys/dev/usb/if_aue.c    | 5 +++--
 sys/dev/usb/if_axe.c    | 2 --
 sys/dev/usb/if_axen.c   | 2 --
 sys/dev/usb/if_cdce.c   | 2 --
 sys/dev/usb/if_cue.c    | 2 --
 sys/dev/usb/if_kue.c    | 2 --
 sys/dev/usb/if_mos.c    | 2 --
 sys/dev/usb/if_mue.c    | 2 --
 sys/dev/usb/if_smsc.c   | 2 --
 sys/dev/usb/if_udav.c   | 5 -----
 sys/dev/usb/if_upl.c    | 2 --
 sys/dev/usb/if_ure.c    | 2 --
 sys/dev/usb/if_url.c    | 2 --
 sys/dev/usb/if_urndis.c | 9 ++++++++-
 sys/dev/usb/usbnet.c    | 7 ++++++-
 15 files changed, 17 insertions(+), 31 deletions(-)

diff --git a/sys/dev/usb/if_aue.c b/sys/dev/usb/if_aue.c
index 89e2c5f55447..b72eff0349c4 100644
--- a/sys/dev/usb/if_aue.c
+++ b/sys/dev/usb/if_aue.c
@@ -1000,11 +1000,9 @@ aue_uno_init(struct ifnet *ifp)
 	struct usbnet * const	un = ifp->if_softc;
 	int rv;
 
-	usbnet_lock_core(un);
 	usbnet_busy(un);
 	rv = aue_init_locked(ifp);
 	usbnet_unbusy(un);
-	usbnet_unlock_core(un);
 
 	return rv;
 }
@@ -1012,6 +1010,7 @@ aue_uno_init(struct ifnet *ifp)
 static int
 aue_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 {
+	struct usbnet * const un = ifp->if_softc;
 
 	AUEHIST_FUNC();
 	AUEHIST_CALLARGSN(5, "aue%jd: enter cmd %#jx data %#jx",
@@ -1021,7 +1020,9 @@ aue_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 	switch (cmd) {
 	case SIOCADDMULTI:
 	case SIOCDELMULTI:
+		usbnet_lock_core(un);
 		aue_uno_init(ifp);
+		usbnet_unlock_core(un);
 		break;
 	default:
 		break;
diff --git a/sys/dev/usb/if_axe.c b/sys/dev/usb/if_axe.c
index eba67386e770..78a4a6546f70 100644
--- a/sys/dev/usb/if_axe.c
+++ b/sys/dev/usb/if_axe.c
@@ -1317,11 +1317,9 @@ axe_uno_init(struct ifnet *ifp)
 {
 	struct usbnet * const un = ifp->if_softc;
 
-	usbnet_lock_core(un);
 	usbnet_busy(un);
 	int ret = axe_init_locked(ifp);
 	usbnet_unbusy(un);
-	usbnet_unlock_core(un);
 
 	return ret;
 }
diff --git a/sys/dev/usb/if_axen.c b/sys/dev/usb/if_axen.c
index fe433722d185..7d90fa1259f9 100644
--- a/sys/dev/usb/if_axen.c
+++ b/sys/dev/usb/if_axen.c
@@ -935,11 +935,9 @@ axen_uno_init(struct ifnet *ifp)
 {
 	struct usbnet * const un = ifp->if_softc;
 
-	usbnet_lock_core(un);
 	usbnet_busy(un);
 	int ret = axen_init_locked(ifp);
 	usbnet_unbusy(un);
-	usbnet_unlock_core(un);
 
 	return ret;
 }
diff --git a/sys/dev/usb/if_cdce.c b/sys/dev/usb/if_cdce.c
index 3edf73d856ca..4785d9a4cc9e 100644
--- a/sys/dev/usb/if_cdce.c
+++ b/sys/dev/usb/if_cdce.c
@@ -261,7 +261,6 @@ cdce_uno_init(struct ifnet *ifp)
 	struct usbnet		*un = ifp->if_softc;
 	int rv;
 
-	usbnet_lock_core(un);
 	if (usbnet_isdying(un))
 		rv = EIO;
 	else {
@@ -269,7 +268,6 @@ cdce_uno_init(struct ifnet *ifp)
 		rv = usbnet_init_rx_tx(un);
 		usbnet_set_link(un, rv == 0);
 	}
-	usbnet_unlock_core(un);
 
 	return rv;
 }
diff --git a/sys/dev/usb/if_cue.c b/sys/dev/usb/if_cue.c
index 587c430a5d15..191f31eb9eca 100644
--- a/sys/dev/usb/if_cue.c
+++ b/sys/dev/usb/if_cue.c
@@ -673,11 +673,9 @@ cue_uno_init(struct ifnet *ifp)
 	struct usbnet * const	un = ifp->if_softc;
 	int rv;
 
-	usbnet_lock_core(un);
 	usbnet_busy(un);
 	rv = cue_init_locked(ifp);
 	usbnet_unbusy(un);
-	usbnet_unlock_core(un);
 
 	return rv;
 }
diff --git a/sys/dev/usb/if_kue.c b/sys/dev/usb/if_kue.c
index 172bc93fa301..6d8af3cd0735 100644
--- a/sys/dev/usb/if_kue.c
+++ b/sys/dev/usb/if_kue.c
@@ -633,11 +633,9 @@ kue_uno_init(struct ifnet *ifp)
 	struct usbnet * const	un = ifp->if_softc;
 	int rv;
 
-	usbnet_lock_core(un);
 	usbnet_busy(un);
 	rv = kue_init_locked(ifp);
 	usbnet_unbusy(un);
-	usbnet_unlock_core(un);
 
 	return rv;
 }
diff --git a/sys/dev/usb/if_mos.c b/sys/dev/usb/if_mos.c
index 347104b7b0df..987bb0484710 100644
--- a/sys/dev/usb/if_mos.c
+++ b/sys/dev/usb/if_mos.c
@@ -760,11 +760,9 @@ mos_uno_init(struct ifnet *ifp)
 {
 	struct usbnet * const un = ifp->if_softc;
 
-	usbnet_lock_core(un);
 	usbnet_busy(un);
 	int ret = mos_init_locked(ifp);
 	usbnet_unbusy(un);
-	usbnet_unlock_core(un);
 
 	return ret;
 }
diff --git a/sys/dev/usb/if_mue.c b/sys/dev/usb/if_mue.c
index 16a52e4c6ed4..81534e865688 100644
--- a/sys/dev/usb/if_mue.c
+++ b/sys/dev/usb/if_mue.c
@@ -1255,11 +1255,9 @@ mue_uno_init(struct ifnet *ifp)
 	struct usbnet * const	un = ifp->if_softc;
 	int rv;
 
-	usbnet_lock_core(un);
 	usbnet_busy(un);
 	rv = mue_init_locked(ifp);
 	usbnet_unbusy(un);
-	usbnet_unlock_core(un);
 
 	return rv;
 }
diff --git a/sys/dev/usb/if_smsc.c b/sys/dev/usb/if_smsc.c
index 12eaf3fa3cc6..4361532efc39 100644
--- a/sys/dev/usb/if_smsc.c
+++ b/sys/dev/usb/if_smsc.c
@@ -552,11 +552,9 @@ smsc_uno_init(struct ifnet *ifp)
 {
 	struct usbnet * const un = ifp->if_softc;
 
-	usbnet_lock_core(un);
 	usbnet_busy(un);
 	int ret = smsc_init_locked(ifp);
 	usbnet_unbusy(un);
-	usbnet_unlock_core(un);
 
 	return ret;
 }
diff --git a/sys/dev/usb/if_udav.c b/sys/dev/usb/if_udav.c
index a38a83a53df0..e22e1f305876 100644
--- a/sys/dev/usb/if_udav.c
+++ b/sys/dev/usb/if_udav.c
@@ -478,10 +478,7 @@ udav_uno_init(struct ifnet *ifp)
 
 	DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__));
 
-	usbnet_lock_core(un);
-
 	if (usbnet_isdying(un)) {
-		usbnet_unlock_core(un);
 		return EIO;
 	}
 
@@ -522,7 +519,6 @@ udav_uno_init(struct ifnet *ifp)
 
 	if (rc != 0) {
 		usbnet_unbusy(un);
-		usbnet_unlock_core(un);
 		return rc;
 	}
 
@@ -532,7 +528,6 @@ udav_uno_init(struct ifnet *ifp)
 		rc = usbnet_init_rx_tx(un);
 
 	usbnet_unbusy(un);
-	usbnet_unlock_core(un);
 
 	return rc;
 }
diff --git a/sys/dev/usb/if_upl.c b/sys/dev/usb/if_upl.c
index fb99702f160e..cf4ba9de209f 100644
--- a/sys/dev/usb/if_upl.c
+++ b/sys/dev/usb/if_upl.c
@@ -257,12 +257,10 @@ upl_uno_init(struct ifnet *ifp)
 	struct usbnet * const un = ifp->if_softc;
 	int rv;
 
-	usbnet_lock_core(un);
 	if (usbnet_isdying(un))
 		rv = EIO;
 	else
 		rv = usbnet_init_rx_tx(un);
-	usbnet_unlock_core(un);
 
 	return rv;
 }
diff --git a/sys/dev/usb/if_ure.c b/sys/dev/usb/if_ure.c
index ea5b3023dd31..db75961fc88e 100644
--- a/sys/dev/usb/if_ure.c
+++ b/sys/dev/usb/if_ure.c
@@ -456,11 +456,9 @@ ure_uno_init(struct ifnet *ifp)
 {
 	struct usbnet * const un = ifp->if_softc;
 
-	usbnet_lock_core(un);
 	usbnet_busy(un);
 	int ret = ure_init_locked(ifp);
 	usbnet_unbusy(un);
-	usbnet_unlock_core(un);
 
 	return ret;
 }
diff --git a/sys/dev/usb/if_url.c b/sys/dev/usb/if_url.c
index dbb57bf66ca7..af766fcd455d 100644
--- a/sys/dev/usb/if_url.c
+++ b/sys/dev/usb/if_url.c
@@ -408,11 +408,9 @@ url_uno_init(struct ifnet *ifp)
 {
 	struct usbnet * const un = ifp->if_softc;
 
-	usbnet_lock_core(un);
 	usbnet_busy(un);
 	int ret = url_init_locked(ifp);
 	usbnet_unbusy(un);
-	usbnet_unlock_core(un);
 
 	return ret;
 }
diff --git a/sys/dev/usb/if_urndis.c b/sys/dev/usb/if_urndis.c
index 381207450d72..ff4da0414739 100644
--- a/sys/dev/usb/if_urndis.c
+++ b/sys/dev/usb/if_urndis.c
@@ -883,8 +883,15 @@ static int
 urndis_uno_init(struct ifnet *ifp)
 {
 	struct usbnet *un = ifp->if_softc;
+	int error;
 
-	return urndis_init_un(ifp, un);
+	KASSERT(IFNET_LOCKED(ifp));
+
+	usbnet_unlock_core(un);
+	error = urndis_init_un(ifp, un);
+	usbnet_lock_core(un);
+
+	return error;
 }
 
 static int
diff --git a/sys/dev/usb/usbnet.c b/sys/dev/usb/usbnet.c
index ace8f78da9d6..80db2a9464a5 100644
--- a/sys/dev/usb/usbnet.c
+++ b/sys/dev/usb/usbnet.c
@@ -1291,6 +1291,7 @@ usbnet_if_init(struct ifnet *ifp)
 	USBNETHIST_FUNC(); USBNETHIST_CALLED();
 	struct usbnet * const un = ifp->if_softc;
 	bool dying;
+	int error;
 
 	KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname);
 
@@ -1304,7 +1305,11 @@ usbnet_if_init(struct ifnet *ifp)
 	if (dying)
 		return EIO;
 
-	return uno_init(un, ifp);
+	mutex_enter(&un->un_pri->unp_core_lock);
+	error = uno_init(un, ifp);
+	mutex_exit(&un->un_pri->unp_core_lock);
+
+	return error;
 }
 
 

From 7f310843ce8ace06e36cee3068c1064d40e5d6bd Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Sun, 26 Dec 2021 01:56:30 +0000
Subject: [PATCH 30/48] usbnet: Print diagnostic about refcnt stragglers.

I don't think there can be any, but this message, if printed, would
falsify my hypothesis!
---
 sys/dev/usb/usbnet.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/sys/dev/usb/usbnet.c b/sys/dev/usb/usbnet.c
index 80db2a9464a5..784f8459b801 100644
--- a/sys/dev/usb/usbnet.c
+++ b/sys/dev/usb/usbnet.c
@@ -1671,6 +1671,10 @@ usbnet_detach(device_t self, int flags)
 
 	mutex_enter(&unp->unp_core_lock);
 	unp->unp_refcnt--;
+	if (unp->unp_refcnt >= 0) {
+		aprint_error_dev(un->un_dev, "%d stragglers\n",
+		    unp->unp_refcnt + 1);
+	}
 	while (unp->unp_refcnt >= 0) {
 		/* Wait for processes to go away */
 		cv_wait(&unp->unp_detachcv, &unp->unp_core_lock);

From a1469acda543bf1b41eb361e2810ec8f07fde856 Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Thu, 30 Dec 2021 11:51:41 +0000
Subject: [PATCH 31/48] usbnet: Use atomic_load/store_relaxed for unp_dying.

This way we don't need to hold the core lock to avoid upsetting
sanitizers (which probably find the current code upsetting), and we
can use it to exit early from timeout loops that run under the core
lock (which is probably not necessary for them to do anyway, but
let's worry about that later).
---
 sys/dev/usb/usbnet.c | 42 ++++++++++++++++++++----------------------
 1 file changed, 20 insertions(+), 22 deletions(-)

diff --git a/sys/dev/usb/usbnet.c b/sys/dev/usb/usbnet.c
index 784f8459b801..4b78d50f9247 100644
--- a/sys/dev/usb/usbnet.c
+++ b/sys/dev/usb/usbnet.c
@@ -77,7 +77,7 @@ struct usbnet_private {
 	struct callout		unp_stat_ch;
 	struct usbd_pipe	*unp_ep[USBNET_ENDPT_MAX];
 
-	bool			unp_dying;
+	volatile bool		unp_dying;
 	bool			unp_stopping;
 	bool			unp_attached;
 	bool			unp_ifp_attached;
@@ -356,7 +356,7 @@ usbnet_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
 
 	mutex_enter(&unp->unp_rxlock);
 
-	if (unp->unp_dying || unp->unp_stopping ||
+	if (usbnet_isdying(un) || unp->unp_stopping ||
 	    status == USBD_INVAL || status == USBD_NOT_STARTED ||
 	    status == USBD_CANCELLED)
 		goto out;
@@ -383,7 +383,7 @@ usbnet_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
 	usbnet_isowned_rx(un);
 
 done:
-	if (unp->unp_dying || unp->unp_stopping)
+	if (usbnet_isdying(un) || unp->unp_stopping)
 		goto out;
 
 	mutex_exit(&unp->unp_rxlock);
@@ -412,7 +412,7 @@ usbnet_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
 	    unp->unp_number, status, (uintptr_t)xfer, 0);
 
 	mutex_enter(&unp->unp_txlock);
-	if (unp->unp_stopping || unp->unp_dying) {
+	if (unp->unp_stopping || usbnet_isdying(un)) {
 		mutex_exit(&unp->unp_txlock);
 		return;
 	}
@@ -456,12 +456,12 @@ usbnet_pipe_intr(struct usbd_xfer *xfer, void *priv, usbd_status status)
 	struct usbnet_private * const unp = un->un_pri;
 	struct usbnet_intr * const uni = un->un_intr;
 
-	if (uni == NULL || unp->unp_dying || unp->unp_stopping ||
+	if (uni == NULL || usbnet_isdying(un) || unp->unp_stopping ||
 	    status == USBD_INVAL || status == USBD_NOT_STARTED ||
 	    status == USBD_CANCELLED) {
 		USBNETHIST_CALLARGS("%jd: uni %#jx d/s %#jx status %#jx",
 		    unp->unp_number, (uintptr_t)uni,
-		    (unp->unp_dying << 8) | unp->unp_stopping, status);
+		    (usbnet_isdying(un) << 8) | unp->unp_stopping, status);
 		return;
 	}
 
@@ -837,7 +837,7 @@ usbnet_init_rx_tx(struct usbnet * const un)
 
 	usbnet_isowned_core(un);
 
-	if (unp->unp_dying) {
+	if (usbnet_isdying(un)) {
 		return EIO;
 	}
 
@@ -918,13 +918,12 @@ usbnet_mii_readreg(device_t dev, int phy, int reg, uint16_t *val)
 {
 	USBNETHIST_FUNC();
 	struct usbnet * const un = device_private(dev);
-	struct usbnet_private * const unp = un->un_pri;
 	int err;
 
 	/* MII layer ensures core_lock is held. */
 	usbnet_isowned_core(un);
 
-	if (unp->unp_dying) {
+	if (usbnet_isdying(un)) {
 		return EIO;
 	}
 
@@ -934,7 +933,7 @@ usbnet_mii_readreg(device_t dev, int phy, int reg, uint16_t *val)
 
 	if (err) {
 		USBNETHIST_CALLARGS("%jd: read PHY failed: %jd",
-		    unp->unp_number, err, 0, 0);
+		    un->un_pri->unp_number, err, 0, 0);
 		return err;
 	}
 
@@ -946,13 +945,12 @@ usbnet_mii_writereg(device_t dev, int phy, int reg, uint16_t val)
 {
 	USBNETHIST_FUNC();
 	struct usbnet * const un = device_private(dev);
-	struct usbnet_private * const unp = un->un_pri;
 	int err;
 
 	/* MII layer ensures core_lock is held. */
 	usbnet_isowned_core(un);
 
-	if (unp->unp_dying) {
+	if (usbnet_isdying(un)) {
 		return EIO;
 	}
 
@@ -962,7 +960,7 @@ usbnet_mii_writereg(device_t dev, int phy, int reg, uint16_t val)
 
 	if (err) {
 		USBNETHIST_CALLARGS("%jd: write PHY failed: %jd",
-		    unp->unp_number, err, 0, 0);
+		    un->un_pri->unp_number, err, 0, 0);
 		return err;
 	}
 
@@ -997,7 +995,7 @@ usbnet_media_upd(struct ifnet *ifp)
 	/* ifmedia changes only with IFNET_LOCK held.  */
 	KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname);
 
-	if (unp->unp_dying)
+	if (usbnet_isdying(un))
 		return EIO;
 
 	unp->unp_link = false;
@@ -1085,7 +1083,7 @@ usbnet_mcast_task(void *arg)
 	USBNETHIST_CALLARGSN(10, "%jd: enter", unp->unp_number, 0, 0, 0);
 
 	/*
-	 * If we're detaching, we must check unp_dying _before_
+	 * If we're detaching, we must check usbnet_isdying _before_
 	 * touching IFNET_LOCK -- the ifnet may have been detached by
 	 * the time this task runs.  This is racy -- unp_dying may be
 	 * set immediately after we test it -- but nevertheless safe,
@@ -1094,7 +1092,7 @@ usbnet_mcast_task(void *arg)
 	 * IFNET_LOCK after if_detach.  See usbnet_detach for details.
 	 */
 	mutex_enter(&unp->unp_core_lock);
-	dying = unp->unp_dying;
+	dying = usbnet_isdying(un);
 	mutex_exit(&unp->unp_core_lock);
 	if (dying)
 		return;
@@ -1171,7 +1169,7 @@ usbnet_stop(struct usbnet *un, struct ifnet *ifp, int disable)
 	 * it's been unplugged then there's no point in trying to touch
 	 * the registers.
 	 */
-	if (!unp->unp_dying)
+	if (!usbnet_isdying(un))
 		uno_stop(un, ifp, disable);
 
 	/* Stop transfers. */
@@ -1280,7 +1278,7 @@ usbnet_tick_task(void *arg)
 	uno_tick(un);
 
 	mutex_enter(&unp->unp_core_lock);
-	if (!unp->unp_stopping && !unp->unp_dying)
+	if (!unp->unp_stopping && !usbnet_isdying(un))
 		callout_schedule(&unp->unp_stat_ch, hz);
 	mutex_exit(&unp->unp_core_lock);
 }
@@ -1300,7 +1298,7 @@ usbnet_if_init(struct ifnet *ifp)
 	 * we're detaching.
 	 */
 	mutex_enter(&un->un_pri->unp_core_lock);
-	dying = un->un_pri->unp_dying;
+	dying = usbnet_isdying(un);
 	mutex_exit(&un->un_pri->unp_core_lock);
 	if (dying)
 		return EIO;
@@ -1360,7 +1358,7 @@ usbnet_havelink(struct usbnet *un)
 bool
 usbnet_isdying(struct usbnet *un)
 {
-	return un->un_pri->unp_dying;
+	return atomic_load_relaxed(&un->un_pri->unp_dying);
 }
 
 
@@ -1594,7 +1592,7 @@ usbnet_detach(device_t self, int flags)
 	 * cannot be brought back up.
 	 */
 	mutex_enter(&unp->unp_core_lock);
-	unp->unp_dying = true;
+	atomic_store_relaxed(&unp->unp_dying, true);
 	mutex_exit(&unp->unp_core_lock);
 
 	/*
@@ -1723,7 +1721,7 @@ usbnet_activate(device_t self, devact_t act)
 		if_deactivate(ifp);
 
 		mutex_enter(&unp->unp_core_lock);
-		unp->unp_dying = true;
+		atomic_store_relaxed(&unp->unp_dying, true);
 		mutex_exit(&unp->unp_core_lock);
 
 		mutex_enter(&unp->unp_rxlock);

From d8789223b76357d4d4d0114c6ad8b97f6cd336ee Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Thu, 30 Dec 2021 12:23:28 +0000
Subject: [PATCH 32/48] usbnet: Omit needless locking around usbnet_isdying.

Now that is tested and set with atomic_load/store, there is no need
to hold the lock -- which means we can set it while the core lock is
held during, e.g., a reset sequence, and use that to interrupt the
sequence so it doesn't get stuck waiting to time out when the device
is physically removed.
---
 sys/dev/usb/usbnet.c | 20 ++++----------------
 1 file changed, 4 insertions(+), 16 deletions(-)

diff --git a/sys/dev/usb/usbnet.c b/sys/dev/usb/usbnet.c
index 4b78d50f9247..4ea0859904b9 100644
--- a/sys/dev/usb/usbnet.c
+++ b/sys/dev/usb/usbnet.c
@@ -1075,12 +1075,11 @@ usbnet_mcast_task(void *arg)
 {
 	USBNETHIST_FUNC();
 	struct usbnet * const un = arg;
-	struct usbnet_private * const unp = un->un_pri;
 	struct ifnet * const ifp = usbnet_ifp(un);
-	bool dying;
 	struct ifreq ifr;
 
-	USBNETHIST_CALLARGSN(10, "%jd: enter", unp->unp_number, 0, 0, 0);
+	USBNETHIST_CALLARGSN(10, "%jd: enter",
+	    un->un_pri->unp_number, 0, 0, 0);
 
 	/*
 	 * If we're detaching, we must check usbnet_isdying _before_
@@ -1091,10 +1090,7 @@ usbnet_mcast_task(void *arg)
 	 * issuing if_detach, and necessary, so that we don't touch
 	 * IFNET_LOCK after if_detach.  See usbnet_detach for details.
 	 */
-	mutex_enter(&unp->unp_core_lock);
-	dying = usbnet_isdying(un);
-	mutex_exit(&unp->unp_core_lock);
-	if (dying)
+	if (usbnet_isdying(un))
 		return;
 
 	/*
@@ -1288,7 +1284,6 @@ usbnet_if_init(struct ifnet *ifp)
 {
 	USBNETHIST_FUNC(); USBNETHIST_CALLED();
 	struct usbnet * const un = ifp->if_softc;
-	bool dying;
 	int error;
 
 	KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname);
@@ -1297,10 +1292,7 @@ usbnet_if_init(struct ifnet *ifp)
 	 * Prevent anyone from bringing the interface back up once
 	 * we're detaching.
 	 */
-	mutex_enter(&un->un_pri->unp_core_lock);
-	dying = usbnet_isdying(un);
-	mutex_exit(&un->un_pri->unp_core_lock);
-	if (dying)
+	if (usbnet_isdying(un))
 		return EIO;
 
 	mutex_enter(&un->un_pri->unp_core_lock);
@@ -1591,9 +1583,7 @@ usbnet_detach(device_t self, int flags)
 	 * Prevent new activity.  After we stop the interface, it
 	 * cannot be brought back up.
 	 */
-	mutex_enter(&unp->unp_core_lock);
 	atomic_store_relaxed(&unp->unp_dying, true);
-	mutex_exit(&unp->unp_core_lock);
 
 	/*
 	 * If we're still running on the network, stop and wait for all
@@ -1720,9 +1710,7 @@ usbnet_activate(device_t self, devact_t act)
 	case DVACT_DEACTIVATE:
 		if_deactivate(ifp);
 
-		mutex_enter(&unp->unp_core_lock);
 		atomic_store_relaxed(&unp->unp_dying, true);
-		mutex_exit(&unp->unp_core_lock);
 
 		mutex_enter(&unp->unp_rxlock);
 		mutex_enter(&unp->unp_txlock);

From 203699b504b9cb43796a08bbdb53aeae01972279 Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Thu, 30 Dec 2021 11:36:01 +0000
Subject: [PATCH 33/48] usbnet drivers: Stop timeout loops early if device is
 detaching.

---
 sys/dev/usb/if_aue.c  |  6 ++++++
 sys/dev/usb/if_mos.c  |  4 ++++
 sys/dev/usb/if_mue.c  |  2 ++
 sys/dev/usb/if_smsc.c |  2 ++
 sys/dev/usb/if_udav.c |  2 ++
 sys/dev/usb/if_ure.c  | 10 ++++++++++
 sys/dev/usb/if_url.c  |  2 ++
 7 files changed, 28 insertions(+)

diff --git a/sys/dev/usb/if_aue.c b/sys/dev/usb/if_aue.c
index b72eff0349c4..b4d0dc36b7b8 100644
--- a/sys/dev/usb/if_aue.c
+++ b/sys/dev/usb/if_aue.c
@@ -483,6 +483,8 @@ aue_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val)
 	aue_csr_write_1(sc, AUE_PHY_CTL, reg | AUE_PHYCTL_READ);
 
 	for (i = 0; i < AUE_TIMEOUT; i++) {
+		if (usbnet_isdying(un))
+			return ENXIO;
 		if (aue_csr_read_1(sc, AUE_PHY_CTL) & AUE_PHYCTL_DONE)
 			break;
 	}
@@ -524,6 +526,8 @@ aue_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val)
 	aue_csr_write_1(sc, AUE_PHY_CTL, reg | AUE_PHYCTL_WRITE);
 
 	for (i = 0; i < AUE_TIMEOUT; i++) {
+		if (usbnet_isdying(un))
+			return ENXIO;
 		if (aue_csr_read_1(sc, AUE_PHY_CTL) & AUE_PHYCTL_DONE)
 			break;
 	}
@@ -680,6 +684,8 @@ aue_reset(struct aue_softc *sc)
 	AUE_SETBIT(sc, AUE_CTL1, AUE_CTL1_RESETMAC);
 
 	for (i = 0; i < AUE_TIMEOUT; i++) {
+		if (usbnet_isdying(un))
+			return;
 		if (!(aue_csr_read_1(sc, AUE_CTL1) & AUE_CTL1_RESETMAC))
 			break;
 	}
diff --git a/sys/dev/usb/if_mos.c b/sys/dev/usb/if_mos.c
index 987bb0484710..e76c9f11893a 100644
--- a/sys/dev/usb/if_mos.c
+++ b/sys/dev/usb/if_mos.c
@@ -364,6 +364,8 @@ mos_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val)
 	    MOS_PHYSTS_PENDING);
 
 	for (i = 0; i < MOS_TIMEOUT; i++) {
+		if (usbnet_isdying(un))
+			return ENXIO;
 		if (mos_reg_read_1(un, MOS_PHY_STS) & MOS_PHYSTS_READY)
 			break;
 	}
@@ -396,6 +398,8 @@ mos_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val)
 	    MOS_PHYSTS_PENDING);
 
 	for (i = 0; i < MOS_TIMEOUT; i++) {
+		if (usbnet_isdying(un))
+			return ENXIO;
 		if (mos_reg_read_1(un, MOS_PHY_STS) & MOS_PHYSTS_READY)
 			break;
 	}
diff --git a/sys/dev/usb/if_mue.c b/sys/dev/usb/if_mue.c
index 81534e865688..034bacc1f587 100644
--- a/sys/dev/usb/if_mue.c
+++ b/sys/dev/usb/if_mue.c
@@ -200,6 +200,8 @@ mue_wait_for_bits(struct usbnet *un, uint32_t reg,
 	int ntries;
 
 	for (ntries = 0; ntries < 1000; ntries++) {
+		if (usbnet_isdying(un))
+			return 1;
 		val = mue_csr_read(un, reg);
 		if ((val & set) || !(val & clear))
 			return 0;
diff --git a/sys/dev/usb/if_smsc.c b/sys/dev/usb/if_smsc.c
index 4361532efc39..de6e4395be5b 100644
--- a/sys/dev/usb/if_smsc.c
+++ b/sys/dev/usb/if_smsc.c
@@ -264,6 +264,8 @@ smsc_wait_for_bits(struct usbnet *un, uint32_t reg, uint32_t bits)
 	int err, i;
 
 	for (i = 0; i < 100; i++) {
+		if (usbnet_isdying(un))
+			return ENXIO;
 		if ((err = smsc_readreg(un, reg, &val)) != 0)
 			return err;
 		if (!(val & bits))
diff --git a/sys/dev/usb/if_udav.c b/sys/dev/usb/if_udav.c
index e22e1f305876..13e5971a4bd6 100644
--- a/sys/dev/usb/if_udav.c
+++ b/sys/dev/usb/if_udav.c
@@ -568,6 +568,8 @@ udav_chip_init(struct usbnet *un)
 	UDAV_SETBIT(un, UDAV_NCR, UDAV_NCR_RST);
 
 	for (int i = 0; i < UDAV_TX_TIMEOUT; i++) {
+		if (usbnet_isdying(un))
+			return;
 		if (!(udav_csr_read1(un, UDAV_NCR) & UDAV_NCR_RST))
 			break;
 		delay(10);	/* XXX */
diff --git a/sys/dev/usb/if_ure.c b/sys/dev/usb/if_ure.c
index db75961fc88e..6ad61447dc3a 100644
--- a/sys/dev/usb/if_ure.c
+++ b/sys/dev/usb/if_ure.c
@@ -396,6 +396,8 @@ ure_reset(struct usbnet *un)
 	ure_write_1(un, URE_PLA_CR, URE_MCU_TYPE_PLA, URE_CR_RST);
 
 	for (i = 0; i < URE_TIMEOUT; i++) {
+		if (usbnet_isdying(un))
+			return;
 		if (!(ure_read_1(un, URE_PLA_CR, URE_MCU_TYPE_PLA) &
 		    URE_CR_RST))
 			break;
@@ -541,6 +543,8 @@ ure_rtl8153_init(struct usbnet *un)
 	    URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2));
 
 	for (i = 0; i < URE_TIMEOUT; i++) {
+		if (usbnet_isdying(un))
+			return;
 		if (ure_read_2(un, URE_PLA_BOOT_CTRL, URE_MCU_TYPE_PLA) &
 		    URE_AUTOLOAD_DONE)
 			break;
@@ -550,6 +554,8 @@ ure_rtl8153_init(struct usbnet *un)
 		URE_PRINTF(un, "timeout waiting for chip autoload\n");
 
 	for (i = 0; i < URE_TIMEOUT; i++) {
+		if (usbnet_isdying(un))
+			return;
 		val = ure_ocp_reg_read(un, URE_OCP_PHY_STATUS) &
 		    URE_PHY_STAT_MASK;
 		if (val == URE_PHY_STAT_LAN_ON || val == URE_PHY_STAT_PWRDN)
@@ -748,6 +754,8 @@ ure_init_fifo(struct usbnet *un)
 	    ure_read_2(un, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA) &
 	    ~URE_MCU_BORW_EN);
 	for (i = 0; i < URE_TIMEOUT; i++) {
+		if (usbnet_isdying(un))
+			return;
 		if (ure_read_1(un, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) &
 		    URE_LINK_LIST_READY)
 			break;
@@ -759,6 +767,8 @@ ure_init_fifo(struct usbnet *un)
 	    ure_read_2(un, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA) |
 	    URE_RE_INIT_LL);
 	for (i = 0; i < URE_TIMEOUT; i++) {
+		if (usbnet_isdying(un))
+			return;
 		if (ure_read_1(un, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) &
 		    URE_LINK_LIST_READY)
 			break;
diff --git a/sys/dev/usb/if_url.c b/sys/dev/usb/if_url.c
index af766fcd455d..28674302ab26 100644
--- a/sys/dev/usb/if_url.c
+++ b/sys/dev/usb/if_url.c
@@ -428,6 +428,8 @@ url_reset(struct usbnet *un)
 	URL_SETBIT(un, URL_CR, URL_CR_SOFT_RST);
 
 	for (i = 0; i < URL_TX_TIMEOUT; i++) {
+		if (usbnet_isdying(un))
+			return;
 		if (!(url_csr_read_1(un, URL_CR) & URL_CR_SOFT_RST))
 			break;
 		delay(10);	/* XXX */

From 57c588509417c8adadd5fe88536a1da5b3b83822 Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Thu, 30 Dec 2021 13:12:07 +0000
Subject: [PATCH 34/48] usbnet: Split multicast filter reprogramming into
 separate operation.

---
 sys/dev/usb/if_aue.c  | 31 +++++++++++++------------------
 sys/dev/usb/if_axe.c  | 19 +++++--------------
 sys/dev/usb/if_axen.c | 20 ++++++++++++++++----
 sys/dev/usb/if_cue.c  | 19 +++++--------------
 sys/dev/usb/if_kue.c  | 19 +++++--------------
 sys/dev/usb/if_mos.c  | 19 +++++--------------
 sys/dev/usb/if_mue.c  | 20 ++++++++++++++++----
 sys/dev/usb/if_smsc.c | 20 ++++++++++++++++----
 sys/dev/usb/if_udav.c | 19 +++++--------------
 sys/dev/usb/if_ure.c  | 19 +++++--------------
 sys/dev/usb/if_url.c  | 19 +++++--------------
 sys/dev/usb/usbnet.c  | 24 +++++++++---------------
 sys/dev/usb/usbnet.h  | 14 ++++++++++----
 13 files changed, 115 insertions(+), 147 deletions(-)

diff --git a/sys/dev/usb/if_aue.c b/sys/dev/usb/if_aue.c
index b4d0dc36b7b8..c47324b59848 100644
--- a/sys/dev/usb/if_aue.c
+++ b/sys/dev/usb/if_aue.c
@@ -240,7 +240,7 @@ CFATTACH_DECL_NEW(aue, sizeof(struct aue_softc), aue_match, aue_attach,
 static void aue_reset_pegasus_II(struct aue_softc *);
 
 static void aue_uno_stop(struct ifnet *, int);
-static int aue_uno_ioctl(struct ifnet *, u_long, void *);
+static void aue_uno_mcast(struct ifnet *);
 static int aue_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *);
 static int aue_uno_mii_write_reg(struct usbnet *, int, int, uint16_t);
 static void aue_uno_mii_statchg(struct ifnet *);
@@ -252,7 +252,7 @@ static void aue_uno_intr(struct usbnet *, usbd_status);
 
 static const struct usbnet_ops aue_ops = {
 	.uno_stop = aue_uno_stop,
-	.uno_ioctl = aue_uno_ioctl,
+	.uno_mcast = aue_uno_mcast,
 	.uno_read_reg = aue_uno_mii_read_reg,
 	.uno_write_reg = aue_uno_mii_write_reg,
 	.uno_statchg = aue_uno_mii_statchg,
@@ -1013,28 +1013,23 @@ aue_uno_init(struct ifnet *ifp)
 	return rv;
 }
 
-static int
-aue_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data)
+static void
+aue_uno_mcast(struct ifnet *ifp)
 {
 	struct usbnet * const un = ifp->if_softc;
 
 	AUEHIST_FUNC();
-	AUEHIST_CALLARGSN(5, "aue%jd: enter cmd %#jx data %#jx",
+	AUEHIST_CALLARGSN(5, "aue%jd: enter",
 	    device_unit(((struct usbnet *)(ifp->if_softc))->un_dev),
-	    cmd, (uintptr_t)data, 0);
-
-	switch (cmd) {
-	case SIOCADDMULTI:
-	case SIOCDELMULTI:
-		usbnet_lock_core(un);
-		aue_uno_init(ifp);
-		usbnet_unlock_core(un);
-		break;
-	default:
-		break;
-	}
+	    0, 0, 0);
 
-	return 0;
+	/*
+	 * XXX I feel like this is pretty heavy-handed!  Maybe we could
+	 * make do with aue_setiff_locked instead?
+	 */
+	usbnet_lock_core(un);
+	aue_uno_init(ifp);
+	usbnet_unlock_core(un);
 }
 
 static void
diff --git a/sys/dev/usb/if_axe.c b/sys/dev/usb/if_axe.c
index 78a4a6546f70..20ca7b276760 100644
--- a/sys/dev/usb/if_axe.c
+++ b/sys/dev/usb/if_axe.c
@@ -259,7 +259,7 @@ CFATTACH_DECL_NEW(axe, sizeof(struct axe_softc),
 	axe_match, axe_attach, usbnet_detach, usbnet_activate);
 
 static void	axe_uno_stop(struct ifnet *, int);
-static int	axe_uno_ioctl(struct ifnet *, u_long, void *);
+static void	axe_uno_mcast(struct ifnet *);
 static int	axe_uno_init(struct ifnet *);
 static int	axe_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *);
 static int	axe_uno_mii_write_reg(struct usbnet *, int, int, uint16_t);
@@ -276,7 +276,7 @@ static void	axe_ax88772b_init(struct axe_softc *);
 
 static const struct usbnet_ops axe_ops = {
 	.uno_stop = axe_uno_stop,
-	.uno_ioctl = axe_uno_ioctl,
+	.uno_mcast = axe_uno_mcast,
 	.uno_read_reg = axe_uno_mii_read_reg,
 	.uno_write_reg = axe_uno_mii_write_reg,
 	.uno_statchg = axe_uno_mii_statchg,
@@ -1324,27 +1324,18 @@ axe_uno_init(struct ifnet *ifp)
 	return ret;
 }
 
-static int
-axe_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data)
+static void
+axe_uno_mcast(struct ifnet *ifp)
 {
 	struct usbnet * const un = ifp->if_softc;
 
 	usbnet_lock_core(un);
 	usbnet_busy(un);
 
-	switch (cmd) {
-	case SIOCADDMULTI:
-	case SIOCDELMULTI:
-		axe_rcvfilt_locked(un);
-		break;
-	default:
-		break;
-	}
+	axe_rcvfilt_locked(un);
 
 	usbnet_unbusy(un);
 	usbnet_unlock_core(un);
-
-	return 0;
 }
 
 static void
diff --git a/sys/dev/usb/if_axen.c b/sys/dev/usb/if_axen.c
index 7d90fa1259f9..3c12ad38c0a7 100644
--- a/sys/dev/usb/if_axen.c
+++ b/sys/dev/usb/if_axen.c
@@ -80,6 +80,7 @@ static void	axen_ax88179_init(struct usbnet *);
 
 static void	axen_uno_stop(struct ifnet *, int);
 static int	axen_uno_ioctl(struct ifnet *, u_long, void *);
+static void	axen_uno_mcast(struct ifnet *);
 static int	axen_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *);
 static int	axen_uno_mii_write_reg(struct usbnet *, int, int, uint16_t);
 static void	axen_uno_mii_statchg(struct ifnet *);
@@ -92,6 +93,7 @@ static int	axen_uno_init(struct ifnet *);
 static const struct usbnet_ops axen_ops = {
 	.uno_stop = axen_uno_stop,
 	.uno_ioctl = axen_uno_ioctl,
+	.uno_mcast = axen_uno_mcast,
 	.uno_read_reg = axen_uno_mii_read_reg,
 	.uno_write_reg = axen_uno_mii_write_reg,
 	.uno_statchg = axen_uno_mii_statchg,
@@ -559,10 +561,6 @@ axen_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 	usbnet_busy(un);
 
 	switch (cmd) {
-	case SIOCADDMULTI:
-	case SIOCDELMULTI:
-		axen_setiff_locked(un);
-		break;
 	case SIOCSIFCAP:
 		axen_setoe_locked(un);
 		break;
@@ -576,6 +574,20 @@ axen_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 	return 0;
 }
 
+static void
+axen_uno_mcast(struct ifnet *ifp)
+{
+	struct usbnet * const un = ifp->if_softc;
+
+	usbnet_lock_core(un);
+	usbnet_busy(un);
+
+	axen_setiff_locked(un);
+
+	usbnet_unbusy(un);
+	usbnet_unlock_core(un);
+}
+
 static int
 axen_match(device_t parent, cfdata_t match, void *aux)
 {
diff --git a/sys/dev/usb/if_cue.c b/sys/dev/usb/if_cue.c
index 191f31eb9eca..54a6c8535e12 100644
--- a/sys/dev/usb/if_cue.c
+++ b/sys/dev/usb/if_cue.c
@@ -141,14 +141,14 @@ CFATTACH_DECL_NEW(cue, sizeof(struct cue_softc), cue_match, cue_attach,
 static unsigned cue_uno_tx_prepare(struct usbnet *, struct mbuf *,
 				   struct usbnet_chain *);
 static void cue_uno_rx_loop(struct usbnet *, struct usbnet_chain *, uint32_t);
-static int cue_uno_ioctl(struct ifnet *, u_long, void *);
+static void cue_uno_mcast(struct ifnet *);
 static void cue_uno_stop(struct ifnet *, int);
 static int cue_uno_init(struct ifnet *);
 static void cue_uno_tick(struct usbnet *);
 
 static const struct usbnet_ops cue_ops = {
 	.uno_stop = cue_uno_stop,
-	.uno_ioctl = cue_uno_ioctl,
+	.uno_mcast = cue_uno_mcast,
 	.uno_tx_prepare = cue_uno_tx_prepare,
 	.uno_rx_loop = cue_uno_rx_loop,
 	.uno_init = cue_uno_init,
@@ -680,27 +680,18 @@ cue_uno_init(struct ifnet *ifp)
 	return rv;
 }
 
-static int
-cue_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data)
+static void
+cue_uno_mcast(struct ifnet *ifp)
 {
 	struct usbnet * const	un = ifp->if_softc;
 
 	usbnet_lock_core(un);
 	usbnet_busy(un);
 
-	switch (cmd) {
-	case SIOCADDMULTI:
-	case SIOCDELMULTI:
-		cue_setiff_locked(un);
-		break;
-	default:
-		break;
-	}
+	cue_setiff_locked(un);
 
 	usbnet_unbusy(un);
 	usbnet_unlock_core(un);
-
-	return 0;
 }
 
 /* Stop and reset the adapter.  */
diff --git a/sys/dev/usb/if_kue.c b/sys/dev/usb/if_kue.c
index 6d8af3cd0735..6c2f417e74df 100644
--- a/sys/dev/usb/if_kue.c
+++ b/sys/dev/usb/if_kue.c
@@ -174,11 +174,11 @@ CFATTACH_DECL_NEW(kue, sizeof(struct kue_softc), kue_match, kue_attach,
 static void kue_uno_rx_loop(struct usbnet *, struct usbnet_chain *, uint32_t);
 static unsigned kue_uno_tx_prepare(struct usbnet *, struct mbuf *,
 				   struct usbnet_chain *);
-static int kue_uno_ioctl(struct ifnet *, u_long, void *);
+static void kue_uno_mcast(struct ifnet *);
 static int kue_uno_init(struct ifnet *);
 
 static const struct usbnet_ops kue_ops = {
-	.uno_ioctl = kue_uno_ioctl,
+	.uno_mcast = kue_uno_mcast,
 	.uno_tx_prepare = kue_uno_tx_prepare,
 	.uno_rx_loop = kue_uno_rx_loop,
 	.uno_init = kue_uno_init,
@@ -640,27 +640,18 @@ kue_uno_init(struct ifnet *ifp)
 	return rv;
 }
 
-static int
-kue_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data)
+static void
+kue_uno_mcast(struct ifnet *ifp)
 {
 	struct usbnet * const	un = ifp->if_softc;
 
 	usbnet_lock_core(un);
 	usbnet_busy(un);
 
-	switch (cmd) {
-	case SIOCADDMULTI:
-	case SIOCDELMULTI:
-		kue_setiff_locked(un);
-		break;
-	default:
-		break;
-	}
+	kue_setiff_locked(un);
 
 	usbnet_unbusy(un);
 	usbnet_unlock_core(un);
-
-	return 0;
 }
 
 #ifdef _MODULE
diff --git a/sys/dev/usb/if_mos.c b/sys/dev/usb/if_mos.c
index e76c9f11893a..26d048b20310 100644
--- a/sys/dev/usb/if_mos.c
+++ b/sys/dev/usb/if_mos.c
@@ -145,7 +145,7 @@ CFATTACH_DECL_NEW(mos, sizeof(struct usbnet),
 static void mos_uno_rx_loop(struct usbnet *, struct usbnet_chain *, uint32_t);
 static unsigned mos_uno_tx_prepare(struct usbnet *, struct mbuf *,
 				   struct usbnet_chain *);
-static int mos_uno_ioctl(struct ifnet *, u_long, void *);
+static void mos_uno_mcast(struct ifnet *);
 static int mos_uno_init(struct ifnet *);
 static void mos_chip_init(struct usbnet *);
 static void mos_uno_stop(struct ifnet *ifp, int disable);
@@ -164,7 +164,7 @@ static int mos_write_mcast(struct usbnet *, uint8_t *);
 
 static const struct usbnet_ops mos_ops = {
 	.uno_stop = mos_uno_stop,
-	.uno_ioctl = mos_uno_ioctl,
+	.uno_mcast = mos_uno_mcast,
 	.uno_read_reg = mos_uno_mii_read_reg,
 	.uno_write_reg = mos_uno_mii_write_reg,
 	.uno_statchg = mos_uno_mii_statchg,
@@ -771,27 +771,18 @@ mos_uno_init(struct ifnet *ifp)
 	return ret;
 }
 
-static int
-mos_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data)
+static void
+mos_uno_mcast(struct ifnet *ifp)
 {
 	struct usbnet * const un = ifp->if_softc;
 
 	usbnet_lock_core(un);
 	usbnet_busy(un);
 
-	switch (cmd) {
-	case SIOCADDMULTI:
-	case SIOCDELMULTI:
-		mos_rcvfilt_locked(un);
-		break;
-	default:
-		break;
-	}
+	mos_rcvfilt_locked(un);
 
 	usbnet_unbusy(un);
 	usbnet_unlock_core(un);
-
-	return 0;
 }
 
 void
diff --git a/sys/dev/usb/if_mue.c b/sys/dev/usb/if_mue.c
index 034bacc1f587..fe14f4422d8f 100644
--- a/sys/dev/usb/if_mue.c
+++ b/sys/dev/usb/if_mue.c
@@ -99,6 +99,7 @@ static void	mue_reset(struct usbnet *);
 
 static void	mue_uno_stop(struct ifnet *, int);
 static int	mue_uno_ioctl(struct ifnet *, u_long, void *);
+static void	mue_uno_mcast(struct ifnet *);
 static int	mue_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *);
 static int	mue_uno_mii_write_reg(struct usbnet *, int, int, uint16_t);
 static void	mue_uno_mii_statchg(struct ifnet *);
@@ -111,6 +112,7 @@ static int	mue_uno_init(struct ifnet *);
 static const struct usbnet_ops mue_ops = {
 	.uno_stop = mue_uno_stop,
 	.uno_ioctl = mue_uno_ioctl,
+	.uno_mcast = mue_uno_mcast,
 	.uno_read_reg = mue_uno_mii_read_reg,
 	.uno_write_reg = mue_uno_mii_write_reg,
 	.uno_statchg = mue_uno_mii_statchg,
@@ -1273,10 +1275,6 @@ mue_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 	usbnet_busy(un);
 
 	switch (cmd) {
-	case SIOCADDMULTI:
-	case SIOCDELMULTI:
-		mue_setiff_locked(un);
-		break;
 	case SIOCSIFCAP:
 		mue_sethwcsum_locked(un);
 		break;
@@ -1293,6 +1291,20 @@ mue_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 	return 0;
 }
 
+static void
+mue_uno_mcast(struct ifnet *ifp)
+{
+	struct usbnet * const un = ifp->if_softc;
+
+	usbnet_lock_core(un);
+	usbnet_busy(un);
+
+	mue_setiff_locked(un);
+
+	usbnet_unbusy(un);
+	usbnet_unlock_core(un);
+}
+
 static void
 mue_reset(struct usbnet *un)
 {
diff --git a/sys/dev/usb/if_smsc.c b/sys/dev/usb/if_smsc.c
index de6e4395be5b..d749af747e09 100644
--- a/sys/dev/usb/if_smsc.c
+++ b/sys/dev/usb/if_smsc.c
@@ -187,6 +187,7 @@ static int	 smsc_uno_miibus_readreg(struct usbnet *, int, int, uint16_t *);
 static int	 smsc_uno_miibus_writereg(struct usbnet *, int, int, uint16_t);
 
 static int	 smsc_uno_ioctl(struct ifnet *, u_long, void *);
+static void	 smsc_uno_mcast(struct ifnet *);
 static unsigned	 smsc_uno_tx_prepare(struct usbnet *, struct mbuf *,
 		     struct usbnet_chain *);
 static void	 smsc_uno_rx_loop(struct usbnet *, struct usbnet_chain *,
@@ -195,6 +196,7 @@ static void	 smsc_uno_rx_loop(struct usbnet *, struct usbnet_chain *,
 static const struct usbnet_ops smsc_ops = {
 	.uno_stop = smsc_uno_stop,
 	.uno_ioctl = smsc_uno_ioctl,
+	.uno_mcast = smsc_uno_mcast,
 	.uno_read_reg = smsc_uno_miibus_readreg,
 	.uno_write_reg = smsc_uno_miibus_writereg,
 	.uno_statchg = smsc_uno_miibus_statchg,
@@ -757,10 +759,6 @@ smsc_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 	usbnet_busy(un);
 
 	switch (cmd) {
-	case SIOCADDMULTI:
-	case SIOCDELMULTI:
-		smsc_setiff_locked(un);
-		break;
 	case SIOCSIFCAP:
 		smsc_setoe_locked(un);
 		break;
@@ -774,6 +772,20 @@ smsc_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 	return 0;
 }
 
+static void
+smsc_uno_mcast(struct ifnet *ifp)
+{
+	struct usbnet * const un = ifp->if_softc;
+
+	usbnet_lock_core(un);
+	usbnet_busy(un);
+
+	smsc_setiff_locked(un);
+
+	usbnet_unbusy(un);
+	usbnet_unlock_core(un);
+}
+
 static int
 smsc_match(device_t parent, cfdata_t match, void *aux)
 {
diff --git a/sys/dev/usb/if_udav.c b/sys/dev/usb/if_udav.c
index 13e5971a4bd6..45f68f89eb32 100644
--- a/sys/dev/usb/if_udav.c
+++ b/sys/dev/usb/if_udav.c
@@ -69,7 +69,7 @@ static unsigned udav_uno_tx_prepare(struct usbnet *, struct mbuf *,
 				    struct usbnet_chain *);
 static void udav_uno_rx_loop(struct usbnet *, struct usbnet_chain *, uint32_t);
 static void udav_uno_stop(struct ifnet *, int);
-static int udav_uno_ioctl(struct ifnet *, u_long, void *);
+static void udav_uno_mcast(struct ifnet *);
 static int udav_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *);
 static int udav_uno_mii_write_reg(struct usbnet *, int, int, uint16_t);
 static void udav_uno_mii_statchg(struct ifnet *);
@@ -132,7 +132,7 @@ static const struct udav_type {
 
 static const struct usbnet_ops udav_ops = {
 	.uno_stop = udav_uno_stop,
-	.uno_ioctl = udav_uno_ioctl,
+	.uno_mcast = udav_uno_mcast,
 	.uno_read_reg = udav_uno_mii_read_reg,
 	.uno_write_reg = udav_uno_mii_write_reg,
 	.uno_statchg = udav_uno_mii_statchg,
@@ -718,27 +718,18 @@ udav_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len)
 	usbnet_enqueue(un, buf, pkt_len, 0, 0, 0);
 }
 
-static int
-udav_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data)
+static void
+udav_uno_mcast(struct ifnet *ifp)
 {
 	struct usbnet * const un = ifp->if_softc;
 
 	usbnet_lock_core(un);
 	usbnet_busy(un);
 
-	switch (cmd) {
-	case SIOCADDMULTI:
-	case SIOCDELMULTI:
-		udav_setiff_locked(un);
-		break;
-	default:
-		break;
-	}
+	udav_setiff_locked(un);
 
 	usbnet_unbusy(un);
 	usbnet_unlock_core(un);
-
-	return 0;
 }
 
 /* Stop the adapter and free any mbufs allocated to the RX and TX lists. */
diff --git a/sys/dev/usb/if_ure.c b/sys/dev/usb/if_ure.c
index 6ad61447dc3a..480bc05e1e6d 100644
--- a/sys/dev/usb/if_ure.c
+++ b/sys/dev/usb/if_ure.c
@@ -86,7 +86,7 @@ static void	ure_disable_teredo(struct usbnet *);
 static void	ure_init_fifo(struct usbnet *);
 
 static void	ure_uno_stop(struct ifnet *, int);
-static int	ure_uno_ioctl(struct ifnet *, u_long, void *);
+static void	ure_uno_mcast(struct ifnet *);
 static int	ure_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *);
 static int	ure_uno_mii_write_reg(struct usbnet *, int, int, uint16_t);
 static void	ure_uno_miibus_statchg(struct ifnet *);
@@ -104,7 +104,7 @@ CFATTACH_DECL_NEW(ure, sizeof(struct usbnet), ure_match, ure_attach,
 
 static const struct usbnet_ops ure_ops = {
 	.uno_stop = ure_uno_stop,
-	.uno_ioctl = ure_uno_ioctl,
+	.uno_mcast = ure_uno_mcast,
 	.uno_read_reg = ure_uno_mii_read_reg,
 	.uno_write_reg = ure_uno_mii_write_reg,
 	.uno_statchg = ure_uno_miibus_statchg,
@@ -802,27 +802,18 @@ ure_init_fifo(struct usbnet *un)
 	    URE_TXFIFO_THR_NORMAL);
 }
 
-static int
-ure_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data)
+static void
+ure_uno_mcast(struct ifnet *ifp)
 {
 	struct usbnet * const un = ifp->if_softc;
 
 	usbnet_lock_core(un);
 	usbnet_busy(un);
 
-	switch (cmd) {
-	case SIOCADDMULTI:
-	case SIOCDELMULTI:
-		ure_rcvfilt_locked(un);
-		break;
-	default:
-		break;
-	}
+	ure_rcvfilt_locked(un);
 
 	usbnet_unbusy(un);
 	usbnet_unlock_core(un);
-
-	return 0;
 }
 
 static int
diff --git a/sys/dev/usb/if_url.c b/sys/dev/usb/if_url.c
index 28674302ab26..907d759f9ad8 100644
--- a/sys/dev/usb/if_url.c
+++ b/sys/dev/usb/if_url.c
@@ -77,7 +77,7 @@ static unsigned	url_uno_tx_prepare(struct usbnet *, struct mbuf *,
 static void url_uno_rx_loop(struct usbnet *, struct usbnet_chain *, uint32_t);
 static int url_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *);
 static int url_uno_mii_write_reg(struct usbnet *, int, int, uint16_t);
-static int url_uno_ioctl(struct ifnet *, u_long, void *);
+static void url_uno_mcast(struct ifnet *);
 static void url_uno_stop(struct ifnet *, int);
 static void url_uno_mii_statchg(struct ifnet *);
 static int url_uno_init(struct ifnet *);
@@ -93,7 +93,7 @@ static int url_mem(struct usbnet *, int, int, void *, int);
 
 static const struct usbnet_ops url_ops = {
 	.uno_stop = url_uno_stop,
-	.uno_ioctl = url_uno_ioctl,
+	.uno_mcast = url_uno_mcast,
 	.uno_read_reg = url_uno_mii_read_reg,
 	.uno_write_reg = url_uno_mii_write_reg,
 	.uno_statchg = url_uno_mii_statchg,
@@ -559,27 +559,18 @@ static void url_intr(void)
 }
 #endif
 
-static int
-url_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data)
+static void
+url_uno_mcast(struct ifnet *ifp)
 {
 	struct usbnet * const un = ifp->if_softc;
 
 	usbnet_lock_core(un);
 	usbnet_busy(un);
 
-	switch (cmd) {
-	case SIOCADDMULTI:
-	case SIOCDELMULTI:
-		url_rcvfilt_locked(un);
-		break;
-	default:
-		break;
-	}
+	url_rcvfilt_locked(un);
 
 	usbnet_unbusy(un);
 	usbnet_unlock_core(un);
-
-	return 0;
 }
 
 /* Stop the adapter and free any mbufs allocated to the RX and TX lists. */
diff --git a/sys/dev/usb/usbnet.c b/sys/dev/usb/usbnet.c
index 4ea0859904b9..80911908fa66 100644
--- a/sys/dev/usb/usbnet.c
+++ b/sys/dev/usb/usbnet.c
@@ -162,13 +162,9 @@ static int
 uno_ioctl(struct usbnet *un, struct ifnet *ifp, u_long cmd, void *data)
 {
 
-	switch (cmd) {
-	case SIOCADDMULTI:
-	case SIOCDELMULTI:
-		break;
-	default:
-		KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname);
-	}
+	KASSERTMSG(cmd != SIOCADDMULTI, "%s", ifp->if_xname);
+	KASSERTMSG(cmd != SIOCDELMULTI, "%s", ifp->if_xname);
+	KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname);
 
 	if (un->un_ops->uno_ioctl)
 		return (*un->un_ops->uno_ioctl)(ifp, cmd, data);
@@ -1076,7 +1072,6 @@ usbnet_mcast_task(void *arg)
 	USBNETHIST_FUNC();
 	struct usbnet * const un = arg;
 	struct ifnet * const ifp = usbnet_ifp(un);
-	struct ifreq ifr;
 
 	USBNETHIST_CALLARGSN(10, "%jd: enter",
 	    un->un_pri->unp_number, 0, 0, 0);
@@ -1094,16 +1089,15 @@ usbnet_mcast_task(void *arg)
 		return;
 
 	/*
-	 * Pass a bogus ifr with SIOCDELMULTI -- the goal is to just
-	 * notify the driver to reprogram any hardware multicast
-	 * filter, according to what's already stored in the ethercom.
-	 * None of the drivers actually examine this argument, so it
-	 * doesn't change the ABI as far as they can tell.
+	 * If the hardware is running, ask the driver to reprogram the
+	 * multicast filter.  If the hardware is not running, the
+	 * driver is responsible for programming the multicast filter
+	 * as part of its uno_init routine to bring the hardware up.
 	 */
 	IFNET_LOCK(ifp);
 	if (ifp->if_flags & IFF_RUNNING) {
-		memset(&ifr, 0, sizeof(ifr));
-		(void)uno_ioctl(un, ifp, SIOCDELMULTI, &ifr);
+		if (un->un_ops->uno_mcast)
+			(*un->un_ops->uno_mcast)(ifp);
 	}
 	IFNET_UNLOCK(ifp);
 }
diff --git a/sys/dev/usb/usbnet.h b/sys/dev/usb/usbnet.h
index 1faa822887c5..fc9c578453a5 100644
--- a/sys/dev/usb/usbnet.h
+++ b/sys/dev/usb/usbnet.h
@@ -131,6 +131,8 @@ enum usbnet_ep {
 typedef void (*usbnet_stop_cb)(struct ifnet *, int);
 /* Interface ioctl callback. */
 typedef int (*usbnet_ioctl_cb)(struct ifnet *, u_long, void *);
+/* Reprogram multicast filters callback. */
+typedef void (*usbnet_mcast_cb)(struct ifnet *);
 /* Initialise device callback. */
 typedef int (*usbnet_init_cb)(struct ifnet *);
 
@@ -170,16 +172,20 @@ typedef void (*usbnet_intr_cb)(struct usbnet *, usbd_status);
  * Note that when CORE_LOCK is held, IFNET_LOCK may or may not also
  * be held.
  *
- * Note that the IFNET_LOCK **may not be held** for some ioctl
- * operations (add/delete multicast addresses, for example).
+ * Note that the IFNET_LOCK **may not be held** for some the ioctl
+ * commands SIOCADDMULTI/SIOCDELMULTI.  These commands are only passed
+ * explicitly to uno_override_ioctl; for all other devices, they are
+ * handled inside usbnet by scheduling a task to asynchronously call
+ * uno_mcast with IFNET_LOCK held.
  *
  * Busy reference counts are maintained across calls to: uno_stop,
  * uno_read_reg, uno_write_reg, uno_statchg, and uno_tick.
  */
 struct usbnet_ops {
 	usbnet_stop_cb		uno_stop;		/* C */
-	usbnet_ioctl_cb		uno_ioctl;		/* I (maybe) */
-	usbnet_ioctl_cb		uno_override_ioctl;	/* I (maybe) */
+	usbnet_ioctl_cb		uno_ioctl;		/* I */
+	usbnet_ioctl_cb		uno_override_ioctl;	/* I (except mcast) */
+	usbnet_mcast_cb		uno_mcast;		/* I */
 	usbnet_init_cb		uno_init;		/* I */
 	usbnet_mii_read_reg_cb	uno_read_reg;		/* C */
 	usbnet_mii_write_reg_cb uno_write_reg;		/* C */

From 8a7f582a0211946a0a115c0133f16ad230e2e46a Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Thu, 30 Dec 2021 13:32:54 +0000
Subject: [PATCH 35/48] usbnet drivers: No need for usbnet_busy in uno_init.

This callback always runs with the IFNET_LOCK held, and the interface
cannot be detached until the IFNET_LOCK is released, so there is no
need to hang onto a reference count here.  (None of the usbnet
drivers touch the IFNET_LOCK except to verify it is held sometimes.)
---
 sys/dev/usb/if_aue.c  | 3 ---
 sys/dev/usb/if_axe.c  | 4 ----
 sys/dev/usb/if_axen.c | 4 ----
 sys/dev/usb/if_cue.c  | 3 ---
 sys/dev/usb/if_kue.c  | 3 ---
 sys/dev/usb/if_mos.c  | 4 ----
 sys/dev/usb/if_mue.c  | 3 ---
 sys/dev/usb/if_smsc.c | 4 ----
 sys/dev/usb/if_udav.c | 5 -----
 sys/dev/usb/if_ure.c  | 4 ----
 sys/dev/usb/if_url.c  | 4 ----
 11 files changed, 41 deletions(-)

diff --git a/sys/dev/usb/if_aue.c b/sys/dev/usb/if_aue.c
index c47324b59848..058c8ae923be 100644
--- a/sys/dev/usb/if_aue.c
+++ b/sys/dev/usb/if_aue.c
@@ -1003,12 +1003,9 @@ aue_init_locked(struct ifnet *ifp)
 static int
 aue_uno_init(struct ifnet *ifp)
 {
-	struct usbnet * const	un = ifp->if_softc;
 	int rv;
 
-	usbnet_busy(un);
 	rv = aue_init_locked(ifp);
-	usbnet_unbusy(un);
 
 	return rv;
 }
diff --git a/sys/dev/usb/if_axe.c b/sys/dev/usb/if_axe.c
index 20ca7b276760..252f28ef8b14 100644
--- a/sys/dev/usb/if_axe.c
+++ b/sys/dev/usb/if_axe.c
@@ -1315,11 +1315,7 @@ axe_init_locked(struct ifnet *ifp)
 static int
 axe_uno_init(struct ifnet *ifp)
 {
-	struct usbnet * const un = ifp->if_softc;
-
-	usbnet_busy(un);
 	int ret = axe_init_locked(ifp);
-	usbnet_unbusy(un);
 
 	return ret;
 }
diff --git a/sys/dev/usb/if_axen.c b/sys/dev/usb/if_axen.c
index 3c12ad38c0a7..f8199ca2f1fc 100644
--- a/sys/dev/usb/if_axen.c
+++ b/sys/dev/usb/if_axen.c
@@ -945,11 +945,7 @@ axen_init_locked(struct ifnet *ifp)
 static int
 axen_uno_init(struct ifnet *ifp)
 {
-	struct usbnet * const un = ifp->if_softc;
-
-	usbnet_busy(un);
 	int ret = axen_init_locked(ifp);
-	usbnet_unbusy(un);
 
 	return ret;
 }
diff --git a/sys/dev/usb/if_cue.c b/sys/dev/usb/if_cue.c
index 54a6c8535e12..6c2db667ba82 100644
--- a/sys/dev/usb/if_cue.c
+++ b/sys/dev/usb/if_cue.c
@@ -670,12 +670,9 @@ cue_init_locked(struct ifnet *ifp)
 static int
 cue_uno_init(struct ifnet *ifp)
 {
-	struct usbnet * const	un = ifp->if_softc;
 	int rv;
 
-	usbnet_busy(un);
 	rv = cue_init_locked(ifp);
-	usbnet_unbusy(un);
 
 	return rv;
 }
diff --git a/sys/dev/usb/if_kue.c b/sys/dev/usb/if_kue.c
index 6c2f417e74df..7d2a03e14c8c 100644
--- a/sys/dev/usb/if_kue.c
+++ b/sys/dev/usb/if_kue.c
@@ -630,12 +630,9 @@ kue_init_locked(struct ifnet *ifp)
 static int
 kue_uno_init(struct ifnet *ifp)
 {
-	struct usbnet * const	un = ifp->if_softc;
 	int rv;
 
-	usbnet_busy(un);
 	rv = kue_init_locked(ifp);
-	usbnet_unbusy(un);
 
 	return rv;
 }
diff --git a/sys/dev/usb/if_mos.c b/sys/dev/usb/if_mos.c
index 26d048b20310..03601b9e752b 100644
--- a/sys/dev/usb/if_mos.c
+++ b/sys/dev/usb/if_mos.c
@@ -762,11 +762,7 @@ mos_init_locked(struct ifnet *ifp)
 static int
 mos_uno_init(struct ifnet *ifp)
 {
-	struct usbnet * const un = ifp->if_softc;
-
-	usbnet_busy(un);
 	int ret = mos_init_locked(ifp);
-	usbnet_unbusy(un);
 
 	return ret;
 }
diff --git a/sys/dev/usb/if_mue.c b/sys/dev/usb/if_mue.c
index fe14f4422d8f..e41fe6b6b091 100644
--- a/sys/dev/usb/if_mue.c
+++ b/sys/dev/usb/if_mue.c
@@ -1256,12 +1256,9 @@ mue_init_locked(struct ifnet *ifp)
 static int
 mue_uno_init(struct ifnet *ifp)
 {
-	struct usbnet * const	un = ifp->if_softc;
 	int rv;
 
-	usbnet_busy(un);
 	rv = mue_init_locked(ifp);
-	usbnet_unbusy(un);
 
 	return rv;
 }
diff --git a/sys/dev/usb/if_smsc.c b/sys/dev/usb/if_smsc.c
index d749af747e09..718638357b93 100644
--- a/sys/dev/usb/if_smsc.c
+++ b/sys/dev/usb/if_smsc.c
@@ -554,11 +554,7 @@ smsc_reset(struct smsc_softc *sc)
 static int
 smsc_uno_init(struct ifnet *ifp)
 {
-	struct usbnet * const un = ifp->if_softc;
-
-	usbnet_busy(un);
 	int ret = smsc_init_locked(ifp);
-	usbnet_unbusy(un);
 
 	return ret;
 }
diff --git a/sys/dev/usb/if_udav.c b/sys/dev/usb/if_udav.c
index 45f68f89eb32..fe70dfb17012 100644
--- a/sys/dev/usb/if_udav.c
+++ b/sys/dev/usb/if_udav.c
@@ -486,8 +486,6 @@ udav_uno_init(struct ifnet *ifp)
 	if (ifp->if_flags & IFF_RUNNING)
 		usbnet_stop(un, ifp, 1);
 
-	usbnet_busy(un);
-
 	memcpy(eaddr, CLLADDR(ifp->if_sadl), sizeof(eaddr));
 	udav_csr_write(un, UDAV_PAR, eaddr, ETHER_ADDR_LEN);
 
@@ -518,7 +516,6 @@ udav_uno_init(struct ifnet *ifp)
 		rc = 0;
 
 	if (rc != 0) {
-		usbnet_unbusy(un);
 		return rc;
 	}
 
@@ -527,8 +524,6 @@ udav_uno_init(struct ifnet *ifp)
 	else
 		rc = usbnet_init_rx_tx(un);
 
-	usbnet_unbusy(un);
-
 	return rc;
 }
 
diff --git a/sys/dev/usb/if_ure.c b/sys/dev/usb/if_ure.c
index 480bc05e1e6d..669677836f8d 100644
--- a/sys/dev/usb/if_ure.c
+++ b/sys/dev/usb/if_ure.c
@@ -456,11 +456,7 @@ ure_init_locked(struct ifnet *ifp)
 static int
 ure_uno_init(struct ifnet *ifp)
 {
-	struct usbnet * const un = ifp->if_softc;
-
-	usbnet_busy(un);
 	int ret = ure_init_locked(ifp);
-	usbnet_unbusy(un);
 
 	return ret;
 }
diff --git a/sys/dev/usb/if_url.c b/sys/dev/usb/if_url.c
index 907d759f9ad8..b0f48c5249c8 100644
--- a/sys/dev/usb/if_url.c
+++ b/sys/dev/usb/if_url.c
@@ -406,11 +406,7 @@ url_init_locked(struct ifnet *ifp)
 static int
 url_uno_init(struct ifnet *ifp)
 {
-	struct usbnet * const un = ifp->if_softc;
-
-	usbnet_busy(un);
 	int ret = url_init_locked(ifp);
-	usbnet_unbusy(un);
 
 	return ret;
 }

From bcfdbe3b080d865f8d9eebb00e5ea102cf7c7745 Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Thu, 30 Dec 2021 13:35:32 +0000
Subject: [PATCH 36/48] usbnet drivers: No need for usbnet_busy in uno_mcast.

This callback always runs with IFNET_LOCK held, and during a task
that usbnet_detach prevents scheduling anew and waits for finishing
before completing the detach, so there is no need to hang onto a
reference count here.
---
 sys/dev/usb/if_axe.c  | 2 --
 sys/dev/usb/if_axen.c | 2 --
 sys/dev/usb/if_cue.c  | 2 --
 sys/dev/usb/if_kue.c  | 2 --
 sys/dev/usb/if_mos.c  | 2 --
 sys/dev/usb/if_mue.c  | 2 --
 sys/dev/usb/if_smsc.c | 2 --
 sys/dev/usb/if_udav.c | 2 --
 sys/dev/usb/if_ure.c  | 2 --
 sys/dev/usb/if_url.c  | 2 --
 10 files changed, 20 deletions(-)

diff --git a/sys/dev/usb/if_axe.c b/sys/dev/usb/if_axe.c
index 252f28ef8b14..5f7663e435e0 100644
--- a/sys/dev/usb/if_axe.c
+++ b/sys/dev/usb/if_axe.c
@@ -1326,11 +1326,9 @@ axe_uno_mcast(struct ifnet *ifp)
 	struct usbnet * const un = ifp->if_softc;
 
 	usbnet_lock_core(un);
-	usbnet_busy(un);
 
 	axe_rcvfilt_locked(un);
 
-	usbnet_unbusy(un);
 	usbnet_unlock_core(un);
 }
 
diff --git a/sys/dev/usb/if_axen.c b/sys/dev/usb/if_axen.c
index f8199ca2f1fc..96f17df1b3cc 100644
--- a/sys/dev/usb/if_axen.c
+++ b/sys/dev/usb/if_axen.c
@@ -580,11 +580,9 @@ axen_uno_mcast(struct ifnet *ifp)
 	struct usbnet * const un = ifp->if_softc;
 
 	usbnet_lock_core(un);
-	usbnet_busy(un);
 
 	axen_setiff_locked(un);
 
-	usbnet_unbusy(un);
 	usbnet_unlock_core(un);
 }
 
diff --git a/sys/dev/usb/if_cue.c b/sys/dev/usb/if_cue.c
index 6c2db667ba82..646cef9178b5 100644
--- a/sys/dev/usb/if_cue.c
+++ b/sys/dev/usb/if_cue.c
@@ -683,11 +683,9 @@ cue_uno_mcast(struct ifnet *ifp)
 	struct usbnet * const	un = ifp->if_softc;
 
 	usbnet_lock_core(un);
-	usbnet_busy(un);
 
 	cue_setiff_locked(un);
 
-	usbnet_unbusy(un);
 	usbnet_unlock_core(un);
 }
 
diff --git a/sys/dev/usb/if_kue.c b/sys/dev/usb/if_kue.c
index 7d2a03e14c8c..c02f40a77dcf 100644
--- a/sys/dev/usb/if_kue.c
+++ b/sys/dev/usb/if_kue.c
@@ -643,11 +643,9 @@ kue_uno_mcast(struct ifnet *ifp)
 	struct usbnet * const	un = ifp->if_softc;
 
 	usbnet_lock_core(un);
-	usbnet_busy(un);
 
 	kue_setiff_locked(un);
 
-	usbnet_unbusy(un);
 	usbnet_unlock_core(un);
 }
 
diff --git a/sys/dev/usb/if_mos.c b/sys/dev/usb/if_mos.c
index 03601b9e752b..1c27bcb6f308 100644
--- a/sys/dev/usb/if_mos.c
+++ b/sys/dev/usb/if_mos.c
@@ -773,11 +773,9 @@ mos_uno_mcast(struct ifnet *ifp)
 	struct usbnet * const un = ifp->if_softc;
 
 	usbnet_lock_core(un);
-	usbnet_busy(un);
 
 	mos_rcvfilt_locked(un);
 
-	usbnet_unbusy(un);
 	usbnet_unlock_core(un);
 }
 
diff --git a/sys/dev/usb/if_mue.c b/sys/dev/usb/if_mue.c
index e41fe6b6b091..663ef0f49c2a 100644
--- a/sys/dev/usb/if_mue.c
+++ b/sys/dev/usb/if_mue.c
@@ -1294,11 +1294,9 @@ mue_uno_mcast(struct ifnet *ifp)
 	struct usbnet * const un = ifp->if_softc;
 
 	usbnet_lock_core(un);
-	usbnet_busy(un);
 
 	mue_setiff_locked(un);
 
-	usbnet_unbusy(un);
 	usbnet_unlock_core(un);
 }
 
diff --git a/sys/dev/usb/if_smsc.c b/sys/dev/usb/if_smsc.c
index 718638357b93..4e75cf65a499 100644
--- a/sys/dev/usb/if_smsc.c
+++ b/sys/dev/usb/if_smsc.c
@@ -774,11 +774,9 @@ smsc_uno_mcast(struct ifnet *ifp)
 	struct usbnet * const un = ifp->if_softc;
 
 	usbnet_lock_core(un);
-	usbnet_busy(un);
 
 	smsc_setiff_locked(un);
 
-	usbnet_unbusy(un);
 	usbnet_unlock_core(un);
 }
 
diff --git a/sys/dev/usb/if_udav.c b/sys/dev/usb/if_udav.c
index fe70dfb17012..f0c23cfea3ae 100644
--- a/sys/dev/usb/if_udav.c
+++ b/sys/dev/usb/if_udav.c
@@ -719,11 +719,9 @@ udav_uno_mcast(struct ifnet *ifp)
 	struct usbnet * const un = ifp->if_softc;
 
 	usbnet_lock_core(un);
-	usbnet_busy(un);
 
 	udav_setiff_locked(un);
 
-	usbnet_unbusy(un);
 	usbnet_unlock_core(un);
 }
 
diff --git a/sys/dev/usb/if_ure.c b/sys/dev/usb/if_ure.c
index 669677836f8d..45b18f48438c 100644
--- a/sys/dev/usb/if_ure.c
+++ b/sys/dev/usb/if_ure.c
@@ -804,11 +804,9 @@ ure_uno_mcast(struct ifnet *ifp)
 	struct usbnet * const un = ifp->if_softc;
 
 	usbnet_lock_core(un);
-	usbnet_busy(un);
 
 	ure_rcvfilt_locked(un);
 
-	usbnet_unbusy(un);
 	usbnet_unlock_core(un);
 }
 
diff --git a/sys/dev/usb/if_url.c b/sys/dev/usb/if_url.c
index b0f48c5249c8..cbc125bd08ea 100644
--- a/sys/dev/usb/if_url.c
+++ b/sys/dev/usb/if_url.c
@@ -561,11 +561,9 @@ url_uno_mcast(struct ifnet *ifp)
 	struct usbnet * const un = ifp->if_softc;
 
 	usbnet_lock_core(un);
-	usbnet_busy(un);
 
 	url_rcvfilt_locked(un);
 
-	usbnet_unbusy(un);
 	usbnet_unlock_core(un);
 }
 

From 863c8315e460bc952ad70aaf3929e0f62bbbf4a5 Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Thu, 30 Dec 2021 13:37:56 +0000
Subject: [PATCH 37/48] usbnet drivers: No need for usbnet_busy in uno_ioctl.

This callback always runs with the IFNET_LOCK held, and the interface
cannot be detached until the IFNET_LOCK is released, so there is no
need to hang onto a reference count here.  (None of the subnet
drivers touch the IFNET_LOCK except to verify it is held sometimes.)
---
 sys/dev/usb/if_axen.c | 2 --
 sys/dev/usb/if_mue.c  | 2 --
 sys/dev/usb/if_smsc.c | 2 --
 3 files changed, 6 deletions(-)

diff --git a/sys/dev/usb/if_axen.c b/sys/dev/usb/if_axen.c
index 96f17df1b3cc..44bb96944b7a 100644
--- a/sys/dev/usb/if_axen.c
+++ b/sys/dev/usb/if_axen.c
@@ -558,7 +558,6 @@ axen_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 	struct usbnet * const un = ifp->if_softc;
 
 	usbnet_lock_core(un);
-	usbnet_busy(un);
 
 	switch (cmd) {
 	case SIOCSIFCAP:
@@ -568,7 +567,6 @@ axen_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 		break;
 	}
 
-	usbnet_unbusy(un);
 	usbnet_unlock_core(un);
 
 	return 0;
diff --git a/sys/dev/usb/if_mue.c b/sys/dev/usb/if_mue.c
index 663ef0f49c2a..d6ab282aa2d7 100644
--- a/sys/dev/usb/if_mue.c
+++ b/sys/dev/usb/if_mue.c
@@ -1269,7 +1269,6 @@ mue_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 	struct usbnet * const un = ifp->if_softc;
 
 	usbnet_lock_core(un);
-	usbnet_busy(un);
 
 	switch (cmd) {
 	case SIOCSIFCAP:
@@ -1282,7 +1281,6 @@ mue_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 		break;
 	}
 
-	usbnet_unbusy(un);
 	usbnet_unlock_core(un);
 
 	return 0;
diff --git a/sys/dev/usb/if_smsc.c b/sys/dev/usb/if_smsc.c
index 4e75cf65a499..d61315fed14d 100644
--- a/sys/dev/usb/if_smsc.c
+++ b/sys/dev/usb/if_smsc.c
@@ -752,7 +752,6 @@ smsc_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 	struct usbnet * const un = ifp->if_softc;
 
 	usbnet_lock_core(un);
-	usbnet_busy(un);
 
 	switch (cmd) {
 	case SIOCSIFCAP:
@@ -762,7 +761,6 @@ smsc_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 		break;
 	}
 
-	usbnet_unbusy(un);
 	usbnet_unlock_core(un);
 
 	return 0;

From a1b74b111133dcf9540ae98955a803df07f338d2 Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Thu, 30 Dec 2021 13:39:06 +0000
Subject: [PATCH 38/48] usbnet drivers: No need for usbnet_busy during attach.

usbnet_detach cannot run until the attach routine has finished
(unless a driver goes out of its way to tie its shoelaces together
and explicitly call it during the attach routine, which none of them
do), so there is no need to hang onto a reference count that we
release before attach returns.
---
 sys/dev/usb/if_axe.c  | 4 ----
 sys/dev/usb/if_axen.c | 6 ------
 sys/dev/usb/if_smsc.c | 2 --
 sys/dev/usb/if_udav.c | 2 --
 sys/dev/usb/if_url.c  | 2 --
 5 files changed, 16 deletions(-)

diff --git a/sys/dev/usb/if_axe.c b/sys/dev/usb/if_axe.c
index 5f7663e435e0..5f65f8d53085 100644
--- a/sys/dev/usb/if_axe.c
+++ b/sys/dev/usb/if_axe.c
@@ -930,10 +930,8 @@ axe_attach(device_t parent, device_t self, void *aux)
 
 	/* We need the PHYID for init dance in some cases */
 	usbnet_lock_core(un);
-	usbnet_busy(un);
 	if (axe_cmd(sc, AXE_CMD_READ_PHYID, 0, 0, &sc->axe_phyaddrs)) {
 		aprint_error_dev(self, "failed to read phyaddrs\n");
-		usbnet_unbusy(un);
 		usbnet_unlock_core(un);
 		return;
 	}
@@ -964,13 +962,11 @@ axe_attach(device_t parent, device_t self, void *aux)
 	} else {
 		if (axe_cmd(sc, AXE_CMD_READ_IPG012, 0, 0, sc->axe_ipgs)) {
 			aprint_error_dev(self, "failed to read ipg\n");
-			usbnet_unbusy(un);
 			usbnet_unlock_core(un);
 			return;
 		}
 	}
 
-	usbnet_unbusy(un);
 	usbnet_unlock_core(un);
 
 	if (!AXE_IS_172(un))
diff --git a/sys/dev/usb/if_axen.c b/sys/dev/usb/if_axen.c
index 44bb96944b7a..ae07b34b0daa 100644
--- a/sys/dev/usb/if_axen.c
+++ b/sys/dev/usb/if_axen.c
@@ -368,7 +368,6 @@ axen_ax88179_init(struct usbnet *un)
 	uint8_t val;
 
 	usbnet_lock_core(un);
-	usbnet_busy(un);
 
 	/* XXX: ? */
 	axen_cmd(un, AXEN_CMD_MAC_READ, 1, AXEN_UNK_05, &val);
@@ -452,7 +451,6 @@ axen_ax88179_init(struct usbnet *un)
 	default:
 		aprint_error_dev(un->un_dev, "unknown uplink bus:0x%02x\n",
 		    val);
-		usbnet_unbusy(un);
 		usbnet_unlock_core(un);
 		return;
 	}
@@ -512,7 +510,6 @@ axen_ax88179_init(struct usbnet *un)
 	usbnet_mii_writereg(un->un_dev, un->un_phyno, 0x1F, 0x0000);
 #endif
 
-	usbnet_unbusy(un);
 	usbnet_unlock_core(un);
 }
 
@@ -682,14 +679,11 @@ axen_attach(device_t parent, device_t self, void *aux)
 
 	/* Get station address.  */
 	usbnet_lock_core(un);
-	usbnet_busy(un);
 	if (axen_get_eaddr(un, &un->un_eaddr)) {
-		usbnet_unbusy(un);
 		usbnet_unlock_core(un);
 		printf("EEPROM checksum error\n");
 		return;
 	}
-	usbnet_unbusy(un);
 	usbnet_unlock_core(un);
 
 	axen_ax88179_init(un);
diff --git a/sys/dev/usb/if_smsc.c b/sys/dev/usb/if_smsc.c
index d61315fed14d..a48336f8b972 100644
--- a/sys/dev/usb/if_smsc.c
+++ b/sys/dev/usb/if_smsc.c
@@ -884,7 +884,6 @@ smsc_attach(device_t parent, device_t self, void *aux)
 	un->un_phyno = 1;
 
 	usbnet_lock_core(un);
-	usbnet_busy(un);
 	/*
 	 * Attempt to get the mac address, if an EEPROM is not attached this
 	 * will just return FF:FF:FF:FF:FF:FF, so in such cases we invent a MAC
@@ -912,7 +911,6 @@ smsc_attach(device_t parent, device_t self, void *aux)
 			un->un_eaddr[0] = (uint8_t)((mac_l) & 0xff);
 		}
 	}
-	usbnet_unbusy(un);
 	usbnet_unlock_core(un);
 
 	usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST,
diff --git a/sys/dev/usb/if_udav.c b/sys/dev/usb/if_udav.c
index f0c23cfea3ae..77f9bd353c5e 100644
--- a/sys/dev/usb/if_udav.c
+++ b/sys/dev/usb/if_udav.c
@@ -240,14 +240,12 @@ udav_attach(device_t parent, device_t self, void *aux)
 	usbnet_attach(un, "udavdet");
 
 	usbnet_lock_core(un);
-	usbnet_busy(un);
 
 // 	/* reset the adapter */
 // 	udav_reset(un);
 
 	/* Get Ethernet Address */
 	err = udav_csr_read(un, UDAV_PAR, un->un_eaddr, ETHER_ADDR_LEN);
-	usbnet_unbusy(un);
 	usbnet_unlock_core(un);
 	if (err) {
 		aprint_error_dev(self, "read MAC address failed\n");
diff --git a/sys/dev/usb/if_url.c b/sys/dev/usb/if_url.c
index cbc125bd08ea..82f1772f180f 100644
--- a/sys/dev/usb/if_url.c
+++ b/sys/dev/usb/if_url.c
@@ -244,7 +244,6 @@ url_attach(device_t parent, device_t self, void *aux)
 	usbnet_attach(un, "urldet");
 
 	usbnet_lock_core(un);
-	usbnet_busy(un);
 
 	/* reset the adapter */
 	url_reset(un);
@@ -252,7 +251,6 @@ url_attach(device_t parent, device_t self, void *aux)
 	/* Get Ethernet Address */
 	err = url_mem(un, URL_CMD_READMEM, URL_IDR0, (void *)un->un_eaddr,
 		      ETHER_ADDR_LEN);
-	usbnet_unbusy(un);
 	usbnet_unlock_core(un);
 	if (err) {
 		aprint_error_dev(self, "read MAC address failed\n");

From 544df257c6f8654994ea69847f4ebdd941e11f30 Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Thu, 30 Dec 2021 13:46:11 +0000
Subject: [PATCH 39/48] usbnet: No need for usbnet_busy in usbnet_init_rx_tx or
 usbnet_stop.

These run with IFNET_LOCK held, and the interface cannot be detached
until the IFNET_LOCK is released, so there is no need to hang onto a
reference count here.
---
 sys/dev/usb/usbnet.c | 7 -------
 1 file changed, 7 deletions(-)

diff --git a/sys/dev/usb/usbnet.c b/sys/dev/usb/usbnet.c
index 80911908fa66..64221164a70c 100644
--- a/sys/dev/usb/usbnet.c
+++ b/sys/dev/usb/usbnet.c
@@ -837,8 +837,6 @@ usbnet_init_rx_tx(struct usbnet * const un)
 		return EIO;
 	}
 
-	usbnet_busy(un);
-
 	/* Open RX and TX pipes. */
 	err = usbnet_ep_open_pipes(un);
 	if (err) {
@@ -879,7 +877,6 @@ out:
 		usbnet_tx_list_fini(un);
 		usbnet_ep_close_pipes(un);
 	}
-	usbnet_unbusy(un);
 
 	usbnet_isowned_core(un);
 
@@ -1126,8 +1123,6 @@ usbnet_stop(struct usbnet *un, struct ifnet *ifp, int disable)
 	    "%s", ifp->if_xname);
 	usbnet_isowned_core(un);
 
-	usbnet_busy(un);
-
 	/*
 	 * Prevent new activity (rescheduling ticks, xfers, &c.) and
 	 * clear the watchdog timer.
@@ -1176,8 +1171,6 @@ usbnet_stop(struct usbnet *un, struct ifnet *ifp, int disable)
 	KASSERTMSG(!unp->unp_ifp_attached || IFNET_LOCKED(ifp),
 	    "%s", ifp->if_xname);
 	ifp->if_flags &= ~IFF_RUNNING;
-
-	usbnet_unbusy(un);
 }
 
 static void

From 3d74ac923ce0f91782b2e45d7f29e399ff6eab1a Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Thu, 30 Dec 2021 13:48:26 +0000
Subject: [PATCH 40/48] usbnet: No need for usbnet_busy in mii callbacks.

After mii_detach, these have all completed and no new ones can be
made, and detach doesn't start destroying anything until after
mii_detach has returned, so there is no need to hang onto a reference
count here.
---
 sys/dev/usb/usbnet.c | 8 --------
 1 file changed, 8 deletions(-)

diff --git a/sys/dev/usb/usbnet.c b/sys/dev/usb/usbnet.c
index 64221164a70c..03c33cda6caf 100644
--- a/sys/dev/usb/usbnet.c
+++ b/sys/dev/usb/usbnet.c
@@ -920,10 +920,7 @@ usbnet_mii_readreg(device_t dev, int phy, int reg, uint16_t *val)
 		return EIO;
 	}
 
-	usbnet_busy(un);
 	err = uno_read_reg(un, phy, reg, val);
-	usbnet_unbusy(un);
-
 	if (err) {
 		USBNETHIST_CALLARGS("%jd: read PHY failed: %jd",
 		    un->un_pri->unp_number, err, 0, 0);
@@ -947,10 +944,7 @@ usbnet_mii_writereg(device_t dev, int phy, int reg, uint16_t val)
 		return EIO;
 	}
 
-	usbnet_busy(un);
 	err = uno_write_reg(un, phy, reg, val);
-	usbnet_unbusy(un);
-
 	if (err) {
 		USBNETHIST_CALLARGS("%jd: write PHY failed: %jd",
 		    un->un_pri->unp_number, err, 0, 0);
@@ -969,9 +963,7 @@ usbnet_mii_statchg(struct ifnet *ifp)
 	/* MII layer ensures core_lock is held. */
 	usbnet_isowned_core(un);
 
-	usbnet_busy(un);
 	uno_mii_statchg(un, ifp);
-	usbnet_unbusy(un);
 }
 
 static int

From 552fd2556b2d56a709c03fbcac08c15028e6477d Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Thu, 30 Dec 2021 13:51:35 +0000
Subject: [PATCH 41/48] usbnet: usbnet_busy is no longer referenced; release
 it!

---
 sys/dev/usb/usbnet.c | 38 --------------------------------------
 sys/dev/usb/usbnet.h |  6 ------
 2 files changed, 44 deletions(-)

diff --git a/sys/dev/usb/usbnet.c b/sys/dev/usb/usbnet.c
index 03c33cda6caf..7b5cc90fe0e9 100644
--- a/sys/dev/usb/usbnet.c
+++ b/sys/dev/usb/usbnet.c
@@ -56,7 +56,6 @@ struct usbnet_private {
 	 *   and the MII / media data.
 	 * - unp_rxlock protects the rx path and its data
 	 * - unp_txlock protects the tx path and its data
-	 * - unp_detachcv handles detach vs open references
 	 *
 	 * the lock ordering is:
 	 *	ifnet lock -> unp_core_lock -> unp_rxlock -> unp_txlock
@@ -66,7 +65,6 @@ struct usbnet_private {
 	kmutex_t		unp_core_lock;
 	kmutex_t		unp_rxlock;
 	kmutex_t		unp_txlock;
-	kcondvar_t		unp_detachcv;
 
 	struct usbnet_cdata	unp_cdata;
 
@@ -83,7 +81,6 @@ struct usbnet_private {
 	bool			unp_ifp_attached;
 	bool			unp_link;
 
-	int			unp_refcnt;
 	int			unp_timer;
 	unsigned short		unp_if_flags;
 	unsigned		unp_number;
@@ -883,27 +880,6 @@ out:
 	return error;
 }
 
-void
-usbnet_busy(struct usbnet *un)
-{
-	struct usbnet_private * const unp = un->un_pri;
-
-	usbnet_isowned_core(un);
-
-	unp->unp_refcnt++;
-}
-
-void
-usbnet_unbusy(struct usbnet *un)
-{
-	struct usbnet_private * const unp = un->un_pri;
-
-	usbnet_isowned_core(un);
-
-	if (--unp->unp_refcnt < 0)
-		cv_broadcast(&unp->unp_detachcv);
-}
-
 /* MII management. */
 
 int
@@ -1443,7 +1419,6 @@ usbnet_attach(struct usbnet *un,
 	mutex_init(&unp->unp_txlock, MUTEX_DEFAULT, IPL_SOFTUSB);
 	mutex_init(&unp->unp_rxlock, MUTEX_DEFAULT, IPL_SOFTUSB);
 	mutex_init(&unp->unp_core_lock, MUTEX_DEFAULT, IPL_NONE);
-	cv_init(&unp->unp_detachcv, detname);
 
 	rnd_attach_source(&unp->unp_rndsrc, device_xname(un->un_dev),
 	    RND_TYPE_NET, RND_FLAG_DEFAULT);
@@ -1636,24 +1611,11 @@ usbnet_detach(device_t self, int flags)
 	usb_rem_task_wait(un->un_udev, &unp->unp_mcasttask, USB_TASKQ_DRIVER,
 	    NULL);
 
-	mutex_enter(&unp->unp_core_lock);
-	unp->unp_refcnt--;
-	if (unp->unp_refcnt >= 0) {
-		aprint_error_dev(un->un_dev, "%d stragglers\n",
-		    unp->unp_refcnt + 1);
-	}
-	while (unp->unp_refcnt >= 0) {
-		/* Wait for processes to go away */
-		cv_wait(&unp->unp_detachcv, &unp->unp_core_lock);
-	}
-	mutex_exit(&unp->unp_core_lock);
-
 	usbnet_rx_list_free(un);
 	usbnet_tx_list_free(un);
 
 	rnd_detach_source(&unp->unp_rndsrc);
 
-	cv_destroy(&unp->unp_detachcv);
 	mutex_destroy(&unp->unp_core_lock);
 	mutex_destroy(&unp->unp_rxlock);
 	mutex_destroy(&unp->unp_txlock);
diff --git a/sys/dev/usb/usbnet.h b/sys/dev/usb/usbnet.h
index fc9c578453a5..10597c14d7b5 100644
--- a/sys/dev/usb/usbnet.h
+++ b/sys/dev/usb/usbnet.h
@@ -177,9 +177,6 @@ typedef void (*usbnet_intr_cb)(struct usbnet *, usbd_status);
  * explicitly to uno_override_ioctl; for all other devices, they are
  * handled inside usbnet by scheduling a task to asynchronously call
  * uno_mcast with IFNET_LOCK held.
- *
- * Busy reference counts are maintained across calls to: uno_stop,
- * uno_read_reg, uno_write_reg, uno_statchg, and uno_tick.
  */
 struct usbnet_ops {
 	usbnet_stop_cb		uno_stop;		/* C */
@@ -314,9 +311,6 @@ usbnet_isowned_core(struct usbnet *un)
 	KASSERT(mutex_owned(usbnet_mutex_core(un)));
 }
 
-void	usbnet_busy(struct usbnet *);
-void	usbnet_unbusy(struct usbnet *);
-
 void	usbnet_lock_rx(struct usbnet *);
 void	usbnet_unlock_rx(struct usbnet *);
 kmutex_t *usbnet_mutex_rx(struct usbnet *);

From d7abd436d42ddd268ab8510d4d6198bc7efff65a Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Thu, 30 Dec 2021 14:02:30 +0000
Subject: [PATCH 42/48] usbnet: Make the tx/rx locks private to usbnet.c.

Suffice it for the drivers to know that uno_tx_prepare and
uno_rx_loop have exclusive access to the chain, and, for tx,
exclusive access to the mbuf.
---
 sys/dev/usb/if_axe.c  |  2 --
 sys/dev/usb/if_cdce.c |  2 --
 sys/dev/usb/usbnet.c  | 41 ++++++++++-------------------------------
 sys/dev/usb/usbnet.h  | 18 ------------------
 4 files changed, 10 insertions(+), 53 deletions(-)

diff --git a/sys/dev/usb/if_axe.c b/sys/dev/usb/if_axe.c
index 5f65f8d53085..ea22523cc651 100644
--- a/sys/dev/usb/if_axe.c
+++ b/sys/dev/usb/if_axe.c
@@ -1136,8 +1136,6 @@ axe_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c)
 	size_t hdr_len = 0, tlr_len = 0;
 	int length, boundary;
 
-	usbnet_isowned_tx(un);
-
 	if (!AXE_IS_172(un)) {
 		/*
 		 * Copy the mbuf data into a contiguous buffer, leaving two
diff --git a/sys/dev/usb/if_cdce.c b/sys/dev/usb/if_cdce.c
index 4785d9a4cc9e..c7ee6bef2792 100644
--- a/sys/dev/usb/if_cdce.c
+++ b/sys/dev/usb/if_cdce.c
@@ -277,8 +277,6 @@ cdce_uno_rx_loop(struct usbnet * un, struct usbnet_chain *c, uint32_t total_len)
 {
 	struct ifnet		*ifp = usbnet_ifp(un);
 
-	usbnet_isowned_rx(un);
-
 	/* Strip off CRC added by Zaurus, if present */
 	if (un->un_flags & CDCE_ZAURUS && total_len > 4)
 		total_len -= 4;
diff --git a/sys/dev/usb/usbnet.c b/sys/dev/usb/usbnet.c
index 7b5cc90fe0e9..f780e98cee9f 100644
--- a/sys/dev/usb/usbnet.c
+++ b/sys/dev/usb/usbnet.c
@@ -96,6 +96,9 @@ struct usbnet_private {
 
 volatile unsigned usbnet_number;
 
+static void usbnet_isowned_rx(struct usbnet *);
+static void usbnet_isowned_tx(struct usbnet *);
+
 static int usbnet_modcmd(modcmd_t, void *);
 
 #ifdef USB_DEBUG
@@ -1323,46 +1326,22 @@ usbnet_unlock_core(struct usbnet *un)
 	mutex_exit(&un->un_pri->unp_core_lock);
 }
 
-kmutex_t *
+kmutex_t*
 usbnet_mutex_core(struct usbnet *un)
 {
 	return &un->un_pri->unp_core_lock;
 }
 
-void
-usbnet_lock_rx(struct usbnet *un)
-{
-	mutex_enter(&un->un_pri->unp_rxlock);
-}
-
-void
-usbnet_unlock_rx(struct usbnet *un)
-{
-	mutex_exit(&un->un_pri->unp_rxlock);
-}
-
-kmutex_t *
-usbnet_mutex_rx(struct usbnet *un)
-{
-	return &un->un_pri->unp_rxlock;
-}
-
-void
-usbnet_lock_tx(struct usbnet *un)
-{
-	mutex_enter(&un->un_pri->unp_txlock);
-}
-
-void
-usbnet_unlock_tx(struct usbnet *un)
+static void
+usbnet_isowned_rx(struct usbnet *un)
 {
-	mutex_exit(&un->un_pri->unp_txlock);
+	KASSERT(mutex_owned(&un->un_pri->unp_rxlock));
 }
 
-kmutex_t *
-usbnet_mutex_tx(struct usbnet *un)
+static void
+usbnet_isowned_tx(struct usbnet *un)
 {
-	return &un->un_pri->unp_txlock;
+	KASSERT(mutex_owned(&un->un_pri->unp_txlock));
 }
 
 /* Autoconf management. */
diff --git a/sys/dev/usb/usbnet.h b/sys/dev/usb/usbnet.h
index 10597c14d7b5..9ce537d7b849 100644
--- a/sys/dev/usb/usbnet.h
+++ b/sys/dev/usb/usbnet.h
@@ -311,24 +311,6 @@ usbnet_isowned_core(struct usbnet *un)
 	KASSERT(mutex_owned(usbnet_mutex_core(un)));
 }
 
-void	usbnet_lock_rx(struct usbnet *);
-void	usbnet_unlock_rx(struct usbnet *);
-kmutex_t *usbnet_mutex_rx(struct usbnet *);
-static __inline__ void
-usbnet_isowned_rx(struct usbnet *un)
-{
-	KASSERT(mutex_owned(usbnet_mutex_rx(un)));
-}
-
-void	usbnet_lock_tx(struct usbnet *);
-void	usbnet_unlock_tx(struct usbnet *);
-kmutex_t *usbnet_mutex_tx(struct usbnet *);
-static __inline__ void
-usbnet_isowned_tx(struct usbnet *un)
-{
-	KASSERT(mutex_owned(usbnet_mutex_tx(un)));
-}
-
 /*
  * Endpoint / rx/tx chain management:
  *

From 0e499b1683a77a88fa45d1f38a96f96e6b717207 Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Thu, 30 Dec 2021 14:09:23 +0000
Subject: [PATCH 43/48] usbnet: No need for the core lock in usbnet_ifflags_cb.

The only state this touches is unp_if_flags, and all paths touching
it also hold IFNET_LOCK -- not to mention this is the only path that
touches unp_if_flags in the first place!
---
 sys/dev/usb/usbnet.c | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/sys/dev/usb/usbnet.c b/sys/dev/usb/usbnet.c
index f780e98cee9f..abe51ceee46d 100644
--- a/sys/dev/usb/usbnet.c
+++ b/sys/dev/usb/usbnet.c
@@ -987,8 +987,6 @@ usbnet_ifflags_cb(struct ethercom *ec)
 
 	KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname);
 
-	mutex_enter(&unp->unp_core_lock);
-
 	const u_short changed = ifp->if_flags ^ unp->unp_if_flags;
 	if ((changed & ~(IFF_CANTCHANGE | IFF_DEBUG)) == 0) {
 		unp->unp_if_flags = ifp->if_flags;
@@ -998,8 +996,6 @@ usbnet_ifflags_cb(struct ethercom *ec)
 		rv = ENETRESET;
 	}
 
-	mutex_exit(&unp->unp_core_lock);
-
 	return rv;
 }
 

From 33aa87057bffc69f7cdfa255f902a93ed17374f6 Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Thu, 30 Dec 2021 14:26:56 +0000
Subject: [PATCH 44/48] usbnet drivers: Omit needless uno_init locked
 subroutines.

uno_init is now called with the core lock already held so there is no
need for a separate locked subroutine.
---
 sys/dev/usb/if_aue.c  | 12 +-----------
 sys/dev/usb/if_axe.c  | 10 +---------
 sys/dev/usb/if_axen.c | 10 +---------
 sys/dev/usb/if_cue.c  | 12 +-----------
 sys/dev/usb/if_kue.c  | 12 +-----------
 sys/dev/usb/if_mos.c  | 10 +---------
 sys/dev/usb/if_mue.c  | 12 +-----------
 sys/dev/usb/if_smsc.c |  9 ---------
 sys/dev/usb/if_ure.c  | 10 +---------
 9 files changed, 8 insertions(+), 89 deletions(-)

diff --git a/sys/dev/usb/if_aue.c b/sys/dev/usb/if_aue.c
index 058c8ae923be..9cc622a1368c 100644
--- a/sys/dev/usb/if_aue.c
+++ b/sys/dev/usb/if_aue.c
@@ -954,7 +954,7 @@ aue_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c)
 }
 
 static int
-aue_init_locked(struct ifnet *ifp)
+aue_uno_init(struct ifnet *ifp)
 {
 	struct usbnet * const	un = ifp->if_softc;
 	struct aue_softc	*sc = usbnet_softc(un);
@@ -1000,16 +1000,6 @@ aue_init_locked(struct ifnet *ifp)
 	return rv;
 }
 
-static int
-aue_uno_init(struct ifnet *ifp)
-{
-	int rv;
-
-	rv = aue_init_locked(ifp);
-
-	return rv;
-}
-
 static void
 aue_uno_mcast(struct ifnet *ifp)
 {
diff --git a/sys/dev/usb/if_axe.c b/sys/dev/usb/if_axe.c
index ea22523cc651..1286dcf944fb 100644
--- a/sys/dev/usb/if_axe.c
+++ b/sys/dev/usb/if_axe.c
@@ -1210,7 +1210,7 @@ axe_csum_cfg(struct axe_softc *sc)
 }
 
 static int
-axe_init_locked(struct ifnet *ifp)
+axe_uno_init(struct ifnet *ifp)
 {
 	AXEHIST_FUNC(); AXEHIST_CALLED();
 	struct usbnet * const un = ifp->if_softc;
@@ -1306,14 +1306,6 @@ axe_init_locked(struct ifnet *ifp)
 	return usbnet_init_rx_tx(un);
 }
 
-static int
-axe_uno_init(struct ifnet *ifp)
-{
-	int ret = axe_init_locked(ifp);
-
-	return ret;
-}
-
 static void
 axe_uno_mcast(struct ifnet *ifp)
 {
diff --git a/sys/dev/usb/if_axen.c b/sys/dev/usb/if_axen.c
index ae07b34b0daa..6db947dd38e2 100644
--- a/sys/dev/usb/if_axen.c
+++ b/sys/dev/usb/if_axen.c
@@ -894,7 +894,7 @@ axen_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c)
 }
 
 static int
-axen_init_locked(struct ifnet *ifp)
+axen_uno_init(struct ifnet *ifp)
 {
 	struct usbnet * const un = ifp->if_softc;
 	uint16_t rxmode;
@@ -932,14 +932,6 @@ axen_init_locked(struct ifnet *ifp)
 	return usbnet_init_rx_tx(un);
 }
 
-static int
-axen_uno_init(struct ifnet *ifp)
-{
-	int ret = axen_init_locked(ifp);
-
-	return ret;
-}
-
 static void
 axen_uno_stop(struct ifnet *ifp, int disable)
 {
diff --git a/sys/dev/usb/if_cue.c b/sys/dev/usb/if_cue.c
index 646cef9178b5..6fc62f924e10 100644
--- a/sys/dev/usb/if_cue.c
+++ b/sys/dev/usb/if_cue.c
@@ -613,7 +613,7 @@ cue_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c)
 }
 
 static int
-cue_init_locked(struct ifnet *ifp)
+cue_uno_init(struct ifnet *ifp)
 {
 	struct usbnet * const	un = ifp->if_softc;
 	int			i, ctl;
@@ -667,16 +667,6 @@ cue_init_locked(struct ifnet *ifp)
 	return usbnet_init_rx_tx(un);
 }
 
-static int
-cue_uno_init(struct ifnet *ifp)
-{
-	int rv;
-
-	rv = cue_init_locked(ifp);
-
-	return rv;
-}
-
 static void
 cue_uno_mcast(struct ifnet *ifp)
 {
diff --git a/sys/dev/usb/if_kue.c b/sys/dev/usb/if_kue.c
index c02f40a77dcf..265c981f4d41 100644
--- a/sys/dev/usb/if_kue.c
+++ b/sys/dev/usb/if_kue.c
@@ -591,7 +591,7 @@ kue_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c)
 }
 
 static int
-kue_init_locked(struct ifnet *ifp)
+kue_uno_init(struct ifnet *ifp)
 {
 	struct usbnet * const	un = ifp->if_softc;
 	struct kue_softc	*sc = usbnet_softc(un);
@@ -627,16 +627,6 @@ kue_init_locked(struct ifnet *ifp)
 	return usbnet_init_rx_tx(un);
 }
 
-static int
-kue_uno_init(struct ifnet *ifp)
-{
-	int rv;
-
-	rv = kue_init_locked(ifp);
-
-	return rv;
-}
-
 static void
 kue_uno_mcast(struct ifnet *ifp)
 {
diff --git a/sys/dev/usb/if_mos.c b/sys/dev/usb/if_mos.c
index 1c27bcb6f308..2e0799a15ebd 100644
--- a/sys/dev/usb/if_mos.c
+++ b/sys/dev/usb/if_mos.c
@@ -723,7 +723,7 @@ mos_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c)
 }
 
 static int
-mos_init_locked(struct ifnet *ifp)
+mos_uno_init(struct ifnet *ifp)
 {
 	struct usbnet * const un = ifp->if_softc;
 	u_int8_t		rxmode;
@@ -759,14 +759,6 @@ mos_init_locked(struct ifnet *ifp)
 	return usbnet_init_rx_tx(un);
 }
 
-static int
-mos_uno_init(struct ifnet *ifp)
-{
-	int ret = mos_init_locked(ifp);
-
-	return ret;
-}
-
 static void
 mos_uno_mcast(struct ifnet *ifp)
 {
diff --git a/sys/dev/usb/if_mue.c b/sys/dev/usb/if_mue.c
index d6ab282aa2d7..3f360bded2f6 100644
--- a/sys/dev/usb/if_mue.c
+++ b/sys/dev/usb/if_mue.c
@@ -1223,7 +1223,7 @@ mue_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len)
 }
 
 static int
-mue_init_locked(struct ifnet *ifp)
+mue_uno_init(struct ifnet *ifp)
 {
 	struct usbnet * const un = ifp->if_softc;
 
@@ -1253,16 +1253,6 @@ mue_init_locked(struct ifnet *ifp)
 	return usbnet_init_rx_tx(un);
 }
 
-static int
-mue_uno_init(struct ifnet *ifp)
-{
-	int rv;
-
-	rv = mue_init_locked(ifp);
-
-	return rv;
-}
-
 static int
 mue_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 {
diff --git a/sys/dev/usb/if_smsc.c b/sys/dev/usb/if_smsc.c
index a48336f8b972..7fac2e4a2497 100644
--- a/sys/dev/usb/if_smsc.c
+++ b/sys/dev/usb/if_smsc.c
@@ -174,7 +174,6 @@ static int	 smsc_chip_init(struct usbnet *);
 static int	 smsc_setmacaddress(struct usbnet *, const uint8_t *);
 
 static int	 smsc_uno_init(struct ifnet *);
-static int	 smsc_init_locked(struct ifnet *);
 static void	 smsc_uno_stop(struct ifnet *, int);
 
 static void	 smsc_reset(struct smsc_softc *);
@@ -553,14 +552,6 @@ smsc_reset(struct smsc_softc *sc)
 
 static int
 smsc_uno_init(struct ifnet *ifp)
-{
-	int ret = smsc_init_locked(ifp);
-
-	return ret;
-}
-
-static int
-smsc_init_locked(struct ifnet *ifp)
 {
 	struct usbnet * const un = ifp->if_softc;
 	struct smsc_softc * const sc = usbnet_softc(un);
diff --git a/sys/dev/usb/if_ure.c b/sys/dev/usb/if_ure.c
index 45b18f48438c..7a49d558a6c7 100644
--- a/sys/dev/usb/if_ure.c
+++ b/sys/dev/usb/if_ure.c
@@ -408,7 +408,7 @@ ure_reset(struct usbnet *un)
 }
 
 static int
-ure_init_locked(struct ifnet *ifp)
+ure_uno_init(struct ifnet *ifp)
 {
 	struct usbnet * const un = ifp->if_softc;
 	uint8_t eaddr[8];
@@ -453,14 +453,6 @@ ure_init_locked(struct ifnet *ifp)
 	return usbnet_init_rx_tx(un);
 }
 
-static int
-ure_uno_init(struct ifnet *ifp)
-{
-	int ret = ure_init_locked(ifp);
-
-	return ret;
-}
-
 static void
 ure_uno_stop(struct ifnet *ifp, int disable __unused)
 {

From 19ab0ec4db6c9df74bd611a4cc0380f0c2124762 Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Thu, 30 Dec 2021 23:17:18 +0000
Subject: [PATCH 45/48] usbnet: Take the core lock around uno_mcast.

Every driver does this already.  This will enable us to change the
lock that serializes access to the registers so we can go back to
doing this synchronously in SIOCADDMULTI/SIOCDELMULTI.
---
 sys/dev/usb/if_aue.c  | 3 ---
 sys/dev/usb/if_axe.c  | 4 ----
 sys/dev/usb/if_axen.c | 4 ----
 sys/dev/usb/if_cue.c  | 4 ----
 sys/dev/usb/if_kue.c  | 4 ----
 sys/dev/usb/if_mos.c  | 4 ----
 sys/dev/usb/if_mue.c  | 4 ----
 sys/dev/usb/if_smsc.c | 4 ----
 sys/dev/usb/if_udav.c | 4 ----
 sys/dev/usb/if_ure.c  | 4 ----
 sys/dev/usb/if_url.c  | 4 ----
 sys/dev/usb/usbnet.c  | 5 ++++-
 12 files changed, 4 insertions(+), 44 deletions(-)

diff --git a/sys/dev/usb/if_aue.c b/sys/dev/usb/if_aue.c
index 9cc622a1368c..6fa49edb4962 100644
--- a/sys/dev/usb/if_aue.c
+++ b/sys/dev/usb/if_aue.c
@@ -1003,7 +1003,6 @@ aue_uno_init(struct ifnet *ifp)
 static void
 aue_uno_mcast(struct ifnet *ifp)
 {
-	struct usbnet * const un = ifp->if_softc;
 
 	AUEHIST_FUNC();
 	AUEHIST_CALLARGSN(5, "aue%jd: enter",
@@ -1014,9 +1013,7 @@ aue_uno_mcast(struct ifnet *ifp)
 	 * XXX I feel like this is pretty heavy-handed!  Maybe we could
 	 * make do with aue_setiff_locked instead?
 	 */
-	usbnet_lock_core(un);
 	aue_uno_init(ifp);
-	usbnet_unlock_core(un);
 }
 
 static void
diff --git a/sys/dev/usb/if_axe.c b/sys/dev/usb/if_axe.c
index 1286dcf944fb..224eac042771 100644
--- a/sys/dev/usb/if_axe.c
+++ b/sys/dev/usb/if_axe.c
@@ -1311,11 +1311,7 @@ axe_uno_mcast(struct ifnet *ifp)
 {
 	struct usbnet * const un = ifp->if_softc;
 
-	usbnet_lock_core(un);
-
 	axe_rcvfilt_locked(un);
-
-	usbnet_unlock_core(un);
 }
 
 static void
diff --git a/sys/dev/usb/if_axen.c b/sys/dev/usb/if_axen.c
index 6db947dd38e2..0e3334022a4e 100644
--- a/sys/dev/usb/if_axen.c
+++ b/sys/dev/usb/if_axen.c
@@ -574,11 +574,7 @@ axen_uno_mcast(struct ifnet *ifp)
 {
 	struct usbnet * const un = ifp->if_softc;
 
-	usbnet_lock_core(un);
-
 	axen_setiff_locked(un);
-
-	usbnet_unlock_core(un);
 }
 
 static int
diff --git a/sys/dev/usb/if_cue.c b/sys/dev/usb/if_cue.c
index 6fc62f924e10..828ea1085584 100644
--- a/sys/dev/usb/if_cue.c
+++ b/sys/dev/usb/if_cue.c
@@ -672,11 +672,7 @@ cue_uno_mcast(struct ifnet *ifp)
 {
 	struct usbnet * const	un = ifp->if_softc;
 
-	usbnet_lock_core(un);
-
 	cue_setiff_locked(un);
-
-	usbnet_unlock_core(un);
 }
 
 /* Stop and reset the adapter.  */
diff --git a/sys/dev/usb/if_kue.c b/sys/dev/usb/if_kue.c
index 265c981f4d41..048a718095a3 100644
--- a/sys/dev/usb/if_kue.c
+++ b/sys/dev/usb/if_kue.c
@@ -632,11 +632,7 @@ kue_uno_mcast(struct ifnet *ifp)
 {
 	struct usbnet * const	un = ifp->if_softc;
 
-	usbnet_lock_core(un);
-
 	kue_setiff_locked(un);
-
-	usbnet_unlock_core(un);
 }
 
 #ifdef _MODULE
diff --git a/sys/dev/usb/if_mos.c b/sys/dev/usb/if_mos.c
index 2e0799a15ebd..df70e79b535a 100644
--- a/sys/dev/usb/if_mos.c
+++ b/sys/dev/usb/if_mos.c
@@ -764,11 +764,7 @@ mos_uno_mcast(struct ifnet *ifp)
 {
 	struct usbnet * const un = ifp->if_softc;
 
-	usbnet_lock_core(un);
-
 	mos_rcvfilt_locked(un);
-
-	usbnet_unlock_core(un);
 }
 
 void
diff --git a/sys/dev/usb/if_mue.c b/sys/dev/usb/if_mue.c
index 3f360bded2f6..201a4dc3f856 100644
--- a/sys/dev/usb/if_mue.c
+++ b/sys/dev/usb/if_mue.c
@@ -1281,11 +1281,7 @@ mue_uno_mcast(struct ifnet *ifp)
 {
 	struct usbnet * const un = ifp->if_softc;
 
-	usbnet_lock_core(un);
-
 	mue_setiff_locked(un);
-
-	usbnet_unlock_core(un);
 }
 
 static void
diff --git a/sys/dev/usb/if_smsc.c b/sys/dev/usb/if_smsc.c
index 7fac2e4a2497..429c2b939899 100644
--- a/sys/dev/usb/if_smsc.c
+++ b/sys/dev/usb/if_smsc.c
@@ -762,11 +762,7 @@ smsc_uno_mcast(struct ifnet *ifp)
 {
 	struct usbnet * const un = ifp->if_softc;
 
-	usbnet_lock_core(un);
-
 	smsc_setiff_locked(un);
-
-	usbnet_unlock_core(un);
 }
 
 static int
diff --git a/sys/dev/usb/if_udav.c b/sys/dev/usb/if_udav.c
index 77f9bd353c5e..3528653f3794 100644
--- a/sys/dev/usb/if_udav.c
+++ b/sys/dev/usb/if_udav.c
@@ -716,11 +716,7 @@ udav_uno_mcast(struct ifnet *ifp)
 {
 	struct usbnet * const un = ifp->if_softc;
 
-	usbnet_lock_core(un);
-
 	udav_setiff_locked(un);
-
-	usbnet_unlock_core(un);
 }
 
 /* Stop the adapter and free any mbufs allocated to the RX and TX lists. */
diff --git a/sys/dev/usb/if_ure.c b/sys/dev/usb/if_ure.c
index 7a49d558a6c7..37e3611f9c87 100644
--- a/sys/dev/usb/if_ure.c
+++ b/sys/dev/usb/if_ure.c
@@ -795,11 +795,7 @@ ure_uno_mcast(struct ifnet *ifp)
 {
 	struct usbnet * const un = ifp->if_softc;
 
-	usbnet_lock_core(un);
-
 	ure_rcvfilt_locked(un);
-
-	usbnet_unlock_core(un);
 }
 
 static int
diff --git a/sys/dev/usb/if_url.c b/sys/dev/usb/if_url.c
index 82f1772f180f..6d93d756bfd0 100644
--- a/sys/dev/usb/if_url.c
+++ b/sys/dev/usb/if_url.c
@@ -558,11 +558,7 @@ url_uno_mcast(struct ifnet *ifp)
 {
 	struct usbnet * const un = ifp->if_softc;
 
-	usbnet_lock_core(un);
-
 	url_rcvfilt_locked(un);
-
-	usbnet_unlock_core(un);
 }
 
 /* Stop the adapter and free any mbufs allocated to the RX and TX lists. */
diff --git a/sys/dev/usb/usbnet.c b/sys/dev/usb/usbnet.c
index abe51ceee46d..31562ec087a7 100644
--- a/sys/dev/usb/usbnet.c
+++ b/sys/dev/usb/usbnet.c
@@ -1060,8 +1060,11 @@ usbnet_mcast_task(void *arg)
 	 */
 	IFNET_LOCK(ifp);
 	if (ifp->if_flags & IFF_RUNNING) {
-		if (un->un_ops->uno_mcast)
+		if (un->un_ops->uno_mcast) {
+			mutex_enter(&un->un_pri->unp_core_lock);
 			(*un->un_ops->uno_mcast)(ifp);
+			mutex_exit(&un->un_pri->unp_core_lock);
+		}
 	}
 	IFNET_UNLOCK(ifp);
 }

From c906e6afe33e179fed197f405e16ae721597a649 Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Thu, 30 Dec 2021 23:36:08 +0000
Subject: [PATCH 46/48] aue(4): Reduce aue_uno_mcast from aue_uno_init to
 aue_setiff_locked.

This operation only needs to update the hardware to reflect
SIOCADDMULTI/SIOCDELMULTI.  Not clear that everything in aue(4) needs
to be reset -- in fact I'm pretty sure that's undesirable!

WARNING: I have not tested this with a real aue(4) device.
---
 sys/dev/usb/if_aue.c | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/sys/dev/usb/if_aue.c b/sys/dev/usb/if_aue.c
index 6fa49edb4962..9292d1e73e0c 100644
--- a/sys/dev/usb/if_aue.c
+++ b/sys/dev/usb/if_aue.c
@@ -1009,11 +1009,7 @@ aue_uno_mcast(struct ifnet *ifp)
 	    device_unit(((struct usbnet *)(ifp->if_softc))->un_dev),
 	    0, 0, 0);
 
-	/*
-	 * XXX I feel like this is pretty heavy-handed!  Maybe we could
-	 * make do with aue_setiff_locked instead?
-	 */
-	aue_uno_init(ifp);
+	aue_setiff_locked(ifp);
 }
 
 static void

From 47a4848bdd1ca01bbdd1aa0e0715a75baf639027 Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Thu, 30 Dec 2021 23:42:29 +0000
Subject: [PATCH 47/48] usbnet drivers: Omit needless uno_mcast locked
 subroutines.

uno_mcast is now called with the core lock already held so there is
no need for a separate locked subroutine.
---
 sys/dev/usb/if_aue.c  | 18 +++---------------
 sys/dev/usb/if_axe.c  | 14 +++-----------
 sys/dev/usb/if_axen.c | 14 +++-----------
 sys/dev/usb/if_cue.c  | 14 +++-----------
 sys/dev/usb/if_kue.c  | 14 +++-----------
 sys/dev/usb/if_mos.c  | 14 +++-----------
 sys/dev/usb/if_mue.c  | 17 ++++-------------
 sys/dev/usb/if_smsc.c | 14 +++-----------
 sys/dev/usb/if_udav.c | 15 +++------------
 sys/dev/usb/if_ure.c  | 14 +++-----------
 sys/dev/usb/if_url.c  | 17 ++++-------------
 11 files changed, 35 insertions(+), 130 deletions(-)

diff --git a/sys/dev/usb/if_aue.c b/sys/dev/usb/if_aue.c
index 9292d1e73e0c..7d1994cfb451 100644
--- a/sys/dev/usb/if_aue.c
+++ b/sys/dev/usb/if_aue.c
@@ -611,10 +611,10 @@ aue_crc(void *addrv)
 }
 
 static void
-aue_setiff_locked(struct usbnet *un)
+aue_uno_mcast(struct ifnet *ifp)
 {
+	struct usbnet * const un = ifp->if_softc;
 	struct aue_softc * const sc = usbnet_softc(un);
-	struct ifnet * const	ifp = usbnet_ifp(un);
 	struct ethercom *	ec = usbnet_ec(un);
 	struct ether_multi	*enm;
 	struct ether_multistep	step;
@@ -988,7 +988,7 @@ aue_uno_init(struct ifnet *ifp)
 	rv = usbnet_init_rx_tx(un);
 
 	/* Load the multicast filter. */
-	aue_setiff_locked(un);
+	aue_uno_mcast(ifp);
 
 	/* Enable RX and TX */
 	aue_csr_write_1(sc, AUE_CTL0, AUE_CTL0_RXSTAT_APPEND | AUE_CTL0_RX_ENB);
@@ -1000,18 +1000,6 @@ aue_uno_init(struct ifnet *ifp)
 	return rv;
 }
 
-static void
-aue_uno_mcast(struct ifnet *ifp)
-{
-
-	AUEHIST_FUNC();
-	AUEHIST_CALLARGSN(5, "aue%jd: enter",
-	    device_unit(((struct usbnet *)(ifp->if_softc))->un_dev),
-	    0, 0, 0);
-
-	aue_setiff_locked(ifp);
-}
-
 static void
 aue_uno_stop(struct ifnet *ifp, int disable)
 {
diff --git a/sys/dev/usb/if_axe.c b/sys/dev/usb/if_axe.c
index 224eac042771..cb42c4ce17a3 100644
--- a/sys/dev/usb/if_axe.c
+++ b/sys/dev/usb/if_axe.c
@@ -426,11 +426,11 @@ axe_uno_mii_statchg(struct ifnet *ifp)
 }
 
 static void
-axe_rcvfilt_locked(struct usbnet *un)
+axe_uno_mcast(struct ifnet *ifp)
 {
 	AXEHIST_FUNC(); AXEHIST_CALLED();
+	struct usbnet * const un = ifp->if_softc;
 	struct axe_softc * const sc = usbnet_softc(un);
-	struct ifnet * const ifp = usbnet_ifp(un);
 	struct ethercom *ec = usbnet_ec(un);
 	struct ether_multi *enm;
 	struct ether_multistep step;
@@ -1301,19 +1301,11 @@ axe_uno_init(struct ifnet *ifp)
 	axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, rxmode, NULL);
 
 	/* Accept multicast frame or run promisc. mode */
-	axe_rcvfilt_locked(un);
+	axe_uno_mcast(ifp);
 
 	return usbnet_init_rx_tx(un);
 }
 
-static void
-axe_uno_mcast(struct ifnet *ifp)
-{
-	struct usbnet * const un = ifp->if_softc;
-
-	axe_rcvfilt_locked(un);
-}
-
 static void
 axe_uno_stop(struct ifnet *ifp, int disable)
 {
diff --git a/sys/dev/usb/if_axen.c b/sys/dev/usb/if_axen.c
index 0e3334022a4e..55ffb9335e3b 100644
--- a/sys/dev/usb/if_axen.c
+++ b/sys/dev/usb/if_axen.c
@@ -225,9 +225,9 @@ axen_uno_mii_statchg(struct ifnet *ifp)
 }
 
 static void
-axen_setiff_locked(struct usbnet *un)
+axen_uno_mcast(struct ifnet *ifp)
 {
-	struct ifnet * const ifp = usbnet_ifp(un);
+	struct usbnet * const un = ifp->if_softc;
 	struct ethercom *ec = usbnet_ec(un);
 	struct ether_multi *enm;
 	struct ether_multistep step;
@@ -569,14 +569,6 @@ axen_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 	return 0;
 }
 
-static void
-axen_uno_mcast(struct ifnet *ifp)
-{
-	struct usbnet * const un = ifp->if_softc;
-
-	axen_setiff_locked(un);
-}
-
 static int
 axen_match(device_t parent, cfdata_t match, void *aux)
 {
@@ -916,7 +908,7 @@ axen_uno_init(struct ifnet *ifp)
 	axen_setoe_locked(un);
 
 	/* Program promiscuous mode and multicast filters. */
-	axen_setiff_locked(un);
+	axen_uno_mcast(ifp);
 
 	/* Enable receiver, set RX mode */
 	axen_cmd(un, AXEN_CMD_MAC_READ2, 2, AXEN_MAC_RXCTL, &wval);
diff --git a/sys/dev/usb/if_cue.c b/sys/dev/usb/if_cue.c
index 828ea1085584..cf85b72d3d57 100644
--- a/sys/dev/usb/if_cue.c
+++ b/sys/dev/usb/if_cue.c
@@ -357,11 +357,11 @@ cue_crc(const char *addr)
 }
 
 static void
-cue_setiff_locked(struct usbnet *un)
+cue_uno_mcast(struct ifnet *ifp)
 {
+	struct usbnet		*un = ifp->if_softc;
 	struct cue_softc	*sc = usbnet_softc(un);
 	struct ethercom		*ec = usbnet_ec(un);
-	struct ifnet		*ifp = usbnet_ifp(un);
 	struct ether_multi	*enm;
 	struct ether_multistep	step;
 	uint32_t		h, i;
@@ -648,7 +648,7 @@ cue_uno_init(struct ifnet *ifp)
 	cue_csr_write_1(un, CUE_ETHCTL, ctl);
 
 	/* Load the multicast filter. */
-	cue_setiff_locked(un);
+	cue_uno_mcast(ifp);
 
 	/*
 	 * Set the number of RX and TX buffers that we want
@@ -667,14 +667,6 @@ cue_uno_init(struct ifnet *ifp)
 	return usbnet_init_rx_tx(un);
 }
 
-static void
-cue_uno_mcast(struct ifnet *ifp)
-{
-	struct usbnet * const	un = ifp->if_softc;
-
-	cue_setiff_locked(un);
-}
-
 /* Stop and reset the adapter.  */
 static void
 cue_uno_stop(struct ifnet *ifp, int disable)
diff --git a/sys/dev/usb/if_kue.c b/sys/dev/usb/if_kue.c
index 048a718095a3..be075ed5e65f 100644
--- a/sys/dev/usb/if_kue.c
+++ b/sys/dev/usb/if_kue.c
@@ -318,11 +318,11 @@ kue_load_fw(struct usbnet *un)
 }
 
 static void
-kue_setiff_locked(struct usbnet *un)
+kue_uno_mcast(struct ifnet *ifp)
 {
+	struct usbnet *		un = ifp->if_softc;
 	struct ethercom *	ec = usbnet_ec(un);
 	struct kue_softc *	sc = usbnet_softc(un);
-	struct ifnet * const	ifp = usbnet_ifp(un);
 	struct ether_multi	*enm;
 	struct ether_multistep	step;
 	int			i;
@@ -622,19 +622,11 @@ kue_uno_init(struct ifnet *ifp)
 	kue_setword(un, KUE_CMD_SET_URB_SIZE, 64);
 
 	/* Load the multicast filter. */
-	kue_setiff_locked(un);
+	kue_uno_mcast(ifp);
 
 	return usbnet_init_rx_tx(un);
 }
 
-static void
-kue_uno_mcast(struct ifnet *ifp)
-{
-	struct usbnet * const	un = ifp->if_softc;
-
-	kue_setiff_locked(un);
-}
-
 #ifdef _MODULE
 #include "ioconf.c"
 #endif
diff --git a/sys/dev/usb/if_mos.c b/sys/dev/usb/if_mos.c
index df70e79b535a..afe02a06ed22 100644
--- a/sys/dev/usb/if_mos.c
+++ b/sys/dev/usb/if_mos.c
@@ -458,9 +458,9 @@ mos_uno_mii_statchg(struct ifnet *ifp)
 }
 
 static void
-mos_rcvfilt_locked(struct usbnet *un)
+mos_uno_mcast(struct ifnet *ifp)
 {
-	struct ifnet		*ifp = usbnet_ifp(un);
+	struct usbnet		*un = ifp->if_softc;
 	struct ethercom		*ec = usbnet_ec(un);
 	struct ether_multi	*enm;
 	struct ether_multistep	step;
@@ -748,7 +748,7 @@ mos_uno_init(struct ifnet *ifp)
 	mos_reg_write_1(un, MOS_IPG1, ipgs[1]);
 
 	/* Accept multicast frame or run promisc. mode */
-	mos_rcvfilt_locked(un);
+	mos_uno_mcast(ifp);
 
 	/* Enable receiver and transmitter, bridge controls speed/duplex mode */
 	rxmode = mos_reg_read_1(un, MOS_CTL);
@@ -759,14 +759,6 @@ mos_uno_init(struct ifnet *ifp)
 	return usbnet_init_rx_tx(un);
 }
 
-static void
-mos_uno_mcast(struct ifnet *ifp)
-{
-	struct usbnet * const un = ifp->if_softc;
-
-	mos_rcvfilt_locked(un);
-}
-
 void
 mos_uno_stop(struct ifnet *ifp, int disable)
 {
diff --git a/sys/dev/usb/if_mue.c b/sys/dev/usb/if_mue.c
index 201a4dc3f856..0f5c29421afc 100644
--- a/sys/dev/usb/if_mue.c
+++ b/sys/dev/usb/if_mue.c
@@ -92,14 +92,13 @@ static int	mue_chip_init(struct usbnet *);
 static void	mue_set_macaddr(struct usbnet *);
 static int	mue_get_macaddr(struct usbnet *, prop_dictionary_t);
 static int	mue_prepare_tso(struct usbnet *, struct mbuf *);
-static void	mue_setiff_locked(struct usbnet *);
+static void	mue_uno_mcast(struct ifnet *);
 static void	mue_sethwcsum_locked(struct usbnet *);
 static void	mue_setmtu_locked(struct usbnet *);
 static void	mue_reset(struct usbnet *);
 
 static void	mue_uno_stop(struct ifnet *, int);
 static int	mue_uno_ioctl(struct ifnet *, u_long, void *);
-static void	mue_uno_mcast(struct ifnet *);
 static int	mue_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *);
 static int	mue_uno_mii_write_reg(struct usbnet *, int, int, uint16_t);
 static void	mue_uno_mii_statchg(struct ifnet *);
@@ -997,10 +996,10 @@ mue_prepare_tso(struct usbnet *un, struct mbuf *m)
 }
 
 static void
-mue_setiff_locked(struct usbnet *un)
+mue_uno_mcast(struct ifnet *ifp)
 {
+	struct usbnet *un = ifp->if_softc;
 	struct ethercom *ec = usbnet_ec(un);
-	struct ifnet * const ifp = usbnet_ifp(un);
 	const uint8_t *enaddr = CLLADDR(ifp->if_sadl);
 	struct ether_multi *enm;
 	struct ether_multistep step;
@@ -1242,7 +1241,7 @@ mue_uno_init(struct ifnet *ifp)
 	mue_set_macaddr(un);
 
 	/* Load the multicast filter. */
-	mue_setiff_locked(un);
+	mue_uno_mcast(ifp);
 
 	/* TCP/UDP checksum offload engines. */
 	mue_sethwcsum_locked(un);
@@ -1276,14 +1275,6 @@ mue_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 	return 0;
 }
 
-static void
-mue_uno_mcast(struct ifnet *ifp)
-{
-	struct usbnet * const un = ifp->if_softc;
-
-	mue_setiff_locked(un);
-}
-
 static void
 mue_reset(struct usbnet *un)
 {
diff --git a/sys/dev/usb/if_smsc.c b/sys/dev/usb/if_smsc.c
index 429c2b939899..57c4f08b77f0 100644
--- a/sys/dev/usb/if_smsc.c
+++ b/sys/dev/usb/if_smsc.c
@@ -411,11 +411,11 @@ smsc_hash(uint8_t addr[ETHER_ADDR_LEN])
 }
 
 static void
-smsc_setiff_locked(struct usbnet *un)
+smsc_uno_mcast(struct ifnet *ifp)
 {
 	USMSCHIST_FUNC(); USMSCHIST_CALLED();
+	struct usbnet * const un = ifp->if_softc;
 	struct smsc_softc * const sc = usbnet_softc(un);
-	struct ifnet * const ifp = usbnet_ifp(un);
 	struct ethercom *ec = usbnet_ec(un);
 	struct ether_multi *enm;
 	struct ether_multistep step;
@@ -568,7 +568,7 @@ smsc_uno_init(struct ifnet *ifp)
 	smsc_reset(sc);
 
 	/* Load the multicast filter. */
-	smsc_setiff_locked(un);
+	smsc_uno_mcast(ifp);
 
 	/* TCP/UDP checksum offload engines. */
 	smsc_setoe_locked(un);
@@ -757,14 +757,6 @@ smsc_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 	return 0;
 }
 
-static void
-smsc_uno_mcast(struct ifnet *ifp)
-{
-	struct usbnet * const un = ifp->if_softc;
-
-	smsc_setiff_locked(un);
-}
-
 static int
 smsc_match(device_t parent, cfdata_t match, void *aux)
 {
diff --git a/sys/dev/usb/if_udav.c b/sys/dev/usb/if_udav.c
index 3528653f3794..791939e5d358 100644
--- a/sys/dev/usb/if_udav.c
+++ b/sys/dev/usb/if_udav.c
@@ -74,7 +74,6 @@ static int udav_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *);
 static int udav_uno_mii_write_reg(struct usbnet *, int, int, uint16_t);
 static void udav_uno_mii_statchg(struct ifnet *);
 static int udav_uno_init(struct ifnet *);
-static void udav_setiff_locked(struct usbnet *);
 static void udav_reset(struct usbnet *);
 
 static int udav_csr_read(struct usbnet *, int, void *, int);
@@ -501,7 +500,7 @@ udav_uno_init(struct ifnet *ifp)
 		UDAV_CLRBIT(un, UDAV_RCR, UDAV_RCR_ALL | UDAV_RCR_PRMSC);
 
 	/* Load the multicast filter */
-	udav_setiff_locked(un);
+	udav_uno_mcast(ifp);
 
 	/* Enable RX */
 	UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_RXEN);
@@ -576,10 +575,10 @@ udav_chip_init(struct usbnet *un)
 	(ether_crc32_le((addr), ETHER_ADDR_LEN) & ((1 << UDAV_BITS) - 1))
 
 static void
-udav_setiff_locked(struct usbnet *un)
+udav_uno_mcast(struct ifnet *ifp)
 {
+	struct usbnet * const un = ifp->if_softc;
 	struct ethercom *ec = usbnet_ec(un);
-	struct ifnet * const ifp = usbnet_ifp(un);
 	struct ether_multi *enm;
 	struct ether_multistep step;
 	uint8_t hashes[8];
@@ -711,14 +710,6 @@ udav_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len)
 	usbnet_enqueue(un, buf, pkt_len, 0, 0, 0);
 }
 
-static void
-udav_uno_mcast(struct ifnet *ifp)
-{
-	struct usbnet * const un = ifp->if_softc;
-
-	udav_setiff_locked(un);
-}
-
 /* Stop the adapter and free any mbufs allocated to the RX and TX lists. */
 static void
 udav_uno_stop(struct ifnet *ifp, int disable)
diff --git a/sys/dev/usb/if_ure.c b/sys/dev/usb/if_ure.c
index 37e3611f9c87..8d6da56a603a 100644
--- a/sys/dev/usb/if_ure.c
+++ b/sys/dev/usb/if_ure.c
@@ -331,10 +331,10 @@ ure_uno_miibus_statchg(struct ifnet *ifp)
 }
 
 static void
-ure_rcvfilt_locked(struct usbnet *un)
+ure_uno_mcast(struct ifnet *ifp)
 {
+	struct usbnet *un = ifp->if_softc;
 	struct ethercom *ec = usbnet_ec(un);
-	struct ifnet *ifp = usbnet_ifp(un);
 	struct ether_multi *enm;
 	struct ether_multistep step;
 	uint32_t mchash[2] = { 0, 0 };
@@ -448,7 +448,7 @@ ure_uno_init(struct ifnet *ifp)
 	    ~URE_RXDY_GATED_EN);
 
 	/* Accept multicast frame or run promisc. mode. */
-	ure_rcvfilt_locked(un);
+	ure_uno_mcast(ifp);
 
 	return usbnet_init_rx_tx(un);
 }
@@ -790,14 +790,6 @@ ure_init_fifo(struct usbnet *un)
 	    URE_TXFIFO_THR_NORMAL);
 }
 
-static void
-ure_uno_mcast(struct ifnet *ifp)
-{
-	struct usbnet * const un = ifp->if_softc;
-
-	ure_rcvfilt_locked(un);
-}
-
 static int
 ure_match(device_t parent, cfdata_t match, void *aux)
 {
diff --git a/sys/dev/usb/if_url.c b/sys/dev/usb/if_url.c
index 6d93d756bfd0..9dbf854db9cb 100644
--- a/sys/dev/usb/if_url.c
+++ b/sys/dev/usb/if_url.c
@@ -77,11 +77,10 @@ static unsigned	url_uno_tx_prepare(struct usbnet *, struct mbuf *,
 static void url_uno_rx_loop(struct usbnet *, struct usbnet_chain *, uint32_t);
 static int url_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *);
 static int url_uno_mii_write_reg(struct usbnet *, int, int, uint16_t);
-static void url_uno_mcast(struct ifnet *);
 static void url_uno_stop(struct ifnet *, int);
 static void url_uno_mii_statchg(struct ifnet *);
 static int url_uno_init(struct ifnet *);
-static void url_rcvfilt_locked(struct usbnet *);
+static void url_uno_mcast(struct ifnet *);
 static void url_reset(struct usbnet *);
 
 static int url_csr_read_1(struct usbnet *, int);
@@ -393,7 +392,7 @@ url_init_locked(struct ifnet *ifp)
 	URL_SETBIT2(un, URL_RCR, URL_RCR_TAIL | URL_RCR_AD | URL_RCR_AB);
 
 	/* Accept multicast frame or run promisc. mode */
-	url_rcvfilt_locked(un);
+	url_uno_mcast(ifp);
 
 	/* Enable RX and TX */
 	URL_SETBIT(un, URL_CR, URL_CR_TE | URL_CR_RE);
@@ -433,9 +432,9 @@ url_reset(struct usbnet *un)
 }
 
 static void
-url_rcvfilt_locked(struct usbnet *un)
+url_uno_mcast(struct ifnet *ifp)
 {
-	struct ifnet * const ifp = usbnet_ifp(un);
+	struct usbnet * const un = ifp->if_softc;
 	struct ethercom *ec = usbnet_ec(un);
 	struct ether_multi *enm;
 	struct ether_multistep step;
@@ -553,14 +552,6 @@ static void url_intr(void)
 }
 #endif
 
-static void
-url_uno_mcast(struct ifnet *ifp)
-{
-	struct usbnet * const un = ifp->if_softc;
-
-	url_rcvfilt_locked(un);
-}
-
 /* Stop the adapter and free any mbufs allocated to the RX and TX lists. */
 static void
 url_uno_stop(struct ifnet *ifp, int disable)

From 8177511bb9390cb26d2491273dd5376d759a823a Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Fri, 31 Dec 2021 00:48:54 +0000
Subject: [PATCH 48/48] usbnet drivers: Stop abusing ifp->if_flags &
 IFF_ALLMULTI.

This legacy flag is a figment of userland's imagination.  The actual
kernel state is ec->ec_flags & ETHER_F_ALLMULTI, protected by the
ETHER_LOCK, so that multicast filter updates -- which run without
IFNET_LOCK -- need not attempt to write racily to ifp->if_flags.
---
 sys/dev/usb/if_aue.c  | 12 ++++++------
 sys/dev/usb/if_cue.c  |  8 ++++----
 sys/dev/usb/if_kue.c  |  8 ++++----
 sys/dev/usb/if_mue.c  |  9 ++++-----
 sys/dev/usb/if_smsc.c |  8 +++++---
 sys/dev/usb/if_udav.c | 12 ++++++++----
 6 files changed, 31 insertions(+), 26 deletions(-)

diff --git a/sys/dev/usb/if_aue.c b/sys/dev/usb/if_aue.c
index 7d1994cfb451..bd9226a3ba67 100644
--- a/sys/dev/usb/if_aue.c
+++ b/sys/dev/usb/if_aue.c
@@ -627,21 +627,20 @@ aue_uno_mcast(struct ifnet *ifp)
 	usbnet_isowned_core(un);
 
 	if (ifp->if_flags & IFF_PROMISC) {
+		ETHER_LOCK(ec);
 allmulti:
-		ifp->if_flags |= IFF_ALLMULTI;
+		ec->ec_flags |= ETHER_F_ALLMULTI;
+		ETHER_UNLOCK(ec);
 		AUE_SETBIT(sc, AUE_CTL0, AUE_CTL0_ALLMULTI);
 		return;
 	}
 
-	AUE_CLRBIT(sc, AUE_CTL0, AUE_CTL0_ALLMULTI);
-
 	/* now program new ones */
 	ETHER_LOCK(ec);
 	ETHER_FIRST_MULTI(step, ec, enm);
 	while (enm != NULL) {
 		if (memcmp(enm->enm_addrlo,
 		    enm->enm_addrhi, ETHER_ADDR_LEN) != 0) {
-			ETHER_UNLOCK(ec);
 			goto allmulti;
 		}
 
@@ -649,13 +648,14 @@ allmulti:
 		hashtbl[h >> 3] |= 1 << (h & 0x7);
 		ETHER_NEXT_MULTI(step, enm);
 	}
+	ec->ec_flags &= ~ETHER_F_ALLMULTI;
 	ETHER_UNLOCK(ec);
 
+	AUE_CLRBIT(sc, AUE_CTL0, AUE_CTL0_ALLMULTI);
+
 	/* write the hashtable */
 	for (i = 0; i < 8; i++)
 		aue_csr_write_1(sc, AUE_MAR0 + i, hashtbl[i]);
-
-	ifp->if_flags &= ~IFF_ALLMULTI;
 }
 
 static void
diff --git a/sys/dev/usb/if_cue.c b/sys/dev/usb/if_cue.c
index cf85b72d3d57..a3902bc54679 100644
--- a/sys/dev/usb/if_cue.c
+++ b/sys/dev/usb/if_cue.c
@@ -370,8 +370,10 @@ cue_uno_mcast(struct ifnet *ifp)
 	    device_xname(un->un_dev), ifp->if_flags));
 
 	if (ifp->if_flags & IFF_PROMISC) {
+		ETHER_LOCK(ec);
 allmulti:
-		ifp->if_flags |= IFF_ALLMULTI;
+		ec->ec_flags |= ETHER_F_ALLMULTI;
+		ETHER_UNLOCK(ec);
 		for (i = 0; i < CUE_MCAST_TABLE_LEN; i++)
 			sc->cue_mctab[i] = 0xFF;
 		cue_mem(un, CUE_CMD_WRITESRAM, CUE_MCAST_TABLE_ADDR,
@@ -389,7 +391,6 @@ allmulti:
 	while (enm != NULL) {
 		if (memcmp(enm->enm_addrlo,
 		    enm->enm_addrhi, ETHER_ADDR_LEN) != 0) {
-			ETHER_UNLOCK(ec);
 			goto allmulti;
 		}
 
@@ -397,10 +398,9 @@ allmulti:
 		sc->cue_mctab[h >> 3] |= 1 << (h & 0x7);
 		ETHER_NEXT_MULTI(step, enm);
 	}
+	ec->ec_flags &= ~ETHER_F_ALLMULTI;
 	ETHER_UNLOCK(ec);
 
-	ifp->if_flags &= ~IFF_ALLMULTI;
-
 	/*
 	 * Also include the broadcast address in the filter
 	 * so we can receive broadcast frames.
diff --git a/sys/dev/usb/if_kue.c b/sys/dev/usb/if_kue.c
index be075ed5e65f..15f32d81409f 100644
--- a/sys/dev/usb/if_kue.c
+++ b/sys/dev/usb/if_kue.c
@@ -336,8 +336,10 @@ kue_uno_mcast(struct ifnet *ifp)
 		sc->kue_rxfilt &= ~KUE_RXFILT_PROMISC;
 
 	if (ifp->if_flags & IFF_PROMISC) {
+		ETHER_LOCK(ec);
 allmulti:
-		ifp->if_flags |= IFF_ALLMULTI;
+		ec->ec_flags |= ETHER_F_ALLMULTI;
+		ETHER_UNLOCK(ec);
 		sc->kue_rxfilt |= KUE_RXFILT_ALLMULTI|KUE_RXFILT_PROMISC;
 		sc->kue_rxfilt &= ~KUE_RXFILT_MULTICAST;
 		kue_setword(un, KUE_CMD_SET_PKT_FILTER, sc->kue_rxfilt);
@@ -353,7 +355,6 @@ allmulti:
 		if (i == KUE_MCFILTCNT(sc) ||
 		    memcmp(enm->enm_addrlo, enm->enm_addrhi,
 		    ETHER_ADDR_LEN) != 0) {
-			ETHER_UNLOCK(ec);
 			goto allmulti;
 		}
 
@@ -361,10 +362,9 @@ allmulti:
 		ETHER_NEXT_MULTI(step, enm);
 		i++;
 	}
+	ec->ec_flags &= ~ETHER_F_ALLMULTI;
 	ETHER_UNLOCK(ec);
 
-	ifp->if_flags &= ~IFF_ALLMULTI;
-
 	sc->kue_rxfilt |= KUE_RXFILT_MULTICAST;
 	kue_ctl(un, KUE_CTL_WRITE, KUE_CMD_SET_MCAST_FILTERS,
 	    i, sc->kue_mcfilters, i * ETHER_ADDR_LEN);
diff --git a/sys/dev/usb/if_mue.c b/sys/dev/usb/if_mue.c
index 0f5c29421afc..c63911009771 100644
--- a/sys/dev/usb/if_mue.c
+++ b/sys/dev/usb/if_mue.c
@@ -1023,10 +1023,11 @@ mue_uno_mcast(struct ifnet *ifp)
 	/* Always accept broadcast frames. */
 	rxfilt |= MUE_RFE_CTL_BROADCAST;
 
+	ETHER_LOCK(ec);
 	if (ifp->if_flags & IFF_PROMISC) {
 		rxfilt |= MUE_RFE_CTL_UNICAST;
 allmulti:	rxfilt |= MUE_RFE_CTL_MULTICAST;
-		ifp->if_flags |= IFF_ALLMULTI;
+		ec->ec_flags |= ETHER_F_ALLMULTI;
 		if (ifp->if_flags & IFF_PROMISC)
 			DPRINTF(un, "promisc\n");
 		else
@@ -1036,7 +1037,6 @@ allmulti:	rxfilt |= MUE_RFE_CTL_MULTICAST;
 		pfiltbl[0][0] = MUE_ENADDR_HI(enaddr) | MUE_ADDR_FILTX_VALID;
 		pfiltbl[0][1] = MUE_ENADDR_LO(enaddr);
 		i = 1;
-		ETHER_LOCK(ec);
 		ETHER_FIRST_MULTI(step, ec, enm);
 		while (enm != NULL) {
 			if (memcmp(enm->enm_addrlo, enm->enm_addrhi,
@@ -1044,7 +1044,6 @@ allmulti:	rxfilt |= MUE_RFE_CTL_MULTICAST;
 				memset(pfiltbl, 0, sizeof(pfiltbl));
 				memset(hashtbl, 0, sizeof(hashtbl));
 				rxfilt &= ~MUE_RFE_CTL_MULTICAST_HASH;
-				ETHER_UNLOCK(ec);
 				goto allmulti;
 			}
 			if (i < MUE_NUM_ADDR_FILTX) {
@@ -1062,14 +1061,14 @@ allmulti:	rxfilt |= MUE_RFE_CTL_MULTICAST;
 			i++;
 			ETHER_NEXT_MULTI(step, enm);
 		}
-		ETHER_UNLOCK(ec);
+		ec->ec_flags &= ~ETHER_F_ALLMULTI;
 		rxfilt |= MUE_RFE_CTL_PERFECT;
-		ifp->if_flags &= ~IFF_ALLMULTI;
 		if (rxfilt & MUE_RFE_CTL_MULTICAST_HASH)
 			DPRINTF(un, "perfect filter and hash tables\n");
 		else
 			DPRINTF(un, "perfect filter\n");
 	}
+	ETHER_UNLOCK(ec);
 
 	for (i = 0; i < MUE_NUM_ADDR_FILTX; i++) {
 		hireg = (un->un_flags & LAN7500) ?
diff --git a/sys/dev/usb/if_smsc.c b/sys/dev/usb/if_smsc.c
index 57c4f08b77f0..751d0c982eb7 100644
--- a/sys/dev/usb/if_smsc.c
+++ b/sys/dev/usb/if_smsc.c
@@ -427,8 +427,11 @@ smsc_uno_mcast(struct ifnet *ifp)
 	if (usbnet_isdying(un))
 		return;
 
-	if (ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) {
+	if (ifp->if_flags & IFF_PROMISC) {
+		ETHER_LOCK(ec);
 allmulti:
+		ec->ec_flags |= ETHER_F_ALLMULTI;
+		ETHER_UNLOCK(ec);
 		DPRINTF("receive all multicast enabled", 0, 0, 0, 0);
 		sc->sc_mac_csr |= SMSC_MAC_CSR_MCPAS;
 		sc->sc_mac_csr &= ~SMSC_MAC_CSR_HPFILT;
@@ -443,7 +446,6 @@ allmulti:
 	ETHER_FIRST_MULTI(step, ec, enm);
 	while (enm != NULL) {
 		if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) {
-			ETHER_UNLOCK(ec);
 			goto allmulti;
 		}
 
@@ -451,6 +453,7 @@ allmulti:
 		hashtbl[hash >> 5] |= 1 << (hash & 0x1F);
 		ETHER_NEXT_MULTI(step, enm);
 	}
+	ec->ec_flags &= ~ETHER_F_ALLMULTI;
 	ETHER_UNLOCK(ec);
 
 	/* Debug */
@@ -463,7 +466,6 @@ allmulti:
 	/* Write the hash table and mac control registers */
 
 	//XXX should we be doing this?
-	ifp->if_flags &= ~IFF_ALLMULTI;
 	smsc_writereg(un, SMSC_HASHH, hashtbl[1]);
 	smsc_writereg(un, SMSC_HASHL, hashtbl[0]);
 	smsc_writereg(un, SMSC_MAC_CSR, sc->sc_mac_csr);
diff --git a/sys/dev/usb/if_udav.c b/sys/dev/usb/if_udav.c
index 791939e5d358..32978d4d2dd5 100644
--- a/sys/dev/usb/if_udav.c
+++ b/sys/dev/usb/if_udav.c
@@ -598,11 +598,16 @@ udav_uno_mcast(struct ifnet *ifp)
 	}
 
 	if (ifp->if_flags & IFF_PROMISC) {
+		ETHER_LOCK(ec);
+		ec->ec_flags |= ETHER_F_ALLMULTI;
+		ETHER_UNLOCK(ec);
 		UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_ALL | UDAV_RCR_PRMSC);
 		return;
-	} else if (ifp->if_flags & IFF_ALLMULTI) {
+	} else if (ifp->if_flags & IFF_ALLMULTI) { /* XXX ??? Can't happen? */
+		ETHER_LOCK(ec);
 allmulti:
-		ifp->if_flags |= IFF_ALLMULTI;
+		ec->ec_flags |= ETHER_F_ALLMULTI;
+		ETHER_UNLOCK(ec);
 		UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_ALL);
 		UDAV_CLRBIT(un, UDAV_RCR, UDAV_RCR_PRMSC);
 		return;
@@ -619,7 +624,6 @@ allmulti:
 	while (enm != NULL) {
 		if (memcmp(enm->enm_addrlo, enm->enm_addrhi,
 		    ETHER_ADDR_LEN) != 0) {
-			ETHER_UNLOCK(ec);
 			goto allmulti;
 		}
 
@@ -627,10 +631,10 @@ allmulti:
 		hashes[h>>3] |= 1 << (h & 0x7);
 		ETHER_NEXT_MULTI(step, enm);
 	}
+	ec->ec_flags &= ~ETHER_F_ALLMULTI;
 	ETHER_UNLOCK(ec);
 
 	/* disable all multicast */
-	ifp->if_flags &= ~IFF_ALLMULTI;
 	UDAV_CLRBIT(un, UDAV_RCR, UDAV_RCR_ALL);
 
 	/* write hash value to the register */


Home | Main Index | Thread Index | Old Index