Module Name:    src
Committed By:   mrg
Date:           Sat Aug 10 02:17:36 UTC 2019

Modified Files:
        src/sys/dev/usb: if_axe.c if_axen.c if_cdce.c if_smsc.c if_udav.c
            if_ure.c if_urndis.c usbnet.c usbnet.h
        src/sys/sys: param.h

Log Message:
reduce the scope of struct usbnet:
- move a large number of members internal to usbnet.c's new
  "struct usbnet_private".
- provide accessors for a few of these
- move struct usbnet_cdata into usbnet.c as well, but move
  bufsz, list count, and xfer flags back out into struct usbnet,
  and have them set as part of the setup efore usbnet_attach()
- split the intr pipe parts into their own structure
- move all the main usbnet*lock* code into usbnet.c too

usbnet_attach() goes down to 2 args, and the inputs needed are
now the full contents of 'struct usbnet' besides the driver
owned 'un_flags' and usbnet owned 'un_pri'.

welcome netbsd 9.99.6.


To generate a diff of this commit:
cvs rdiff -u -r1.108 -r1.109 src/sys/dev/usb/if_axe.c
cvs rdiff -u -r1.58 -r1.59 src/sys/dev/usb/if_axen.c
cvs rdiff -u -r1.60 -r1.61 src/sys/dev/usb/if_cdce.c
cvs rdiff -u -r1.50 -r1.51 src/sys/dev/usb/if_smsc.c
cvs rdiff -u -r1.64 -r1.65 src/sys/dev/usb/if_udav.c
cvs rdiff -u -r1.20 -r1.21 src/sys/dev/usb/if_ure.c
cvs rdiff -u -r1.26 -r1.27 src/sys/dev/usb/if_urndis.c
cvs rdiff -u -r1.10 -r1.11 src/sys/dev/usb/usbnet.c
cvs rdiff -u -r1.8 -r1.9 src/sys/dev/usb/usbnet.h
cvs rdiff -u -r1.604 -r1.605 src/sys/sys/param.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_axe.c
diff -u src/sys/dev/usb/if_axe.c:1.108 src/sys/dev/usb/if_axe.c:1.109
--- src/sys/dev/usb/if_axe.c:1.108	Fri Aug  9 02:52:59 2019
+++ src/sys/dev/usb/if_axe.c	Sat Aug 10 02:17:36 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_axe.c,v 1.108 2019/08/09 02:52:59 mrg Exp $	*/
+/*	$NetBSD: if_axe.c,v 1.109 2019/08/10 02:17:36 mrg 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.108 2019/08/09 02:52:59 mrg Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_axe.c,v 1.109 2019/08/10 02:17:36 mrg Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_usb.h"
@@ -385,7 +385,7 @@ axe_mii_statchg_cb(struct ifnet *ifp)
 		return;
 
 	val = 0;
-	un->un_link = false;
+	usbnet_set_link(un, false);
 	if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) {
 		val |= AXE_MEDIA_FULL_DUPLEX;
 		if (AXE_IS_178_FAMILY(un)) {
@@ -404,14 +404,14 @@ axe_mii_statchg_cb(struct ifnet *ifp)
 		switch (IFM_SUBTYPE(mii->mii_media_active)) {
 		case IFM_1000_T:
 			val |= AXE_178_MEDIA_GMII | AXE_178_MEDIA_ENCK;
-			un->un_link = true;
+			usbnet_set_link(un, true);
 			break;
 		case IFM_100_TX:
 			val |= AXE_178_MEDIA_100TX;
-			un->un_link = true;
+			usbnet_set_link(un, true);
 			break;
 		case IFM_10_T:
-			un->un_link = true;
+			usbnet_set_link(un, true);
 			break;
 		}
 	}
@@ -886,6 +886,10 @@ axe_attach(device_t parent, device_t sel
 	un->un_udev = dev;
 	un->un_sc = sc;
 	un->un_ops = &axe_ops;
+	un->un_rx_xfer_flags = USBD_SHORT_XFER_OK;
+	un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER;
+	un->un_rx_list_cnt = AXE_RX_LIST_CNT;
+	un->un_tx_list_cnt = AXE_TX_LIST_CNT;
 
 	err = usbd_set_config_no(dev, AXE_CONFIG_NO, 1);
 	if (err) {
@@ -910,6 +914,7 @@ axe_attach(device_t parent, device_t sel
 		    AXE_178_MAX_BUFSZ : AXE_178_MIN_BUFSZ;
 	else
 		bufsz = AXE_172_BUFSZ;
+	un->un_rx_bufsz = un->un_tx_bufsz = bufsz;
 
 	un->un_ed[USBNET_ENDPT_RX] = 0;
 	un->un_ed[USBNET_ENDPT_TX] = 0;
@@ -937,8 +942,7 @@ axe_attach(device_t parent, device_t sel
 	}
 
 	/* Set these up now for axe_cmd().  */
-	usbnet_attach(un, "axedet", AXE_RX_LIST_CNT, AXE_TX_LIST_CNT,
-		      USBD_SHORT_XFER_OK, USBD_FORCE_SHORT_XFER, bufsz, bufsz);
+	usbnet_attach(un, "axedet");
 
 	/* We need the PHYID for init dance in some cases */
 	usbnet_lock_mii(un);

Index: src/sys/dev/usb/if_axen.c
diff -u src/sys/dev/usb/if_axen.c:1.58 src/sys/dev/usb/if_axen.c:1.59
--- src/sys/dev/usb/if_axen.c:1.58	Fri Aug  9 02:52:59 2019
+++ src/sys/dev/usb/if_axen.c	Sat Aug 10 02:17:36 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_axen.c,v 1.58 2019/08/09 02:52:59 mrg Exp $	*/
+/*	$NetBSD: if_axen.c,v 1.59 2019/08/10 02:17:36 mrg 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.58 2019/08/09 02:52:59 mrg Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_axen.c,v 1.59 2019/08/10 02:17:36 mrg Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_usb.h"
@@ -169,16 +169,16 @@ axen_mii_statchg(struct ifnet *ifp)
 	if (usbnet_isdying(un))
 		return;
 
-	un->un_link = false;
+	usbnet_set_link(un, false);
 	if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) ==
 	    (IFM_ACTIVE | IFM_AVALID)) {
 		switch (IFM_SUBTYPE(mii->mii_media_active)) {
 		case IFM_10_T:
 		case IFM_100_TX:
-			un->un_link = true;
+			usbnet_set_link(un, true);
 			break;
 		case IFM_1000_T:
-			un->un_link = true;
+			usbnet_set_link(un, true);
 			break;
 		default:
 			break;
@@ -186,7 +186,7 @@ axen_mii_statchg(struct ifnet *ifp)
 	}
 
 	/* Lost link, do nothing. */
-	if (!un->un_link)
+	if (!usbnet_havelink(un))
 		return;
 
 	val = 0;
@@ -599,7 +599,6 @@ axen_attach(device_t parent, device_t se
 	usb_interface_descriptor_t *id;
 	usb_endpoint_descriptor_t *ed;
 	char *devinfop;
-	unsigned rx_bufsz, tx_bufsz;
 	uint16_t axen_flags;
 	int i;
 
@@ -613,6 +612,10 @@ axen_attach(device_t parent, device_t se
 	un->un_udev = dev;
 	un->un_sc = un;
 	un->un_ops = &axen_ops;
+	un->un_rx_xfer_flags = USBD_SHORT_XFER_OK;
+	un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER;
+	un->un_rx_list_cnt = AXEN_RX_LIST_CNT;
+	un->un_tx_list_cnt = AXEN_TX_LIST_CNT;
 
 	err = usbd_set_config_no(dev, AXEN_CONFIG_NO, 1);
 	if (err) {
@@ -632,17 +635,17 @@ axen_attach(device_t parent, device_t se
 	/* decide on what our bufsize will be */
 	switch (dev->ud_speed) {
 	case USB_SPEED_SUPER:
-		rx_bufsz = AXEN_BUFSZ_SS * 1024;
+		un->un_rx_bufsz = AXEN_BUFSZ_SS * 1024;
 		break;
 	case USB_SPEED_HIGH:
-		rx_bufsz = AXEN_BUFSZ_HS * 1024;
+		un->un_rx_bufsz = AXEN_BUFSZ_HS * 1024;
 		break;
 	default:
-		rx_bufsz = AXEN_BUFSZ_LS * 1024;
+		un->un_rx_bufsz = AXEN_BUFSZ_LS * 1024;
 		break;
 	}
-	tx_bufsz = IP_MAXPACKET + ETHER_HDR_LEN + ETHER_CRC_LEN +
-		   ETHER_VLAN_ENCAP_LEN + sizeof(struct axen_sframe_hdr);
+	un->un_tx_bufsz = IP_MAXPACKET + ETHER_HDR_LEN + ETHER_CRC_LEN +
+	    ETHER_VLAN_ENCAP_LEN + sizeof(struct axen_sframe_hdr);
 
 	/* Find endpoints. */
 	id = usbd_get_interface_descriptor(un->un_iface);
@@ -667,9 +670,7 @@ axen_attach(device_t parent, device_t se
 	}
 
 	/* Set these up now for axen_cmd().  */
-	usbnet_attach(un, "axendet", AXEN_RX_LIST_CNT, AXEN_TX_LIST_CNT,
-		      USBD_SHORT_XFER_OK, USBD_FORCE_SHORT_XFER,
-		      rx_bufsz, tx_bufsz);
+	usbnet_attach(un, "axendet");
 
 	un->un_phyno = AXEN_PHY_ID;
 	DPRINTF(("%s: phyno %d\n", device_xname(self), un->un_phyno));
@@ -876,7 +877,7 @@ axen_tx_prepare(struct usbnet *un, struc
 	}
 
 	length = m->m_pkthdr.len + sizeof(hdr);
-	KASSERT(length <= un->un_cdata.uncd_tx_bufsz);
+	KASSERT(length <= un->un_tx_bufsz);
 
 	hdr.plen = htole32(m->m_pkthdr.len);
 

Index: src/sys/dev/usb/if_cdce.c
diff -u src/sys/dev/usb/if_cdce.c:1.60 src/sys/dev/usb/if_cdce.c:1.61
--- src/sys/dev/usb/if_cdce.c:1.60	Fri Aug  9 02:52:59 2019
+++ src/sys/dev/usb/if_cdce.c	Sat Aug 10 02:17:36 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_cdce.c,v 1.60 2019/08/09 02:52:59 mrg Exp $ */
+/*	$NetBSD: if_cdce.c,v 1.61 2019/08/10 02:17:36 mrg Exp $ */
 
 /*
  * Copyright (c) 1997, 1998, 1999, 2000-2003 Bill Paul <wp...@windriver.com>
@@ -40,7 +40,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_cdce.c,v 1.60 2019/08/09 02:52:59 mrg Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_cdce.c,v 1.61 2019/08/10 02:17:36 mrg Exp $");
 
 #include <sys/param.h>
 #include <sys/kernel.h>
@@ -133,6 +133,12 @@ cdce_attach(device_t parent, device_t se
 	un->un_udev = dev;
 	un->un_sc = un;
 	un->un_ops = &cdce_ops;
+	un->un_rx_xfer_flags = USBD_SHORT_XFER_OK;
+	un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER;
+	un->un_rx_list_cnt = CDCE_RX_LIST_CNT;
+	un->un_tx_list_cnt = CDCE_TX_LIST_CNT;
+	un->un_rx_bufsz = CDCE_BUFSZ;
+	un->un_tx_bufsz = CDCE_BUFSZ;
 
 	t = cdce_lookup(uiaa->uiaa_vendor, uiaa->uiaa_product);
 	if (t)
@@ -242,9 +248,7 @@ cdce_attach(device_t parent, device_t se
 		un->un_eaddr[5] = (uint8_t)(device_unit(un->un_dev));
 	}
 
-	usbnet_attach(un, "cdcedet", CDCE_RX_LIST_CNT, CDCE_TX_LIST_CNT,
-		      USBD_SHORT_XFER_OK, USBD_FORCE_SHORT_XFER,
-		      CDCE_BUFSZ, CDCE_BUFSZ);
+	usbnet_attach(un, "cdcedet");
 	usbnet_attach_ifp(un, false, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST,
             0, 0);
 }
@@ -261,8 +265,7 @@ cdce_init(struct ifnet *ifp)
 	else {
 		usbnet_stop(un, ifp, 1);
 		rv = usbnet_init_rx_tx(un);
-		if (rv == 0)
-			un->un_link = true;
+		usbnet_set_link(un, rv == 0);
 	}
 	usbnet_unlock(un);
 

Index: src/sys/dev/usb/if_smsc.c
diff -u src/sys/dev/usb/if_smsc.c:1.50 src/sys/dev/usb/if_smsc.c:1.51
--- src/sys/dev/usb/if_smsc.c:1.50	Fri Aug  9 07:54:05 2019
+++ src/sys/dev/usb/if_smsc.c	Sat Aug 10 02:17:36 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_smsc.c,v 1.50 2019/08/09 07:54:05 skrll Exp $	*/
+/*	$NetBSD: if_smsc.c,v 1.51 2019/08/10 02:17:36 mrg Exp $	*/
 
 /*	$OpenBSD: if_smsc.c,v 1.4 2012/09/27 12:38:11 jsg Exp $	*/
 /*	$FreeBSD: src/sys/dev/usb/net/if_smsc.c,v 1.1 2012/08/15 04:03:55 gonzo Exp $ */
@@ -61,7 +61,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_smsc.c,v 1.50 2019/08/09 07:54:05 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_smsc.c,v 1.51 2019/08/10 02:17:36 mrg Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_usb.h"
@@ -319,13 +319,13 @@ smsc_miibus_statchg(struct ifnet *ifp)
 	uint32_t flow;
 	uint32_t afc_cfg;
 
-	un->un_link = false;
+	usbnet_set_link(un, false);
 	if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) ==
 	    (IFM_ACTIVE | IFM_AVALID)) {
 		switch (IFM_SUBTYPE(mii->mii_media_active)) {
 			case IFM_10_T:
 			case IFM_100_TX:
-				un->un_link = true;
+				usbnet_set_link(un, true);
 				break;
 			case IFM_1000_T:
 				/* Gigabit ethernet not supported by chipset */
@@ -336,7 +336,7 @@ smsc_miibus_statchg(struct ifnet *ifp)
 	}
 
 	/* Lost link, do nothing. */
-	if (!un->un_link)
+	if (!usbnet_havelink(un))
 		return;
 
 	usbnet_lock_mii(un);
@@ -801,6 +801,10 @@ smsc_attach(device_t parent, device_t se
 	un->un_udev = dev;
 	un->un_sc = sc;
 	un->un_ops = &smsc_ops;
+	un->un_rx_xfer_flags = USBD_SHORT_XFER_OK;
+	un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER;
+	un->un_rx_list_cnt = SMSC_RX_LIST_CNT;
+	un->un_tx_list_cnt = SMSC_TX_LIST_CNT;
 
 	devinfop = usbd_devinfo_alloc(un->un_udev, 0);
 	aprint_normal_dev(self, "%s\n", devinfop);
@@ -827,6 +831,8 @@ smsc_attach(device_t parent, device_t se
 	} else {
 		bufsz = SMSC_MIN_BUFSZ;
 	}
+	un->un_rx_bufsz = bufsz;
+	un->un_tx_bufsz = bufsz;
 
 	/* Find endpoints. */
 	for (i = 0; i < id->bNumEndpoints; i++) {
@@ -849,8 +855,7 @@ smsc_attach(device_t parent, device_t se
 		}
 	}
 
-	usbnet_attach(un, "smscdet", SMSC_RX_LIST_CNT, SMSC_TX_LIST_CNT,
-		      USBD_SHORT_XFER_OK, USBD_FORCE_SHORT_XFER, bufsz, bufsz);
+	usbnet_attach(un, "smscdet");
 
 #ifdef notyet
 	/*

Index: src/sys/dev/usb/if_udav.c
diff -u src/sys/dev/usb/if_udav.c:1.64 src/sys/dev/usb/if_udav.c:1.65
--- src/sys/dev/usb/if_udav.c:1.64	Fri Aug  9 06:44:42 2019
+++ src/sys/dev/usb/if_udav.c	Sat Aug 10 02:17:36 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_udav.c,v 1.64 2019/08/09 06:44:42 mrg Exp $	*/
+/*	$NetBSD: if_udav.c,v 1.65 2019/08/10 02:17:36 mrg 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.64 2019/08/09 06:44:42 mrg Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_udav.c,v 1.65 2019/08/10 02:17:36 mrg Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_usb.h"
@@ -180,6 +180,12 @@ udav_attach(device_t parent, device_t se
 	un->un_udev = dev;
 	un->un_sc = un;
 	un->un_ops = &udav_ops;
+	un->un_rx_xfer_flags = USBD_SHORT_XFER_OK;
+	un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER;
+	un->un_rx_list_cnt = UDAV_RX_LIST_CNT;
+	un->un_tx_list_cnt = UDAV_TX_LIST_CNT;
+	un->un_rx_bufsz = UDAV_BUFSZ;
+	un->un_tx_bufsz = UDAV_BUFSZ;
 
 	/* Move the device into the configured state. */
 	err = usbd_set_config_no(dev, UDAV_CONFIG_NO, 1); /* idx 0 */
@@ -237,9 +243,7 @@ udav_attach(device_t parent, device_t se
 // 	/* reset the adapter */
 // 	udav_reset(un);
 
-	usbnet_attach(un, "udavdet", UDAV_RX_LIST_CNT, UDAV_TX_LIST_CNT,
-		      USBD_SHORT_XFER_OK, USBD_FORCE_SHORT_XFER,
-		      UDAV_BUFSZ, UDAV_BUFSZ);
+	usbnet_attach(un, "udavdet");
 
 	/* Get Ethernet Address */
 	usbnet_lock_mii(un);
@@ -252,7 +256,7 @@ udav_attach(device_t parent, device_t se
 
 	bool have_mii = !ISSET(un->un_flags, UDAV_NO_PHY);
 	if (!have_mii)
-		un->un_link = 1;
+		usbnet_set_link(un, true);
 
 	/* initialize interface information */
 	usbnet_attach_ifp(un, have_mii,
@@ -867,12 +871,12 @@ udav_mii_statchg(struct ifnet *ifp)
 	if (usbnet_isdying(un))
 		return;
 
-	un->un_link = false;
+	usbnet_set_link(un, false);
 	if (mii->mii_media_status & IFM_ACTIVE &&
 	    IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
 		DPRINTF(("%s: %s: got link\n",
 			 device_xname(un->un_dev), __func__));
-		un->un_link = true;
+		usbnet_set_link(un, true);
 	}
 }
 

Index: src/sys/dev/usb/if_ure.c
diff -u src/sys/dev/usb/if_ure.c:1.20 src/sys/dev/usb/if_ure.c:1.21
--- src/sys/dev/usb/if_ure.c:1.20	Fri Aug  9 02:52:59 2019
+++ src/sys/dev/usb/if_ure.c	Sat Aug 10 02:17:36 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_ure.c,v 1.20 2019/08/09 02:52:59 mrg Exp $	*/
+/*	$NetBSD: if_ure.c,v 1.21 2019/08/10 02:17:36 mrg Exp $	*/
 /*	$OpenBSD: if_ure.c,v 1.10 2018/11/02 21:32:30 jcs Exp $	*/
 
 /*-
@@ -30,7 +30,7 @@
 /* RealTek RTL8152/RTL8153 10/100/Gigabit USB Ethernet device */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_ure.c,v 1.20 2019/08/09 02:52:59 mrg Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_ure.c,v 1.21 2019/08/10 02:17:36 mrg Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_usb.h"
@@ -302,18 +302,18 @@ ure_miibus_statchg(struct ifnet *ifp)
 	if (usbnet_isdying(un))
 		return;
 
-	un->un_link = false;
+	usbnet_set_link(un, false);
 	if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) ==
 	    (IFM_ACTIVE | IFM_AVALID)) {
 		switch (IFM_SUBTYPE(mii->mii_media_active)) {
 		case IFM_10_T:
 		case IFM_100_TX:
-			un->un_link = true;
+			usbnet_set_link(un, true);
 			break;
 		case IFM_1000_T:
 			if ((un->un_flags & URE_FLAG_8152) != 0)
 				break;
-			un->un_link = true;
+			usbnet_set_link(un, true);
 			break;
 		default:
 			break;
@@ -855,6 +855,12 @@ ure_attach(device_t parent, device_t sel
 	un->un_udev = dev;
 	un->un_sc = un;
 	un->un_ops = &ure_ops;
+	un->un_rx_xfer_flags = USBD_SHORT_XFER_OK;
+	un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER;
+	un->un_rx_list_cnt = URE_RX_LIST_CNT;
+	un->un_tx_list_cnt = URE_TX_LIST_CNT;
+	un->un_rx_bufsz = URE_BUFSZ;
+	un->un_tx_bufsz = URE_BUFSZ;
 
 #define URE_CONFIG_NO	1 /* XXX */
 	error = usbd_set_config_no(dev, URE_CONFIG_NO, 1);
@@ -892,9 +898,7 @@ ure_attach(device_t parent, device_t sel
 	}
 
 	/* Set these up now for ure_ctl().  */
-	usbnet_attach(un, "uredet", URE_RX_LIST_CNT, URE_TX_LIST_CNT,
-		      USBD_SHORT_XFER_OK, USBD_FORCE_SHORT_XFER,
-		      URE_BUFSZ, URE_BUFSZ);
+	usbnet_attach(un, "uredet");
 
 	un->un_phyno = 0;
 

Index: src/sys/dev/usb/if_urndis.c
diff -u src/sys/dev/usb/if_urndis.c:1.26 src/sys/dev/usb/if_urndis.c:1.27
--- src/sys/dev/usb/if_urndis.c:1.26	Fri Aug  9 06:38:39 2019
+++ src/sys/dev/usb/if_urndis.c	Sat Aug 10 02:17:36 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_urndis.c,v 1.26 2019/08/09 06:38:39 mrg Exp $ */
+/*	$NetBSD: if_urndis.c,v 1.27 2019/08/10 02:17:36 mrg Exp $ */
 /*	$OpenBSD: if_urndis.c,v 1.31 2011/07/03 15:47:17 matthew Exp $ */
 
 /*
@@ -21,7 +21,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_urndis.c,v 1.26 2019/08/09 06:38:39 mrg Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_urndis.c,v 1.27 2019/08/10 02:17:36 mrg Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_usb.h"
@@ -130,7 +130,7 @@ urndis_ctrl_send(struct usbnet *un, void
 	struct urndis_softc	*sc = usbnet_softc(un);
 	usbd_status err;
 
-	if (un->un_dying)
+	if (usbnet_isdying(un))
 		return(0);
 
 	err = urndis_ctrl_msg(un, UT_WRITE_CLASS_INTERFACE, UR_GET_STATUS,
@@ -150,7 +150,7 @@ urndis_ctrl_recv(struct usbnet *un)
 	char			*buf;
 	usbd_status		 err;
 
-	if (un->un_dying)
+	if (usbnet_isdying(un))
 		return(0);
 
 	buf = kmem_alloc(URNDIS_RESPONSE_LEN, KM_SLEEP);
@@ -866,13 +866,12 @@ urndis_init_un(struct ifnet *ifp, struct
 		return EIO;
 
 	usbnet_lock(un);
-	if (un->un_dying)
+	if (usbnet_isdying(un))
 		err = EIO;
 	else {
 		usbnet_stop(un, ifp, 1);
 		err = usbnet_init_rx_tx(un);
-		if (err == 0)
-			un->un_link = true;
+		usbnet_set_link(un, err == 0);
 	}
 	usbnet_unlock(un);
 
@@ -943,6 +942,12 @@ urndis_attach(device_t parent, device_t 
 	un->un_udev = dev;
 	un->un_sc = sc;
 	un->un_ops = &urndis_ops;
+	un->un_rx_xfer_flags = USBD_SHORT_XFER_OK;
+	un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER;
+	un->un_rx_list_cnt = RNDIS_RX_LIST_CNT;
+	un->un_tx_list_cnt = RNDIS_TX_LIST_CNT;
+	un->un_rx_bufsz = RNDIS_BUFSZ;
+	un->un_tx_bufsz = RNDIS_BUFSZ;
 
 	iface_ctl = uiaa->uiaa_iface;
 	un->un_iface = uiaa->uiaa_iface;
@@ -1044,9 +1049,7 @@ urndis_attach(device_t parent, device_t 
 	ifp->if_watchdog = urndis_watchdog;
 #endif
 
-	usbnet_attach(un, "urndisdet", RNDIS_RX_LIST_CNT, RNDIS_TX_LIST_CNT,
-		      USBD_SHORT_XFER_OK, USBD_FORCE_SHORT_XFER,
-		      RNDIS_BUFSZ, RNDIS_BUFSZ);
+	usbnet_attach(un, "urndisdet");
 
 	urndis_init_un(ifp, un);
 

Index: src/sys/dev/usb/usbnet.c
diff -u src/sys/dev/usb/usbnet.c:1.10 src/sys/dev/usb/usbnet.c:1.11
--- src/sys/dev/usb/usbnet.c:1.10	Fri Aug  9 01:17:33 2019
+++ src/sys/dev/usb/usbnet.c	Sat Aug 10 02:17:36 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: usbnet.c,v 1.10 2019/08/09 01:17:33 mrg Exp $	*/
+/*	$NetBSD: usbnet.c,v 1.11 2019/08/10 02:17:36 mrg Exp $	*/
 
 /*
  * Copyright (c) 2019 Matthew R. Green
@@ -33,7 +33,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: usbnet.c,v 1.10 2019/08/09 01:17:33 mrg Exp $");
+__KERNEL_RCSID(0, "$NetBSD: usbnet.c,v 1.11 2019/08/10 02:17:36 mrg Exp $");
 
 #include <sys/param.h>
 #include <sys/kernel.h>
@@ -43,6 +43,55 @@ __KERNEL_RCSID(0, "$NetBSD: usbnet.c,v 1
 #include <dev/usb/usbnet.h>
 #include <dev/usb/usbhist.h>
 
+struct usbnet_cdata {
+	struct usbnet_chain	*uncd_tx_chain;
+	struct usbnet_chain	*uncd_rx_chain;
+
+	int			uncd_tx_prod;
+	int			uncd_tx_cnt;
+	int			uncd_rx_cnt;
+};
+
+struct usbnet_private {
+	/*
+	 * - unp_lock protects most of the structure, and the public one
+	 * - unp_miilock must be held to access this device's MII bus
+	 * - unp_rxlock protects the rx path and its data
+	 * - unp_txlock protects the tx path and its data
+	 * - unp_detachcv handles detach vs open references
+	 */
+	kmutex_t		unp_lock;
+	kmutex_t		unp_miilock;
+	kmutex_t		unp_rxlock;
+	kmutex_t		unp_txlock;
+	kcondvar_t		unp_detachcv;
+
+	struct usbnet_cdata	unp_cdata;
+
+	struct ethercom		unp_ec;
+	struct mii_data		unp_mii;
+	struct usb_task		unp_ticktask;
+	struct callout		unp_stat_ch;
+	struct usbd_pipe	*unp_ep[USBNET_ENDPT_MAX];
+
+	bool			unp_dying;
+	bool			unp_stopping;
+	bool			unp_attached;
+	bool			unp_link;
+
+	int			unp_refcnt;
+	int			unp_timer;
+	int			unp_if_flags;
+
+	krndsource_t		unp_rndsrc;
+
+	struct timeval		unp_rx_notice;
+	struct timeval		unp_tx_notice;
+	struct timeval		unp_intr_notice;
+};
+
+#define un_cdata(un)	(&(un)->un_pri->unp_cdata)
+
 static int usbnet_modcmd(modcmd_t, void *);
 
 #ifdef USB_DEBUG
@@ -190,10 +239,10 @@ usbnet_enqueue(struct usbnet * const un,
 	       int csum_flags, uint32_t csum_data, int mbuf_flags)
 {
 	USBNETHIST_FUNC(); USBNETHIST_CALLED();
-	struct ifnet *ifp = &un->un_ec.ec_if;
+	struct ifnet * const ifp = usbnet_ifp(un);
 	struct mbuf *m;
 
-	KASSERT(mutex_owned(&un->un_rxlock));
+	KASSERT(mutex_owned(&un->un_pri->unp_rxlock));
 
 	m = usbnet_newbuf();
 	if (m == NULL) {
@@ -219,7 +268,7 @@ usbnet_input(struct usbnet * const un, u
 	struct ifnet * const ifp = usbnet_ifp(un);
 	struct mbuf *m;
 
-	KASSERT(mutex_owned(&un->un_rxlock));
+	KASSERT(mutex_owned(&un->un_pri->unp_rxlock));
 
 	m = usbnet_newbuf();
 	if (m == NULL) {
@@ -243,75 +292,76 @@ static void
 usbnet_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
 {
 	USBNETHIST_FUNC(); USBNETHIST_CALLED();
-	struct usbnet_chain *c = priv;
+	struct usbnet_chain * const c = priv;
 	struct usbnet * const un = c->unc_un;
-	struct usbnet_cdata *cd = &un->un_cdata;
+	struct usbnet_private * const unp = un->un_pri;
 	struct ifnet * const ifp = usbnet_ifp(un);
 	uint32_t total_len;
 
-	mutex_enter(&un->un_rxlock);
+	mutex_enter(&unp->unp_rxlock);
 
-	if (un->un_dying || un->un_stopping ||
+	if (unp->unp_dying || unp->unp_stopping ||
 	    status == USBD_INVAL || status == USBD_NOT_STARTED ||
 	    status == USBD_CANCELLED || !(ifp->if_flags & IFF_RUNNING))
 		goto out;
 
 	if (status != USBD_NORMAL_COMPLETION) {
-		if (usbd_ratecheck(&un->un_rx_notice))
+		if (usbd_ratecheck(&unp->unp_rx_notice))
 			aprint_error_dev(un->un_dev, "usb errors on rx: %s\n",
 			    usbd_errstr(status));
 		if (status == USBD_STALLED)
-			usbd_clear_endpoint_stall_async(un->un_ep[USBNET_ENDPT_RX]);
+			usbd_clear_endpoint_stall_async(unp->unp_ep[USBNET_ENDPT_RX]);
 		goto done;
 	}
 
 	usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
 
-	if (total_len > cd->uncd_rx_bufsz) {
+	if (total_len > un->un_rx_bufsz) {
 		aprint_error_dev(un->un_dev,
 		    "rxeof: too large transfer (%u > %u)\n",
-		    total_len, cd->uncd_rx_bufsz);
+		    total_len, un->un_rx_bufsz);
 		goto done;
 	}
 
 	uno_rx_loop(un, xfer, c, total_len);
-	KASSERT(mutex_owned(&un->un_rxlock));
+	KASSERT(mutex_owned(&unp->unp_rxlock));
 
 done:
-	if (un->un_dying || un->un_stopping)
+	if (unp->unp_dying || unp->unp_stopping)
 		goto out;
 
-	mutex_exit(&un->un_rxlock);
+	mutex_exit(&unp->unp_rxlock);
 
 	/* Setup new transfer. */
-	usbd_setup_xfer(xfer, c, c->unc_buf, cd->uncd_rx_bufsz,
-	    cd->uncd_rx_xfer_flags, USBD_NO_TIMEOUT, usbnet_rxeof);
+	usbd_setup_xfer(xfer, c, c->unc_buf, un->un_rx_bufsz,
+	    un->un_rx_xfer_flags, USBD_NO_TIMEOUT, usbnet_rxeof);
 	usbd_transfer(xfer);
 	return;
 
 out:
-	mutex_exit(&un->un_rxlock);
+	mutex_exit(&unp->unp_rxlock);
 }
 
 static void
 usbnet_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
 {
 	USBNETHIST_FUNC(); USBNETHIST_CALLED();
-	struct usbnet_chain *c = priv;
+	struct usbnet_chain * const c = priv;
 	struct usbnet * const un = c->unc_un;
-	struct usbnet_cdata *cd = &un->un_cdata;
+	struct usbnet_cdata * const cd = un_cdata(un);
+	struct usbnet_private * const unp = un->un_pri;
 	struct ifnet * const ifp = usbnet_ifp(un);
 
-	mutex_enter(&un->un_txlock);
-	if (un->un_stopping || un->un_dying) {
-		mutex_exit(&un->un_txlock);
+	mutex_enter(&unp->unp_txlock);
+	if (unp->unp_stopping || unp->unp_dying) {
+		mutex_exit(&unp->unp_txlock);
 		return;
 	}
 
 	KASSERT(cd->uncd_tx_cnt > 0);
 	cd->uncd_tx_cnt--;
 
-	un->un_timer = 0;
+	unp->unp_timer = 0;
 
 	switch (status) {
 	case USBD_NOT_STARTED:
@@ -325,39 +375,41 @@ usbnet_txeof(struct usbd_xfer *xfer, voi
 	default:
 
 		ifp->if_oerrors++;
-		if (usbd_ratecheck(&un->un_tx_notice))
+		if (usbd_ratecheck(&unp->unp_tx_notice))
 			aprint_error_dev(un->un_dev, "usb error on tx: %s\n",
 			    usbd_errstr(status));
 		if (status == USBD_STALLED)
-			usbd_clear_endpoint_stall_async(un->un_ep[USBNET_ENDPT_TX]);
+			usbd_clear_endpoint_stall_async(unp->unp_ep[USBNET_ENDPT_TX]);
 		break;
 	}
 
-	mutex_exit(&un->un_txlock);
+	mutex_exit(&unp->unp_txlock);
 
 	if (status == USBD_NORMAL_COMPLETION && !IFQ_IS_EMPTY(&ifp->if_snd))
 		(*ifp->if_start)(ifp);
 }
 
 static void
-usbnet_intr(struct usbd_xfer *xfer, void *priv, usbd_status status)
+usbnet_pipe_intr(struct usbd_xfer *xfer, void *priv, usbd_status status)
 {
 	USBNETHIST_FUNC(); USBNETHIST_CALLED();
-	struct usbnet		*un = priv;
-	struct ifnet		*ifp = usbnet_ifp(un);
+	struct usbnet * const un = priv;
+	struct usbnet_private * const unp = un->un_pri;
+	struct usbnet_intr * const uni = un->un_intr;
+	struct ifnet * const ifp = usbnet_ifp(un);
 
-	if (un->un_dying || un->un_stopping ||
+	if (uni == NULL || unp->unp_dying || unp->unp_stopping ||
 	    status == USBD_INVAL || status == USBD_NOT_STARTED ||
 	    status == USBD_CANCELLED || !(ifp->if_flags & IFF_RUNNING))
 		return;
 
 	if (status != USBD_NORMAL_COMPLETION) {
-		if (usbd_ratecheck(&un->un_intr_notice)) {
+		if (usbd_ratecheck(&unp->unp_intr_notice)) {
 			aprint_error_dev(un->un_dev, "usb error on intr: %s\n",
 			    usbd_errstr(status));
 		}
 		if (status == USBD_STALLED)
-			usbd_clear_endpoint_stall_async(un->un_ep[USBNET_ENDPT_INTR]);
+			usbd_clear_endpoint_stall_async(unp->unp_ep[USBNET_ENDPT_INTR]);
 		return;
 	}
 
@@ -369,19 +421,20 @@ usbnet_start_locked(struct ifnet *ifp)
 {
 	USBNETHIST_FUNC(); USBNETHIST_CALLED();
 	struct usbnet * const un = ifp->if_softc;
-	struct usbnet_cdata *cd = &un->un_cdata;
+	struct usbnet_cdata * const cd = un_cdata(un);
+	struct usbnet_private * const unp = un->un_pri;
 	struct mbuf *m;
 	unsigned length;
 	int idx;
 
-	KASSERT(mutex_owned(&un->un_txlock));
-	KASSERT(cd->uncd_tx_cnt <= cd->uncd_tx_list_cnt);
+	KASSERT(mutex_owned(&unp->unp_txlock));
+	KASSERT(cd->uncd_tx_cnt <= un->un_tx_list_cnt);
 
-	if (!un->un_link || (ifp->if_flags & IFF_RUNNING) == 0)
+	if (!unp->unp_link || (ifp->if_flags & IFF_RUNNING) == 0)
 		return;
 
 	idx = cd->uncd_tx_prod;
-	while (cd->uncd_tx_cnt < cd->uncd_tx_list_cnt) {
+	while (cd->uncd_tx_cnt < un->un_tx_list_cnt) {
 		IFQ_POLL(&ifp->if_snd, m);
 		if (m == NULL)
 			break;
@@ -400,7 +453,7 @@ usbnet_start_locked(struct ifnet *ifp)
 		}
 
 		usbd_setup_xfer(c->unc_xfer, c, c->unc_buf, length,
-		    cd->uncd_tx_xfer_flags, 10000, usbnet_txeof);
+		    un->un_tx_xfer_flags, 10000, usbnet_txeof);
 
 		/* Transmit */
 		usbd_status err = usbd_transfer(c->unc_xfer);
@@ -418,7 +471,7 @@ usbnet_start_locked(struct ifnet *ifp)
 		bpf_mtap(ifp, m, BPF_D_OUT);
 		m_freem(m);
 
-		idx = (idx + 1) % cd->uncd_tx_list_cnt;
+		idx = (idx + 1) % un->un_tx_list_cnt;
 		cd->uncd_tx_cnt++;
 	}
 	cd->uncd_tx_prod = idx;
@@ -426,18 +479,19 @@ usbnet_start_locked(struct ifnet *ifp)
 	/*
 	 * Set a timeout in case the chip goes out to lunch.
 	 */
-	un->un_timer = 5;
+	unp->unp_timer = 5;
 }
 
 static void
 usbnet_start(struct ifnet *ifp)
 {
 	struct usbnet * const un = ifp->if_softc;
+	struct usbnet_private * const unp = un->un_pri;
 
-	mutex_enter(&un->un_txlock);
-	if (!un->un_stopping)
+	mutex_enter(&unp->unp_txlock);
+	if (!unp->unp_stopping)
 		usbnet_start_locked(ifp);
-	mutex_exit(&un->un_txlock);
+	mutex_exit(&unp->unp_txlock);
 }
 
 /*
@@ -449,26 +503,26 @@ usbnet_start(struct ifnet *ifp)
 /* Start of common RX functions */
 
 static size_t
-usbnet_rx_list_size(struct usbnet_cdata *cd)
+usbnet_rx_list_size(struct usbnet_cdata *cd, struct usbnet *un)
 {
-	return sizeof(*cd->uncd_rx_chain) * cd->uncd_rx_list_cnt;
+	return sizeof(*cd->uncd_rx_chain) * un->un_rx_list_cnt;
 }
 
 static void
 usbnet_rx_list_alloc(struct usbnet *un)
 {
-	struct usbnet_cdata *cd = &un->un_cdata;
+	struct usbnet_cdata * const cd = un_cdata(un);
 
-	cd->uncd_rx_chain = kmem_zalloc(usbnet_rx_list_size(cd), KM_SLEEP);
+	cd->uncd_rx_chain = kmem_zalloc(usbnet_rx_list_size(cd, un), KM_SLEEP);
 }
 
 static void
 usbnet_rx_list_free(struct usbnet *un)
 {
-	struct usbnet_cdata *cd = &un->un_cdata;
+	struct usbnet_cdata * const cd = un_cdata(un);
 
 	if (cd->uncd_rx_chain) {
-		kmem_free(cd->uncd_rx_chain, usbnet_rx_list_size(cd));
+		kmem_free(cd->uncd_rx_chain, usbnet_rx_list_size(cd, un));
 		cd->uncd_rx_chain = NULL;
 	}
 }
@@ -476,15 +530,16 @@ usbnet_rx_list_free(struct usbnet *un)
 static int
 usbnet_rx_list_init(struct usbnet *un)
 {
-	struct usbnet_cdata *cd = &un->un_cdata;
+	struct usbnet_cdata * const cd = un_cdata(un);
+	struct usbnet_private * const unp = un->un_pri;
 
-	for (size_t i = 0; i < cd->uncd_rx_list_cnt; i++) {
+	for (size_t i = 0; i < un->un_rx_list_cnt; i++) {
 		struct usbnet_chain *c = &cd->uncd_rx_chain[i];
 
 		c->unc_un = un;
 		if (c->unc_xfer == NULL) {
-			int err = usbd_create_xfer(un->un_ep[USBNET_ENDPT_RX],
-			    cd->uncd_rx_bufsz, cd->uncd_rx_xfer_flags, 0,
+			int err = usbd_create_xfer(unp->unp_ep[USBNET_ENDPT_RX],
+			    un->un_rx_bufsz, un->un_rx_xfer_flags, 0,
 			    &c->unc_xfer);
 			if (err)
 				return err;
@@ -498,9 +553,9 @@ usbnet_rx_list_init(struct usbnet *un)
 static void
 usbnet_rx_list_fini(struct usbnet *un)
 {
-	struct usbnet_cdata *cd = &un->un_cdata;
+	struct usbnet_cdata * const cd = un_cdata(un);
 
-	for (size_t i = 0; i < cd->uncd_rx_list_cnt; i++) {
+	for (size_t i = 0; i < un->un_rx_list_cnt; i++) {
 		struct usbnet_chain *c = &cd->uncd_rx_chain[i];
 
 		if (c->unc_xfer != NULL) {
@@ -516,47 +571,48 @@ usbnet_rx_list_fini(struct usbnet *un)
 static void
 usbnet_rx_start_pipes(struct usbnet *un, usbd_callback cb)
 {
-	struct usbnet_cdata *cd = &un->un_cdata;
+	struct usbnet_cdata * const cd = un_cdata(un);
+	struct usbnet_private * const unp = un->un_pri;
 
-	mutex_enter(&un->un_rxlock);
-	mutex_enter(&un->un_txlock);
-	un->un_stopping = false;
+	mutex_enter(&unp->unp_rxlock);
+	mutex_enter(&unp->unp_txlock);
+	unp->unp_stopping = false;
 
-	for (size_t i = 0; i < cd->uncd_rx_list_cnt; i++) {
+	for (size_t i = 0; i < un->un_rx_list_cnt; i++) {
 		struct usbnet_chain *c = &cd->uncd_rx_chain[i];
 
-		usbd_setup_xfer(c->unc_xfer, c, c->unc_buf, cd->uncd_rx_bufsz,
-		    cd->uncd_rx_xfer_flags, USBD_NO_TIMEOUT, cb);
+		usbd_setup_xfer(c->unc_xfer, c, c->unc_buf, un->un_rx_bufsz,
+		    un->un_rx_xfer_flags, USBD_NO_TIMEOUT, cb);
 		usbd_transfer(c->unc_xfer);
 	}
 
-	mutex_exit(&un->un_txlock);
-	mutex_exit(&un->un_rxlock);
+	mutex_exit(&unp->unp_txlock);
+	mutex_exit(&unp->unp_rxlock);
 }
 
 /* Start of common TX functions */
 
 static size_t
-usbnet_tx_list_size(struct usbnet_cdata *cd)
+usbnet_tx_list_size(struct usbnet_cdata *cd, struct usbnet *un)
 {
-	return sizeof(*cd->uncd_tx_chain) * cd->uncd_tx_list_cnt;
+	return sizeof(*cd->uncd_tx_chain) * un->un_tx_list_cnt;
 }
 
 static void
 usbnet_tx_list_alloc(struct usbnet *un)
 {
-	struct usbnet_cdata *cd = &un->un_cdata;
+	struct usbnet_cdata * const cd = un_cdata(un);
 
-	cd->uncd_tx_chain = kmem_zalloc(usbnet_tx_list_size(cd), KM_SLEEP);
+	cd->uncd_tx_chain = kmem_zalloc(usbnet_tx_list_size(cd, un), KM_SLEEP);
 }
 
 static void
 usbnet_tx_list_free(struct usbnet *un)
 {
-	struct usbnet_cdata *cd = &un->un_cdata;
+	struct usbnet_cdata * const cd = un_cdata(un);
 
 	if (cd->uncd_tx_chain) {
-		kmem_free(cd->uncd_tx_chain, usbnet_tx_list_size(cd));
+		kmem_free(cd->uncd_tx_chain, usbnet_tx_list_size(cd, un));
 		cd->uncd_tx_chain = NULL;
 	}
 }
@@ -564,15 +620,16 @@ usbnet_tx_list_free(struct usbnet *un)
 static int
 usbnet_tx_list_init(struct usbnet *un)
 {
-	struct usbnet_cdata *cd = &un->un_cdata;
+	struct usbnet_cdata * const cd = un_cdata(un);
+	struct usbnet_private * const unp = un->un_pri;
 
-	for (size_t i = 0; i < cd->uncd_tx_list_cnt; i++) {
+	for (size_t i = 0; i < un->un_tx_list_cnt; i++) {
 		struct usbnet_chain *c = &cd->uncd_tx_chain[i];
 
 		c->unc_un = un;
 		if (c->unc_xfer == NULL) {
-			int err = usbd_create_xfer(un->un_ep[USBNET_ENDPT_TX],
-			    cd->uncd_tx_bufsz, cd->uncd_tx_xfer_flags, 0,
+			int err = usbd_create_xfer(unp->unp_ep[USBNET_ENDPT_TX],
+			    un->un_tx_bufsz, un->un_tx_xfer_flags, 0,
 			    &c->unc_xfer);
 			if (err)
 				return err;
@@ -586,9 +643,9 @@ usbnet_tx_list_init(struct usbnet *un)
 static void
 usbnet_tx_list_fini(struct usbnet *un)
 {
-	struct usbnet_cdata *cd = &un->un_cdata;
+	struct usbnet_cdata * const cd = un_cdata(un);
 
-	for (size_t i = 0; i < cd->uncd_tx_list_cnt; i++) {
+	for (size_t i = 0; i < un->un_tx_list_cnt; i++) {
 		struct usbnet_chain *c = &cd->uncd_tx_chain[i];
 
 		if (c->unc_xfer != NULL) {
@@ -606,34 +663,39 @@ usbnet_tx_list_fini(struct usbnet *un)
 static void
 usbnet_ep_close_pipes(struct usbnet *un)
 {
-	for (size_t i = 0; i < __arraycount(un->un_ep); i++) {
-		if (un->un_ep[i] == NULL)
+	struct usbnet_private * const unp = un->un_pri;
+
+	for (size_t i = 0; i < __arraycount(unp->unp_ep); i++) {
+		if (unp->unp_ep[i] == NULL)
 			continue;
-		usbd_status err = usbd_close_pipe(un->un_ep[i]);
+		usbd_status err = usbd_close_pipe(unp->unp_ep[i]);
 		if (err)
 			aprint_error_dev(un->un_dev, "close pipe %zu: %s\n", i,
 			    usbd_errstr(err));
-		un->un_ep[i] = NULL;
+		unp->unp_ep[i] = NULL;
 	}
 }
 
 static usbd_status
 usbnet_ep_open_pipes(struct usbnet *un)
 {
-	for (size_t i = 0; i < __arraycount(un->un_ep); i++) {
+	struct usbnet_intr * const uni = un->un_intr;
+	struct usbnet_private * const unp = un->un_pri;
+
+	for (size_t i = 0; i < __arraycount(unp->unp_ep); i++) {
 		usbd_status err;
 
 		if (un->un_ed[i] == 0)
 			continue;
 
-		if (i == USBNET_ENDPT_INTR && un->un_intr_buf) {
+		if (i == USBNET_ENDPT_INTR && uni) {
 			err = usbd_open_pipe_intr(un->un_iface, un->un_ed[i],
-			    USBD_EXCLUSIVE_USE | USBD_MPSAFE, &un->un_ep[i], un,
-			    un->un_intr_buf, un->un_intr_bufsz, usbnet_intr,
-			    un->un_intr_interval);
+			    USBD_EXCLUSIVE_USE | USBD_MPSAFE, &unp->unp_ep[i], un,
+			    uni->uni_buf, uni->uni_bufsz, usbnet_pipe_intr,
+			    uni->uni_interval);
 		} else {
 			err = usbd_open_pipe(un->un_iface, un->un_ed[i],
-			    USBD_EXCLUSIVE_USE | USBD_MPSAFE, &un->un_ep[i]);
+			    USBD_EXCLUSIVE_USE | USBD_MPSAFE, &unp->unp_ep[i]);
 		}
 		if (err) {
 			usbnet_ep_close_pipes(un);
@@ -647,10 +709,12 @@ usbnet_ep_open_pipes(struct usbnet *un)
 static usbd_status
 usbnet_ep_stop_pipes(struct usbnet *un)
 {
-	for (size_t i = 0; i < __arraycount(un->un_ep); i++) {
-		if (un->un_ep[i] == NULL)
+	struct usbnet_private * const unp = un->un_pri;
+
+	for (size_t i = 0; i < __arraycount(unp->unp_ep); i++) {
+		if (unp->unp_ep[i] == NULL)
 			continue;
-		usbd_status err = usbd_abort_pipe(un->un_ep[i]);
+		usbd_status err = usbd_abort_pipe(unp->unp_ep[i]);
 		if (err)
 			return err;
 	}
@@ -662,16 +726,17 @@ int
 usbnet_init_rx_tx(struct usbnet * const un)
 {
 	USBNETHIST_FUNC(); USBNETHIST_CALLED();
+	struct usbnet_private * const unp = un->un_pri;
 	struct ifnet * const ifp = usbnet_ifp(un);
 	usbd_status err;
 	int error = 0;
 
 	usbnet_isowned(un);
 
-	if (un->un_dying) {
+	if (unp->unp_dying) {
 		return EIO;
 	}
-	un->un_refcnt++;
+	unp->unp_refcnt++;
 
 	/* Open RX and TX pipes. */
 	err = usbnet_ep_open_pipes(un);
@@ -703,7 +768,7 @@ usbnet_init_rx_tx(struct usbnet * const 
 	KASSERT(ifp->if_softc == NULL || IFNET_LOCKED(ifp));
 	ifp->if_flags |= IFF_RUNNING;
 
-	callout_schedule(&un->un_stat_ch, hz);
+	callout_schedule(&unp->unp_stat_ch, hz);
 
 out:
 	if (error) {
@@ -711,8 +776,8 @@ out:
 		usbnet_tx_list_fini(un);
 		usbnet_ep_close_pipes(un);
 	}
-	if (--un->un_refcnt < 0)
-		cv_broadcast(&un->un_detachcv);
+	if (--unp->unp_refcnt < 0)
+		cv_broadcast(&unp->unp_detachcv);
 
 	usbnet_isowned(un);
 
@@ -728,56 +793,71 @@ out:
 void
 usbnet_lock_mii(struct usbnet *un)
 {
+	struct usbnet_private * const unp = un->un_pri;
 
-	mutex_enter(&un->un_lock);
-	un->un_refcnt++;
-	mutex_exit(&un->un_lock);
+	mutex_enter(&unp->unp_lock);
+	unp->unp_refcnt++;
+	mutex_exit(&unp->unp_lock);
 
-	mutex_enter(&un->un_miilock);
+	mutex_enter(&unp->unp_miilock);
 }
 
 void
 usbnet_lock_mii_un_locked(struct usbnet *un)
 {
-	KASSERT(mutex_owned(&un->un_lock));
+	struct usbnet_private * const unp = un->un_pri;
+
+	KASSERT(mutex_owned(&unp->unp_lock));
 
-	un->un_refcnt++;
-	mutex_enter(&un->un_miilock);
+	unp->unp_refcnt++;
+	mutex_enter(&unp->unp_miilock);
 }
 
 void
 usbnet_unlock_mii(struct usbnet *un)
 {
+	struct usbnet_private * const unp = un->un_pri;
 
-	mutex_exit(&un->un_miilock);
-	mutex_enter(&un->un_lock);
-	if (--un->un_refcnt < 0)
-		cv_broadcast(&un->un_detachcv);
-	mutex_exit(&un->un_lock);
+	mutex_exit(&unp->unp_miilock);
+	mutex_enter(&unp->unp_lock);
+	if (--unp->unp_refcnt < 0)
+		cv_broadcast(&unp->unp_detachcv);
+	mutex_exit(&unp->unp_lock);
 }
 
 void
 usbnet_unlock_mii_un_locked(struct usbnet *un)
 {
-	KASSERT(mutex_owned(&un->un_lock));
+	struct usbnet_private * const unp = un->un_pri;
 
-	mutex_exit(&un->un_miilock);
-	if (--un->un_refcnt < 0)
-		cv_broadcast(&un->un_detachcv);
+	KASSERT(mutex_owned(&unp->unp_lock));
+
+	mutex_exit(&unp->unp_miilock);
+	if (--unp->unp_refcnt < 0)
+		cv_broadcast(&unp->unp_detachcv);
+}
+
+kmutex_t *
+usbnet_mutex_mii(struct usbnet *un)
+{
+	struct usbnet_private * const unp = un->un_pri;
+
+	return &unp->unp_miilock;
 }
 
 int
 usbnet_mii_readreg(device_t dev, int phy, int reg, uint16_t *val)
 {
 	struct usbnet * const un = device_private(dev);
+	struct usbnet_private * const unp = un->un_pri;
 	usbd_status err;
 
-	mutex_enter(&un->un_lock);
-	if (un->un_dying || un->un_phyno != phy) {
-		mutex_exit(&un->un_lock);
+	mutex_enter(&unp->unp_lock);
+	if (unp->unp_dying || un->un_phyno != phy) {
+		mutex_exit(&unp->unp_lock);
 		return EIO;
 	}
-	mutex_exit(&un->un_lock);
+	mutex_exit(&unp->unp_lock);
 
 	usbnet_lock_mii(un);
 	err = uno_read_reg(un, phy, reg, val);
@@ -795,14 +875,15 @@ int
 usbnet_mii_writereg(device_t dev, int phy, int reg, uint16_t val)
 {
 	struct usbnet * const un = device_private(dev);
+	struct usbnet_private * const unp = un->un_pri;
 	usbd_status err;
 
-	mutex_enter(&un->un_lock);
-	if (un->un_dying || un->un_phyno != phy) {
-		mutex_exit(&un->un_lock);
+	mutex_enter(&unp->unp_lock);
+	if (unp->unp_dying || un->un_phyno != phy) {
+		mutex_exit(&unp->unp_lock);
 		return EIO;
 	}
-	mutex_exit(&un->un_lock);
+	mutex_exit(&unp->unp_lock);
 
 	usbnet_lock_mii(un);
 	err = uno_write_reg(un, phy, reg, val);
@@ -830,12 +911,13 @@ usbnet_media_upd(struct ifnet *ifp)
 {
 	USBNETHIST_FUNC(); USBNETHIST_CALLED();
 	struct usbnet * const un = ifp->if_softc;
+	struct usbnet_private * const unp = un->un_pri;
 	struct mii_data * const mii = usbnet_mii(un);
 
-	if (un->un_dying)
+	if (unp->unp_dying)
 		return EIO;
 
-	un->un_link = false;
+	unp->unp_link = false;
 
 	if (mii->mii_instance) {
 		struct mii_softc *miisc;
@@ -855,20 +937,21 @@ usbnet_ifflags_cb(struct ethercom *ec)
 	USBNETHIST_FUNC(); USBNETHIST_CALLED();
 	struct ifnet *ifp = &ec->ec_if;
 	struct usbnet *un = ifp->if_softc;
+	struct usbnet_private * const unp = un->un_pri;
 	int rv = 0;
 
-	mutex_enter(&un->un_lock);
+	mutex_enter(&unp->unp_lock);
 
-	const int changed = ifp->if_flags ^ un->un_if_flags;
+	const int changed = ifp->if_flags ^ unp->unp_if_flags;
 	if ((changed & ~(IFF_CANTCHANGE | IFF_DEBUG)) == 0) {
-		un->un_if_flags = ifp->if_flags;
+		unp->unp_if_flags = ifp->if_flags;
 		if ((changed & IFF_PROMISC) != 0)
 			rv = ENETRESET;
 	} else {
 		rv = ENETRESET;
 	}
 
-	mutex_exit(&un->un_lock);
+	mutex_exit(&unp->unp_lock);
 
 	return rv;
 }
@@ -906,15 +989,17 @@ usbnet_ioctl(struct ifnet *ifp, u_long c
 void
 usbnet_stop(struct usbnet *un, struct ifnet *ifp, int disable)
 {
+	struct usbnet_private * const unp = un->un_pri;
+
 	USBNETHIST_FUNC(); USBNETHIST_CALLED();
 
-	KASSERT(mutex_owned(&un->un_lock));
+	KASSERT(mutex_owned(&unp->unp_lock));
 
-	mutex_enter(&un->un_rxlock);
-	mutex_enter(&un->un_txlock);
-	un->un_stopping = true;
-	mutex_exit(&un->un_txlock);
-	mutex_exit(&un->un_rxlock);
+	mutex_enter(&unp->unp_rxlock);
+	mutex_enter(&unp->unp_txlock);
+	unp->unp_stopping = true;
+	mutex_exit(&unp->unp_txlock);
+	mutex_exit(&unp->unp_rxlock);
 
 	uno_stop(un, ifp, disable);
 
@@ -926,10 +1011,10 @@ usbnet_stop(struct usbnet *un, struct if
 	 * and unlock is already held.
 	 */
 	ifp->if_flags &= ~IFF_RUNNING;
-	un->un_timer = 0;
+	unp->unp_timer = 0;
 
-	callout_stop(&un->un_stat_ch);
-	un->un_link = false;
+	callout_stop(&unp->unp_stat_ch);
+	unp->unp_link = false;
 
 	/* Stop transfers. */
 	usbnet_ep_stop_pipes(un);
@@ -946,10 +1031,11 @@ static void
 usbnet_stop_ifp(struct ifnet *ifp, int disable)
 {
 	struct usbnet * const un = ifp->if_softc;
+	struct usbnet_private * const unp = un->un_pri;
 
-	mutex_enter(&un->un_lock);
+	mutex_enter(&unp->unp_lock);
 	usbnet_stop(un, ifp, disable);
-	mutex_exit(&un->un_lock);
+	mutex_exit(&unp->unp_lock);
 }
 
 /*
@@ -962,20 +1048,21 @@ static void
 usbnet_tick(void *arg)
 {
 	struct usbnet * const un = arg;
+	struct usbnet_private * const unp = un->un_pri;
 
-	mutex_enter(&un->un_lock);
-	if (!un->un_stopping && !un->un_dying) {
+	mutex_enter(&unp->unp_lock);
+	if (!unp->unp_stopping && !unp->unp_dying) {
 		/* Perform periodic stuff in process context */
-		usb_add_task(un->un_udev, &un->un_ticktask, USB_TASKQ_DRIVER);
+		usb_add_task(un->un_udev, &unp->unp_ticktask, USB_TASKQ_DRIVER);
 	}
-	mutex_exit(&un->un_lock);
+	mutex_exit(&unp->unp_lock);
 }
 
 static void
 usbnet_watchdog(struct ifnet *ifp)
 {
 	struct usbnet * const un = ifp->if_softc;
-	struct usbnet_cdata *cd = &un->un_cdata;
+	struct usbnet_cdata * const cd = un_cdata(un);
 	usbd_status stat;
 
 	ifp->if_oerrors++;
@@ -985,7 +1072,7 @@ usbnet_watchdog(struct ifnet *ifp)
 		/*
 		 * XXX index 0
 		 */
-		struct usbnet_chain *c = &un->un_cdata.uncd_tx_chain[0];
+		struct usbnet_chain *c = &un_cdata(un)->uncd_tx_chain[0];
 		usbd_get_xfer_status(c->unc_xfer, NULL, NULL, NULL, &stat);
 		usbnet_txeof(c->unc_xfer, c, stat);
 	}
@@ -999,35 +1086,36 @@ usbnet_tick_task(void *arg)
 {
 	USBNETHIST_FUNC(); USBNETHIST_CALLED();
 	struct usbnet * const un = arg;
+	struct usbnet_private * const unp = un->un_pri;
 
-	mutex_enter(&un->un_lock);
-	if (un->un_stopping || un->un_dying) {
-		mutex_exit(&un->un_lock);
+	mutex_enter(&unp->unp_lock);
+	if (unp->unp_stopping || unp->unp_dying) {
+		mutex_exit(&unp->unp_lock);
 		return;
 	}
 
 	struct ifnet * const ifp = usbnet_ifp(un);
 	struct mii_data * const mii = usbnet_mii(un);
 
-	un->un_refcnt++;
-	mutex_exit(&un->un_lock);
+	unp->unp_refcnt++;
+	mutex_exit(&unp->unp_lock);
 
-	if (ifp && un->un_timer != 0 && --un->un_timer == 0)
+	if (ifp && unp->unp_timer != 0 && --unp->unp_timer == 0)
 		usbnet_watchdog(ifp);
 
 	if (mii && ifp) {
 		mii_tick(mii);
 
-		if (!un->un_link)
+		if (!unp->unp_link)
 			(*mii->mii_statchg)(ifp);
 	}
 
-	mutex_enter(&un->un_lock);
-	if (--un->un_refcnt < 0)
-		cv_broadcast(&un->un_detachcv);
-	if (!un->un_stopping && !un->un_dying)
-		callout_schedule(&un->un_stat_ch, hz);
-	mutex_exit(&un->un_lock);
+	mutex_enter(&unp->unp_lock);
+	if (--unp->unp_refcnt < 0)
+		cv_broadcast(&unp->unp_detachcv);
+	if (!unp->unp_stopping && !unp->unp_dying)
+		callout_schedule(&unp->unp_stat_ch, hz);
+	mutex_exit(&unp->unp_lock);
 }
 
 static int
@@ -1039,6 +1127,114 @@ usbnet_init(struct ifnet *ifp)
 	return uno_init(un, ifp);
 }
 
+/* Various accessors. */
+
+void
+usbnet_set_link(struct usbnet *un, bool link)
+{
+	un->un_pri->unp_link = link;
+}
+
+struct ifnet *
+usbnet_ifp(struct usbnet *un)
+{
+	return &un->un_pri->unp_ec.ec_if;
+}
+
+struct ethercom *
+usbnet_ec(struct usbnet *un)
+{
+	return &un->un_pri->unp_ec;
+}
+
+struct mii_data *
+usbnet_mii(struct usbnet *un)
+{
+	return un->un_pri->unp_ec.ec_mii;
+}
+
+krndsource_t *
+usbnet_rndsrc(struct usbnet *un)
+{
+	return &un->un_pri->unp_rndsrc;
+}
+
+void *
+usbnet_softc(struct usbnet *un)
+{
+	//return un->un_pri->unp_sc;
+	return un->un_sc;
+}
+
+bool
+usbnet_havelink(struct usbnet *un)
+{
+	return un->un_pri->unp_link;
+}
+
+bool
+usbnet_isdying(struct usbnet *un)
+{
+	return un->un_pri->unp_dying;
+}
+
+
+/* Locking. */
+
+void
+usbnet_lock(struct usbnet *un)
+{
+	mutex_enter(&un->un_pri->unp_lock);
+}
+
+void
+usbnet_unlock(struct usbnet *un)
+{
+	mutex_exit(&un->un_pri->unp_lock);
+}
+
+kmutex_t *
+usbnet_mutex(struct usbnet *un)
+{
+	return &un->un_pri->unp_lock;
+}
+
+void
+usbnet_lock_rx(struct usbnet *un)
+{
+	mutex_enter(&un->un_pri->unp_rxlock);
+}
+
+void
+usbnet_unlock_rx(struct usbnet *un)
+{
+	mutex_exit(&un->un_pri->unp_rxlock);
+}
+
+kmutex_t *
+usbnet_mutex_rx(struct usbnet *un)
+{
+	return &un->un_pri->unp_rxlock;
+}
+
+void
+usbnet_lock_tx(struct usbnet *un)
+{
+	mutex_enter(&un->un_pri->unp_txlock);
+}
+
+void
+usbnet_unlock_tx(struct usbnet *un)
+{
+	mutex_exit(&un->un_pri->unp_txlock);
+}
+
+kmutex_t *
+usbnet_mutex_tx(struct usbnet *un)
+{
+	return &un->un_pri->unp_txlock;
+}
+
 /* Autoconf management. */
 
 static bool
@@ -1061,62 +1257,51 @@ usbnet_empty_eaddr(struct usbnet *un)
  * To skip ethernet configuration (eg, point-to-point), make sure that
  * the un_eaddr[] is fully zero.
  */
+
 void
 usbnet_attach(struct usbnet *un,
-	      const char *detname,	/* detach cv name */
-	      unsigned rx_list_cnt,	/* size of rx chain list */
-	      unsigned tx_list_cnt,	/* size of tx chain list */
-	      unsigned rx_flags,	/* flags for rx xfer */
-	      unsigned tx_flags,	/* flags for tx xfer */
-	      unsigned rx_bufsz,	/* size of rx buffers */
-	      unsigned tx_bufsz)	/* size of tx buffers */
+	      const char *detname)	/* detach cv name */
 {
 	USBNETHIST_FUNC(); USBNETHIST_CALLED();
-	struct usbnet_cdata *cd = &un->un_cdata;
 
 	/* Required inputs.  */
 	KASSERT(un->un_ops->uno_tx_prepare);
 	KASSERT(un->un_ops->uno_rx_loop);
 	KASSERT(un->un_ops->uno_init);
-	KASSERT(rx_bufsz);
-	KASSERT(tx_bufsz);
-	KASSERT(rx_list_cnt);
-	KASSERT(tx_list_cnt);
-
-	cd->uncd_rx_xfer_flags = rx_flags;
-	cd->uncd_tx_xfer_flags = tx_flags;
-	cd->uncd_rx_list_cnt = rx_list_cnt;
-	cd->uncd_tx_list_cnt = tx_list_cnt;
-	cd->uncd_rx_bufsz = rx_bufsz;
-	cd->uncd_tx_bufsz = tx_bufsz;
-
-	ether_set_ifflags_cb(&un->un_ec, usbnet_ifflags_cb);
-
-	usb_init_task(&un->un_ticktask, usbnet_tick_task, un, USB_TASKQ_MPSAFE);
-	callout_init(&un->un_stat_ch, CALLOUT_MPSAFE);
-	callout_setfunc(&un->un_stat_ch, usbnet_tick, un);
-
-	mutex_init(&un->un_miilock, MUTEX_DEFAULT, IPL_NONE);
-	mutex_init(&un->un_txlock, MUTEX_DEFAULT, IPL_SOFTUSB);
-	mutex_init(&un->un_rxlock, MUTEX_DEFAULT, IPL_SOFTUSB);
-	mutex_init(&un->un_lock, MUTEX_DEFAULT, IPL_NONE);
-	cv_init(&un->un_detachcv, detname);
+	KASSERT(un->un_rx_bufsz);
+	KASSERT(un->un_tx_bufsz);
+	KASSERT(un->un_rx_list_cnt);
+	KASSERT(un->un_tx_list_cnt);
+
+	un->un_pri = kmem_zalloc(sizeof(*un->un_pri), KM_SLEEP);
+	struct usbnet_private * const unp = un->un_pri;
+
+	usb_init_task(&unp->unp_ticktask, usbnet_tick_task, un, USB_TASKQ_MPSAFE);
+	callout_init(&unp->unp_stat_ch, CALLOUT_MPSAFE);
+	callout_setfunc(&unp->unp_stat_ch, usbnet_tick, un);
+
+	mutex_init(&unp->unp_miilock, MUTEX_DEFAULT, IPL_NONE);
+	mutex_init(&unp->unp_txlock, MUTEX_DEFAULT, IPL_SOFTUSB);
+	mutex_init(&unp->unp_rxlock, MUTEX_DEFAULT, IPL_SOFTUSB);
+	mutex_init(&unp->unp_lock, MUTEX_DEFAULT, IPL_NONE);
+	cv_init(&unp->unp_detachcv, detname);
 
-	rnd_attach_source(&un->un_rndsrc, device_xname(un->un_dev),
+	rnd_attach_source(&unp->unp_rndsrc, device_xname(un->un_dev),
 	    RND_TYPE_NET, RND_FLAG_DEFAULT);
 
 	usbnet_rx_list_alloc(un);
 	usbnet_tx_list_alloc(un);
 
-	un->un_attached = true;
+	unp->unp_attached = true;
 }
 
 static void
 usbnet_attach_mii(struct usbnet *un, int mii_flags)
 {
 	USBNETHIST_FUNC(); USBNETHIST_CALLED();
-	struct mii_data * const mii = &un->un_mii;
-	struct ifnet *ifp = usbnet_ifp(un);
+	struct usbnet_private * const unp = un->un_pri;
+	struct mii_data * const mii = &unp->unp_mii;
+	struct ifnet * const ifp = usbnet_ifp(un);
 
 	KASSERT(un->un_ops->uno_read_reg);
 	KASSERT(un->un_ops->uno_write_reg);
@@ -1128,7 +1313,7 @@ usbnet_attach_mii(struct usbnet *un, int
 	mii->mii_statchg = usbnet_mii_statchg;
 	mii->mii_flags = MIIF_AUTOTSLEEP;
 
-	un->un_ec.ec_mii = mii;
+	usbnet_ec(un)->ec_mii = mii;
 	ifmedia_init(&mii->mii_media, 0, usbnet_media_upd, ether_mediastatus);
 	mii_attach(un->un_dev, mii, 0xffffffff, MII_PHY_ANY,
 		   MII_OFFSET_ANY, mii_flags);
@@ -1148,9 +1333,10 @@ usbnet_attach_ifp(struct usbnet *un,
 		  int mii_flags)		/* additional mii_attach flags */
 {
 	USBNETHIST_FUNC(); USBNETHIST_CALLED();
-	struct ifnet *ifp = usbnet_ifp(un);
+	struct usbnet_private * const unp = un->un_pri;
+	struct ifnet * const ifp = usbnet_ifp(un);
 
-	KASSERT(un->un_attached);
+	KASSERT(unp->unp_attached);
 
 	IFQ_SET_READY(&ifp->if_snd);
 
@@ -1168,7 +1354,7 @@ usbnet_attach_ifp(struct usbnet *un,
 	if (have_mii)
 		usbnet_attach_mii(un, mii_flags);
 	else
-		un->un_link = true;
+		unp->unp_link = true;
 
 	/* Attach the interface. */
 	if_attach(ifp);
@@ -1178,6 +1364,7 @@ usbnet_attach_ifp(struct usbnet *un,
 	 * instead attach bpf here..
 	 */
 	if (!usbnet_empty_eaddr(un)) {
+		ether_set_ifflags_cb(&unp->unp_ec, usbnet_ifflags_cb);
 		aprint_normal_dev(un->un_dev, "Ethernet address %s\n",
 		    ether_sprintf(un->un_eaddr));
 		ether_ifattach(ifp, un->un_eaddr);
@@ -1197,19 +1384,20 @@ usbnet_detach(device_t self, int flags)
 {
 	USBNETHIST_FUNC(); USBNETHIST_CALLED();
 	struct usbnet * const un = device_private(self);
-	struct ifnet *ifp = usbnet_ifp(un);
-	struct mii_data *mii = usbnet_mii(un);
+	struct ifnet * const ifp = usbnet_ifp(un);
+	struct mii_data * const mii = usbnet_mii(un);
+	struct usbnet_private * const unp = un->un_pri;
 
-	mutex_enter(&un->un_lock);
-	un->un_dying = true;
-	mutex_exit(&un->un_lock);
+	mutex_enter(&unp->unp_lock);
+	unp->unp_dying = true;
+	mutex_exit(&unp->unp_lock);
 
 	/* Detached before attached finished, so just bail out. */
-	if (!un->un_attached)
+	if (!unp->unp_attached)
 		return 0;
 
-	callout_halt(&un->un_stat_ch, NULL);
-	usb_rem_task_wait(un->un_udev, &un->un_ticktask, USB_TASKQ_DRIVER, NULL);
+	callout_halt(&unp->unp_stat_ch, NULL);
+	usb_rem_task_wait(un->un_udev, &unp->unp_ticktask, USB_TASKQ_DRIVER, NULL);
 
 	if (ifp->if_flags & IFF_RUNNING) {
 		IFNET_LOCK(ifp);
@@ -1217,19 +1405,19 @@ usbnet_detach(device_t self, int flags)
 		IFNET_UNLOCK(ifp);
 	}
 
-	mutex_enter(&un->un_lock);
-	un->un_refcnt--;
-	while (un->un_refcnt > 0) {
+	mutex_enter(&unp->unp_lock);
+	unp->unp_refcnt--;
+	while (unp->unp_refcnt > 0) {
 		/* Wait for processes to go away */
-		cv_wait(&un->un_detachcv, &un->un_lock);
+		cv_wait(&unp->unp_detachcv, &unp->unp_lock);
 	}
-	mutex_exit(&un->un_lock);
+	mutex_exit(&unp->unp_lock);
 
 	usbnet_rx_list_free(un);
 	usbnet_tx_list_free(un);
 
-	callout_destroy(&un->un_stat_ch);
-	rnd_detach_source(&un->un_rndsrc);
+	callout_destroy(&unp->unp_stat_ch);
+	rnd_detach_source(&unp->unp_rndsrc);
 
 	if (mii) {
 		mii_detach(mii, MII_PHY_ANY, MII_OFFSET_ANY);
@@ -1243,16 +1431,18 @@ usbnet_detach(device_t self, int flags)
 		if_detach(ifp);
 	}
 
-	cv_destroy(&un->un_detachcv);
-	mutex_destroy(&un->un_lock);
-	mutex_destroy(&un->un_rxlock);
-	mutex_destroy(&un->un_txlock);
-	mutex_destroy(&un->un_miilock);
+	cv_destroy(&unp->unp_detachcv);
+	mutex_destroy(&unp->unp_lock);
+	mutex_destroy(&unp->unp_rxlock);
+	mutex_destroy(&unp->unp_txlock);
+	mutex_destroy(&unp->unp_miilock);
 
 	pmf_device_deregister(un->un_dev);
 
 	usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, un->un_udev, un->un_dev);
 
+	kmem_free(unp, sizeof(*unp));
+
 	return 0;
 }
 
@@ -1261,21 +1451,22 @@ usbnet_activate(device_t self, devact_t 
 {
 	USBNETHIST_FUNC(); USBNETHIST_CALLED();
 	struct usbnet * const un = device_private(self);
+	struct usbnet_private * const unp = un->un_pri;
 	struct ifnet * const ifp = usbnet_ifp(un);
 
 	switch (act) {
 	case DVACT_DEACTIVATE:
 		if_deactivate(ifp);
 
-		mutex_enter(&un->un_lock);
-		un->un_dying = true;
-		mutex_exit(&un->un_lock);
-
-		mutex_enter(&un->un_rxlock);
-		mutex_enter(&un->un_txlock);
-		un->un_stopping = true;
-		mutex_exit(&un->un_txlock);
-		mutex_exit(&un->un_rxlock);
+		mutex_enter(&unp->unp_lock);
+		unp->unp_dying = true;
+		mutex_exit(&unp->unp_lock);
+
+		mutex_enter(&unp->unp_rxlock);
+		mutex_enter(&unp->unp_txlock);
+		unp->unp_stopping = true;
+		mutex_exit(&unp->unp_txlock);
+		mutex_exit(&unp->unp_rxlock);
 
 		return 0;
 	default:

Index: src/sys/dev/usb/usbnet.h
diff -u src/sys/dev/usb/usbnet.h:1.8 src/sys/dev/usb/usbnet.h:1.9
--- src/sys/dev/usb/usbnet.h:1.8	Fri Aug  9 02:14:35 2019
+++ src/sys/dev/usb/usbnet.h	Sat Aug 10 02:17:36 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: usbnet.h,v 1.8 2019/08/09 02:14:35 mrg Exp $	*/
+/*	$NetBSD: usbnet.h,v 1.9 2019/08/10 02:17:36 mrg Exp $	*/
 
 /*
  * Copyright (c) 2019 Matthew R. Green
@@ -113,23 +113,6 @@ struct usbnet_chain {
 	uint8_t			*unc_buf;
 };
 
-struct usbnet_cdata {
-	struct usbnet_chain	*uncd_tx_chain;
-	struct usbnet_chain	*uncd_rx_chain;
-
-	unsigned		uncd_rx_bufsz;
-	unsigned		uncd_tx_bufsz;
-	unsigned		uncd_rx_list_cnt;
-	unsigned		uncd_tx_list_cnt;
-
-	int			uncd_rx_xfer_flags;
-	int			uncd_tx_xfer_flags;
-
-	int			uncd_tx_prod;
-	int			uncd_tx_cnt;
-	int			uncd_rx_cnt;
-};
-
 /*
  * Extend this as necessary.  axe(4) claims to want 6 total, but
  * does not implement them.
@@ -180,162 +163,144 @@ struct usbnet_ops {
 };
 
 /*
- * Generic USB ethernet structure.  Use this as ifp->if_softc and
- * set as device_private() in attach.
+ * USB interrupt pipe support.  Use this if usbd_open_pipe_intr() should
+ * be used for the interrupt pipe.
+ */
+struct usbnet_intr {
+	/*
+	 * Point un_intr to this structure to use usbd_open_pipe_intr() not
+	 * usbd_open_pipe() for USBNET_ENDPT_INTR, with this buffer, size,
+	 * and interval.
+	 */
+	void			*uni_buf;
+	unsigned		uni_bufsz;
+	unsigned		uni_interval;
+};
+
+/*
+ * Generic USB ethernet structure.  Use this as ifp->if_softc and set as
+ * device_private() in attach unless already using struct usbnet here.
  *
  * Devices without MII should call usbnet_attach_ifp() with have_mii set
  * to true, and should ensure that the un_statchg_cb callback sets the
  * un_link member.  Devices without MII have this forced to true.
  */
+struct usbnet_private;
 struct usbnet {
+	/*
+	 * This section should be filled in before calling
+	 * usbnet_attach().
+	 */
 	void			*un_sc;			/* real softc */
 	device_t		un_dev;
 	struct usbd_interface	*un_iface;
-	struct usbd_device *	un_udev;
-
-	krndsource_t		un_rndsrc;
+	struct usbd_device	*un_udev;
 	struct usbnet_ops	*un_ops;
+	struct usbnet_intr	*un_intr;
 
-	struct ethercom		un_ec;
-	struct mii_data		un_mii;
-	int			un_phyno;
-	uint8_t			un_eaddr[ETHER_ADDR_LEN];
+	/* Inputs for rx/tx chain control. */
+	unsigned		un_rx_bufsz;
+	unsigned		un_tx_bufsz;
+	unsigned		un_rx_list_cnt;
+	unsigned		un_tx_list_cnt;
+	int			un_rx_xfer_flags;
+	int			un_tx_xfer_flags;
 
+	/*
+	 * This section should be filled in before calling
+	 * usbnet_attach_ifp().
+	 */
 	enum usbnet_ep		un_ed[USBNET_ENDPT_MAX];
-	struct usbd_pipe	*un_ep[USBNET_ENDPT_MAX];
 
-	struct usbnet_cdata	un_cdata;
-	struct callout		un_stat_ch;
-	int			un_if_flags;
-
-	/* This is for driver to use. */
-	unsigned		un_flags;
+	/* MII specific. Not used without MII. */
+	int			un_phyno;
+	/* Ethernet specific. All zeroes indicates non-Ethernet. */
+	uint8_t			un_eaddr[ETHER_ADDR_LEN];
 
 	/*
-	 * - un_lock protects most of the structure
-	 * - un_miilock must be held to access this device's MII bus
-	 * - un_rxlock protects the rx path and its data
-	 * - un_txlock protects the tx path and its data
-	 * - un_detachcv handles detach vs open references
+	 * This section is for driver to use, not touched by usbnet.
 	 */
-	kmutex_t		un_lock;
-	kmutex_t		un_miilock;
-	kmutex_t		un_rxlock;
-	kmutex_t		un_txlock;
-	kcondvar_t		un_detachcv;
-
-	struct usb_task		un_ticktask;
-
-	int			un_refcnt;
-	int			un_timer;
-
-	bool			un_dying;
-	bool			un_stopping;
-	bool			un_link;
-	bool			un_attached;
-
-	struct timeval		un_rx_notice;
-	struct timeval		un_tx_notice;
-	struct timeval		un_intr_notice;
+	unsigned		un_flags;
 
 	/*
-	 * if un_intr_buf is not NULL, use usbd_open_pipe_intr() not
-	 * usbd_open_pipe() for USBNET_ENDPT_INTR, with this buffer,
-	 * size, and interval.
+	 * This section is private to usbnet. Don't touch.
 	 */
-	void			*un_intr_buf;
-	unsigned		un_intr_bufsz;
-	unsigned		un_intr_interval;
+	struct usbnet_private	*un_pri;
 };
 
-#define usbnet_ifp(un)		(&(un)->un_ec.ec_if)
-#define usbnet_ec(un)		(&(un)->un_ec)
-#define usbnet_rndsrc(un)	(&(un)->un_rndsrc)
-#define usbnet_mii(un)		((un)->un_ec.ec_mii)
-#define usbnet_softc(un)	((un)->un_sc)
-#define usbnet_isdying(un)	((un)->un_dying)
+/* Various accessors. */
 
-/*
- * Endpoint / rx/tx chain management:
- *
- * usbnet_attach() allocates rx and tx chains
- * usbnet_init_rx_tx() open pipes, initialises the rx/tx chains for use
- * usbnet_stop() stops pipes, cleans (not frees) rx/tx chains, locked
- *                version assumes un_lock is held
- * usbnet_detach() frees the rx/tx chains
- *
- * Setup un_ed[] with valid end points before calling usbnet_init_rx_tx().
- * Will return with un_ep[] initialised upon success.
- */
-int	usbnet_init_rx_tx(struct usbnet * const);
-
-/* locking */
-static __inline__ void
-usbnet_lock(struct usbnet *un)
-{
-	mutex_enter(&un->un_lock);
-}
+void usbnet_set_link(struct usbnet *, bool);
 
-static __inline__ void
-usbnet_unlock(struct usbnet *un)
-{
-	mutex_exit(&un->un_lock);
-}
+struct ifnet *usbnet_ifp(struct usbnet *);
+struct ethercom *usbnet_ec(struct usbnet *);
+struct mii_data *usbnet_mii(struct usbnet *);
+krndsource_t *usbnet_rndsrc(struct usbnet *);
+void *usbnet_softc(struct usbnet *);
 
-static __inline__ void
-usbnet_isowned(struct usbnet *un)
-{
-	KASSERT(mutex_owned(&un->un_lock));
-}
+bool usbnet_havelink(struct usbnet *);
+bool usbnet_isdying(struct usbnet *);
 
-static __inline__ void
-usbnet_lock_rx(struct usbnet *un)
-{
-	mutex_enter(&un->un_rxlock);
-}
 
+/*
+ * Locking.  Note that the isowned() are implemented here so that
+ * empty-KASSERT() causes them to be elided for non-DIAG builds.
+ */
+void	usbnet_lock(struct usbnet *);
+void	usbnet_unlock(struct usbnet *);
+kmutex_t *usbnet_mutex(struct usbnet *);
 static __inline__ void
-usbnet_unlock_rx(struct usbnet *un)
+usbnet_isowned(struct usbnet *un)
 {
-	mutex_exit(&un->un_rxlock);
+	KASSERT(mutex_owned(usbnet_mutex(un)));
 }
 
+void	usbnet_lock_rx(struct usbnet *);
+void	usbnet_unlock_rx(struct usbnet *);
+kmutex_t *usbnet_mutex_rx(struct usbnet *);
 static __inline__ void
 usbnet_isowned_rx(struct usbnet *un)
 {
-	KASSERT(mutex_owned(&un->un_rxlock));
-}
-
-static __inline__ void
-usbnet_lock_tx(struct usbnet *un)
-{
-	mutex_enter(&un->un_txlock);
-}
-
-static __inline__ void
-usbnet_unlock_tx(struct usbnet *un)
-{
-	mutex_exit(&un->un_txlock);
+	KASSERT(mutex_owned(usbnet_mutex_rx(un)));
 }
 
+void	usbnet_lock_tx(struct usbnet *);
+void	usbnet_unlock_tx(struct usbnet *);
+kmutex_t *usbnet_mutex_tx(struct usbnet *);
 static __inline__ void
 usbnet_isowned_tx(struct usbnet *un)
 {
-	KASSERT(mutex_owned(&un->un_txlock));
+	KASSERT(mutex_owned(usbnet_mutex_tx(un)));
 }
 
-/* mii */
+/*
+ * Endpoint / rx/tx chain management:
+ *
+ * usbnet_attach() allocates rx and tx chains
+ * usbnet_init_rx_tx() open pipes, initialises the rx/tx chains for use
+ * usbnet_stop() stops pipes, cleans (not frees) rx/tx chains, locked
+ *               version assumes un_lock is held
+ * usbnet_detach() frees the rx/tx chains
+ *
+ * Setup un_ed[] with valid end points before calling usbnet_attach().
+ * Call usbnet_init_rx_tx() to initialise pipes, which will be open
+ * upon success.
+ */
+int	usbnet_init_rx_tx(struct usbnet * const);
+
+/* MII. */
 void	usbnet_lock_mii(struct usbnet *);
 void	usbnet_lock_mii_un_locked(struct usbnet *);
 void	usbnet_unlock_mii(struct usbnet *);
 void	usbnet_unlock_mii_un_locked(struct usbnet *);
-
+kmutex_t *usbnet_mutex_mii(struct usbnet *);
 static __inline__ void
 usbnet_isowned_mii(struct usbnet *un)
 {
-	KASSERT(mutex_owned(&un->un_miilock));
+	KASSERT(mutex_owned(usbnet_mutex_mii(un)));
 }
 
+
 int	usbnet_mii_readreg(device_t, int, int, uint16_t *);
 int	usbnet_mii_writereg(device_t, int, int, uint16_t);
 void	usbnet_mii_statchg(struct ifnet *);
@@ -346,8 +311,7 @@ void	usbnet_enqueue(struct usbnet * cons
 void	usbnet_input(struct usbnet * const, uint8_t *, size_t);
 
 /* autoconf */
-void	usbnet_attach(struct usbnet *un, const char *, unsigned, unsigned,
-		      unsigned, unsigned, unsigned, unsigned);
+void	usbnet_attach(struct usbnet *un, const char *);
 void	usbnet_attach_ifp(struct usbnet *, bool, unsigned, unsigned, int);
 int	usbnet_detach(device_t, int);
 int	usbnet_activate(device_t, devact_t);

Index: src/sys/sys/param.h
diff -u src/sys/sys/param.h:1.604 src/sys/sys/param.h:1.605
--- src/sys/sys/param.h:1.604	Fri Aug  9 01:17:33 2019
+++ src/sys/sys/param.h	Sat Aug 10 02:17:36 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: param.h,v 1.604 2019/08/09 01:17:33 mrg Exp $	*/
+/*	$NetBSD: param.h,v 1.605 2019/08/10 02:17:36 mrg Exp $	*/
 
 /*-
  * Copyright (c) 1982, 1986, 1989, 1993
@@ -67,7 +67,7 @@
  *	2.99.9		(299000900)
  */
 
-#define	__NetBSD_Version__	999000500	/* NetBSD 9.99.5 */
+#define	__NetBSD_Version__	999000600	/* NetBSD 9.99.6 */
 
 #define __NetBSD_Prereq__(M,m,p) (((((M) * 100000000) + \
     (m) * 1000000) + (p) * 100) <= __NetBSD_Version__)

Reply via email to