diff --git a/share/man/man9/usbnet.9 b/share/man/man9/usbnet.9
index c23157073660..21e3ff59f3d6 100644
--- a/share/man/man9/usbnet.9
+++ b/share/man/man9/usbnet.9
@@ -47,6 +47,8 @@
 .Fn usbnet_softc "struct usbnet *un"
 .Ft bool
 .Fn usbnet_havelink "struct usbnet *un"
+.Ft int
+.Fn usbnet_ispromisc "struct usbnet *un"
 .Ft bool
 .Fn usbnet_isdying "struct usbnet *un"
 .Ft void
@@ -243,6 +245,20 @@ Returns pointer to this
 device softc.
 .It Fn usbnet_havelink un
 Returns true if link is active.
+.It Fn usbnet_ispromisc un
+True if
+.Dv IFF_PROMISC
+is enabled, false if not.
+.Pp
+May be used only in
+.Dq uno_init
+and
+.Dq uno_mcast .
+.Pp
+Drivers must use this in
+.Dq uno_mcast
+instead of reading
+.Li ifp->if_flags .
 .It Fn usbnet_isdying un
 Returns true if device is dying (has been pulled or deactivated,
 pending detach).
diff --git a/sys/dev/usb/if_aue.c b/sys/dev/usb/if_aue.c
index 57b06a472546..355be8a7ca8a 100644
--- a/sys/dev/usb/if_aue.c
+++ b/sys/dev/usb/if_aue.c
@@ -619,7 +619,7 @@ aue_uno_mcast(struct ifnet *ifp)
 	AUEHIST_FUNC();
 	AUEHIST_CALLARGSN(5, "aue%jd: enter", device_unit(un->un_dev), 0, 0, 0);
 
-	if (ifp->if_flags & IFF_PROMISC) {
+	if (usbnet_ispromisc(un)) {
 		ETHER_LOCK(ec);
 allmulti:
 		ec->ec_flags |= ETHER_F_ALLMULTI;
@@ -962,7 +962,7 @@ aue_uno_init(struct ifnet *ifp)
 		aue_csr_write_1(sc, AUE_PAR0 + i, eaddr[i]);
 
 	 /* If we want promiscuous mode, set the allframes bit. */
-	if (ifp->if_flags & IFF_PROMISC)
+	if (usbnet_ispromisc(un))
 		AUE_SETBIT(sc, AUE_CTL2, AUE_CTL2_RX_PROMISC);
 	else
 		AUE_CLRBIT(sc, AUE_CTL2, AUE_CTL2_RX_PROMISC);
diff --git a/sys/dev/usb/if_axe.c b/sys/dev/usb/if_axe.c
index 9b0b76d05151..d55cda1c0d47 100644
--- a/sys/dev/usb/if_axe.c
+++ b/sys/dev/usb/if_axe.c
@@ -452,7 +452,7 @@ axe_uno_mcast(struct ifnet *ifp)
 	    ~(AXE_RXCMD_ALLMULTI | AXE_RXCMD_PROMISC | AXE_RXCMD_MULTICAST);
 
 	ETHER_LOCK(ec);
-	if (ifp->if_flags & IFF_PROMISC) {
+	if (usbnet_ispromisc(un)) {
 		ec->ec_flags |= ETHER_F_ALLMULTI;
 		ETHER_UNLOCK(ec);
 		/* run promisc. mode */
diff --git a/sys/dev/usb/if_axen.c b/sys/dev/usb/if_axen.c
index 4ab976dd1cfa..b02a641af9b0 100644
--- a/sys/dev/usb/if_axen.c
+++ b/sys/dev/usb/if_axen.c
@@ -249,7 +249,7 @@ axen_uno_mcast(struct ifnet *ifp)
 	rxmode &= ~(AXEN_RXCTL_ACPT_ALL_MCAST | AXEN_RXCTL_PROMISC |
 	    AXEN_RXCTL_ACPT_MCAST);
 
-	if (ifp->if_flags & IFF_PROMISC) {
+	if (usbnet_ispromisc(un)) {
 		DPRINTF(("%s: promisc\n", device_xname(un->un_dev)));
 		rxmode |= AXEN_RXCTL_PROMISC;
 allmulti:
diff --git a/sys/dev/usb/if_cue.c b/sys/dev/usb/if_cue.c
index e46981457228..7cef84486570 100644
--- a/sys/dev/usb/if_cue.c
+++ b/sys/dev/usb/if_cue.c
@@ -366,10 +366,10 @@ cue_uno_mcast(struct ifnet *ifp)
 	struct ether_multistep	step;
 	uint32_t		h, i;
 
-	DPRINTFN(2,("%s: cue_setiff if_flags=%#x\n",
-	    device_xname(un->un_dev), ifp->if_flags));
+	DPRINTFN(2,("%s: cue_setiff promisc=%d\n",
+	    device_xname(un->un_dev), usbnet_ispromisc(un)));
 
-	if (ifp->if_flags & IFF_PROMISC) {
+	if (usbnet_ispromisc(un)) {
 		ETHER_LOCK(ec);
 allmulti:
 		ec->ec_flags |= ETHER_F_ALLMULTI;
@@ -405,10 +405,8 @@ allmulti:
 	 * Also include the broadcast address in the filter
 	 * so we can receive broadcast frames.
 	 */
-	if (ifp->if_flags & IFF_BROADCAST) {
-		h = cue_crc(etherbroadcastaddr);
-		sc->cue_mctab[h >> 3] |= 1 << (h & 0x7);
-	}
+	h = cue_crc(etherbroadcastaddr);
+	sc->cue_mctab[h >> 3] |= 1 << (h & 0x7);
 
 	cue_mem(un, CUE_CMD_WRITESRAM, CUE_MCAST_TABLE_ADDR,
 	    &sc->cue_mctab, CUE_MCAST_TABLE_LEN);
@@ -636,7 +634,7 @@ cue_uno_init(struct ifnet *ifp)
 
 	/* Enable RX logic. */
 	ctl = CUE_ETHCTL_RX_ON | CUE_ETHCTL_MCAST_ON;
-	if (ifp->if_flags & IFF_PROMISC)
+	if (usbnet_ispromisc(un))
 		ctl |= CUE_ETHCTL_PROMISC;
 	cue_csr_write_1(un, CUE_ETHCTL, ctl);
 
diff --git a/sys/dev/usb/if_kue.c b/sys/dev/usb/if_kue.c
index 50411164221e..fa441f45b62b 100644
--- a/sys/dev/usb/if_kue.c
+++ b/sys/dev/usb/if_kue.c
@@ -330,12 +330,12 @@ kue_uno_mcast(struct ifnet *ifp)
 	DPRINTFN(5,("%s: %s: enter\n", device_xname(un->un_dev), __func__));
 
 	 /* If we want promiscuous mode, set the allframes bit. */
-	if (ifp->if_flags & IFF_PROMISC)
+	if (usbnet_ispromisc(un))
 		sc->kue_rxfilt |= KUE_RXFILT_PROMISC;
 	else
 		sc->kue_rxfilt &= ~KUE_RXFILT_PROMISC;
 
-	if (ifp->if_flags & IFF_PROMISC) {
+	if (usbnet_ispromisc(un)) {
 		ETHER_LOCK(ec);
 allmulti:
 		ec->ec_flags |= ETHER_F_ALLMULTI;
diff --git a/sys/dev/usb/if_mos.c b/sys/dev/usb/if_mos.c
index 2f64a19ffcf9..c9e6875dcc63 100644
--- a/sys/dev/usb/if_mos.c
+++ b/sys/dev/usb/if_mos.c
@@ -477,7 +477,7 @@ mos_uno_mcast(struct ifnet *ifp)
 	rxmode &= ~(MOS_CTL_ALLMULTI | MOS_CTL_RX_PROMISC);
 
 	ETHER_LOCK(ec);
-	if (ifp->if_flags & IFF_PROMISC) {
+	if (usbnet_ispromisc(un)) {
 		ec->ec_flags |= ETHER_F_ALLMULTI;
 		ETHER_UNLOCK(ec);
 		/* run promisc. mode */
diff --git a/sys/dev/usb/if_mue.c b/sys/dev/usb/if_mue.c
index e19576151ae5..a0bf825e8457 100644
--- a/sys/dev/usb/if_mue.c
+++ b/sys/dev/usb/if_mue.c
@@ -1028,11 +1028,11 @@ mue_uno_mcast(struct ifnet *ifp)
 	rxfilt |= MUE_RFE_CTL_BROADCAST;
 
 	ETHER_LOCK(ec);
-	if (ifp->if_flags & IFF_PROMISC) {
+	if (usbnet_ispromisc(un)) {
 		rxfilt |= MUE_RFE_CTL_UNICAST;
 allmulti:	rxfilt |= MUE_RFE_CTL_MULTICAST;
 		ec->ec_flags |= ETHER_F_ALLMULTI;
-		if (ifp->if_flags & IFF_PROMISC)
+		if (usbnet_ispromisc(un))
 			DPRINTF(un, "promisc\n");
 		else
 			DPRINTF(un, "allmulti\n");
diff --git a/sys/dev/usb/if_smsc.c b/sys/dev/usb/if_smsc.c
index 305781e53517..74c2b57669dd 100644
--- a/sys/dev/usb/if_smsc.c
+++ b/sys/dev/usb/if_smsc.c
@@ -425,7 +425,7 @@ smsc_uno_mcast(struct ifnet *ifp)
 	if (usbnet_isdying(un))
 		return;
 
-	if (ifp->if_flags & IFF_PROMISC) {
+	if (usbnet_ispromisc(un)) {
 		ETHER_LOCK(ec);
 allmulti:
 		ec->ec_flags |= ETHER_F_ALLMULTI;
diff --git a/sys/dev/usb/if_udav.c b/sys/dev/usb/if_udav.c
index add37bc874ac..cc6389458dbc 100644
--- a/sys/dev/usb/if_udav.c
+++ b/sys/dev/usb/if_udav.c
@@ -482,7 +482,7 @@ udav_uno_init(struct ifnet *ifp)
 	UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_DIS_LONG | UDAV_RCR_DIS_CRC);
 
 	/* If we want promiscuous mode, accept all physical frames. */
-	if (ifp->if_flags & IFF_PROMISC)
+	if (usbnet_ispromisc(un))
 		UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_ALL | UDAV_RCR_PRMSC);
 	else
 		UDAV_CLRBIT(un, UDAV_RCR, UDAV_RCR_ALL | UDAV_RCR_PRMSC);
@@ -576,20 +576,12 @@ udav_uno_mcast(struct ifnet *ifp)
 		return;
 	}
 
-	if (ifp->if_flags & IFF_PROMISC) {
+	if (usbnet_ispromisc(un)) {
 		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) { /* XXX ??? Can't happen? */
-		ETHER_LOCK(ec);
-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;
 	}
 
 	/* first, zot all the existing hash bits */
@@ -603,7 +595,11 @@ allmulti:
 	while (enm != NULL) {
 		if (memcmp(enm->enm_addrlo, enm->enm_addrhi,
 		    ETHER_ADDR_LEN) != 0) {
-			goto 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;
 		}
 
 		h = UDAV_CALCHASH(enm->enm_addrlo);
diff --git a/sys/dev/usb/if_ure.c b/sys/dev/usb/if_ure.c
index f05d5b4f75d0..42d359db0d1f 100644
--- a/sys/dev/usb/if_ure.c
+++ b/sys/dev/usb/if_ure.c
@@ -352,7 +352,7 @@ ure_uno_mcast(struct ifnet *ifp)
 	/* continue to accept my own DA and bcast frames */
 
 	ETHER_LOCK(ec);
-	if (ifp->if_flags & IFF_PROMISC) {
+	if (usbnet_ispromisc(un)) {
 		ec->ec_flags |= ETHER_F_ALLMULTI;
 		ETHER_UNLOCK(ec);
 		/* run promisc. mode */
diff --git a/sys/dev/usb/if_url.c b/sys/dev/usb/if_url.c
index 7a51a59f75cf..36624a9f8f1c 100644
--- a/sys/dev/usb/if_url.c
+++ b/sys/dev/usb/if_url.c
@@ -433,7 +433,7 @@ url_uno_mcast(struct ifnet *ifp)
 	rcr &= ~(URL_RCR_AAP | URL_RCR_AAM | URL_RCR_AM);
 
 	ETHER_LOCK(ec);
-	if (ifp->if_flags & IFF_PROMISC) {
+	if (usbnet_ispromisc(un)) {
 		ec->ec_flags |= ETHER_F_ALLMULTI;
 		ETHER_UNLOCK(ec);
 		/* run promisc. mode */
diff --git a/sys/dev/usb/usbnet.c b/sys/dev/usb/usbnet.c
index e9d378db5e4c..781ce9ab0544 100644
--- a/sys/dev/usb/usbnet.c
+++ b/sys/dev/usb/usbnet.c
@@ -52,18 +52,17 @@ struct usbnet_cdata {
 
 struct usbnet_private {
 	/*
-	 * - unp_core_lock protects most of this structure, the public one,
-	 *   and the MII / media data.
+	 * - unp_miilock protects the MII / media data and tick scheduling.
 	 * - unp_rxlock protects the rx path and its data
 	 * - unp_txlock protects the tx path and its data
 	 *
 	 * the lock ordering is:
-	 *	ifnet lock -> unp_core_lock -> unp_rxlock -> unp_txlock
-	 *				    -> unp_mcastlock
-	 * - ifnet lock is not needed for unp_core_lock, but if ifnet lock is
-	 *   involved, it must be taken first
+	 *	ifnet lock -> unp_miilock
+	 *		   -> unp_rxlock
+	 *		   -> unp_txlock
+	 *		   -> unp_mcastlock
 	 */
-	kmutex_t		unp_core_lock;
+	kmutex_t		unp_miilock;
 	kmutex_t		unp_rxlock;
 	kmutex_t		unp_txlock;
 
@@ -79,7 +78,9 @@ struct usbnet_private {
 	struct usbd_pipe	*unp_ep[USBNET_ENDPT_MAX];
 
 	volatile bool		unp_dying;
-	bool			unp_stopping;
+	bool			unp_stopped;
+	bool			unp_rxstopped;
+	bool			unp_txstopped;
 	bool			unp_attached;
 	bool			unp_ifp_attached;
 	bool			unp_link;
@@ -103,9 +104,9 @@ static void usbnet_isowned_rx(struct usbnet *);
 static void usbnet_isowned_tx(struct usbnet *);
 
 static inline void
-usbnet_isowned_core(struct usbnet *un)
+usbnet_isowned_mii(struct usbnet *un)
 {
-	KASSERT(mutex_owned(&un->un_pri->unp_core_lock));
+	KASSERT(mutex_owned(&un->un_pri->unp_miilock));
 }
 
 static int usbnet_modcmd(modcmd_t, void *);
@@ -161,7 +162,7 @@ static void
 uno_stop(struct usbnet *un, struct ifnet *ifp, int disable)
 {
 	KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname);
-	usbnet_isowned_core(un);
+	usbnet_isowned_mii(un);
 	if (un->un_ops->uno_stop)
 		(*un->un_ops->uno_stop)(ifp, disable);
 }
@@ -204,21 +205,21 @@ uno_init(struct usbnet *un, struct ifnet *ifp)
 static int
 uno_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val)
 {
-	usbnet_isowned_core(un);
+	usbnet_isowned_mii(un);
 	return (*un->un_ops->uno_read_reg)(un, phy, reg, val);
 }
 
 static int
 uno_write_reg(struct usbnet *un, int phy, int reg, uint16_t val)
 {
-	usbnet_isowned_core(un);
+	usbnet_isowned_mii(un);
 	return (*un->un_ops->uno_write_reg)(un, phy, reg, val);
 }
 
 static void
 uno_mii_statchg(struct usbnet *un, struct ifnet *ifp)
 {
-	usbnet_isowned_core(un);
+	usbnet_isowned_mii(un);
 	(*un->un_ops->uno_statchg)(ifp);
 }
 
@@ -341,7 +342,7 @@ usbnet_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
 
 	mutex_enter(&unp->unp_rxlock);
 
-	if (usbnet_isdying(un) || unp->unp_stopping ||
+	if (usbnet_isdying(un) || unp->unp_rxstopped ||
 	    status == USBD_INVAL || status == USBD_NOT_STARTED ||
 	    status == USBD_CANCELLED)
 		goto out;
@@ -368,7 +369,7 @@ usbnet_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
 	usbnet_isowned_rx(un);
 
 done:
-	if (usbnet_isdying(un) || unp->unp_stopping)
+	if (usbnet_isdying(un) || unp->unp_rxstopped)
 		goto out;
 
 	mutex_exit(&unp->unp_rxlock);
@@ -397,7 +398,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 || usbnet_isdying(un)) {
+	if (unp->unp_txstopped || usbnet_isdying(un)) {
 		mutex_exit(&unp->unp_txlock);
 		return;
 	}
@@ -439,14 +440,14 @@ usbnet_pipe_intr(struct usbd_xfer *xfer, void *priv, usbd_status status)
 	USBNETHIST_FUNC();
 	struct usbnet * const un = priv;
 	struct usbnet_private * const unp = un->un_pri;
-	struct usbnet_intr * const uni = un->un_intr;
+	struct usbnet_intr * const uni __unused = un->un_intr;
 
-	if (uni == NULL || usbnet_isdying(un) || unp->unp_stopping ||
+	if (usbnet_isdying(un) ||
 	    status == USBD_INVAL || status == USBD_NOT_STARTED ||
 	    status == USBD_CANCELLED) {
-		USBNETHIST_CALLARGS("%jd: uni %#jx d/s %#jx status %#jx",
+		USBNETHIST_CALLARGS("%jd: uni %#jx dying %#jx status %#jx",
 		    unp->unp_number, (uintptr_t)uni,
-		    (usbnet_isdying(un) << 8) | unp->unp_stopping, status);
+		    usbnet_isdying(un), status);
 		return;
 	}
 
@@ -569,11 +570,11 @@ usbnet_if_start(struct ifnet *ifp)
 	struct usbnet_private * const unp = un->un_pri;
 
 	USBNETHIST_FUNC();
-	USBNETHIST_CALLARGS("%jd: stopping %jd",
-	    unp->unp_number, unp->unp_stopping, 0, 0);
+	USBNETHIST_CALLARGS("%jd: txstopped %jd",
+	    unp->unp_number, unp->unp_txstopped, 0, 0);
 
 	mutex_enter(&unp->unp_txlock);
-	if (!unp->unp_stopping)
+	if (!unp->unp_txstopped)
 		usbnet_start_locked(ifp);
 	mutex_exit(&unp->unp_txlock);
 }
@@ -659,8 +660,8 @@ usbnet_rx_start_pipes(struct usbnet * const un)
 	struct usbnet_private * const unp = un->un_pri;
 
 	mutex_enter(&unp->unp_rxlock);
-	mutex_enter(&unp->unp_txlock);
-	unp->unp_stopping = false;
+	KASSERT(unp->unp_rxstopped);
+	unp->unp_rxstopped = false;
 
 	for (size_t i = 0; i < un->un_rx_list_cnt; i++) {
 		struct usbnet_chain *c = &cd->uncd_rx_chain[i];
@@ -670,7 +671,6 @@ usbnet_rx_start_pipes(struct usbnet * const un)
 		usbd_transfer(c->unc_xfer);
 	}
 
-	mutex_exit(&unp->unp_txlock);
 	mutex_exit(&unp->unp_rxlock);
 }
 
@@ -811,8 +811,6 @@ usbnet_init_rx_tx(struct usbnet * const un)
 
 	KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname);
 
-	usbnet_isowned_core(un);
-
 	if (usbnet_isdying(un)) {
 		return EIO;
 	}
@@ -855,10 +853,20 @@ usbnet_init_rx_tx(struct usbnet * const un)
 		mutex_exit(&unp->unp_mcastlock);
 	}
 
+	/* Allow transmit.  */
+	mutex_enter(&unp->unp_txlock);
+	KASSERT(unp->unp_txstopped);
+	unp->unp_txstopped = false;
+	mutex_exit(&unp->unp_txlock);
+
 	/* Start up the receive pipe(s). */
 	usbnet_rx_start_pipes(un);
 
+	/* Kick off the watchdog/stats/mii tick.  */
+	mutex_enter(&unp->unp_miilock);
+	unp->unp_stopped = false;
 	callout_schedule(&unp->unp_stat_ch, hz);
+	mutex_exit(&unp->unp_miilock);
 
 out:
 	if (error) {
@@ -871,10 +879,11 @@ out:
 	 * For devices without any media autodetection, treat success
 	 * here as an active link.
 	 */
-	if (un->un_ops->uno_statchg == NULL)
+	if (un->un_ops->uno_statchg == NULL) {
+		mutex_enter(&unp->unp_miilock);
 		usbnet_set_link(un, error == 0);
-
-	usbnet_isowned_core(un);
+		mutex_exit(&unp->unp_miilock);
+	}
 
 	return error;
 }
@@ -888,8 +897,8 @@ usbnet_mii_readreg(device_t dev, int phy, int reg, uint16_t *val)
 	struct usbnet * const un = device_private(dev);
 	int err;
 
-	/* MII layer ensures core_lock is held. */
-	usbnet_isowned_core(un);
+	/* MII layer ensures miilock is held. */
+	usbnet_isowned_mii(un);
 
 	if (usbnet_isdying(un)) {
 		return EIO;
@@ -912,8 +921,8 @@ usbnet_mii_writereg(device_t dev, int phy, int reg, uint16_t val)
 	struct usbnet * const un = device_private(dev);
 	int err;
 
-	/* MII layer ensures core_lock is held. */
-	usbnet_isowned_core(un);
+	/* MII layer ensures miilock is held. */
+	usbnet_isowned_mii(un);
 
 	if (usbnet_isdying(un)) {
 		return EIO;
@@ -935,8 +944,8 @@ usbnet_mii_statchg(struct ifnet *ifp)
 	USBNETHIST_FUNC(); USBNETHIST_CALLED();
 	struct usbnet * const un = ifp->if_softc;
 
-	/* MII layer ensures core_lock is held. */
-	usbnet_isowned_core(un);
+	/* MII layer ensures miilock is held. */
+	usbnet_isowned_mii(un);
 
 	uno_mii_statchg(un, ifp);
 }
@@ -949,8 +958,8 @@ usbnet_media_upd(struct ifnet *ifp)
 	struct usbnet_private * const unp = un->un_pri;
 	struct mii_data * const mii = usbnet_mii(un);
 
-	/* ifmedia layer ensures core_lock is held. */
-	usbnet_isowned_core(un);
+	/* ifmedia layer ensures miilock is held. */
+	usbnet_isowned_mii(un);
 
 	/* ifmedia changes only with IFNET_LOCK held.  */
 	KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname);
@@ -967,7 +976,7 @@ usbnet_media_upd(struct ifnet *ifp)
 			mii_phy_reset(miisc);
 	}
 
-	if (unp->unp_stopping)
+	if (unp->unp_stopped)
 		return 0;
 	return ether_mediachange(ifp);
 }
@@ -987,8 +996,22 @@ usbnet_ifflags_cb(struct ethercom *ec)
 
 	const u_short changed = ifp->if_flags ^ unp->unp_if_flags;
 	if ((changed & ~(IFF_CANTCHANGE | IFF_DEBUG)) == 0) {
+		mutex_enter(&unp->unp_mcastlock);
 		unp->unp_if_flags = ifp->if_flags;
-		if ((changed & IFF_PROMISC) != 0)
+		mutex_exit(&unp->unp_mcastlock);
+		/*
+		 * XXX Can we just do uno_mcast synchronously here
+		 * instead of resetting the whole interface?
+		 *
+		 * Not yet, because some usbnet drivers (e.g., aue(4))
+		 * initialize the hardware differently in uno_init
+		 * depending on IFF_PROMISC.  But some (again, aue(4))
+		 * _also_ need to know whether IFF_PROMISC is set in
+		 * uno_mcast and do something different with it there.
+		 * Maybe the logic can be unified, but it will require
+		 * an audit and testing of all the usbnet drivers.
+		 */
+		if (changed & IFF_PROMISC)
 			rv = ENETRESET;
 	} else {
 		rv = ENETRESET;
@@ -997,6 +1020,18 @@ usbnet_ifflags_cb(struct ethercom *ec)
 	return rv;
 }
 
+bool
+usbnet_ispromisc(struct usbnet *un)
+{
+	struct ifnet * const ifp = usbnet_ifp(un);
+	struct usbnet_private * const unp = un->un_pri;
+
+	KASSERTMSG(mutex_owned(&unp->unp_mcastlock) || IFNET_LOCKED(ifp),
+	    "%s", ifp->if_xname);
+
+	return unp->unp_if_flags & IFF_PROMISC;
+}
+
 static int
 usbnet_if_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 {
@@ -1055,17 +1090,16 @@ static void
 usbnet_stop(struct usbnet *un, struct ifnet *ifp, int disable)
 {
 	struct usbnet_private * const unp = un->un_pri;
+	struct mii_data * const mii = usbnet_mii(un);
 
 	USBNETHIST_FUNC(); USBNETHIST_CALLED();
 
 	KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname);
-	usbnet_isowned_core(un);
 
 	/*
 	 * For drivers with hardware multicast filter update callbacks:
 	 * Prevent concurrent access to the hardware registers by
-	 * multicast filter updates, which happens without IFNET_LOCK
-	 * or the usbnet core lock.
+	 * multicast filter updates, which happens without IFNET_LOCK.
 	 */
 	if (un->un_ops->uno_mcast) {
 		mutex_enter(&unp->unp_mcastlock);
@@ -1077,22 +1111,38 @@ usbnet_stop(struct usbnet *un, struct ifnet *ifp, int disable)
 	 * Prevent new activity (rescheduling ticks, xfers, &c.) and
 	 * clear the watchdog timer.
 	 */
+	mutex_enter(&unp->unp_miilock);
+	unp->unp_stopped = true;
+	mutex_exit(&unp->unp_miilock);
+
 	mutex_enter(&unp->unp_rxlock);
+	unp->unp_rxstopped = true;
+	mutex_exit(&unp->unp_rxlock);
+
 	mutex_enter(&unp->unp_txlock);
-	unp->unp_stopping = true;
+	unp->unp_txstopped = true;
 	unp->unp_timer = 0;
 	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
+	 * only after it last fired.  Setting unp_stopped prevents the
 	 * timer task from being scheduled again.
 	 */
-	callout_halt(&unp->unp_stat_ch, &unp->unp_core_lock);
+	callout_halt(&unp->unp_stat_ch, NULL);
 	usb_rem_task_wait(un->un_udev, &unp->unp_ticktask, USB_TASKQ_DRIVER,
-	    &unp->unp_core_lock);
+	    NULL);
+
+	/*
+	 * Now that we have stopped calling mii_tick, bring the MII
+	 * state machine down.
+	 */
+	if (mii) {
+		mutex_enter(&unp->unp_miilock);
+		mii_down(mii);
+		mutex_exit(&unp->unp_miilock);
+	}
 
 	/* Stop transfers. */
 	usbnet_ep_stop_pipes(un);
@@ -1126,7 +1176,6 @@ static void
 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);
 
@@ -1140,9 +1189,7 @@ usbnet_if_stop(struct ifnet *ifp, int disable)
 	if ((ifp->if_flags & IFF_RUNNING) == 0)
 		return;
 
-	mutex_enter(&unp->unp_core_lock);
 	usbnet_stop(un, ifp, disable);
-	mutex_exit(&unp->unp_core_lock);
 }
 
 /*
@@ -1203,22 +1250,20 @@ usbnet_tick_task(void *arg)
 	if (timeout)
 		usbnet_watchdog(ifp);
 
+	/* Call driver if requested. */
+	uno_tick(un);
+
+	mutex_enter(&unp->unp_miilock);
 	DPRINTFN(8, "mii %#jx ifp %#jx", (uintptr_t)mii, (uintptr_t)ifp, 0, 0);
 	if (mii) {
-		mutex_enter(&unp->unp_core_lock);
 		mii_tick(mii);
 		if (!unp->unp_link)
 			(*mii->mii_statchg)(ifp);
-		mutex_exit(&unp->unp_core_lock);
 	}
 
-	/* Call driver if requested. */
-	uno_tick(un);
-
-	mutex_enter(&unp->unp_core_lock);
-	if (!unp->unp_stopping && !usbnet_isdying(un))
+	if (!unp->unp_stopped && !usbnet_isdying(un))
 		callout_schedule(&unp->unp_stat_ch, hz);
-	mutex_exit(&unp->unp_core_lock);
+	mutex_exit(&unp->unp_miilock);
 }
 
 static int
@@ -1247,16 +1292,14 @@ usbnet_if_init(struct ifnet *ifp)
 	if (ifp->if_flags & IFF_RUNNING)
 		return 0;
 
-	mutex_enter(&un->un_pri->unp_core_lock);
 	error = uno_init(un, ifp);
 	if (error)
-		goto out;
+		return error;
 	error = usbnet_init_rx_tx(un);
 	if (error)
-		goto out;
-out:	mutex_exit(&un->un_pri->unp_core_lock);
+		return error;
 
-	return error;
+	return 0;
 }
 
 
@@ -1265,6 +1308,7 @@ out:	mutex_exit(&un->un_pri->unp_core_lock);
 void
 usbnet_set_link(struct usbnet *un, bool link)
 {
+	usbnet_isowned_mii(un);
 	un->un_pri->unp_link = link;
 }
 
@@ -1374,7 +1418,7 @@ 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);
+	mutex_init(&unp->unp_miilock, MUTEX_DEFAULT, IPL_NONE);
 	mutex_init(&unp->unp_mcastlock, MUTEX_DEFAULT, IPL_SOFTCLOCK);
 
 	rnd_attach_source(&unp->unp_rndsrc, device_xname(un->un_dev),
@@ -1385,6 +1429,9 @@ usbnet_attach(struct usbnet *un)
 
 	unp->unp_number = atomic_inc_uint_nv(&usbnet_number);
 
+	unp->unp_stopped = true;
+	unp->unp_rxstopped = true;
+	unp->unp_txstopped = true;
 	unp->unp_attached = true;
 }
 
@@ -1408,7 +1455,7 @@ usbnet_attach_mii(struct usbnet *un, const struct usbnet_mii *unm)
 
 	usbnet_ec(un)->ec_mii = mii;
 	ifmedia_init_with_lock(&mii->mii_media, 0,
-	    usbnet_media_upd, ether_mediastatus, &unp->unp_core_lock);
+	    usbnet_media_upd, ether_mediastatus, &unp->unp_miilock);
 	mii_attach(un->un_dev, mii, unm->un_mii_capmask, unm->un_mii_phyloc,
 	    unm->un_mii_offset, unm->un_mii_flags);
 
@@ -1537,7 +1584,7 @@ usbnet_detach(device_t self, int flags)
 	rnd_detach_source(&unp->unp_rndsrc);
 
 	mutex_destroy(&unp->unp_mcastlock);
-	mutex_destroy(&unp->unp_core_lock);
+	mutex_destroy(&unp->unp_miilock);
 	mutex_destroy(&unp->unp_rxlock);
 	mutex_destroy(&unp->unp_txlock);
 
@@ -1574,11 +1621,17 @@ usbnet_activate(device_t self, devact_t act)
 
 		atomic_store_relaxed(&unp->unp_dying, true);
 
+		mutex_enter(&unp->unp_miilock);
+		unp->unp_stopped = true;
+		mutex_exit(&unp->unp_miilock);
+
 		mutex_enter(&unp->unp_rxlock);
+		unp->unp_rxstopped = true;
+		mutex_exit(&unp->unp_rxlock);
+
 		mutex_enter(&unp->unp_txlock);
-		unp->unp_stopping = true;
+		unp->unp_txstopped = true;
 		mutex_exit(&unp->unp_txlock);
-		mutex_exit(&unp->unp_rxlock);
 
 		return 0;
 	default:
diff --git a/sys/dev/usb/usbnet.h b/sys/dev/usb/usbnet.h
index 1ffd3bf86374..3c6dd5dd763a 100644
--- a/sys/dev/usb/usbnet.h
+++ b/sys/dev/usb/usbnet.h
@@ -285,6 +285,7 @@ void *usbnet_softc(struct usbnet *);
 
 bool usbnet_havelink(struct usbnet *);
 bool usbnet_isdying(struct usbnet *);
+bool usbnet_ispromisc(struct usbnet *);
 
 /*
  * Endpoint / rx/tx chain management: