Module Name:    src
Committed By:   skrll
Date:           Mon Dec 12 13:15:39 UTC 2016

Modified Files:
        src/sys/dev/usb [nick-nhusb]: if_aue.c if_auereg.h if_axe.c if_axen.c
            if_axenreg.h if_axereg.h if_cdce.c if_cdcereg.h if_cue.c
            if_cuereg.h if_udav.c if_udavreg.h

Log Message:
WIP MPification


To generate a diff of this commit:
cvs rdiff -u -r1.132.4.13 -r1.132.4.14 src/sys/dev/usb/if_aue.c
cvs rdiff -u -r1.25.24.3 -r1.25.24.4 src/sys/dev/usb/if_auereg.h
cvs rdiff -u -r1.67.4.12 -r1.67.4.13 src/sys/dev/usb/if_axe.c
cvs rdiff -u -r1.3.6.12 -r1.3.6.13 src/sys/dev/usb/if_axen.c
cvs rdiff -u -r1.1.12.2 -r1.1.12.3 src/sys/dev/usb/if_axenreg.h
cvs rdiff -u -r1.16.6.4 -r1.16.6.5 src/sys/dev/usb/if_axereg.h
cvs rdiff -u -r1.38.14.9 -r1.38.14.10 src/sys/dev/usb/if_cdce.c
cvs rdiff -u -r1.7.24.4 -r1.7.24.5 src/sys/dev/usb/if_cdcereg.h
cvs rdiff -u -r1.68.4.12 -r1.68.4.13 src/sys/dev/usb/if_cue.c
cvs rdiff -u -r1.18.24.4 -r1.18.24.5 src/sys/dev/usb/if_cuereg.h
cvs rdiff -u -r1.43.4.11 -r1.43.4.12 src/sys/dev/usb/if_udav.c
cvs rdiff -u -r1.9.16.4 -r1.9.16.5 src/sys/dev/usb/if_udavreg.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/usb/if_aue.c
diff -u src/sys/dev/usb/if_aue.c:1.132.4.13 src/sys/dev/usb/if_aue.c:1.132.4.14
--- src/sys/dev/usb/if_aue.c:1.132.4.13	Mon Dec  5 10:55:18 2016
+++ src/sys/dev/usb/if_aue.c	Mon Dec 12 13:15:39 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_aue.c,v 1.132.4.13 2016/12/05 10:55:18 skrll Exp $	*/
+/*	$NetBSD: if_aue.c,v 1.132.4.14 2016/12/12 13:15:39 skrll Exp $	*/
 
 /*
  * Copyright (c) 1997, 1998, 1999, 2000
@@ -71,14 +71,13 @@
  * TODO:
  * better error messages from rxstat
  * split out if_auevar.h
- * add thread to avoid register reads from interrupt context
  * more error checks
  * investigate short rx problem
  * proper cleanup on errors
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_aue.c,v 1.132.4.13 2016/12/05 10:55:18 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_aue.c,v 1.132.4.14 2016/12/12 13:15:39 skrll Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_usb.h"
@@ -217,11 +216,11 @@ extern struct cfdriver aue_cd;
 CFATTACH_DECL_NEW(aue, sizeof(struct aue_softc), aue_match, aue_attach,
     aue_detach, aue_activate);
 
-Static void aue_multithread(void *);
-
 Static void aue_reset_pegasus_II(struct aue_softc *);
 Static int aue_tx_list_init(struct aue_softc *);
+Static void aue_tx_list_free(struct aue_softc *);
 Static int aue_rx_list_init(struct aue_softc *);
+Static void aue_rx_list_free(struct aue_softc *);
 Static int aue_newbuf(struct aue_softc *, struct aue_chain *, struct mbuf *);
 Static int aue_send(struct aue_softc *, struct mbuf *, int);
 Static void aue_intr(struct usbd_xfer *, void *, usbd_status);
@@ -230,11 +229,14 @@ Static void aue_txeof(struct usbd_xfer *
 Static void aue_tick(void *);
 Static void aue_tick_task(void *);
 Static void aue_start(struct ifnet *);
+Static void aue_start_locked(struct ifnet *);
 Static int aue_ioctl(struct ifnet *, u_long, void *);
-Static void aue_init(void *);
-Static void aue_stop(struct aue_softc *);
+Static int aue_ifflags_cb(struct ethercom *);
+Static int aue_init(struct ifnet *);
+Static int aue_init_locked(struct ifnet *);
+Static void aue_stop(struct ifnet *, int);
+Static void aue_stop_locked(struct ifnet *, int);
 Static void aue_watchdog(struct ifnet *);
-Static int aue_openpipes(struct aue_softc *);
 Static int aue_ifmedia_upd(struct ifnet *);
 
 Static int aue_eeprom_getword(struct aue_softc *, int);
@@ -723,7 +725,6 @@ aue_attach(device_t parent, device_t sel
 	struct aue_softc *sc = device_private(self);
 	struct usb_attach_arg *uaa = aux;
 	char			*devinfop;
-	int			s;
 	u_char			eaddr[ETHER_ADDR_LEN];
 	struct ifnet		*ifp;
 	struct mii_data		*mii;
@@ -755,6 +756,9 @@ aue_attach(device_t parent, device_t sel
 	usb_init_task(&sc->aue_tick_task, aue_tick_task, sc, 0);
 	usb_init_task(&sc->aue_stop_task, (void (*)(void *))aue_stop, sc, 0);
 	mutex_init(&sc->aue_mii_lock, MUTEX_DEFAULT, IPL_NONE);
+	mutex_init(&sc->aue_lock, MUTEX_DEFAULT, IPL_NONE);
+	mutex_init(&sc->aue_txlock, MUTEX_DEFAULT, IPL_SOFTUSB);
+	mutex_init(&sc->aue_rxlock, MUTEX_DEFAULT, IPL_SOFTUSB);
 
 	err = usbd_device2interface_handle(dev, AUE_IFACE_IDX, &iface);
 	if (err) {
@@ -764,13 +768,8 @@ aue_attach(device_t parent, device_t sel
 	sc->aue_closing = 0;
 
 	mutex_init(&sc->aue_mcmtx, MUTEX_DRIVER, IPL_NET);
-	cv_init(&sc->aue_domc, "auemc");
 	cv_init(&sc->aue_closemc, "auemccl");
 
-	err = kthread_create(PRI_NONE, 0, NULL,
-		aue_multithread, sc, &sc->aue_thread,
-		"%s-mc", device_xname(sc->aue_dev));
-
 	if (err) {
 		aprint_error_dev(self,
 		    "creating multicast configuration thread\n");
@@ -813,7 +812,6 @@ aue_attach(device_t parent, device_t sel
 	}
 
 
-	s = splnet();
 
 	/* Reset the adapter. */
 	aue_reset(sc);
@@ -833,6 +831,8 @@ aue_attach(device_t parent, device_t sel
 	ifp->if_softc = sc;
 	ifp->if_mtu = ETHERMTU;
 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+	ifp->if_extflags = IFEF_START_MPSAFE;
+	ifp->if_init = aue_init;
 	ifp->if_ioctl = aue_ioctl;
 	ifp->if_start = aue_start;
 	ifp->if_watchdog = aue_watchdog;
@@ -857,15 +857,17 @@ aue_attach(device_t parent, device_t sel
 		ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_AUTO);
 
 	/* Attach the interface. */
-	if_attach(ifp);
+	if_initialize(ifp);
+	sc->aue_ipq = if_percpuq_create(&sc->aue_ec.ec_if);
 	ether_ifattach(ifp, eaddr);
+	if_register(ifp);
+	ether_set_ifflags_cb(&sc->aue_ec, aue_ifflags_cb);
 	rnd_attach_source(&sc->rnd_source, device_xname(sc->aue_dev),
 	    RND_TYPE_NET, RND_FLAG_DEFAULT);
 
 	callout_init(&(sc->aue_stat_ch), 0);
 
 	sc->aue_attached = 1;
-	splx(s);
 
 	usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->aue_udev, sc->aue_dev);
 
@@ -895,20 +897,18 @@ aue_detach(device_t self, int flags)
 	usb_rem_task(sc->aue_udev, &sc->aue_stop_task);
 
 	sc->aue_closing = 1;
-	cv_signal(&sc->aue_domc);
 
 	mutex_enter(&sc->aue_mcmtx);
 	cv_wait(&sc->aue_closemc,&sc->aue_mcmtx);
 	mutex_exit(&sc->aue_mcmtx);
 
 	mutex_destroy(&sc->aue_mcmtx);
-	cv_destroy(&sc->aue_domc);
 	cv_destroy(&sc->aue_closemc);
 
 	s = splusb();
 
 	if (ifp->if_flags & IFF_RUNNING)
-		aue_stop(sc);
+		aue_stop(ifp, 1);
 
 	rnd_detach_source(&sc->rnd_source);
 	mii_detach(&sc->aue_mii, MII_PHY_ANY, MII_OFFSET_ANY);
@@ -1025,6 +1025,22 @@ aue_rx_list_init(struct aue_softc *sc)
 	return 0;
 }
 
+Static void
+aue_rx_list_free(struct aue_softc *sc)
+{
+	/* Free RX resources. */
+	for (int i = 0; i < AUE_RX_LIST_CNT; i++) {
+		if (sc->aue_cdata.aue_rx_chain[i].aue_mbuf != NULL) {
+			m_freem(sc->aue_cdata.aue_rx_chain[i].aue_mbuf);
+			sc->aue_cdata.aue_rx_chain[i].aue_mbuf = NULL;
+		}
+		if (sc->aue_cdata.aue_rx_chain[i].aue_xfer != NULL) {
+			usbd_destroy_xfer(sc->aue_cdata.aue_rx_chain[i].aue_xfer);
+			sc->aue_cdata.aue_rx_chain[i].aue_xfer = NULL;
+		}
+	}
+}
+
 Static int
 aue_tx_list_init(struct aue_softc *sc)
 {
@@ -1054,6 +1070,22 @@ aue_tx_list_init(struct aue_softc *sc)
 }
 
 Static void
+aue_tx_list_free(struct aue_softc *sc)
+{
+	/* Free TX resources. */
+	for (int i = 0; i < AUE_TX_LIST_CNT; i++) {
+		if (sc->aue_cdata.aue_tx_chain[i].aue_mbuf != NULL) {
+			m_freem(sc->aue_cdata.aue_tx_chain[i].aue_mbuf);
+			sc->aue_cdata.aue_tx_chain[i].aue_mbuf = NULL;
+		}
+		if (sc->aue_cdata.aue_tx_chain[i].aue_xfer != NULL) {
+			usbd_destroy_xfer(sc->aue_cdata.aue_tx_chain[i].aue_xfer);
+			sc->aue_cdata.aue_tx_chain[i].aue_xfer = NULL;
+		}
+	}
+}
+
+Static void
 aue_intr(struct usbd_xfer *xfer, void *priv,
     usbd_status status)
 {
@@ -1346,6 +1378,17 @@ aue_send(struct aue_softc *sc, struct mb
 Static void
 aue_start(struct ifnet *ifp)
 {
+	struct aue_softc *sc = ifp->if_softc;
+	KASSERT(ifp->if_extflags & IFEF_START_MPSAFE);
+
+	mutex_enter(&sc->aue_txlock);
+	aue_start_locked(ifp);
+	mutex_exit(&sc->aue_txlock);
+}
+
+Static void
+aue_start_locked(struct ifnet *ifp)
+{
 	struct aue_softc	*sc = ifp->if_softc;
 	struct mbuf		*m_head = NULL;
 
@@ -1366,7 +1409,6 @@ aue_start(struct ifnet *ifp)
 		return;
 
 	if (aue_send(sc, m_head, 0)) {
-		ifp->if_flags |= IFF_OACTIVE;
 		return;
 	}
 
@@ -1386,24 +1428,33 @@ aue_start(struct ifnet *ifp)
 	ifp->if_timer = 5;
 }
 
-Static void
-aue_init(void *xsc)
+Static int
+aue_init(struct ifnet *ifp)
 {
-	struct aue_softc	*sc = xsc;
-	struct ifnet		*ifp = GET_IFP(sc);
+	struct aue_softc	*sc = ifp->if_softc;
+
+	mutex_enter(&sc->aue_lock);
+	int ret = aue_init_locked(ifp);
+	mutex_exit(&sc->aue_lock);
+
+	return ret;
+}
+
+Static int
+aue_init_locked(struct ifnet *ifp)
+{
+	struct aue_softc	*sc = ifp->if_softc;
 	struct mii_data		*mii = GET_MII(sc);
-	int			i, s;
+	int			i;
 	const u_char		*eaddr;
+	usbd_status		err;
 
 	DPRINTFN(5,("%s: %s: enter\n", device_xname(sc->aue_dev), __func__));
 
 	if (sc->aue_dying)
-		return;
-
-	if (ifp->if_flags & IFF_RUNNING)
-		return;
+		return EIO;
 
-	s = splnet();
+	aue_stop_locked(ifp, 1);
 
 	/*
 	 * Cancel pending I/O and free all RX/TX buffers.
@@ -1421,23 +1472,41 @@ aue_init(void *xsc)
 		AUE_CLRBIT(sc, AUE_CTL2, AUE_CTL2_RX_PROMISC);
 
 	if (sc->aue_ep[AUE_ENDPT_RX] == NULL) {
-		if (aue_openpipes(sc)) {
-			splx(s);
-			return;
+		/* Open RX and TX pipes. */
+		err = usbd_open_pipe(sc->aue_iface, sc->aue_ed[AUE_ENDPT_RX],
+		USBD_EXCLUSIVE_USE, &sc->aue_ep[AUE_ENDPT_RX]);
+		if (err) {
+			aprint_error_dev(sc->aue_dev, "open rx pipe failed: %s\n",
+			usbd_errstr(err));
+			goto fail;
+		}
+		err = usbd_open_pipe(sc->aue_iface, sc->aue_ed[AUE_ENDPT_TX],
+		USBD_EXCLUSIVE_USE, &sc->aue_ep[AUE_ENDPT_TX]);
+		if (err) {
+			aprint_error_dev(sc->aue_dev, "open tx pipe failed: %s\n",
+			usbd_errstr(err));
+			goto fail1;
+		}
+		err = usbd_open_pipe_intr(sc->aue_iface, sc->aue_ed[AUE_ENDPT_INTR],
+			USBD_EXCLUSIVE_USE, &sc->aue_ep[AUE_ENDPT_INTR], sc,
+			&sc->aue_cdata.aue_ibuf, AUE_INTR_PKTLEN, aue_intr,
+			AUE_INTR_INTERVAL);
+		if (err) {
+			aprint_error_dev(sc->aue_dev, "open intr pipe failed: %s\n",
+			usbd_errstr(err));
+			goto fail2;
 		}
 	}
 	/* Init TX ring. */
 	if (aue_tx_list_init(sc)) {
 		aprint_error_dev(sc->aue_dev, "tx list init failed\n");
-		splx(s);
-		return;
+		goto fail3;
 	}
 
 	/* Init RX ring. */
 	if (aue_rx_list_init(sc)) {
 		aprint_error_dev(sc->aue_dev, "rx list init failed\n");
-		splx(s);
-		return;
+		goto fail4;
 	}
 
 	/* Start up the receive pipe. */
@@ -1465,42 +1534,19 @@ aue_init(void *xsc)
 	ifp->if_flags |= IFF_RUNNING;
 	ifp->if_flags &= ~IFF_OACTIVE;
 
-	splx(s);
-
 	callout_reset(&(sc->aue_stat_ch), (hz), (aue_tick), (sc));
-}
-
-Static int
-aue_openpipes(struct aue_softc *sc)
-{
-	usbd_status		err;
-
-	/* Open RX and TX pipes. */
-	err = usbd_open_pipe(sc->aue_iface, sc->aue_ed[AUE_ENDPT_RX],
-	    USBD_EXCLUSIVE_USE, &sc->aue_ep[AUE_ENDPT_RX]);
-	if (err) {
-		aprint_error_dev(sc->aue_dev, "open rx pipe failed: %s\n",
-		    usbd_errstr(err));
-		return EIO;
-	}
-	err = usbd_open_pipe(sc->aue_iface, sc->aue_ed[AUE_ENDPT_TX],
-	    USBD_EXCLUSIVE_USE, &sc->aue_ep[AUE_ENDPT_TX]);
-	if (err) {
-		aprint_error_dev(sc->aue_dev, "open tx pipe failed: %s\n",
-		    usbd_errstr(err));
-		return EIO;
-	}
-	err = usbd_open_pipe_intr(sc->aue_iface, sc->aue_ed[AUE_ENDPT_INTR],
-	    USBD_EXCLUSIVE_USE, &sc->aue_ep[AUE_ENDPT_INTR], sc,
-	    &sc->aue_cdata.aue_ibuf, AUE_INTR_PKTLEN, aue_intr,
-	    AUE_INTR_INTERVAL);
-	if (err) {
-		aprint_error_dev(sc->aue_dev, "open intr pipe failed: %s\n",
-		    usbd_errstr(err));
-		return EIO;
-	}
-
 	return 0;
+
+fail4:
+	aue_tx_list_free(sc);
+fail3:
+	usbd_close_pipe(sc->aue_ep[AUE_ENDPT_INTR]);
+fail2:
+	usbd_close_pipe(sc->aue_ep[AUE_ENDPT_TX]);
+fail1:
+	usbd_close_pipe(sc->aue_ep[AUE_ENDPT_RX]);
+fail:
+	return EIO;
 }
 
 /*
@@ -1529,76 +1575,42 @@ Static int
 aue_ioctl(struct ifnet *ifp, u_long command, void *data)
 {
 	struct aue_softc	*sc = ifp->if_softc;
-	struct ifaddr 		*ifa = (struct ifaddr *)data;
-	struct ifreq		*ifr = (struct ifreq *)data;
 	int			s, error = 0;
 
 	if (sc->aue_dying)
 		return EIO;
 
 	s = splnet();
+	error = ether_ioctl(ifp, command, data);
+	splx(s);
 
-	switch(command) {
-	case SIOCINITIFADDR:
-		ifp->if_flags |= IFF_UP;
-		aue_init(sc);
+	return error;
+}
 
-		switch (ifa->ifa_addr->sa_family) {
-#ifdef INET
-		case AF_INET:
-			arp_ifinit(ifp, ifa);
-			break;
-#endif /* INET */
-		}
-		break;
+Static int
+aue_ifflags_cb(struct ethercom *ec)
+{
+	struct ifnet *ifp = &ec->ec_if;
+	struct aue_softc *sc = ifp->if_softc;
 
-	case SIOCSIFMTU:
-		if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > ETHERMTU)
-			error = EINVAL;
-		else if ((error = ifioctl_common(ifp, command, data)) == ENETRESET)
-			error = 0;
-		break;
+	mutex_enter(&sc->aue_lock);
 
-	case SIOCSIFFLAGS:
-		if ((error = ifioctl_common(ifp, command, data)) != 0)
-			break;
-		if (ifp->if_flags & IFF_UP) {
-			if (ifp->if_flags & IFF_RUNNING &&
-			    ifp->if_flags & IFF_PROMISC &&
-			    !(sc->aue_if_flags & IFF_PROMISC)) {
-				AUE_SETBIT(sc, AUE_CTL2, AUE_CTL2_RX_PROMISC);
-			} else if (ifp->if_flags & IFF_RUNNING &&
-			    !(ifp->if_flags & IFF_PROMISC) &&
-			    sc->aue_if_flags & IFF_PROMISC) {
-				AUE_CLRBIT(sc, AUE_CTL2, AUE_CTL2_RX_PROMISC);
-			} else if (!(ifp->if_flags & IFF_RUNNING))
-				aue_init(sc);
-		} else {
-			if (ifp->if_flags & IFF_RUNNING)
-				aue_stop(sc);
-		}
-		sc->aue_if_flags = ifp->if_flags;
-		error = 0;
-		break;
-	case SIOCADDMULTI:
-	case SIOCDELMULTI:
-	case SIOCGIFMEDIA:
-	case SIOCSIFMEDIA:
-		if ((error = ether_ioctl(ifp, command, data)) == ENETRESET) {
-			if (ifp->if_flags & IFF_RUNNING) {
-				cv_signal(&sc->aue_domc);
-			}
-			error = 0;
+	if (ifp->if_flags & IFF_UP) {
+		if (ifp->if_flags & IFF_RUNNING &&
+		    ifp->if_flags & IFF_PROMISC &&
+		    !(sc->aue_if_flags & IFF_PROMISC)) {
+			AUE_SETBIT(sc, AUE_CTL2, AUE_CTL2_RX_PROMISC);
+		} else if (ifp->if_flags & IFF_RUNNING &&
+		    !(ifp->if_flags & IFF_PROMISC) &&
+		    sc->aue_if_flags & IFF_PROMISC) {
+			AUE_CLRBIT(sc, AUE_CTL2, AUE_CTL2_RX_PROMISC);
 		}
-		break;
-	default:
-		error = ether_ioctl(ifp, command, data);
-		break;
 	}
+	sc->aue_if_flags = ifp->if_flags;
+	aue_setmulti(sc);
+	mutex_exit(&sc->aue_lock);
 
-	splx(s);
-
-	return error;
+	return 0;
 }
 
 Static void
@@ -1629,15 +1641,23 @@ aue_watchdog(struct ifnet *ifp)
  * RX and TX lists.
  */
 Static void
-aue_stop(struct aue_softc *sc)
+aue_stop(struct ifnet *ifp, int disable)
+{
+	struct aue_softc *sc = ifp->if_softc;
+
+	mutex_enter(&sc->aue_lock);
+	aue_stop_locked(ifp, disable);
+	mutex_exit(&sc->aue_lock);
+}
+
+Static void
+aue_stop_locked(struct ifnet *ifp, int disable)
 {
 	usbd_status		err;
-	struct ifnet		*ifp;
-	int			i;
+	struct aue_softc	*sc = ifp->if_softc;
 
 	DPRINTFN(5,("%s: %s: enter\n", device_xname(sc->aue_dev), __func__));
 
-	ifp = GET_IFP(sc);
 	ifp->if_timer = 0;
 
 	aue_csr_write_1(sc, AUE_CTL0, 0);
@@ -1676,29 +1696,9 @@ aue_stop(struct aue_softc *sc)
 		}
 	}
 
-	/* Free RX resources. */
-	for (i = 0; i < AUE_RX_LIST_CNT; i++) {
-		if (sc->aue_cdata.aue_rx_chain[i].aue_mbuf != NULL) {
-			m_freem(sc->aue_cdata.aue_rx_chain[i].aue_mbuf);
-			sc->aue_cdata.aue_rx_chain[i].aue_mbuf = NULL;
-		}
-		if (sc->aue_cdata.aue_rx_chain[i].aue_xfer != NULL) {
-			usbd_destroy_xfer(sc->aue_cdata.aue_rx_chain[i].aue_xfer);
-			sc->aue_cdata.aue_rx_chain[i].aue_xfer = NULL;
-		}
-	}
+	aue_rx_list_free(sc);
 
-	/* Free TX resources. */
-	for (i = 0; i < AUE_TX_LIST_CNT; i++) {
-		if (sc->aue_cdata.aue_tx_chain[i].aue_mbuf != NULL) {
-			m_freem(sc->aue_cdata.aue_tx_chain[i].aue_mbuf);
-			sc->aue_cdata.aue_tx_chain[i].aue_mbuf = NULL;
-		}
-		if (sc->aue_cdata.aue_tx_chain[i].aue_xfer != NULL) {
-			usbd_destroy_xfer(sc->aue_cdata.aue_tx_chain[i].aue_xfer);
-			sc->aue_cdata.aue_tx_chain[i].aue_xfer = NULL;
-		}
-	}
+	aue_tx_list_free(sc);
 
 	/* Close pipes */
 	if (sc->aue_ep[AUE_ENDPT_TX] != NULL) {
@@ -1724,30 +1724,3 @@ aue_stop(struct aue_softc *sc)
 	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
 }
 
-Static void
-aue_multithread(void *arg)
-{
-	struct aue_softc *sc;
-	int s;
-
-	sc = (struct aue_softc *)arg;
-
-	while (1) {
-		mutex_enter(&sc->aue_mcmtx);
-		cv_wait(&sc->aue_domc,&sc->aue_mcmtx);
-		mutex_exit(&sc->aue_mcmtx);
-
-		if (sc->aue_closing)
-			break;
-
-		s = splnet();
-		aue_init(sc);
-		/* XXX called by aue_init, but rc ifconfig hangs without it: */
-		aue_setmulti(sc);
-		splx(s);
-	}
-
-	cv_signal(&sc->aue_closemc);
-
-	kthread_exit(0);
-}

Index: src/sys/dev/usb/if_auereg.h
diff -u src/sys/dev/usb/if_auereg.h:1.25.24.3 src/sys/dev/usb/if_auereg.h:1.25.24.4
--- src/sys/dev/usb/if_auereg.h:1.25.24.3	Sat Jun  6 14:40:13 2015
+++ src/sys/dev/usb/if_auereg.h	Mon Dec 12 13:15:39 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_auereg.h,v 1.25.24.3 2015/06/06 14:40:13 skrll Exp $	*/
+/*	$NetBSD: if_auereg.h,v 1.25.24.4 2016/12/12 13:15:39 skrll Exp $	*/
 /*
  * Copyright (c) 1997, 1998, 1999
  *	Bill Paul <wp...@ee.columbia.edu>.  All rights reserved.
@@ -233,7 +233,6 @@ struct aue_softc {
 	krndsource_t	rnd_source;
 	struct lwp		*aue_thread;
 	int			aue_closing;
-	kcondvar_t		aue_domc;
 	kcondvar_t		aue_closemc;
 	kmutex_t		aue_mcmtx;
 #define GET_IFP(sc) (&(sc)->aue_ec.ec_if)
@@ -264,6 +263,11 @@ struct aue_softc {
 	struct usb_task		aue_stop_task;
 
 	kmutex_t		aue_mii_lock;
+	kmutex_t		aue_lock;
+	kmutex_t		aue_txlock;
+	kmutex_t		aue_rxlock;
+
+	struct if_percpuq	*aue_ipq;
 };
 
 #define AUE_TIMEOUT		1000

Index: src/sys/dev/usb/if_axe.c
diff -u src/sys/dev/usb/if_axe.c:1.67.4.12 src/sys/dev/usb/if_axe.c:1.67.4.13
--- src/sys/dev/usb/if_axe.c:1.67.4.12	Mon Dec  5 10:55:18 2016
+++ src/sys/dev/usb/if_axe.c	Mon Dec 12 13:15:39 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_axe.c,v 1.67.4.12 2016/12/05 10:55:18 skrll Exp $	*/
+/*	$NetBSD: if_axe.c,v 1.67.4.13 2016/12/12 13:15:39 skrll Exp $	*/
 /*	$OpenBSD: if_axe.c,v 1.137 2016/04/13 11:03:37 mpi Exp $ */
 
 /*
@@ -87,7 +87,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_axe.c,v 1.67.4.12 2016/12/05 10:55:18 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_axe.c,v 1.67.4.13 2016/12/12 13:15:39 skrll Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -246,16 +246,23 @@ CFATTACH_DECL_NEW(axe, sizeof(struct axe
 	axe_match, axe_attach, axe_detach, axe_activate);
 
 static int	axe_tx_list_init(struct axe_softc *);
+#if 0
+static void	axe_tx_list_free(struct axe_softc *);
+#endif
 static int	axe_rx_list_init(struct axe_softc *);
+static void	axe_rx_list_free(struct axe_softc *);
 static int	axe_encap(struct axe_softc *, struct mbuf *, int);
 static void	axe_rxeof(struct usbd_xfer *, void *, usbd_status);
 static void	axe_txeof(struct usbd_xfer *, void *, usbd_status);
 static void	axe_tick(void *);
 static void	axe_tick_task(void *);
 static void	axe_start(struct ifnet *);
+static void	axe_start_locked(struct ifnet *);
 static int	axe_ioctl(struct ifnet *, u_long, void *);
 static int	axe_init(struct ifnet *);
+static int	axe_init_locked(struct ifnet *);
 static void	axe_stop(struct ifnet *, int);
+static void	axe_stop_locked(struct ifnet *, int);
 static void	axe_watchdog(struct ifnet *);
 static int	axe_miibus_readreg_locked(device_t, int, int);
 static int	axe_miibus_readreg(device_t, int, int);
@@ -741,6 +748,32 @@ axe_ax88772_init(struct axe_softc *sc)
 	axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL);
 }
 
+static int
+axe_ifflags_cb(struct ethercom *ec)
+{
+	struct ifnet *ifp = &ec->ec_if;
+	struct axe_softc *sc = ifp->if_softc;
+	int rc = 0;
+
+	mutex_enter(&sc->axe_lock);
+	int change = ifp->if_flags ^ sc->axe_if_flags;
+	sc->axe_if_flags = ifp->if_flags;
+
+	if ((change & ~(IFF_CANTCHANGE | IFF_DEBUG)) != 0) {
+		rc = ENETRESET;
+		goto out;
+	}
+
+	if ((change & IFF_PROMISC) != 0) {
+		axe_setmulti(sc);
+	}
+
+out:
+	mutex_exit(&sc->axe_lock);
+
+	return rc;
+}
+
 static void
 axe_ax88772_phywake(struct axe_softc *sc)
 {
@@ -887,6 +920,9 @@ axe_attach(device_t parent, device_t sel
 
 	sc->axe_flags = axe_lookup(uaa->uaa_vendor, uaa->uaa_product)->axe_flags;
 
+	mutex_init(&sc->axe_lock, MUTEX_DEFAULT, IPL_NONE);
+	mutex_init(&sc->axe_txlock, MUTEX_DEFAULT, IPL_SOFTUSB);
+	mutex_init(&sc->axe_rxlock, MUTEX_DEFAULT, IPL_SOFTUSB);
 	mutex_init(&sc->axe_mii_lock, MUTEX_DEFAULT, IPL_NONE);
 	usb_init_task(&sc->axe_tick_task, axe_tick_task, sc, 0);
 
@@ -990,6 +1026,7 @@ axe_attach(device_t parent, device_t sel
 	ifp->if_softc = sc;
 	strncpy(ifp->if_xname, devname, IFNAMSIZ);
 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+	ifp->if_extflags = IFEF_START_MPSAFE;
 	ifp->if_ioctl = axe_ioctl;
 	ifp->if_start = axe_start;
 	ifp->if_init = axe_init;
@@ -1043,8 +1080,12 @@ axe_attach(device_t parent, device_t sel
 		ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_AUTO);
 
 	/* Attach the interface. */
-	if_attach(ifp);
+	if_initialize(ifp);
+	sc->axe_ipq = if_percpuq_create(&sc->axe_ec.ec_if);
 	ether_ifattach(ifp, sc->axe_enaddr);
+	if_register(ifp);
+	ether_set_ifflags_cb(&sc->axe_ec, axe_ifflags_cb);
+
 	rnd_attach_source(&sc->rnd_source, device_xname(sc->axe_dev),
 	    RND_TYPE_NET, RND_FLAG_DEFAULT);
 
@@ -1101,6 +1142,9 @@ axe_detach(device_t self, int flags)
 	}
 
 	callout_destroy(&sc->axe_stat_ch);
+	mutex_destroy(&sc->axe_lock);
+	mutex_destroy(&sc->axe_txlock);
+	mutex_destroy(&sc->axe_rxlock);
 	mutex_destroy(&sc->axe_mii_lock);
 	rnd_detach_source(&sc->rnd_source);
 	mii_detach(&sc->axe_mii, MII_PHY_ANY, MII_OFFSET_ANY);
@@ -1166,6 +1210,18 @@ axe_rx_list_init(struct axe_softc *sc)
 	return 0;
 }
 
+static void
+axe_rx_list_free(struct axe_softc *sc)
+{
+	/* Free RX resources */
+	for (size_t i = 0; i < AXE_RX_LIST_CNT; i++) {
+		if (sc->axe_cdata.axe_rx_chain[i].axe_xfer != NULL) {
+			usbd_destroy_xfer(sc->axe_cdata.axe_rx_chain[i].axe_xfer);
+			sc->axe_cdata.axe_rx_chain[i].axe_xfer = NULL;
+		}
+	}
+}
+
 static int
 axe_tx_list_init(struct axe_softc *sc)
 {
@@ -1192,6 +1248,18 @@ axe_tx_list_init(struct axe_softc *sc)
 	return 0;
 }
 
+static void
+axe_tx_list_free(struct axe_softc *sc)
+{
+	/* Free TX resources */
+	for (size_t i = 0; i < AXE_TX_LIST_CNT; i++) {
+		if (sc->axe_cdata.axe_tx_chain[i].axe_xfer != NULL) {
+			usbd_destroy_xfer(sc->axe_cdata.axe_tx_chain[i].axe_xfer);
+			sc->axe_cdata.axe_tx_chain[i].axe_xfer = NULL;
+		}
+	}
+}
+
 /*
  * A frame has been uploaded: pass the resulting mbuf chain up to
  * the higher level protocols.
@@ -1206,7 +1274,6 @@ axe_rxeof(struct usbd_xfer *xfer, void *
 	uint8_t *buf;
 	uint32_t total_len;
 	struct mbuf *m;
-	int s;
 
 	c = (struct axe_chain *)priv;
 	sc = c->axe_sc;
@@ -1374,13 +1441,9 @@ axe_rxeof(struct usbd_xfer *xfer, void *
 
 		DPRINTFN(10, "deliver %d (%#x)", m->m_len, m->m_len, 0, 0);
 
-		s = splnet();
-
 		bpf_mtap(ifp, m);
 
-		if_percpuq_enqueue((ifp)->if_percpuq, (m));
-
-		splx(s);
+		if_percpuq_enqueue(sc->axe_ipq, (m));
 
 	} while (total_len > 0);
 
@@ -1587,10 +1650,18 @@ axe_csum_cfg(struct axe_softc *sc)
 static void
 axe_start(struct ifnet *ifp)
 {
-	struct axe_softc *sc;
-	struct mbuf *m;
+	struct axe_softc *sc = ifp->if_softc;
 
-	sc = ifp->if_softc;
+	mutex_enter(&sc->axe_txlock);
+	axe_start_locked(ifp);
+	mutex_exit(&sc->axe_txlock);
+}
+
+static void
+axe_start_locked(struct ifnet *ifp)
+{
+	struct axe_softc *sc = ifp->if_softc;
+	struct mbuf *m;
 
 	if ((ifp->if_flags & (IFF_OACTIVE|IFF_RUNNING)) != IFF_RUNNING)
 		return;
@@ -1601,7 +1672,6 @@ axe_start(struct ifnet *ifp)
 	}
 
 	if (axe_encap(sc, m, 0)) {
-		ifp->if_flags |= IFF_OACTIVE;
 		return;
 	}
 	IFQ_DEQUEUE(&ifp->if_snd, m);
@@ -1626,17 +1696,25 @@ axe_start(struct ifnet *ifp)
 static int
 axe_init(struct ifnet *ifp)
 {
+	struct axe_softc *sc = ifp->if_softc;
+
+	mutex_enter(&sc->axe_lock);
+	int ret = axe_init_locked(ifp);
+	mutex_exit(&sc->axe_lock);
+
+	return ret;
+}
+
+static int
+axe_init_locked(struct ifnet *ifp)
+{
 	AXEHIST_FUNC(); AXEHIST_CALLED();
 	struct axe_softc *sc = ifp->if_softc;
-	struct axe_chain *c;
 	usbd_status err;
 	int rxmode;
-	int i, s;
+	int i, error;
 
-	s = splnet();
-
-	if (ifp->if_flags & IFF_RUNNING)
-		axe_stop(ifp, 0);
+	axe_stop_locked(ifp, 0);
 
 	/*
 	 * Cancel pending I/O and free all RX/TX buffers.
@@ -1735,8 +1813,8 @@ axe_init(struct ifnet *ifp)
 	if (err) {
 		aprint_error_dev(sc->axe_dev, "open rx pipe failed: %s\n",
 		    usbd_errstr(err));
-		splx(s);
-		return EIO;
+		error = EIO;
+		goto fail;
 	}
 
 	err = usbd_open_pipe(sc->axe_iface, sc->axe_ed[AXE_ENDPT_TX],
@@ -1744,27 +1822,27 @@ axe_init(struct ifnet *ifp)
 	if (err) {
 		aprint_error_dev(sc->axe_dev, "open tx pipe failed: %s\n",
 		    usbd_errstr(err));
-		splx(s);
-		return EIO;
+		error = EIO;
+		goto fail1;
 	}
 
 	/* Init RX ring. */
 	if (axe_rx_list_init(sc) != 0) {
 		aprint_error_dev(sc->axe_dev, "rx list init failed\n");
-		splx(s);
-		return ENOBUFS;
+		error = ENOBUFS;
+		goto fail2;
 	}
 
 	/* Init TX ring. */
 	if (axe_tx_list_init(sc) != 0) {
 		aprint_error_dev(sc->axe_dev, "tx list init failed\n");
-		splx(s);
-		return ENOBUFS;
+		error = ENOBUFS;
+		goto fail3;
 	}
 
 	/* Start up the receive pipe. */
 	for (i = 0; i < AXE_RX_LIST_CNT; i++) {
-		c = &sc->axe_cdata.axe_rx_chain[i];
+		struct axe_chain *c = &sc->axe_cdata.axe_rx_chain[i];
 		usbd_setup_xfer(c->axe_xfer, c, c->axe_buf, sc->axe_bufsz,
 		    USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, axe_rxeof);
 		usbd_transfer(c->axe_xfer);
@@ -1773,10 +1851,17 @@ axe_init(struct ifnet *ifp)
 	ifp->if_flags |= IFF_RUNNING;
 	ifp->if_flags &= ~IFF_OACTIVE;
 
-	splx(s);
-
 	callout_schedule(&sc->axe_stat_ch, hz);
+
 	return 0;
+fail3:
+	axe_rx_list_free(sc);
+fail2:
+	usbd_close_pipe(sc->axe_ep[AXE_ENDPT_TX]);
+fail1:
+	usbd_close_pipe(sc->axe_ep[AXE_ENDPT_RX]);
+fail:
+	return error;
 }
 
 static int
@@ -1787,40 +1872,19 @@ axe_ioctl(struct ifnet *ifp, u_long cmd,
 	int error = 0;
 
 	s = splnet();
+	error = ether_ioctl(ifp, cmd, data);
+	splx(s);
 
-	switch(cmd) {
-	case SIOCSIFFLAGS:
-		if ((error = ifioctl_common(ifp, cmd, data)) != 0)
-			break;
-
-		switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
-		case IFF_RUNNING:
-			axe_stop(ifp, 1);
-			break;
-		case IFF_UP:
-			axe_init(ifp);
-			break;
-		case IFF_UP | IFF_RUNNING:
-			if ((ifp->if_flags ^ sc->axe_if_flags) == IFF_PROMISC)
-				axe_setmulti(sc);
-			else
-				axe_init(ifp);
-			break;
-		}
-		sc->axe_if_flags = ifp->if_flags;
-		break;
-
-	default:
-		if ((error = ether_ioctl(ifp, cmd, data)) != ENETRESET)
-			break;
-
+	if (error == ENETRESET) {
 		error = 0;
-
-		if (cmd == SIOCADDMULTI || cmd == SIOCDELMULTI)
+		if (cmd != SIOCADDMULTI && cmd != SIOCDELMULTI)
+			;
+		else if (ifp->if_flags & IFF_RUNNING) {
+			mutex_enter(&sc->axe_lock);
 			axe_setmulti(sc);
-
+			mutex_exit(&sc->axe_lock);
+		}
 	}
-	splx(s);
 
 	return error;
 }
@@ -1852,12 +1916,22 @@ axe_watchdog(struct ifnet *ifp)
  * Stop the adapter and free any mbufs allocated to the
  * RX and TX lists.
  */
+
 static void
 axe_stop(struct ifnet *ifp, int disable)
 {
 	struct axe_softc *sc = ifp->if_softc;
+
+	mutex_enter(&sc->axe_lock);
+	axe_stop_locked(ifp, disable);
+	mutex_exit(&sc->axe_lock);
+}
+
+static void
+axe_stop_locked(struct ifnet *ifp, int disable)
+{
+	struct axe_softc *sc = ifp->if_softc;
 	usbd_status err;
-	int i;
 
 	ifp->if_timer = 0;
 	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
@@ -1891,21 +1965,9 @@ axe_stop(struct ifnet *ifp, int disable)
 
 	axe_reset(sc);
 
-	/* Free RX resources. */
-	for (i = 0; i < AXE_RX_LIST_CNT; i++) {
-		if (sc->axe_cdata.axe_rx_chain[i].axe_xfer != NULL) {
-			usbd_destroy_xfer(sc->axe_cdata.axe_rx_chain[i].axe_xfer);
-			sc->axe_cdata.axe_rx_chain[i].axe_xfer = NULL;
-		}
-	}
+	axe_rx_list_free(sc);
 
-	/* Free TX resources. */
-	for (i = 0; i < AXE_TX_LIST_CNT; i++) {
-		if (sc->axe_cdata.axe_tx_chain[i].axe_xfer != NULL) {
-			usbd_destroy_xfer(sc->axe_cdata.axe_tx_chain[i].axe_xfer);
-			sc->axe_cdata.axe_tx_chain[i].axe_xfer = NULL;
-		}
-	}
+	axe_tx_list_free(sc);
 
 	/* Close pipes. */
 	if (sc->axe_ep[AXE_ENDPT_RX] != NULL) {

Index: src/sys/dev/usb/if_axen.c
diff -u src/sys/dev/usb/if_axen.c:1.3.6.12 src/sys/dev/usb/if_axen.c:1.3.6.13
--- src/sys/dev/usb/if_axen.c:1.3.6.12	Mon Dec  5 10:55:18 2016
+++ src/sys/dev/usb/if_axen.c	Mon Dec 12 13:15:39 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_axen.c,v 1.3.6.12 2016/12/05 10:55:18 skrll Exp $	*/
+/*	$NetBSD: if_axen.c,v 1.3.6.13 2016/12/12 13:15:39 skrll Exp $	*/
 /*	$OpenBSD: if_axen.c,v 1.3 2013/10/21 10:10:22 yuo Exp $	*/
 
 /*
@@ -23,7 +23,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_axen.c,v 1.3.6.12 2016/12/05 10:55:18 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_axen.c,v 1.3.6.13 2016/12/12 13:15:39 skrll Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -93,7 +93,9 @@ CFATTACH_DECL_NEW(axen, sizeof(struct ax
 	axen_match, axen_attach, axen_detach, axen_activate);
 
 static int	axen_tx_list_init(struct axen_softc *);
+static void	axen_tx_list_free(struct axen_softc *);
 static int	axen_rx_list_init(struct axen_softc *);
+static void	axen_rx_list_free(struct axen_softc *);
 static struct mbuf *axen_newbuf(void);
 static int	axen_encap(struct axen_softc *, struct mbuf *, int);
 static void	axen_rxeof(struct usbd_xfer *, void *, usbd_status);
@@ -101,9 +103,13 @@ static void	axen_txeof(struct usbd_xfer 
 static void	axen_tick(void *);
 static void	axen_tick_task(void *);
 static void	axen_start(struct ifnet *);
+static void	axen_start_locked(struct ifnet *);
 static int	axen_ioctl(struct ifnet *, u_long, void *);
+static int	axen_ifflags_cb(struct ethercom *ec);
 static int	axen_init(struct ifnet *);
+static int	axen_init_locked(struct ifnet *);
 static void	axen_stop(struct ifnet *, int);
+static void	axen_stop_locked(struct ifnet *, int);
 static void	axen_watchdog(struct ifnet *);
 static int	axen_miibus_readreg(device_t, int, int);
 static void	axen_miibus_writereg(device_t, int, int, int);
@@ -654,7 +660,7 @@ axen_attach(device_t parent, device_t se
 	char *devinfop;
 	const char *devname = device_xname(self);
 	struct ifnet *ifp;
-	int i, s;
+	int i;
 
 	aprint_naive("\n");
 	aprint_normal("\n");
@@ -678,6 +684,10 @@ axen_attach(device_t parent, device_t se
 	rw_init(&sc->axen_mii_lock);
 	usb_init_task(&sc->axen_tick_task, axen_tick_task, sc, 0);
 
+	mutex_init(&sc->axen_lock, MUTEX_DEFAULT, IPL_NONE);
+	mutex_init(&sc->axen_txlock, MUTEX_DEFAULT, IPL_SOFTUSB);
+	mutex_init(&sc->axen_rxlock, MUTEX_DEFAULT, IPL_SOFTUSB);
+
 	err = usbd_device2interface_handle(dev, AXEN_IFACE_IDX,&sc->axen_iface);
 	if (err) {
 		aprint_error_dev(self, "getting interface handle failed\n");
@@ -721,8 +731,6 @@ axen_attach(device_t parent, device_t se
 		}
 	}
 
-	s = splnet();
-
 	sc->axen_phyno = AXEN_PHY_ID;
 	DPRINTF(("%s: phyno %d\n", device_xname(self), sc->axen_phyno));
 
@@ -756,6 +764,7 @@ axen_attach(device_t parent, device_t se
 	ifp->if_softc = sc;
 	strlcpy(ifp->if_xname, devname, IFNAMSIZ);
 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+	ifp->if_extflags = IFEF_START_MPSAFE;
 	ifp->if_ioctl = axen_ioctl;
 	ifp->if_start = axen_start;
 	ifp->if_init = axen_init;
@@ -792,8 +801,11 @@ axen_attach(device_t parent, device_t se
 		ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_AUTO);
 
 	/* Attach the interface. */
-	if_attach(ifp);
+	if_initialize(ifp);
+	sc->axen_ipq = if_percpuq_create(&sc->axen_ec.ec_if);
 	ether_ifattach(ifp, eaddr);
+	if_register(ifp);
+	ether_set_ifflags_cb(&sc->axen_ec, axen_ifflags_cb);
 	rnd_attach_source(&sc->rnd_source, device_xname(sc->axen_dev),
 	    RND_TYPE_NET, RND_FLAG_DEFAULT);
 
@@ -801,7 +813,6 @@ axen_attach(device_t parent, device_t se
 	callout_setfunc(&sc->axen_stat_ch, axen_tick, sc);
 
 	sc->axen_attached = true;
-	splx(s);
 
 	usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->axen_udev,sc->axen_dev);
 
@@ -908,13 +919,12 @@ axen_newbuf(void)
 static int
 axen_rx_list_init(struct axen_softc *sc)
 {
-	struct axen_cdata *cd;
+	struct axen_cdata *cd = &sc->axen_cdata;
 	struct axen_chain *c;
 	int i;
 
 	DPRINTF(("%s: %s: enter\n", device_xname(sc->axen_dev), __func__));
 
-	cd = &sc->axen_cdata;
 	for (i = 0; i < AXEN_RX_LIST_CNT; i++) {
 		c = &cd->axen_rx_chain[i];
 		c->axen_sc = sc;
@@ -932,6 +942,17 @@ axen_rx_list_init(struct axen_softc *sc)
 	return 0;
 }
 
+static void
+axen_rx_list_free(struct axen_softc *sc)
+{
+	for (size_t i = 0; i < AXEN_RX_LIST_CNT; i++) {
+		if (sc->axen_cdata.axen_rx_chain[i].axen_xfer != NULL) {
+			usbd_destroy_xfer(sc->axen_cdata.axen_rx_chain[i].axen_xfer);
+			sc->axen_cdata.axen_rx_chain[i].axen_xfer = NULL;
+		}
+	}
+}
+
 static int
 axen_tx_list_init(struct axen_softc *sc)
 {
@@ -959,6 +980,17 @@ axen_tx_list_init(struct axen_softc *sc)
 	return 0;
 }
 
+static void
+axen_tx_list_free(struct axen_softc *sc)
+{
+	for (size_t i = 0; i < AXEN_TX_LIST_CNT; i++) {
+		if (sc->axen_cdata.axen_tx_chain[i].axen_xfer != NULL) {
+			usbd_destroy_xfer(sc->axen_cdata.axen_tx_chain[i].axen_xfer);
+			sc->axen_cdata.axen_tx_chain[i].axen_xfer = NULL;
+		}
+	}
+}
+
 /*
  * A frame has been uploaded: pass the resulting mbuf chain up to
  * the higher level protocols.
@@ -977,7 +1009,6 @@ axen_rxeof(struct usbd_xfer *xfer, void 
 	uint16_t hdr_offset, pkt_count;
 	size_t pkt_len;
 	size_t temp;
-	int s;
 
 	DPRINTFN(10,("%s: %s: enter\n", device_xname(sc->axen_dev), __func__));
 
@@ -1105,10 +1136,8 @@ axen_rxeof(struct usbd_xfer *xfer, void 
 		memcpy(mtod(m, char *), buf + 2, pkt_len - 6);
 
 		/* push the packet up */
-		s = splnet();
 		bpf_mtap(ifp, m);
-		if_percpuq_enqueue((ifp)->if_percpuq, (m));
-		splx(s);
+		if_percpuq_enqueue(sc->axen_ipq, (m));
 
 nextpkt:
 		/*
@@ -1278,6 +1307,17 @@ axen_encap(struct axen_softc *sc, struct
 static void
 axen_start(struct ifnet *ifp)
 {
+	struct axen_softc * const sc = ifp->if_softc;
+	KASSERT(ifp->if_extflags & IFEF_START_MPSAFE);
+
+	mutex_enter(&sc->axen_txlock);
+	axen_start_locked(ifp);
+	mutex_exit(&sc->axen_txlock);
+}
+
+static void
+axen_start_locked(struct ifnet *ifp)
+{
 	struct axen_softc *sc;
 	struct mbuf *m;
 
@@ -1294,7 +1334,6 @@ axen_start(struct ifnet *ifp)
 		return;
 
 	if (axen_encap(sc, m, 0)) {
-		ifp->if_flags |= IFF_OACTIVE;
 		return;
 	}
 	IFQ_DEQUEUE(&ifp->if_snd, m);
@@ -1318,17 +1357,26 @@ static int
 axen_init(struct ifnet *ifp)
 {
 	struct axen_softc *sc = ifp->if_softc;
+
+	mutex_enter(&sc->axen_lock);
+	int ret = axen_init_locked(ifp);
+	mutex_exit(&sc->axen_lock);
+
+	return ret;
+}
+
+static int
+axen_init_locked(struct ifnet *ifp)
+{
+	struct axen_softc *sc = ifp->if_softc;
 	struct axen_chain *c;
 	usbd_status err;
-	int i, s;
+	int i;
 	uint16_t rxmode;
 	uint16_t wval;
 	uint8_t bval;
 
-	s = splnet();
-
-	if (ifp->if_flags & IFF_RUNNING)
-		axen_stop(ifp, 0);
+	axen_stop_locked(ifp, 1);
 
 	/*
 	 * Cancel pending I/O and free all RX/TX buffers.
@@ -1359,8 +1407,7 @@ axen_init(struct ifnet *ifp)
 	if (err) {
 		aprint_error_dev(sc->axen_dev, "open rx pipe failed: %s\n",
 		    usbd_errstr(err));
-		splx(s);
-		return EIO;
+		goto fail;
 	}
 
 	err = usbd_open_pipe(sc->axen_iface, sc->axen_ed[AXEN_ENDPT_TX],
@@ -1368,22 +1415,19 @@ axen_init(struct ifnet *ifp)
 	if (err) {
 		aprint_error_dev(sc->axen_dev, "open tx pipe failed: %s\n",
 		    usbd_errstr(err));
-		splx(s);
-		return EIO;
+		goto fail1;
 	}
 
 	/* Init RX ring. */
 	if (axen_rx_list_init(sc)) {
 		aprint_error_dev(sc->axen_dev, "rx list init failed\n");
-		splx(s);
-		return ENOBUFS;
+		goto fail2;
 	}
 
 	/* Init TX ring. */
 	if (axen_tx_list_init(sc)) {
 		aprint_error_dev(sc->axen_dev, "tx list init failed\n");
-		splx(s);
-		return ENOBUFS;
+		goto fail3;
 	}
 
 	/* Start up the receive pipe. */
@@ -1398,56 +1442,52 @@ axen_init(struct ifnet *ifp)
 	ifp->if_flags |= IFF_RUNNING;
 	ifp->if_flags &= ~IFF_OACTIVE;
 
-	splx(s);
-
 	callout_schedule(&sc->axen_stat_ch, hz);
 	return 0;
+
+fail3:
+	axen_rx_list_free(sc);
+fail2:
+	usbd_close_pipe(sc->axen_ep[AXEN_ENDPT_TX]);
+fail1:
+	usbd_close_pipe(sc->axen_ep[AXEN_ENDPT_RX]);
+fail:
+	return EIO;
 }
 
 static int
 axen_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 {
-	struct axen_softc *sc = ifp->if_softc;
 	int s;
 	int error = 0;
 
 	s = splnet();
+	error = ether_ioctl(ifp, cmd, data);
+	splx(s);
 
-	switch (cmd) {
-	case SIOCSIFFLAGS:
-		if ((error = ifioctl_common(ifp, cmd, data)) != 0)
-			break;
+	return error;
+}
 
-		switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
-		case IFF_RUNNING:
-			axen_stop(ifp, 1);
-			break;
-		case IFF_UP:
-			axen_init(ifp);
-			break;
-		case IFF_UP | IFF_RUNNING:
-			if ((ifp->if_flags ^ sc->axen_if_flags) == IFF_PROMISC)
-				axen_iff(sc);
-			else
-				axen_init(ifp);
-			break;
-		}
-		sc->axen_if_flags = ifp->if_flags;
-		break;
+static int
+axen_ifflags_cb(struct ethercom *ec)
+{
+	struct ifnet *ifp = &ec->ec_if;
+	struct axen_softc *sc = ifp->if_softc;
+	int ret;
 
-	default:
-		if ((error = ether_ioctl(ifp, cmd, data)) != ENETRESET)
-			break;
+	mutex_enter(&sc->axen_lock);
 
-		error = 0;
+	int change = ifp->if_flags ^ sc->axen_if_flags;
+	sc->axen_if_flags = ifp->if_flags;
 
-		if (cmd == SIOCADDMULTI || cmd == SIOCDELMULTI)
-			axen_iff(sc);
-		break;
+	if ((change & IFF_PROMISC) == 0) {
+		ret = ENETRESET;
+	} else {
+		axen_iff(sc);
+		ret = 0;
 	}
-	splx(s);
-
-	return error;
+	mutex_exit(&sc->axen_lock);
+	return ret;
 }
 
 static void
@@ -1480,11 +1520,20 @@ axen_watchdog(struct ifnet *ifp)
 static void
 axen_stop(struct ifnet *ifp, int disable)
 {
+	struct axen_softc * const sc = ifp->if_softc;
+
+	mutex_enter(&sc->axen_lock);
+	axen_stop_locked(ifp, disable);
+	mutex_exit(&sc->axen_lock);
+}
+
+static void
+axen_stop_locked(struct ifnet *ifp, int disable)
+{
 	struct axen_softc *sc = ifp->if_softc;
 	usbd_status err;
-	int i;
 
-	axen_reset(sc);
+//	axen_reset(sc);
 
 	ifp->if_timer = 0;
 	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
@@ -1517,21 +1566,9 @@ axen_stop(struct ifnet *ifp, int disable
 		}
 	}
 
-	/* Free RX resources. */
-	for (i = 0; i < AXEN_RX_LIST_CNT; i++) {
-		if (sc->axen_cdata.axen_rx_chain[i].axen_xfer != NULL) {
-			usbd_destroy_xfer(sc->axen_cdata.axen_rx_chain[i].axen_xfer);
-			sc->axen_cdata.axen_rx_chain[i].axen_xfer = NULL;
-		}
-	}
+	axen_rx_list_free(sc);
 
-	/* Free TX resources. */
-	for (i = 0; i < AXEN_TX_LIST_CNT; i++) {
-		if (sc->axen_cdata.axen_tx_chain[i].axen_xfer != NULL) {
-			usbd_destroy_xfer(sc->axen_cdata.axen_tx_chain[i].axen_xfer);
-			sc->axen_cdata.axen_tx_chain[i].axen_xfer = NULL;
-		}
-	}
+	axen_tx_list_free(sc);
 
 	/* Close pipes. */
 	if (sc->axen_ep[AXEN_ENDPT_RX] != NULL) {
@@ -1562,6 +1599,9 @@ axen_stop(struct ifnet *ifp, int disable
 	}
 
 	sc->axen_link = 0;
+
+	ifp->if_timer = 0;
+	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
 }
 
 MODULE(MODULE_CLASS_DRIVER, if_axen, "bpf");

Index: src/sys/dev/usb/if_axenreg.h
diff -u src/sys/dev/usb/if_axenreg.h:1.1.12.2 src/sys/dev/usb/if_axenreg.h:1.1.12.3
--- src/sys/dev/usb/if_axenreg.h:1.1.12.2	Sat Jun  6 14:40:13 2015
+++ src/sys/dev/usb/if_axenreg.h	Mon Dec 12 13:15:39 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_axenreg.h,v 1.1.12.2 2015/06/06 14:40:13 skrll Exp $	*/
+/*	$NetBSD: if_axenreg.h,v 1.1.12.3 2016/12/12 13:15:39 skrll Exp $	*/
 /*	$OpenBSD: if_axenreg.h,v 1.1 2013/10/07 05:37:41 yuo Exp $	*/
 
 /*
@@ -276,6 +276,8 @@ struct axen_softc {
 	uint16_t		axen_vendor;
 	uint16_t		axen_product;
 	uint16_t		axen_flags;
+	
+	struct if_percpuq	*axen_ipq;
 
 	int			axen_ed[AXEN_ENDPT_MAX];
 	struct usbd_pipe	*axen_ep[AXEN_ENDPT_MAX];
@@ -289,6 +291,9 @@ struct axen_softc {
 
 	struct usb_task		axen_tick_task;
 
+	kmutex_t		axen_lock;
+	kmutex_t		axen_txlock;
+	kmutex_t		axen_rxlock;
 	krwlock_t		axen_mii_lock;
 
 	int			axen_link;

Index: src/sys/dev/usb/if_axereg.h
diff -u src/sys/dev/usb/if_axereg.h:1.16.6.4 src/sys/dev/usb/if_axereg.h:1.16.6.5
--- src/sys/dev/usb/if_axereg.h:1.16.6.4	Mon Dec  5 10:55:18 2016
+++ src/sys/dev/usb/if_axereg.h	Mon Dec 12 13:15:39 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_axereg.h,v 1.16.6.4 2016/12/05 10:55:18 skrll Exp $	*/
+/*	$NetBSD: if_axereg.h,v 1.16.6.5 2016/12/12 13:15:39 skrll Exp $	*/
 
 /*
  * Copyright (c) 1997, 1998, 1999, 2000-2003
@@ -435,8 +435,13 @@ struct axe_softc {
 
 	struct usb_task		axe_tick_task;
 
+	kmutex_t		axe_lock;
+	kmutex_t		axe_txlock;
+	kmutex_t		axe_rxlock;
 	kmutex_t		axe_mii_lock;
 
+	struct if_percpuq	*axe_ipq;
+
 	int			axe_link;
 
 	uint8_t			axe_ipgs[3];

Index: src/sys/dev/usb/if_cdce.c
diff -u src/sys/dev/usb/if_cdce.c:1.38.14.9 src/sys/dev/usb/if_cdce.c:1.38.14.10
--- src/sys/dev/usb/if_cdce.c:1.38.14.9	Sat Jul  9 20:25:15 2016
+++ src/sys/dev/usb/if_cdce.c	Mon Dec 12 13:15:39 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_cdce.c,v 1.38.14.9 2016/07/09 20:25:15 skrll Exp $ */
+/*	$NetBSD: if_cdce.c,v 1.38.14.10 2016/12/12 13:15:39 skrll Exp $ */
 
 /*
  * Copyright (c) 1997, 1998, 1999, 2000-2003 Bill Paul <wp...@windriver.com>
@@ -41,7 +41,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_cdce.c,v 1.38.14.9 2016/07/09 20:25:15 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_cdce.c,v 1.38.14.10 2016/12/12 13:15:39 skrll Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -79,17 +79,22 @@ __KERNEL_RCSID(0, "$NetBSD: if_cdce.c,v 
 #include <dev/usb/if_cdcereg.h>
 
 Static int	 cdce_tx_list_init(struct cdce_softc *);
+Static void	 cdce_tx_list_free(struct cdce_softc *);
 Static int	 cdce_rx_list_init(struct cdce_softc *);
+Static void	 cdce_rx_list_free(struct cdce_softc *);
 Static int	 cdce_newbuf(struct cdce_softc *, struct cdce_chain *,
 		    struct mbuf *);
 Static int	 cdce_encap(struct cdce_softc *, struct mbuf *, int);
 Static void	 cdce_rxeof(struct usbd_xfer *, void *, usbd_status);
 Static void	 cdce_txeof(struct usbd_xfer *, void *, usbd_status);
 Static void	 cdce_start(struct ifnet *);
+Static void	 cdce_start_locked(struct ifnet *);
 Static int	 cdce_ioctl(struct ifnet *, u_long, void *);
-Static void	 cdce_init(void *);
+Static int	 cdce_init(struct ifnet *);
+Static int	 cdce_init_locked(struct ifnet *);
 Static void	 cdce_watchdog(struct ifnet *);
-Static void	 cdce_stop(struct cdce_softc *);
+Static void	 cdce_stop(struct ifnet *, int);
+Static void	 cdce_stop_locked(struct ifnet *, int);
 
 Static const struct cdce_type cdce_devs[] = {
   {{ USB_VENDOR_ACERLABS, USB_PRODUCT_ACERLABS_M5632 }, CDCE_NO_UNION },
@@ -136,7 +141,6 @@ cdce_attach(device_t parent, device_t se
 	struct cdce_softc *sc = device_private(self);
 	struct usbif_attach_arg *uiaa = aux;
 	char				*devinfop;
-	int				 s;
 	struct ifnet			*ifp;
 	struct usbd_device	        *dev = uiaa->uiaa_device;
 	const struct cdce_type		*t;
@@ -159,6 +163,10 @@ cdce_attach(device_t parent, device_t se
 	aprint_normal_dev(self, "%s\n", devinfop);
 	usbd_devinfo_free(devinfop);
 
+	mutex_init(&sc->cdce_lock, MUTEX_DEFAULT, IPL_NONE);
+	mutex_init(&sc->cdce_txlock, MUTEX_DEFAULT, IPL_SOFTUSB);
+	mutex_init(&sc->cdce_rxlock, MUTEX_DEFAULT, IPL_SOFTUSB);
+
 	sc->cdce_udev = uiaa->uiaa_device;
 	sc->cdce_ctl_iface = uiaa->uiaa_iface;
 
@@ -271,13 +279,13 @@ cdce_attach(device_t parent, device_t se
 		eaddr[5] = (uint8_t)(device_unit(sc->cdce_dev));
 	}
 
-	s = splnet();
-
 	aprint_normal_dev(self, "address %s\n", ether_sprintf(eaddr));
 
 	ifp = GET_IFP(sc);
 	ifp->if_softc = sc;
 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+	ifp->if_extflags = IFEF_START_MPSAFE;
+	ifp->if_init = cdce_init;
 	ifp->if_ioctl = cdce_ioctl;
 	ifp->if_start = cdce_start;
 	ifp->if_watchdog = cdce_watchdog;
@@ -285,11 +293,12 @@ cdce_attach(device_t parent, device_t se
 
 	IFQ_SET_READY(&ifp->if_snd);
 
-	if_attach(ifp);
+	if_initialize(ifp);
+	sc->cdce_ipq = if_percpuq_create(&sc->cdce_ec.ec_if);
 	ether_ifattach(ifp, eaddr);
+	if_register(ifp);
 
 	sc->cdce_attached = 1;
-	splx(s);
 
 	usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->cdce_udev,
 	    sc->cdce_dev);
@@ -317,7 +326,7 @@ cdce_detach(device_t self, int flags)
 	}
 
 	if (ifp->if_flags & IFF_RUNNING)
-		cdce_stop(sc);
+		cdce_stop(ifp, 1);
 
 	ether_ifdetach(ifp);
 
@@ -333,6 +342,17 @@ Static void
 cdce_start(struct ifnet *ifp)
 {
 	struct cdce_softc	*sc = ifp->if_softc;
+	KASSERT(ifp->if_extflags & IFEF_START_MPSAFE);
+
+	mutex_enter(&sc->cdce_txlock);
+	cdce_start_locked(ifp);
+	mutex_exit(&sc->cdce_txlock);
+}
+
+Static void
+cdce_start_locked(struct ifnet *ifp)
+{
+	struct cdce_softc	*sc = ifp->if_softc;
 	struct mbuf		*m_head = NULL;
 
 	if (sc->cdce_dying || (ifp->if_flags & IFF_OACTIVE))
@@ -343,7 +363,6 @@ cdce_start(struct ifnet *ifp)
 		return;
 
 	if (cdce_encap(sc, m_head, 0)) {
-		ifp->if_flags |= IFF_OACTIVE;
 		return;
 	}
 
@@ -359,12 +378,9 @@ cdce_start(struct ifnet *ifp)
 Static int
 cdce_encap(struct cdce_softc *sc, struct mbuf *m, int idx)
 {
-	struct cdce_chain	*c;
-	usbd_status		 err;
+	struct cdce_chain	*c = &sc->cdce_cdata.cdce_tx_chain[idx];
 	int			 extra = 0;
 
-	c = &sc->cdce_cdata.cdce_tx_chain[idx];
-
 	m_copydata(m, 0, m->m_pkthdr.len, c->cdce_buf);
 	if (sc->cdce_flags & CDCE_ZAURUS) {
 		/* Zaurus wants a 32-bit CRC appended to every frame */
@@ -378,9 +394,9 @@ cdce_encap(struct cdce_softc *sc, struct
 
 	usbd_setup_xfer(c->cdce_xfer, c, c->cdce_buf, m->m_pkthdr.len + extra,
 	    USBD_FORCE_SHORT_XFER, 10000, cdce_txeof);
-	err = usbd_transfer(c->cdce_xfer);
+	usbd_status err = usbd_transfer(c->cdce_xfer);
 	if (err != USBD_IN_PROGRESS) {
-		cdce_stop(sc);
+		cdce_stop(GET_IFP(sc), 0);
 		return EIO;
 	}
 
@@ -390,11 +406,20 @@ cdce_encap(struct cdce_softc *sc, struct
 }
 
 Static void
-cdce_stop(struct cdce_softc *sc)
+cdce_stop(struct ifnet *ifp, int disable)
 {
+	struct cdce_softc * const sc = ifp->if_softc;
+
+	mutex_enter(&sc->cdce_lock);
+	cdce_stop_locked(ifp, disable);
+	mutex_exit(&sc->cdce_lock);
+}
+
+Static void
+cdce_stop_locked(struct ifnet *ifp, int disable)
+{
+	struct cdce_softc * const sc = ifp->if_softc;
 	usbd_status	 err;
-	struct ifnet	*ifp = GET_IFP(sc);
-	int		 i;
 
 	ifp->if_timer = 0;
 
@@ -412,29 +437,9 @@ cdce_stop(struct cdce_softc *sc)
 			    device_xname(sc->cdce_dev), usbd_errstr(err));
 	}
 
-	for (i = 0; i < CDCE_RX_LIST_CNT; i++) {
-		if (sc->cdce_cdata.cdce_rx_chain[i].cdce_mbuf != NULL) {
-			m_freem(sc->cdce_cdata.cdce_rx_chain[i].cdce_mbuf);
-			sc->cdce_cdata.cdce_rx_chain[i].cdce_mbuf = NULL;
-		}
-		if (sc->cdce_cdata.cdce_rx_chain[i].cdce_xfer != NULL) {
-			usbd_destroy_xfer
-			    (sc->cdce_cdata.cdce_rx_chain[i].cdce_xfer);
-			sc->cdce_cdata.cdce_rx_chain[i].cdce_xfer = NULL;
-		}
-	}
+	cdce_rx_list_free(sc);
 
-	for (i = 0; i < CDCE_TX_LIST_CNT; i++) {
-		if (sc->cdce_cdata.cdce_tx_chain[i].cdce_mbuf != NULL) {
-			m_freem(sc->cdce_cdata.cdce_tx_chain[i].cdce_mbuf);
-			sc->cdce_cdata.cdce_tx_chain[i].cdce_mbuf = NULL;
-		}
-		if (sc->cdce_cdata.cdce_tx_chain[i].cdce_xfer != NULL) {
-			usbd_destroy_xfer(
-				sc->cdce_cdata.cdce_tx_chain[i].cdce_xfer);
-			sc->cdce_cdata.cdce_tx_chain[i].cdce_xfer = NULL;
-		}
-	}
+	cdce_tx_list_free(sc);
 
 	if (sc->cdce_bulkin_pipe != NULL) {
 		err = usbd_close_pipe(sc->cdce_bulkin_pipe);
@@ -452,6 +457,7 @@ cdce_stop(struct cdce_softc *sc)
 		sc->cdce_bulkout_pipe = NULL;
 	}
 
+	ifp->if_timer = 0;
 	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
 }
 
@@ -459,56 +465,13 @@ Static int
 cdce_ioctl(struct ifnet *ifp, u_long command, void *data)
 {
 	struct cdce_softc	*sc = ifp->if_softc;
-	struct ifaddr		*ifa = (struct ifaddr *)data;
-	struct ifreq		*ifr = (struct ifreq *)data;
 	int			 s, error = 0;
 
 	if (sc->cdce_dying)
 		return EIO;
 
 	s = splnet();
-
-	switch(command) {
-	case SIOCINITIFADDR:
-		ifp->if_flags |= IFF_UP;
-		cdce_init(sc);
-		switch (ifa->ifa_addr->sa_family) {
-#ifdef INET
-		case AF_INET:
-			arp_ifinit(ifp, ifa);
-			break;
-#endif /* INET */
-		}
-		break;
-
-	case SIOCSIFMTU:
-		if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > ETHERMTU)
-			error = EINVAL;
-		else if ((error = ifioctl_common(ifp, command, data)) == ENETRESET)
-			error = 0;
-		break;
-
-	case SIOCSIFFLAGS:
-		if ((error = ifioctl_common(ifp, command, data)) != 0)
-			break;
-		/* XXX re-use ether_ioctl() */
-		switch (ifp->if_flags & (IFF_UP|IFF_RUNNING)) {
-		case IFF_UP:
-			cdce_init(sc);
-			break;
-		case IFF_RUNNING:
-			cdce_stop(sc);
-			break;
-		default:
-			break;
-		}
-		break;
-
-	default:
-		error = ether_ioctl(ifp, command, data);
-		break;
-	}
-
+	error = ether_ioctl(ifp, command, data);
 	splx(s);
 
 	if (error == ENETRESET)
@@ -529,29 +492,32 @@ cdce_watchdog(struct ifnet *ifp)
 	printf("%s: watchdog timeout\n", device_xname(sc->cdce_dev));
 }
 
-Static void
-cdce_init(void *xsc)
+Static int
+cdce_init(struct ifnet *ifp)
 {
-	struct cdce_softc	*sc = xsc;
-	struct ifnet		*ifp = GET_IFP(sc);
-	struct cdce_chain	*c;
-	usbd_status		 err;
-	int			 s, i;
+	struct cdce_softc * const sc = ifp->if_softc;
 
-	if (ifp->if_flags & IFF_RUNNING)
-		return;
+	mutex_enter(&sc->cdce_lock);
+	int ret = cdce_init_locked(ifp);
+	mutex_exit(&sc->cdce_lock);
 
-	s = splnet();
+	return ret;
+}
 
-	/* Maybe set multicast / broadcast here??? */
+Static int
+cdce_init_locked(struct ifnet *ifp)
+{
+	struct cdce_softc * const sc = ifp->if_softc;
+	struct cdce_chain	*c;
+	usbd_status		 err;
+	int			 i;
 
 	err = usbd_open_pipe(sc->cdce_data_iface, sc->cdce_bulkin_no,
 	    USBD_EXCLUSIVE_USE, &sc->cdce_bulkin_pipe);
 	if (err) {
 		printf("%s: open rx pipe failed: %s\n", device_xname(sc->cdce_dev),
 		    usbd_errstr(err));
-		splx(s);
-		return;
+		goto fail;
 	}
 
 	err = usbd_open_pipe(sc->cdce_data_iface, sc->cdce_bulkout_no,
@@ -559,20 +525,17 @@ cdce_init(void *xsc)
 	if (err) {
 		printf("%s: open tx pipe failed: %s\n",
 		    device_xname(sc->cdce_dev), usbd_errstr(err));
-		splx(s);
-		return;
+		goto fail1;
 	}
 
 	if (cdce_tx_list_init(sc)) {
 		printf("%s: tx list init failed\n", device_xname(sc->cdce_dev));
-		splx(s);
-		return;
+		goto fail2;
 	}
 
 	if (cdce_rx_list_init(sc)) {
 		printf("%s: rx list init failed\n", device_xname(sc->cdce_dev));
-		splx(s);
-		return;
+		goto fail3;
 	}
 
 	for (i = 0; i < CDCE_RX_LIST_CNT; i++) {
@@ -586,7 +549,16 @@ cdce_init(void *xsc)
 	ifp->if_flags |= IFF_RUNNING;
 	ifp->if_flags &= ~IFF_OACTIVE;
 
-	splx(s);
+	return 0;
+
+fail3:
+	cdce_tx_list_free(sc);
+fail2:
+	usbd_close_pipe(sc->cdce_bulkout_pipe);
+fail1:
+	usbd_close_pipe(sc->cdce_bulkin_pipe);
+fail:
+	return EIO;
 }
 
 Static int
@@ -621,11 +593,10 @@ cdce_newbuf(struct cdce_softc *sc, struc
 Static int
 cdce_rx_list_init(struct cdce_softc *sc)
 {
-	struct cdce_cdata	*cd;
+	struct cdce_cdata	*cd = &sc->cdce_cdata;
 	struct cdce_chain	*c;
 	int			 i;
 
-	cd = &sc->cdce_cdata;
 	for (i = 0; i < CDCE_RX_LIST_CNT; i++) {
 		c = &cd->cdce_rx_chain[i];
 		c->cdce_sc = sc;
@@ -644,14 +615,29 @@ cdce_rx_list_init(struct cdce_softc *sc)
 	return 0;
 }
 
+Static void
+cdce_rx_list_free(struct cdce_softc *sc)
+{
+	/* Free RX resources */
+	for (size_t i = 0; i < CDCE_RX_LIST_CNT; i++) {
+		if (sc->cdce_cdata.cdce_rx_chain[i].cdce_mbuf != NULL) {
+			m_freem(sc->cdce_cdata.cdce_rx_chain[i].cdce_mbuf);
+			sc->cdce_cdata.cdce_rx_chain[i].cdce_mbuf = NULL;
+		}
+		if (sc->cdce_cdata.cdce_rx_chain[i].cdce_xfer != NULL) {
+			usbd_destroy_xfer(sc->cdce_cdata.cdce_rx_chain[i].cdce_xfer);
+			sc->cdce_cdata.cdce_rx_chain[i].cdce_xfer = NULL;
+		}
+	}
+}
+
 Static int
 cdce_tx_list_init(struct cdce_softc *sc)
 {
-	struct cdce_cdata	*cd;
+	struct cdce_cdata	*cd = &sc->cdce_cdata;
 	struct cdce_chain	*c;
 	int			 i;
 
-	cd = &sc->cdce_cdata;
 	for (i = 0; i < CDCE_TX_LIST_CNT; i++) {
 		c = &cd->cdce_tx_chain[i];
 		c->cdce_sc = sc;
@@ -671,6 +657,22 @@ cdce_tx_list_init(struct cdce_softc *sc)
 }
 
 Static void
+cdce_tx_list_free(struct cdce_softc *sc)
+{
+	/* Free TX resources */
+	for (size_t i = 0; i < CDCE_TX_LIST_CNT; i++) {
+		if (sc->cdce_cdata.cdce_tx_chain[i].cdce_mbuf != NULL) {
+			m_freem(sc->cdce_cdata.cdce_tx_chain[i].cdce_mbuf);
+			sc->cdce_cdata.cdce_tx_chain[i].cdce_mbuf = NULL;
+		}
+		if (sc->cdce_cdata.cdce_tx_chain[i].cdce_xfer != NULL) {
+			usbd_destroy_xfer(sc->cdce_cdata.cdce_tx_chain[i].cdce_xfer);
+			sc->cdce_cdata.cdce_tx_chain[i].cdce_xfer = NULL;
+		}
+	}
+}
+
+Static void
 cdce_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
 {
 	struct cdce_chain	*c = priv;
@@ -678,7 +680,6 @@ cdce_rxeof(struct usbd_xfer *xfer, void 
 	struct ifnet		*ifp = GET_IFP(sc);
 	struct mbuf		*m;
 	int			 total_len = 0;
-	int			 s;
 
 	if (sc->cdce_dying || !(ifp->if_flags & IFF_RUNNING))
 		return;
@@ -716,19 +717,14 @@ cdce_rxeof(struct usbd_xfer *xfer, void 
 	m->m_pkthdr.len = m->m_len = total_len;
 	m_set_rcvif(m, ifp);
 
-	s = splnet();
-
 	if (cdce_newbuf(sc, c, NULL) == ENOBUFS) {
 		ifp->if_ierrors++;
-		goto done1;
+		goto done;
 	}
 
 	bpf_mtap(ifp, m);
 
-	if_percpuq_enqueue((ifp)->if_percpuq, (m));
-
-done1:
-	splx(s);
+	if_percpuq_enqueue(sc->cdce_ipq, (m));
 
 done:
 	/* Setup new transfer. */
@@ -745,12 +741,11 @@ cdce_txeof(struct usbd_xfer *xfer, void 
 	struct cdce_softc	*sc = c->cdce_sc;
 	struct ifnet		*ifp = GET_IFP(sc);
 	usbd_status		 err;
-	int			 s;
 
 	if (sc->cdce_dying)
 		return;
 
-	s = splnet();
+	int s = splnet();
 
 	ifp->if_timer = 0;
 	ifp->if_flags &= ~IFF_OACTIVE;

Index: src/sys/dev/usb/if_cdcereg.h
diff -u src/sys/dev/usb/if_cdcereg.h:1.7.24.4 src/sys/dev/usb/if_cdcereg.h:1.7.24.5
--- src/sys/dev/usb/if_cdcereg.h:1.7.24.4	Sun Mar 20 08:42:19 2016
+++ src/sys/dev/usb/if_cdcereg.h	Mon Dec 12 13:15:39 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_cdcereg.h,v 1.7.24.4 2016/03/20 08:42:19 skrll Exp $ */
+/*	$NetBSD: if_cdcereg.h,v 1.7.24.5 2016/12/12 13:15:39 skrll Exp $ */
 
 /*
  * Copyright (c) 1997, 1998, 1999, 2000-2003 Bill Paul <wp...@windriver.com>
@@ -70,7 +70,7 @@ struct cdce_cdata {
 struct cdce_softc {
 	device_t cdce_dev;
 	struct ethercom		 cdce_ec;
-	krndsource_t	 rnd_source;
+	krndsource_t		 rnd_source;
 #define GET_IFP(sc) (&(sc)->cdce_ec.ec_if)
 	struct usbd_device *	 cdce_udev;
 	struct usbd_interface *	 cdce_ctl_iface;
@@ -85,4 +85,10 @@ struct cdce_softc {
 	int			 cdce_rxeof_errors;
 	uint16_t		 cdce_flags;
 	char			 cdce_attached;
+
+	struct if_percpuq	*cdce_ipq;
+
+	kmutex_t		 cdce_lock;
+	kmutex_t		 cdce_txlock;
+	kmutex_t		 cdce_rxlock;
 };

Index: src/sys/dev/usb/if_cue.c
diff -u src/sys/dev/usb/if_cue.c:1.68.4.12 src/sys/dev/usb/if_cue.c:1.68.4.13
--- src/sys/dev/usb/if_cue.c:1.68.4.12	Mon Dec  5 10:55:18 2016
+++ src/sys/dev/usb/if_cue.c	Mon Dec 12 13:15:39 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_cue.c,v 1.68.4.12 2016/12/05 10:55:18 skrll Exp $	*/
+/*	$NetBSD: if_cue.c,v 1.68.4.13 2016/12/12 13:15:39 skrll Exp $	*/
 /*
  * Copyright (c) 1997, 1998, 1999, 2000
  *	Bill Paul <wp...@ee.columbia.edu>.  All rights reserved.
@@ -56,7 +56,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_cue.c,v 1.68.4.12 2016/12/05 10:55:18 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_cue.c,v 1.68.4.13 2016/12/12 13:15:39 skrll Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -120,9 +120,12 @@ extern struct cfdriver cue_cd;
 CFATTACH_DECL_NEW(cue, sizeof(struct cue_softc), cue_match, cue_attach,
     cue_detach, cue_activate);
 
-Static int cue_open_pipes(struct cue_softc *);
 Static int cue_tx_list_init(struct cue_softc *);
+Static void cue_tx_list_free(struct cue_softc *);
 Static int cue_rx_list_init(struct cue_softc *);
+#if 0
+Static void cue_rx_list_free(struct cue_softc *);
+#endif
 Static int cue_newbuf(struct cue_softc *, struct cue_chain *, struct mbuf *);
 Static int cue_send(struct cue_softc *, struct mbuf *, int);
 Static void cue_rxeof(struct usbd_xfer *, void *, usbd_status);
@@ -130,9 +133,13 @@ Static void cue_txeof(struct usbd_xfer *
 Static void cue_tick(void *);
 Static void cue_tick_task(void *);
 Static void cue_start(struct ifnet *);
+Static void cue_start_locked(struct ifnet *);
 Static int cue_ioctl(struct ifnet *, u_long, void *);
-Static void cue_init(void *);
+Static int cue_ifflags_cb(struct ethercom *);
+Static int cue_init(struct ifnet *);
+Static int cue_init_locked(struct ifnet *);
 Static void cue_stop(struct cue_softc *);
+Static void cue_stop_locked(struct cue_softc *);
 Static void cue_watchdog(struct ifnet *);
 
 Static void cue_setmulti(struct cue_softc *);
@@ -455,7 +462,6 @@ cue_attach(device_t parent, device_t sel
 	struct cue_softc *sc = device_private(self);
 	struct usb_attach_arg *uaa = aux;
 	char			*devinfop;
-	int			s;
 	u_char			eaddr[ETHER_ADDR_LEN];
 	struct usbd_device *	dev = uaa->uaa_device;
 	struct usbd_interface *	iface;
@@ -490,6 +496,10 @@ cue_attach(device_t parent, device_t sel
 	usb_init_task(&sc->cue_tick_task, cue_tick_task, sc, 0);
 	usb_init_task(&sc->cue_stop_task, (void (*)(void *))cue_stop, sc, 0);
 
+	mutex_init(&sc->cue_lock, MUTEX_DEFAULT, IPL_NONE);
+	mutex_init(&sc->cue_txlock, MUTEX_DEFAULT, IPL_SOFTUSB);
+	mutex_init(&sc->cue_rxlock, MUTEX_DEFAULT, IPL_SOFTUSB);
+
 	err = usbd_device2interface_handle(dev, CUE_IFACE_IDX, &iface);
 	if (err) {
 		aprint_error_dev(self, "getting interface handle failed\n");
@@ -527,8 +537,6 @@ cue_attach(device_t parent, device_t sel
 	 */
 	cue_getmac(sc, &eaddr);
 
-	s = splnet();
-
 	/*
 	 * A CATC chip was detected. Inform the world.
 	 */
@@ -539,6 +547,8 @@ cue_attach(device_t parent, device_t sel
 	ifp->if_softc = sc;
 	ifp->if_mtu = ETHERMTU;
 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+	ifp->if_extflags = IFEF_START_MPSAFE;
+	ifp->if_init = cue_init;
 	ifp->if_ioctl = cue_ioctl;
 	ifp->if_start = cue_start;
 	ifp->if_watchdog = cue_watchdog;
@@ -547,15 +557,17 @@ cue_attach(device_t parent, device_t sel
 	IFQ_SET_READY(&ifp->if_snd);
 
 	/* Attach the interface. */
-	if_attach(ifp);
+	if_initialize(ifp);
+	sc->cue_ipq = if_percpuq_create(&sc->cue_ec.ec_if);
 	ether_ifattach(ifp, eaddr);
+	if_register(ifp);
+	ether_set_ifflags_cb(&sc->cue_ec, cue_ifflags_cb);
 	rnd_attach_source(&sc->rnd_source, device_xname(sc->cue_dev),
 	    RND_TYPE_NET, RND_FLAG_DEFAULT);
 
 	callout_init(&(sc->cue_stat_ch), 0);
 
 	sc->cue_attached = 1;
-	splx(s);
 
 	usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->cue_udev, sc->cue_dev);
 
@@ -688,7 +700,19 @@ cue_rx_list_init(struct cue_softc *sc)
 
 	return 0;
 }
-
+#if 0
+Static void
+cue_rx_list_free(struct cue_softc *sc)
+{
+	/* Free RX resources. */
+	for (int i = 0; i < CUE_RX_LIST_CNT; i++) {
+		if (sc->cue_cdata.cue_rx_chain[i].cue_xfer != NULL) {
+			usbd_destroy_xfer(sc->cue_cdata.cue_rx_chain[i].cue_xfer);
+			sc->cue_cdata.cue_rx_chain[i].cue_xfer = NULL;
+		}
+	}
+}
+#endif
 Static int
 cue_tx_list_init(struct cue_softc *sc)
 {
@@ -714,6 +738,22 @@ cue_tx_list_init(struct cue_softc *sc)
 	return 0;
 }
 
+Static void
+cue_tx_list_free(struct cue_softc *sc)
+{
+	/* Free TX resources. */
+	for (int i = 0; i < CUE_TX_LIST_CNT; i++) {
+		if (sc->cue_cdata.cue_tx_chain[i].cue_mbuf != NULL) {
+			m_freem(sc->cue_cdata.cue_tx_chain[i].cue_mbuf);
+			sc->cue_cdata.cue_tx_chain[i].cue_mbuf = NULL;
+		}
+		if (sc->cue_cdata.cue_tx_chain[i].cue_xfer != NULL) {
+			usbd_destroy_xfer(sc->cue_cdata.cue_tx_chain[i].cue_xfer);
+			sc->cue_cdata.cue_tx_chain[i].cue_xfer = NULL;
+		}
+	}
+}
+
 /*
  * A frame has been uploaded: pass the resulting mbuf chain up to
  * the higher level protocols.
@@ -727,7 +767,6 @@ cue_rxeof(struct usbd_xfer *xfer, void *
 	struct mbuf		*m;
 	int			total_len = 0;
 	uint16_t		len;
-	int			s;
 
 	DPRINTFN(10,("%s: %s: enter status=%d\n", device_xname(sc->cue_dev),
 		     __func__, status));
@@ -774,12 +813,10 @@ cue_rxeof(struct usbd_xfer *xfer, void *
 
 	m_set_rcvif(m, ifp);
 
-	s = splnet();
-
 	/* XXX ugly */
 	if (cue_newbuf(sc, c, NULL) == ENOBUFS) {
 		ifp->if_ierrors++;
-		goto done1;
+		goto done;
 	}
 
 	/*
@@ -792,9 +829,7 @@ cue_rxeof(struct usbd_xfer *xfer, void *
 
 	DPRINTFN(10,("%s: %s: deliver %d\n", device_xname(sc->cue_dev),
 		    __func__, m->m_len));
-	if_percpuq_enqueue(ifp->if_percpuq, m);
- done1:
-	splx(s);
+	if_percpuq_enqueue(sc->cue_ipq, m);
 
 done:
 
@@ -942,6 +977,17 @@ cue_send(struct cue_softc *sc, struct mb
 Static void
 cue_start(struct ifnet *ifp)
 {
+	struct cue_softc *sc = ifp->if_softc;
+	KASSERT(ifp->if_extflags & IFEF_START_MPSAFE);
+
+	mutex_enter(&sc->cue_txlock);
+	cue_start_locked(ifp);
+	mutex_exit(&sc->cue_txlock);
+}
+
+Static void
+cue_start_locked(struct ifnet *ifp)
+{
 	struct cue_softc	*sc = ifp->if_softc;
 	struct mbuf		*m_head = NULL;
 
@@ -978,23 +1024,32 @@ cue_start(struct ifnet *ifp)
 	ifp->if_timer = 5;
 }
 
-Static void
-cue_init(void *xsc)
+Static int
+cue_init(struct ifnet *ifp)
 {
-	struct cue_softc	*sc = xsc;
-	struct ifnet		*ifp = GET_IFP(sc);
-	int			i, s, ctl;
+	struct cue_softc *sc = ifp->if_softc;
+
+	mutex_enter(&sc->cue_lock);
+	int ret = cue_init_locked(ifp);
+	mutex_exit(&sc->cue_lock);
+
+	return ret;
+}
+
+Static int
+cue_init_locked(struct ifnet *ifp)
+{
+	struct cue_softc	*sc = ifp->if_softc;
+	int			i, ctl, err = 0;
 	const u_char		*eaddr;
 
 	if (sc->cue_dying)
-		return;
+		return EIO;
 
 	DPRINTFN(10,("%s: %s: enter\n", device_xname(sc->cue_dev),__func__));
 
 	if (ifp->if_flags & IFF_RUNNING)
-		return;
-
-	s = splnet();
+		return 0;
 
 	/*
 	 * Cancel pending I/O and free all RX/TX buffers.
@@ -1036,139 +1091,113 @@ cue_init(void *xsc)
 	cue_csr_write_1(sc, CUE_LEDCTL, CUE_LEDCTL_FOLLOW_LINK);
 
 	if (sc->cue_ep[CUE_ENDPT_RX] == NULL) {
-		if (cue_open_pipes(sc)) {
-			splx(s);
-			return;
+		/* Open RX and TX pipes. */
+		err = usbd_open_pipe(sc->cue_iface, sc->cue_ed[CUE_ENDPT_RX],
+		    USBD_EXCLUSIVE_USE, &sc->cue_ep[CUE_ENDPT_RX]);
+		if (err) {
+			printf("%s: open rx pipe failed: %s\n",
+			device_xname(sc->cue_dev), usbd_errstr(err));
+			goto fail;
+		}
+		err = usbd_open_pipe(sc->cue_iface, sc->cue_ed[CUE_ENDPT_TX],
+		    USBD_EXCLUSIVE_USE, &sc->cue_ep[CUE_ENDPT_TX]);
+		if (err) {
+			printf("%s: open tx pipe failed: %s\n",
+			device_xname(sc->cue_dev), usbd_errstr(err));
+			goto fail1;
 		}
 	}
 	/* Init TX ring. */
 	if (cue_tx_list_init(sc)) {
 		printf("%s: tx list init failed\n", device_xname(sc->cue_dev));
-		splx(s);
-		return;
+		goto fail2;
 	}
 
 	/* Init RX ring. */
 	if (cue_rx_list_init(sc)) {
 		printf("%s: rx list init failed\n", device_xname(sc->cue_dev));
-		splx(s);
-		return;
+		goto fail3;
 	}
 
+	/* Start up the receive pipe. */
+	for (i = 0; i < CUE_RX_LIST_CNT; i++) {
+		struct cue_chain *c = &sc->cue_cdata.cue_rx_chain[i];
+		usbd_setup_xfer(c->cue_xfer, c, c->cue_buf, CUE_BUFSZ,
+		USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, cue_rxeof);
+		usbd_transfer(c->cue_xfer);
+	}
 
 	ifp->if_flags |= IFF_RUNNING;
 	ifp->if_flags &= ~IFF_OACTIVE;
 
-	splx(s);
-
 	callout_reset(&(sc->cue_stat_ch), (hz), (cue_tick), (sc));
+
+	return 0;
+
+fail3:
+	cue_tx_list_free(sc);
+fail2:
+	usbd_close_pipe(sc->cue_ep[CUE_ENDPT_TX]);
+fail1:
+	usbd_close_pipe(sc->cue_ep[CUE_ENDPT_RX]);
+fail:
+	return EIO;
 }
 
 Static int
-cue_open_pipes(struct cue_softc	*sc)
+cue_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 {
-	struct cue_chain	*c;
-	usbd_status		err;
-	int			i;
+	struct cue_softc	*sc = ifp->if_softc;
+	int			s, error = 0;
 
-	/* Open RX and TX pipes. */
-	err = usbd_open_pipe(sc->cue_iface, sc->cue_ed[CUE_ENDPT_RX],
-	    USBD_EXCLUSIVE_USE, &sc->cue_ep[CUE_ENDPT_RX]);
-	if (err) {
-		printf("%s: open rx pipe failed: %s\n",
-		    device_xname(sc->cue_dev), usbd_errstr(err));
-		return EIO;
-	}
-	err = usbd_open_pipe(sc->cue_iface, sc->cue_ed[CUE_ENDPT_TX],
-	    USBD_EXCLUSIVE_USE, &sc->cue_ep[CUE_ENDPT_TX]);
-	if (err) {
-		printf("%s: open tx pipe failed: %s\n",
-		    device_xname(sc->cue_dev), usbd_errstr(err));
+	if (sc->cue_dying)
 		return EIO;
-	}
 
-	/* Start up the receive pipe. */
-	for (i = 0; i < CUE_RX_LIST_CNT; i++) {
-		c = &sc->cue_cdata.cue_rx_chain[i];
+	s = splnet();
+	error = ether_ioctl(ifp, cmd, data);
+	splx(s);
 
-		usbd_setup_xfer(c->cue_xfer, c, c->cue_buf, CUE_BUFSZ,
-		    USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, cue_rxeof);
-		usbd_transfer(c->cue_xfer);
+	if (error == ENETRESET) {
+		error = 0;
+		if (cmd == SIOCADDMULTI || cmd == SIOCDELMULTI) {
+			mutex_enter(&sc->cue_lock);
+			cue_setmulti(sc);
+			mutex_exit(&sc->cue_lock);
+		}
 	}
-
-	return 0;
+	return error;
 }
 
 Static int
-cue_ioctl(struct ifnet *ifp, u_long command, void *data)
+cue_ifflags_cb(struct ethercom *ec)
 {
-	struct cue_softc	*sc = ifp->if_softc;
-	struct ifaddr 		*ifa = (struct ifaddr *)data;
-	struct ifreq		*ifr = (struct ifreq *)data;
-	int			s, error = 0;
+	struct ifnet *ifp = &ec->ec_if;
+	struct cue_softc *sc = ifp->if_softc;
+	int rc = 0;
 
-	if (sc->cue_dying)
-		return EIO;
+	mutex_enter(&sc->cue_lock);
 
-	s = splnet();
+	int change = ifp->if_flags ^ sc->cue_if_flags;
+	sc->cue_if_flags = ifp->if_flags;
 
-	switch(command) {
-	case SIOCINITIFADDR:
-		ifp->if_flags |= IFF_UP;
-		cue_init(sc);
+	if ((change & ~(IFF_CANTCHANGE | IFF_DEBUG)) != 0) {
+		rc = ENETRESET;
+		goto out;
+	}
 
-		switch (ifa->ifa_addr->sa_family) {
-#ifdef INET
-		case AF_INET:
-			arp_ifinit(ifp, ifa);
-			break;
-#endif /* INET */
-		}
-		break;
-
-	case SIOCSIFMTU:
-		if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > ETHERMTU)
-			error = EINVAL;
-		else if ((error = ifioctl_common(ifp, command, data)) == ENETRESET)
-			error = 0;
-		break;
-
-	case SIOCSIFFLAGS:
-		if ((error = ifioctl_common(ifp, command, data)) != 0)
-			break;
-		if (ifp->if_flags & IFF_UP) {
-			if (ifp->if_flags & IFF_RUNNING &&
-			    ifp->if_flags & IFF_PROMISC &&
-			    !(sc->cue_if_flags & IFF_PROMISC)) {
-				CUE_SETBIT(sc, CUE_ETHCTL, CUE_ETHCTL_PROMISC);
-				cue_setmulti(sc);
-			} else if (ifp->if_flags & IFF_RUNNING &&
-			    !(ifp->if_flags & IFF_PROMISC) &&
-			    sc->cue_if_flags & IFF_PROMISC) {
-				CUE_CLRBIT(sc, CUE_ETHCTL, CUE_ETHCTL_PROMISC);
-				cue_setmulti(sc);
-			} else if (!(ifp->if_flags & IFF_RUNNING))
-				cue_init(sc);
-		} else {
-			if (ifp->if_flags & IFF_RUNNING)
-				cue_stop(sc);
+	if ((change & IFF_PROMISC) != 0) {
+		if (ifp->if_flags & IFF_PROMISC) {
+			CUE_SETBIT(sc, CUE_ETHCTL, CUE_ETHCTL_PROMISC);
+		} else if (!(ifp->if_flags & IFF_PROMISC)) {
+			CUE_CLRBIT(sc, CUE_ETHCTL, CUE_ETHCTL_PROMISC);
 		}
-		sc->cue_if_flags = ifp->if_flags;
-		error = 0;
-		break;
-	case SIOCADDMULTI:
-	case SIOCDELMULTI:
 		cue_setmulti(sc);
-		error = 0;
-		break;
-	default:
-		error = ether_ioctl(ifp, command, data);
-		break;
 	}
 
-	splx(s);
+out:
+	mutex_exit(&sc->cue_lock);
 
-	return error;
+	return rc;
 }
 
 Static void
@@ -1204,9 +1233,16 @@ cue_watchdog(struct ifnet *ifp)
 Static void
 cue_stop(struct cue_softc *sc)
 {
+	mutex_enter(&sc->cue_lock);
+	cue_stop_locked(sc);
+	mutex_exit(&sc->cue_lock);
+}
+
+Static void
+cue_stop_locked(struct cue_softc *sc)
+{
 	usbd_status		err;
 	struct ifnet		*ifp;
-	int			i;
 
 	DPRINTFN(10,("%s: %s: enter\n", device_xname(sc->cue_dev),__func__));
 
@@ -1242,26 +1278,6 @@ cue_stop(struct cue_softc *sc)
 		}
 	}
 
-	/* Free RX resources. */
-	for (i = 0; i < CUE_RX_LIST_CNT; i++) {
-		if (sc->cue_cdata.cue_rx_chain[i].cue_xfer != NULL) {
-			usbd_destroy_xfer(sc->cue_cdata.cue_rx_chain[i].cue_xfer);
-			sc->cue_cdata.cue_rx_chain[i].cue_xfer = NULL;
-		}
-	}
-
-	/* Free TX resources. */
-	for (i = 0; i < CUE_TX_LIST_CNT; i++) {
-		if (sc->cue_cdata.cue_tx_chain[i].cue_mbuf != NULL) {
-			m_freem(sc->cue_cdata.cue_tx_chain[i].cue_mbuf);
-			sc->cue_cdata.cue_tx_chain[i].cue_mbuf = NULL;
-		}
-		if (sc->cue_cdata.cue_tx_chain[i].cue_xfer != NULL) {
-			usbd_destroy_xfer(sc->cue_cdata.cue_tx_chain[i].cue_xfer);
-			sc->cue_cdata.cue_tx_chain[i].cue_xfer = NULL;
-		}
-	}
-
 	/* Stop transfers. */
 	if (sc->cue_ep[CUE_ENDPT_RX] != NULL) {
 		err = usbd_close_pipe(sc->cue_ep[CUE_ENDPT_RX]);

Index: src/sys/dev/usb/if_cuereg.h
diff -u src/sys/dev/usb/if_cuereg.h:1.18.24.4 src/sys/dev/usb/if_cuereg.h:1.18.24.5
--- src/sys/dev/usb/if_cuereg.h:1.18.24.4	Sun Mar 20 08:42:19 2016
+++ src/sys/dev/usb/if_cuereg.h	Mon Dec 12 13:15:39 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_cuereg.h,v 1.18.24.4 2016/03/20 08:42:19 skrll Exp $	*/
+/*	$NetBSD: if_cuereg.h,v 1.18.24.5 2016/12/12 13:15:39 skrll Exp $	*/
 /*
  * Copyright (c) 1997, 1998, 1999, 2000
  *	Bill Paul <wp...@ee.columbia.edu>.  All rights reserved.
@@ -185,6 +185,12 @@ struct cue_softc {
 	uint16_t		cue_rxfilt;
 	struct cue_cdata	cue_cdata;
 
+	kmutex_t		cue_lock;
+	kmutex_t		cue_txlock;
+	kmutex_t		cue_rxlock;
+
+	struct if_percpuq	*cue_ipq;
+
 	char			cue_dying;
 	char			cue_attached;
 	u_int			cue_rx_errs;

Index: src/sys/dev/usb/if_udav.c
diff -u src/sys/dev/usb/if_udav.c:1.43.4.11 src/sys/dev/usb/if_udav.c:1.43.4.12
--- src/sys/dev/usb/if_udav.c:1.43.4.11	Mon Dec  5 10:55:18 2016
+++ src/sys/dev/usb/if_udav.c	Mon Dec 12 13:15:39 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_udav.c,v 1.43.4.11 2016/12/05 10:55:18 skrll Exp $	*/
+/*	$NetBSD: if_udav.c,v 1.43.4.12 2016/12/12 13:15:39 skrll Exp $	*/
 /*	$nabe: if_udav.c,v 1.3 2003/08/21 16:57:19 nabe Exp $	*/
 
 /*
@@ -45,7 +45,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_udav.c,v 1.43.4.11 2016/12/05 10:55:18 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_udav.c,v 1.43.4.12 2016/12/12 13:15:39 skrll Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -96,9 +96,12 @@ CFATTACH_DECL_NEW(udav, sizeof(struct ud
 
 Static int udav_openpipes(struct udav_softc *);
 Static int udav_rx_list_init(struct udav_softc *);
+Static void udav_rx_list_free(struct udav_softc *);
 Static int udav_tx_list_init(struct udav_softc *);
+Static void udav_tx_list_free(struct udav_softc *);
 Static int udav_newbuf(struct udav_softc *, struct udav_chain *, struct mbuf *);
 Static void udav_start(struct ifnet *);
+Static void udav_start_locked(struct ifnet *);
 Static int udav_send(struct udav_softc *, struct mbuf *, int);
 Static void udav_txeof(struct usbd_xfer *, void *, usbd_status);
 Static void udav_rxeof(struct usbd_xfer *, void *, usbd_status);
@@ -107,6 +110,7 @@ Static void udav_tick_task(void *);
 Static int udav_ioctl(struct ifnet *, u_long, void *);
 Static void udav_stop_task(struct udav_softc *);
 Static void udav_stop(struct ifnet *, int);
+Static void udav_stop_locked(struct ifnet *, int);
 Static void udav_watchdog(struct ifnet *);
 Static int udav_ifmedia_change(struct ifnet *);
 Static void udav_ifmedia_status(struct ifnet *, struct ifmediareq *);
@@ -116,6 +120,7 @@ Static int udav_miibus_readreg(device_t,
 Static void udav_miibus_writereg(device_t, int, int, int);
 Static void udav_miibus_statchg(struct ifnet *);
 Static int udav_init(struct ifnet *);
+Static int udav_init_locked(struct ifnet *);
 Static void udav_setmulti(struct udav_softc *);
 Static void udav_reset(struct udav_softc *);
 
@@ -198,7 +203,7 @@ udav_attach(device_t parent, device_t se
 	struct ifnet *ifp;
 	struct mii_data *mii;
 	u_char eaddr[ETHER_ADDR_LEN];
-	int i, s;
+	int i;
 
 	sc->sc_dev = self;
 
@@ -219,6 +224,9 @@ udav_attach(device_t parent, device_t se
 
 	usb_init_task(&sc->sc_tick_task, udav_tick_task, sc, 0);
 	mutex_init(&sc->sc_mii_lock, MUTEX_DEFAULT, IPL_NONE);
+	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
+	mutex_init(&sc->sc_txlock, MUTEX_DEFAULT, IPL_SOFTUSB);
+	mutex_init(&sc->sc_rxlock, MUTEX_DEFAULT, IPL_SOFTUSB);
 	usb_init_task(&sc->sc_stop_task, (void (*)(void *))udav_stop_task, sc,
 	    0);
 
@@ -263,8 +271,6 @@ udav_attach(device_t parent, device_t se
 		goto bad;
 	}
 
-	s = splnet();
-
 	/* reset the adapter */
 	udav_reset(sc);
 
@@ -272,7 +278,6 @@ udav_attach(device_t parent, device_t se
 	err = udav_csr_read(sc, UDAV_PAR, (void *)eaddr, ETHER_ADDR_LEN);
 	if (err) {
 		aprint_error_dev(self, "read MAC address failed\n");
-		splx(s);
 		goto bad;
 	}
 
@@ -285,6 +290,7 @@ udav_attach(device_t parent, device_t se
 	ifp->if_mtu = ETHERMTU;
 	strncpy(ifp->if_xname, device_xname(self), IFNAMSIZ);
 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+	ifp->if_extflags = IFEF_START_MPSAFE;
 	ifp->if_start = udav_start;
 	ifp->if_ioctl = udav_ioctl;
 	ifp->if_watchdog = udav_watchdog;
@@ -319,15 +325,16 @@ udav_attach(device_t parent, device_t se
 
 skipmii:
 	/* attach the interface */
-	if_attach(ifp);
+	if_initialize(ifp);
+	sc->sc_ipq = if_percpuq_create(&sc->sc_ec.ec_if);
 	ether_ifattach(ifp, eaddr);
+	if_register(ifp);
 
 	rnd_attach_source(&sc->rnd_source, device_xname(self),
 	    RND_TYPE_NET, RND_FLAG_DEFAULT);
 
 	callout_init(&sc->sc_stat_ch, 0);
 	sc->sc_attached = 1;
-	splx(s);
 
 	usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, dev, sc->sc_dev);
 
@@ -635,19 +642,29 @@ Static int
 udav_init(struct ifnet *ifp)
 {
 	struct udav_softc *sc = ifp->if_softc;
+
+	mutex_enter(&sc->sc_lock);
+	int ret = udav_init_locked(ifp);
+	mutex_exit(&sc->sc_lock);
+
+	return ret;
+}
+
+Static int
+udav_init_locked(struct ifnet *ifp)
+{
+	struct udav_softc *sc = ifp->if_softc;
 	struct mii_data *mii = GET_MII(sc);
 	uint8_t eaddr[ETHER_ADDR_LEN];
-	int rc, s;
+	int rc;
 
 	DPRINTF(("%s: %s: enter\n", device_xname(sc->sc_dev), __func__));
 
 	if (sc->sc_dying)
 		return EIO;
 
-	s = splnet();
-
 	/* Cancel pending I/O and free all TX/RX buffers */
-	udav_stop(ifp, 1);
+	udav_stop_locked(ifp, 1);
 
 	memcpy(eaddr, CLLADDR(ifp->if_sadl), sizeof(eaddr));
 	udav_csr_write(sc, UDAV_PAR, eaddr, ETHER_ADDR_LEN);
@@ -678,11 +695,10 @@ udav_init(struct ifnet *ifp)
 	if ((rc = mii_mediachg(mii)) == ENXIO)
 		rc = 0;
 	else if (rc != 0)
-		goto out;
+		return rc;
 
 	if (sc->sc_pipe_tx == NULL || sc->sc_pipe_rx == NULL) {
 		if (udav_openpipes(sc)) {
-			splx(s);
 			return EIO;
 		}
 	}
@@ -690,15 +706,13 @@ udav_init(struct ifnet *ifp)
 	/* Initialize transmit ring */
 	if (udav_tx_list_init(sc)) {
 		printf("%s: tx list init failed\n", device_xname(sc->sc_dev));
-		splx(s);
-		return EIO;
+		goto fail;
 	}
 
 	/* Initialize receive ring */
 	if (udav_rx_list_init(sc)) {
 		printf("%s: rx list init failed\n", device_xname(sc->sc_dev));
-		splx(s);
-		return EIO;
+		goto fail1;
 	}
 
 	/* Start up the receive pipe. */
@@ -716,9 +730,11 @@ udav_init(struct ifnet *ifp)
 
 	callout_reset(&sc->sc_stat_ch, hz, udav_tick, sc);
 
-out:
-	splx(s);
 	return rc;
+fail1:
+	udav_tx_list_free(sc);
+fail:
+	return EIO;
 }
 
 Static void
@@ -861,6 +877,7 @@ udav_openpipes(struct udav_softc *sc)
 	err = usbd_open_pipe(sc->sc_ctl_iface, sc->sc_bulkout_no,
 			     USBD_EXCLUSIVE_USE, &sc->sc_pipe_tx);
 	if (err) {
+		usbd_close_pipe(sc->sc_pipe_rx);
 		printf("%s: open tx pipe failed: %s\n",
 		       device_xname(sc->sc_dev), usbd_errstr(err));
 		error = EIO;
@@ -951,6 +968,21 @@ udav_rx_list_init(struct udav_softc *sc)
 	return 0;
 }
 
+Static void
+udav_rx_list_free(struct udav_softc *sc)
+{
+	for (int i = 0; i < UDAV_RX_LIST_CNT; i++) {
+		if (sc->sc_cdata.udav_rx_chain[i].udav_mbuf != NULL) {
+			m_freem(sc->sc_cdata.udav_rx_chain[i].udav_mbuf);
+			sc->sc_cdata.udav_rx_chain[i].udav_mbuf = NULL;
+		}
+		if (sc->sc_cdata.udav_rx_chain[i].udav_xfer != NULL) {
+			usbd_destroy_xfer(sc->sc_cdata.udav_rx_chain[i].udav_xfer);
+			sc->sc_cdata.udav_rx_chain[i].udav_xfer = NULL;
+		}
+	}
+}
+
 Static int
 udav_tx_list_init(struct udav_softc *sc)
 {
@@ -979,8 +1011,34 @@ udav_tx_list_init(struct udav_softc *sc)
 }
 
 Static void
+udav_tx_list_free(struct udav_softc *sc)
+{
+	for (int i = 0; i < UDAV_TX_LIST_CNT; i++) {
+		if (sc->sc_cdata.udav_tx_chain[i].udav_mbuf != NULL) {
+			m_freem(sc->sc_cdata.udav_tx_chain[i].udav_mbuf);
+			sc->sc_cdata.udav_tx_chain[i].udav_mbuf = NULL;
+		}
+		if (sc->sc_cdata.udav_tx_chain[i].udav_xfer != NULL) {
+			usbd_destroy_xfer(sc->sc_cdata.udav_tx_chain[i].udav_xfer);
+			sc->sc_cdata.udav_tx_chain[i].udav_xfer = NULL;
+		}
+	}
+}
+
+Static void
 udav_start(struct ifnet *ifp)
 {
+	struct udav_softc * const sc = ifp->if_softc;
+	KASSERT(ifp->if_extflags & IFEF_START_MPSAFE);
+
+	mutex_enter(&sc->sc_txlock);
+	udav_start_locked(ifp);
+	mutex_exit(&sc->sc_txlock);
+}
+
+Static void
+udav_start_locked(struct ifnet *ifp)
+{
 	struct udav_softc *sc = ifp->if_softc;
 	struct mbuf *m_head = NULL;
 
@@ -1001,7 +1059,6 @@ udav_start(struct ifnet *ifp)
 		return;
 
 	if (udav_send(sc, m_head, 0)) {
-		ifp->if_flags |= IFF_OACTIVE;
 		return;
 	}
 
@@ -1124,7 +1181,6 @@ udav_rxeof(struct usbd_xfer *xfer, void 
 	struct mbuf *m;
 	uint32_t total_len;
 	uint8_t *pktstat;
-	int s;
 
 	DPRINTF(("%s: %s: enter\n", device_xname(sc->sc_dev),__func__));
 
@@ -1182,21 +1238,16 @@ udav_rxeof(struct usbd_xfer *xfer, void 
 	m->m_pkthdr.len = m->m_len = total_len;
 	m_set_rcvif(m, ifp);
 
-	s = splnet();
-
 	if (udav_newbuf(sc, c, NULL) == ENOBUFS) {
 		ifp->if_ierrors++;
-		goto done1;
+		goto done;
 	}
 
 	bpf_mtap(ifp, m);
 
 	DPRINTF(("%s: %s: deliver %d\n", device_xname(sc->sc_dev),
 		 __func__, m->m_len));
-	if_percpuq_enqueue((ifp)->if_percpuq, (m));
-
- done1:
-	splx(s);
+	if_percpuq_enqueue(sc->sc_ipq, (m));
 
  done:
 	/* Setup new transfer */
@@ -1270,19 +1321,28 @@ udav_stop_task(struct udav_softc *sc)
 	udav_stop(GET_IFP(sc), 1);
 }
 
-/* Stop the adapter and free any mbufs allocated to the RX and TX lists. */
 Static void
 udav_stop(struct ifnet *ifp, int disable)
 {
+	struct udav_softc * const sc = ifp->if_softc;
+
+	mutex_enter(&sc->sc_lock);
+	udav_stop_locked(ifp, disable);
+	mutex_exit(&sc->sc_lock);
+}
+
+/* Stop the adapter and free any mbufs allocated to the RX and TX lists. */
+Static void
+udav_stop_locked(struct ifnet *ifp, int disable)
+{
 	struct udav_softc *sc = ifp->if_softc;
 	usbd_status err;
-	int i;
 
 	DPRINTF(("%s: %s: enter\n", device_xname(sc->sc_dev), __func__));
 
 	ifp->if_timer = 0;
 
-	udav_reset(sc);
+//	udav_reset(sc);
 
 	callout_stop(&sc->sc_stat_ch);
 
@@ -1319,29 +1379,9 @@ udav_stop(struct ifnet *ifp, int disable
 	}
 #endif
 
-	/* Free RX resources. */
-	for (i = 0; i < UDAV_RX_LIST_CNT; i++) {
-		if (sc->sc_cdata.udav_rx_chain[i].udav_mbuf != NULL) {
-			m_freem(sc->sc_cdata.udav_rx_chain[i].udav_mbuf);
-			sc->sc_cdata.udav_rx_chain[i].udav_mbuf = NULL;
-		}
-		if (sc->sc_cdata.udav_rx_chain[i].udav_xfer != NULL) {
-			usbd_destroy_xfer(sc->sc_cdata.udav_rx_chain[i].udav_xfer);
-			sc->sc_cdata.udav_rx_chain[i].udav_xfer = NULL;
-		}
-	}
+	udav_rx_list_free(sc);
 
-	/* Free TX resources. */
-	for (i = 0; i < UDAV_TX_LIST_CNT; i++) {
-		if (sc->sc_cdata.udav_tx_chain[i].udav_mbuf != NULL) {
-			m_freem(sc->sc_cdata.udav_tx_chain[i].udav_mbuf);
-			sc->sc_cdata.udav_tx_chain[i].udav_mbuf = NULL;
-		}
-		if (sc->sc_cdata.udav_tx_chain[i].udav_xfer != NULL) {
-			usbd_destroy_xfer(sc->sc_cdata.udav_tx_chain[i].udav_xfer);
-			sc->sc_cdata.udav_tx_chain[i].udav_xfer = NULL;
-		}
-	}
+	udav_tx_list_free(sc);
 
 	/* Close pipes */
 	/* RX endpoint */

Index: src/sys/dev/usb/if_udavreg.h
diff -u src/sys/dev/usb/if_udavreg.h:1.9.16.4 src/sys/dev/usb/if_udavreg.h:1.9.16.5
--- src/sys/dev/usb/if_udavreg.h:1.9.16.4	Sun Mar 20 08:42:19 2016
+++ src/sys/dev/usb/if_udavreg.h	Mon Dec 12 13:15:39 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_udavreg.h,v 1.9.16.4 2016/03/20 08:42:19 skrll Exp $	*/
+/*	$NetBSD: if_udavreg.h,v 1.9.16.5 2016/12/12 13:15:39 skrll Exp $	*/
 /*	$nabe: if_udavreg.h,v 1.2 2003/08/21 16:26:40 nabe Exp $	*/
 /*
  * Copyright (c) 2003
@@ -189,6 +189,9 @@ struct udav_softc {
 	struct ethercom		sc_ec; /* ethernet common */
 	struct mii_data		sc_mii;
 	kmutex_t		sc_mii_lock;
+	kmutex_t		sc_lock;
+	kmutex_t		sc_txlock;
+	kmutex_t		sc_rxlock;
 	int			sc_link;
 #define	sc_media udav_mii.mii_media
 	krndsource_t	rnd_source;
@@ -202,4 +205,6 @@ struct udav_softc {
 	struct usb_task		sc_stop_task;
 
 	uint16_t		sc_flags;
+
+	struct if_percpuq *	sc_ipq;
 };

Reply via email to