Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 31 Oct 2010 14:47:04 -0700
From:      Weongyo Jeong <weongyo.jeong@gmail.com>
To:        freebsd-usb@freebsd.org
Subject:   [CFR 2/n] removes uther dependency of aue(4)
Message-ID:  <20101031214704.GA3918@weongyo>

next in thread | raw e-mail | index | archive | help
Hello,

The following patch is to remove uether(4) dependency of aue(4) and
change logs would be as follows:

  - removes uether module dependency of aue(4) that finally uether
    module would be gone.  The reasons why I'm trying to remove uether
    module are that
      I discussed with USB ethernet maintainers about whether it's
      useful or not.  yongari@ answered that it's not helpful, not
      straight forward to understand and make code complex.
  - adds newly two uether APIs, uether_alloc_unr and uether_free_unr for
    backward compatibility because current interface names for each
    ethernet devices are linux-style `ue[0-9]+'.  The naming rule would
    be kept at STABLE_8 but not sure at STABLE_9.

If no objections I'd like to see this patch at HEAD.

regards,
Weongyo Jeong

Index: usb_ethernet.c
===================================================================
--- usb_ethernet.c	(revision 214568)
+++ usb_ethernet.c	(working copy)
@@ -597,5 +597,19 @@ uether_rxflush(struct usb_ether *ue)
 	}
 }
 
+int
+uether_alloc_unr(void)
+{
+
+	return (alloc_unr(ueunit));
+}
+
+void
+uether_free_unr(int unit)
+{
+
+	free_unr(ueunit, unit);
+}
+
 DECLARE_MODULE(uether, uether_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
 MODULE_VERSION(uether, 1);
Index: if_aue.c
===================================================================
--- if_aue.c	(revision 214568)
+++ if_aue.c	(working copy)
@@ -81,6 +81,8 @@ __FBSDID("$FreeBSD$");
 #include <sys/lock.h>
 #include <sys/mutex.h>
 #include <sys/condvar.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
 #include <sys/sysctl.h>
 #include <sys/sx.h>
 #include <sys/unistd.h>
@@ -88,6 +90,19 @@ __FBSDID("$FreeBSD$");
 #include <sys/malloc.h>
 #include <sys/priv.h>
 
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_types.h>
+#include <net/bpf.h>
+#include <net/ethernet.h>
+
+#include "miibus_if.h"
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+
 #include <dev/usb/usb.h>
 #include <dev/usb/usbdi.h>
 #include <dev/usb/usbdi_util.h>
@@ -96,6 +111,7 @@ __FBSDID("$FreeBSD$");
 #define	USB_DEBUG_VAR aue_debug
 #include <dev/usb/usb_debug.h>
 #include <dev/usb/usb_process.h>
+#include <dev/usb/usb_sleepout.h>
 
 #include <dev/usb/net/usb_ethernet.h>
 #include <dev/usb/net/if_auereg.h>
@@ -197,14 +213,6 @@ static usb_callback_t aue_intr_callback;
 static usb_callback_t aue_bulk_read_callback;
 static usb_callback_t aue_bulk_write_callback;
 
-static uether_fn_t aue_attach_post;
-static uether_fn_t aue_init;
-static uether_fn_t aue_stop;
-static uether_fn_t aue_start;
-static uether_fn_t aue_tick;
-static uether_fn_t aue_setmulti;
-static uether_fn_t aue_setpromisc;
-
 static uint8_t	aue_csr_read_1(struct aue_softc *, uint16_t);
 static uint16_t	aue_csr_read_2(struct aue_softc *, uint16_t);
 static void	aue_csr_write_1(struct aue_softc *, uint16_t, uint8_t);
@@ -217,6 +225,20 @@ static void	aue_reset_pegasus_II(struct aue_softc
 
 static int	aue_ifmedia_upd(struct ifnet *);
 static void	aue_ifmedia_sts(struct ifnet *, struct ifmediareq *);
+static int	aue_ioctl(struct ifnet *, u_long, caddr_t);
+static void	aue_start(struct ifnet *);
+static void	aue_start_locked(struct ifnet *);
+static void	aue_init(void *);
+static void	aue_stop_locked(struct aue_softc *);
+static void	aue_setmulti(void *, int);
+static void	aue_setmulti_locked(struct aue_softc *);
+static void	aue_rxflush(struct aue_softc *);
+static int	aue_rxbuf(struct aue_softc *, struct usb_page_cache *, 
+		    unsigned int, unsigned int);
+static void	aue_setpromisc(void *, int);
+static void	aue_setpromisc_locked(struct aue_softc *);
+static void	aue_init_locked(struct aue_softc *);
+static void	aue_watchdog(void *);
 
 static const struct usb_config aue_config[AUE_N_TRANSFER] = {
 
@@ -283,24 +305,19 @@ MODULE_DEPEND(aue, ether, 1, 1, 1);
 MODULE_DEPEND(aue, miibus, 1, 1, 1);
 MODULE_VERSION(aue, 1);
 
-static const struct usb_ether_methods aue_ue_methods = {
-	.ue_attach_post = aue_attach_post,
-	.ue_start = aue_start,
-	.ue_init = aue_init,
-	.ue_stop = aue_stop,
-	.ue_tick = aue_tick,
-	.ue_setmulti = aue_setmulti,
-	.ue_setpromisc = aue_setpromisc,
-	.ue_mii_upd = aue_ifmedia_upd,
-	.ue_mii_sts = aue_ifmedia_sts,
-};
-
 #define	AUE_SETBIT(sc, reg, x) \
 	aue_csr_write_1(sc, reg, aue_csr_read_1(sc, reg) | (x))
 
 #define	AUE_CLRBIT(sc, reg, x) \
 	aue_csr_write_1(sc, reg, aue_csr_read_1(sc, reg) & ~(x))
 
+static void
+aue_pause(struct aue_softc *sc, unsigned int _ticks)
+{
+
+	usb_pause_mtx(&sc->sc_mtx, _ticks);
+}
+
 static uint8_t
 aue_csr_read_1(struct aue_softc *sc, uint16_t reg)
 {
@@ -314,7 +331,8 @@ aue_csr_read_1(struct aue_softc *sc, uint16_t reg)
 	USETW(req.wIndex, reg);
 	USETW(req.wLength, 1);
 
-	err = uether_do_request(&sc->sc_ue, &req, &val, 1000);
+	err = usbd_do_request_flags(sc->sc_udev, &sc->sc_mtx, &req, &val, 0,
+	    NULL, 1000);
 	if (err)
 		return (0);
 	return (val);
@@ -333,7 +351,8 @@ aue_csr_read_2(struct aue_softc *sc, uint16_t reg)
 	USETW(req.wIndex, reg);
 	USETW(req.wLength, 2);
 
-	err = uether_do_request(&sc->sc_ue, &req, &val, 1000);
+	err = usbd_do_request_flags(sc->sc_udev, &sc->sc_mtx, &req, &val, 0,
+	    NULL, 1000);
 	if (err)
 		return (0);
 	return (le16toh(val));
@@ -351,9 +370,9 @@ aue_csr_write_1(struct aue_softc *sc, uint16_t reg
 	USETW(req.wIndex, reg);
 	USETW(req.wLength, 1);
 
-	if (uether_do_request(&sc->sc_ue, &req, &val, 1000)) {
-		/* error ignored */
-	}
+	/* XXX error ignored */
+	(void)usbd_do_request_flags(sc->sc_udev, &sc->sc_mtx, &req, &val, 0,
+	    NULL, 1000);
 }
 
 static void
@@ -369,9 +388,9 @@ aue_csr_write_2(struct aue_softc *sc, uint16_t reg
 
 	val = htole16(val);
 
-	if (uether_do_request(&sc->sc_ue, &req, &val, 1000)) {
-		/* error ignored */
-	}
+	/* XXX error ignored */
+	(void)usbd_do_request_flags(sc->sc_udev, &sc->sc_mtx, &req, &val, 0,
+	    NULL, 1000);
 }
 
 /*
@@ -389,12 +408,11 @@ aue_eeprom_getword(struct aue_softc *sc, int addr,
 	for (i = 0; i != AUE_TIMEOUT; i++) {
 		if (aue_csr_read_1(sc, AUE_EE_CTL) & AUE_EECTL_DONE)
 			break;
-		if (uether_pause(&sc->sc_ue, hz / 100))
-			break;
+		aue_pause(sc, hz / 100);
 	}
 
 	if (i == AUE_TIMEOUT)
-		device_printf(sc->sc_ue.ue_dev, "EEPROM read timed out\n");
+		device_printf(sc->sc_dev, "EEPROM read timed out\n");
 
 	word = aue_csr_read_2(sc, AUE_EE_DATA);
 	*dest = word;
@@ -446,12 +464,11 @@ aue_miibus_readreg(device_t dev, int phy, int reg)
 	for (i = 0; i != AUE_TIMEOUT; i++) {
 		if (aue_csr_read_1(sc, AUE_PHY_CTL) & AUE_PHYCTL_DONE)
 			break;
-		if (uether_pause(&sc->sc_ue, hz / 100))
-			break;
+		aue_pause(sc, hz / 100);
 	}
 
 	if (i == AUE_TIMEOUT)
-		device_printf(sc->sc_ue.ue_dev, "MII read timed out\n");
+		device_printf(sc->sc_dev, "MII read timed out\n");
 
 	val = aue_csr_read_2(sc, AUE_PHY_DATA);
 
@@ -482,12 +499,11 @@ aue_miibus_writereg(device_t dev, int phy, int reg
 	for (i = 0; i != AUE_TIMEOUT; i++) {
 		if (aue_csr_read_1(sc, AUE_PHY_CTL) & AUE_PHYCTL_DONE)
 			break;
-		if (uether_pause(&sc->sc_ue, hz / 100))
-			break;
+		aue_pause(sc, hz / 100);
 	}
 
 	if (i == AUE_TIMEOUT)
-		device_printf(sc->sc_ue.ue_dev, "MII write timed out\n");
+		device_printf(sc->sc_dev, "MII write timed out\n");
 
 	if (!locked)
 		AUE_UNLOCK(sc);
@@ -533,12 +549,21 @@ aue_miibus_statchg(device_t dev)
 		AUE_UNLOCK(sc);
 }
 
+static void
+aue_setmulti(void *arg, int npending)
+{
+	struct aue_softc *sc = arg;
+
+	AUE_LOCK(sc);
+	aue_setmulti_locked(sc);
+	AUE_UNLOCK(sc);
+}
+
 #define	AUE_BITS	6
 static void
-aue_setmulti(struct usb_ether *ue)
+aue_setmulti_locked(struct aue_softc *sc)
 {
-	struct aue_softc *sc = uether_getsc(ue);
-	struct ifnet *ifp = uether_getifp(ue);
+	struct ifnet *ifp = sc->sc_ifp;
 	struct ifmultiaddr *ifma;
 	uint32_t h = 0;
 	uint32_t i;
@@ -572,6 +597,7 @@ static void
 static void
 aue_reset_pegasus_II(struct aue_softc *sc)
 {
+
 	/* Magic constants taken from Linux driver. */
 	aue_csr_write_1(sc, AUE_REG_1D, 0);
 	aue_csr_write_1(sc, AUE_REG_7B, 2);
@@ -593,12 +619,11 @@ aue_reset(struct aue_softc *sc)
 	for (i = 0; i != AUE_TIMEOUT; i++) {
 		if (!(aue_csr_read_1(sc, AUE_CTL1) & AUE_CTL1_RESETMAC))
 			break;
-		if (uether_pause(&sc->sc_ue, hz / 100))
-			break;
+		aue_pause(sc, hz / 100);
 	}
 
 	if (i == AUE_TIMEOUT)
-		device_printf(sc->sc_ue.ue_dev, "reset failed\n");
+		device_printf(sc->sc_dev, "reset failed\n");
 
 	/*
 	 * The PHY(s) attached to the Pegasus chip may be held
@@ -625,21 +650,9 @@ aue_reset(struct aue_softc *sc)
 		aue_reset_pegasus_II(sc);
 
 	/* Wait a little while for the chip to get its brains in order: */
-	uether_pause(&sc->sc_ue, hz / 100);
+	aue_pause(sc, hz / 100);
 }
 
-static void
-aue_attach_post(struct usb_ether *ue)
-{
-	struct aue_softc *sc = uether_getsc(ue);
-
-	/* reset the adapter */
-	aue_reset(sc);
-
-	/* get station address from the EEPROM */
-	aue_read_eeprom(sc, ue->ue_eaddr, 0, 3);
-}
-
 /*
  * Probe for a Pegasus chip.
  */
@@ -676,7 +689,7 @@ aue_attach(device_t dev)
 {
 	struct usb_attach_arg *uaa = device_get_ivars(dev);
 	struct aue_softc *sc = device_get_softc(dev);
-	struct usb_ether *ue = &sc->sc_ue;
+	struct ifnet *ifp;
 	uint8_t iface_index;
 	int error;
 
@@ -688,7 +701,16 @@ aue_attach(device_t dev)
 	}
 
 	device_set_usb_desc(dev);
+	sc->sc_dev = dev;
+	sc->sc_udev = uaa->device;
+	sc->sc_unit = uether_alloc_unr();
+
 	mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
+	sx_init(&sc->sc_sx, "aue sxlock");
+	sleepout_create(&sc->sc_sleepout, "aue sleepout");
+	sleepout_init_mtx(&sc->sc_sleepout, &sc->sc_watchdog, &sc->sc_mtx, 0);
+	TASK_INIT(&sc->sc_setmulti, 0, aue_setmulti, sc);
+	TASK_INIT(&sc->sc_setpromisc, 0, aue_setpromisc, sc);
 
 	iface_index = AUE_IFACE_IDX;
 	error = usbd_transfer_setup(uaa->device, &iface_index,
@@ -699,19 +721,42 @@ aue_attach(device_t dev)
 		goto detach;
 	}
 
-	ue->ue_sc = sc;
-	ue->ue_dev = dev;
-	ue->ue_udev = uaa->device;
-	ue->ue_mtx = &sc->sc_mtx;
-	ue->ue_methods = &aue_ue_methods;
+	AUE_LOCK(sc);
+	/* reset the adapter */
+	aue_reset(sc);
+	/* get station address from the EEPROM */
+	aue_read_eeprom(sc, sc->sc_eaddr, 0, 3);
+	AUE_UNLOCK(sc);
 
-	error = uether_ifattach(ue);
+	sc->sc_ifp = ifp = if_alloc(IFT_ETHER);
+	if (ifp == NULL) {
+		device_printf(sc->sc_dev, "could not allocate ifnet\n");
+		goto detach;
+	}
+
+	ifp->if_softc = sc;
+	if_initname(ifp, "ue", sc->sc_unit);
+	ifp->if_mtu = ETHERMTU;
+	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+	ifp->if_ioctl = aue_ioctl;
+	ifp->if_start = aue_start;
+	ifp->if_init = aue_init;
+	IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
+	ifp->if_snd.ifq_drv_maxlen = ifqmaxlen;
+	IFQ_SET_READY(&ifp->if_snd);
+
+	error = mii_attach(sc->sc_dev, &sc->sc_miibus, ifp,
+	    aue_ifmedia_upd, aue_ifmedia_sts,
+	    BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, 0);
 	if (error) {
-		device_printf(dev, "could not attach interface\n");
+		device_printf(sc->sc_dev, "MII without any PHY\n");
 		goto detach;
 	}
-	return (0);			/* success */
 
+	if_printf(ifp, "<USB Ethernet> on %s\n",
+	    device_get_nameunit(sc->sc_dev));
+	ether_ifattach(ifp, sc->sc_eaddr);
+	return (0);
 detach:
 	aue_detach(dev);
 	return (ENXIO);			/* failure */
@@ -721,11 +766,26 @@ static int
 aue_detach(device_t dev)
 {
 	struct aue_softc *sc = device_get_softc(dev);
-	struct usb_ether *ue = &sc->sc_ue;
+	struct ifnet *ifp = sc->sc_ifp;
 
+	sleepout_drain(&sc->sc_watchdog);
+	SLEEPOUT_DRAINTASK(&sc->sc_sleepout, &sc->sc_setpromisc);
+	SLEEPOUT_DRAINTASK(&sc->sc_sleepout, &sc->sc_setmulti);
 	usbd_transfer_unsetup(sc->sc_xfer, AUE_N_TRANSFER);
-	uether_ifdetach(ue);
+
+	if (sc->sc_miibus != NULL)
+		device_delete_child(sc->sc_dev, sc->sc_miibus);
+	if (ifp != NULL) {
+		AUE_LOCK(sc);
+		ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
+		AUE_UNLOCK(sc);
+		ether_ifdetach(ifp);
+		if_free(ifp);
+	}
+	sleepout_free(&sc->sc_sleepout);
+	sx_destroy(&sc->sc_sx);
 	mtx_destroy(&sc->sc_mtx);
+	uether_free_unr(sc->sc_unit);
 
 	return (0);
 }
@@ -734,7 +794,7 @@ static void
 aue_intr_callback(struct usb_xfer *xfer, usb_error_t error)
 {
 	struct aue_softc *sc = usbd_xfer_softc(xfer);
-	struct ifnet *ifp = uether_getifp(&sc->sc_ue);
+	struct ifnet *ifp = sc->sc_ifp;
 	struct aue_intrpkt pkt;
 	struct usb_page_cache *pc;
 	int actlen;
@@ -743,10 +803,8 @@ aue_intr_callback(struct usb_xfer *xfer, usb_error
 
 	switch (USB_GET_STATE(xfer)) {
 	case USB_ST_TRANSFERRED:
-
 		if ((ifp->if_drv_flags & IFF_DRV_RUNNING) &&
 		    actlen >= sizeof(pkt)) {
-
 			pc = usbd_xfer_get_frame(xfer, 0);
 			usbd_copy_out(pc, 0, &pkt, sizeof(pkt));
 
@@ -762,7 +820,6 @@ tr_setup:
 		usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
 		usbd_transfer_submit(xfer);
 		return;
-
 	default:			/* Error */
 		if (error != USB_ERR_CANCELLED) {
 			/* try to clear stall first */
@@ -777,8 +834,7 @@ static void
 aue_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error)
 {
 	struct aue_softc *sc = usbd_xfer_softc(xfer);
-	struct usb_ether *ue = &sc->sc_ue;
-	struct ifnet *ifp = uether_getifp(ue);
+	struct ifnet *ifp = sc->sc_ifp;
 	struct aue_rxpkt stat;
 	struct usb_page_cache *pc;
 	int actlen;
@@ -791,13 +847,11 @@ aue_bulk_read_callback(struct usb_xfer *xfer, usb_
 		DPRINTFN(11, "received %d bytes\n", actlen);
 
 		if (sc->sc_flags & AUE_FLAG_VER_2) {
-
 			if (actlen == 0) {
 				ifp->if_ierrors++;
 				goto tr_setup;
 			}
 		} else {
-
 			if (actlen <= sizeof(stat) + ETHER_CRC_LEN) {
 				ifp->if_ierrors++;
 				goto tr_setup;
@@ -817,16 +871,14 @@ aue_bulk_read_callback(struct usb_xfer *xfer, usb_
 			/* No errors; receive the packet. */
 			actlen -= (sizeof(stat) + ETHER_CRC_LEN);
 		}
-		uether_rxbuf(ue, pc, 0, actlen);
-
+		aue_rxbuf(sc, pc, 0, actlen);
 		/* FALLTHROUGH */
 	case USB_ST_SETUP:
 tr_setup:
 		usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
 		usbd_transfer_submit(xfer);
-		uether_rxflush(ue);
+		aue_rxflush(sc);
 		return;
-
 	default:			/* Error */
 		DPRINTF("bulk read error, %s\n",
 		    usbd_errstr(error));
@@ -844,7 +896,7 @@ static void
 aue_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
 {
 	struct aue_softc *sc = usbd_xfer_softc(xfer);
-	struct ifnet *ifp = uether_getifp(&sc->sc_ue);
+	struct ifnet *ifp = sc->sc_ifp;
 	struct usb_page_cache *pc;
 	struct mbuf *m;
 	uint8_t buf[2];
@@ -857,7 +909,6 @@ aue_bulk_write_callback(struct usb_xfer *xfer, usb
 	case USB_ST_TRANSFERRED:
 		DPRINTFN(11, "transfer of %d bytes complete\n", actlen);
 		ifp->if_opackets++;
-
 		/* FALLTHROUGH */
 	case USB_ST_SETUP:
 tr_setup:
@@ -874,13 +925,10 @@ tr_setup:
 		if (m->m_pkthdr.len > MCLBYTES)
 			m->m_pkthdr.len = MCLBYTES;
 		if (sc->sc_flags & AUE_FLAG_VER_2) {
-
 			usbd_xfer_set_frame_len(xfer, 0, m->m_pkthdr.len);
 
 			usbd_m_copy_in(pc, 0, m, 0, m->m_pkthdr.len);
-
 		} else {
-
 			usbd_xfer_set_frame_len(xfer, 0, (m->m_pkthdr.len + 2));
 
 			/*
@@ -908,7 +956,6 @@ tr_setup:
 
 		usbd_transfer_submit(xfer);
 		return;
-
 	default:			/* Error */
 		DPRINTFN(11, "transfer error, %s\n",
 		    usbd_errstr(error));
@@ -925,9 +972,8 @@ tr_setup:
 }
 
 static void
-aue_tick(struct usb_ether *ue)
+aue_tick(struct aue_softc *sc)
 {
-	struct aue_softc *sc = uether_getsc(ue);
 	struct mii_data *mii = GET_MII(sc);
 
 	AUE_LOCK_ASSERT(sc, MA_OWNED);
@@ -937,15 +983,27 @@ static void
 	    && mii->mii_media_status & IFM_ACTIVE &&
 	    IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
 		sc->sc_flags |= AUE_FLAG_LINK;
-		aue_start(ue);
+		aue_start_locked(sc->sc_ifp);
 	}
 }
 
 static void
-aue_start(struct usb_ether *ue)
+aue_start(struct ifnet *ifp)
 {
-	struct aue_softc *sc = uether_getsc(ue);
+	struct aue_softc *sc = ifp->if_softc;
 
+	AUE_LOCK(sc);
+	aue_start_locked(ifp);
+	AUE_UNLOCK(sc);
+}
+
+static void
+aue_start_locked(struct ifnet *ifp)
+{
+	struct aue_softc *sc = ifp->if_softc;
+
+	AUE_LOCK_ASSERT(sc, MA_OWNED);
+
 	/*
 	 * start the USB transfers, if not already started:
 	 */
@@ -955,10 +1013,21 @@ static void
 }
 
 static void
-aue_init(struct usb_ether *ue)
+aue_init(void *arg)
 {
-	struct aue_softc *sc = uether_getsc(ue);
-	struct ifnet *ifp = uether_getifp(ue);
+	struct aue_softc *sc = arg;
+
+	AUE_SXLOCK(sc);
+	AUE_LOCK(sc);
+	aue_init_locked(sc);
+	AUE_UNLOCK(sc);
+	AUE_SXUNLOCK(sc);
+}
+
+static void
+aue_init_locked(struct aue_softc *sc)
+{
+	struct ifnet *ifp = sc->sc_ifp;
 	int i;
 
 	AUE_LOCK_ASSERT(sc, MA_OWNED);
@@ -973,10 +1042,10 @@ static void
 		aue_csr_write_1(sc, AUE_PAR0 + i, IF_LLADDR(ifp)[i]);
 
 	/* update promiscuous setting */
-	aue_setpromisc(ue);
+	aue_setpromisc_locked(sc);
 
 	/* Load the multicast filter. */
-	aue_setmulti(ue);
+	aue_setmulti_locked(sc);
 
 	/* Enable RX and TX */
 	aue_csr_write_1(sc, AUE_CTL0, AUE_CTL0_RXSTAT_APPEND | AUE_CTL0_RX_ENB);
@@ -986,15 +1055,25 @@ static void
 	usbd_xfer_set_stall(sc->sc_xfer[AUE_BULK_DT_WR]);
 
 	ifp->if_drv_flags |= IFF_DRV_RUNNING;
-	aue_start(ue);
+	sleepout_reset(&sc->sc_watchdog, hz, aue_watchdog, sc);
+	aue_start_locked(sc->sc_ifp);
 }
 
 static void
-aue_setpromisc(struct usb_ether *ue)
+aue_setpromisc(void *arg, int npending)
 {
-	struct aue_softc *sc = uether_getsc(ue);
-	struct ifnet *ifp = uether_getifp(ue);
+	struct aue_softc *sc = arg;
 
+	AUE_LOCK(sc);
+	aue_setpromisc_locked(sc);
+	AUE_UNLOCK(sc);
+}
+
+static void
+aue_setpromisc_locked(struct aue_softc *sc)
+{
+	struct ifnet *ifp = sc->sc_ifp;
+
 	AUE_LOCK_ASSERT(sc, MA_OWNED);
 
 	/* if we want promiscuous mode, set the allframes bit: */
@@ -1013,8 +1092,7 @@ aue_ifmedia_upd(struct ifnet *ifp)
 	struct aue_softc *sc = ifp->if_softc;
 	struct mii_data *mii = GET_MII(sc);
 
-	AUE_LOCK_ASSERT(sc, MA_OWNED);
-
+	AUE_LOCK(sc);
         sc->sc_flags &= ~AUE_FLAG_LINK;
 	if (mii->mii_instance) {
 		struct mii_softc *miisc;
@@ -1023,6 +1101,7 @@ aue_ifmedia_upd(struct ifnet *ifp)
 			mii_phy_reset(miisc);
 	}
 	mii_mediachg(mii);
+	AUE_UNLOCK(sc);
 	return (0);
 }
 
@@ -1047,11 +1126,21 @@ aue_ifmedia_sts(struct ifnet *ifp, struct ifmediar
  * RX and TX lists.
  */
 static void
-aue_stop(struct usb_ether *ue)
+aue_stop(struct aue_softc *sc)
 {
-	struct aue_softc *sc = uether_getsc(ue);
-	struct ifnet *ifp = uether_getifp(ue);
 
+	AUE_SXLOCK(sc);
+	AUE_LOCK(sc);
+	aue_stop_locked(sc);
+	AUE_UNLOCK(sc);
+	AUE_SXUNLOCK(sc);
+}
+
+static void
+aue_stop_locked(struct aue_softc *sc)
+{
+	struct ifnet *ifp = sc->sc_ifp;
+
 	AUE_LOCK_ASSERT(sc, MA_OWNED);
 
 	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
@@ -1068,3 +1157,125 @@ static void
 	aue_csr_write_1(sc, AUE_CTL1, 0);
 	aue_reset(sc);
 }
+
+static int
+aue_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
+{
+	struct aue_softc *sc = ifp->if_softc;
+	struct ifreq *ifr = (struct ifreq *)data;
+	struct mii_data *mii = GET_MII(sc);
+	int error = 0, drv_flags, flags;
+
+	switch (command) {
+	case SIOCSIFFLAGS:
+		/* Avoids race and LOR between mutex and sx lock. */
+		AUE_LOCK(sc);
+		flags = ifp->if_flags;
+		drv_flags = ifp->if_drv_flags;
+		AUE_UNLOCK(sc);
+		/* device up and down is synchronous using sx(9) lock */
+		if (flags & IFF_UP) {
+			if (drv_flags & IFF_DRV_RUNNING)
+				SLEEPOUT_RUNTASK(&sc->sc_sleepout,
+				    &sc->sc_setpromisc);
+			else
+				aue_init(sc);
+		} else
+			aue_stop(sc);
+		break;
+	case SIOCADDMULTI:
+	case SIOCDELMULTI:
+		/* To avoid LOR by in_multi_mtx (netinet/in_mcast.c) */
+		if (ifp->if_flags & IFF_UP &&
+		    ifp->if_drv_flags & IFF_DRV_RUNNING)
+			SLEEPOUT_RUNTASK(&sc->sc_sleepout, &sc->sc_setmulti);
+		break;
+	case SIOCGIFMEDIA:
+	case SIOCSIFMEDIA:
+		error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
+		break;
+	default:
+		error = ether_ioctl(ifp, command, data);
+		break;
+	}
+	return (error);
+}
+
+static void
+aue_rxflush(struct aue_softc *sc)
+{
+	struct ifnet *ifp = sc->sc_ifp;
+	struct mbuf *m;
+
+	AUE_LOCK_ASSERT(sc, MA_OWNED);
+
+	for (;;) {
+		_IF_DEQUEUE(&sc->sc_rxq, m);
+		if (m == NULL)
+			break;
+
+		/*
+		 * The USB xfer has been resubmitted so its safe to unlock now.
+		 */
+		AUE_UNLOCK(sc);
+		ifp->if_input(ifp, m);
+		AUE_LOCK(sc);
+	}
+}
+
+static struct mbuf *
+aue_newbuf(void)
+{
+	struct mbuf *m_new;
+
+	m_new = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+	if (m_new == NULL)
+		return (NULL);
+	m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
+
+	m_adj(m_new, ETHER_ALIGN);
+	return (m_new);
+}
+
+static int
+aue_rxbuf(struct aue_softc *sc, struct usb_page_cache *pc, 
+    unsigned int offset, unsigned int len)
+{
+	struct ifnet *ifp = sc->sc_ifp;
+	struct mbuf *m;
+
+	AUE_LOCK_ASSERT(sc, MA_OWNED);
+
+	if (len < ETHER_HDR_LEN || len > MCLBYTES - ETHER_ALIGN)
+		return (1);
+
+	m = aue_newbuf();
+	if (m == NULL) {
+		ifp->if_ierrors++;
+		return (ENOMEM);
+	}
+
+	usbd_copy_out(pc, offset, mtod(m, uint8_t *), len);
+
+	/* finalize mbuf */
+	ifp->if_ipackets++;
+	m->m_pkthdr.rcvif = ifp;
+	m->m_pkthdr.len = m->m_len = len;
+
+	/* enqueue for later when the lock can be released */
+	_IF_ENQUEUE(&sc->sc_rxq, m);
+	return (0);
+}
+
+static void
+aue_watchdog(void *arg)
+{
+	struct aue_softc *sc = arg;
+	struct ifnet *ifp = sc->sc_ifp;
+
+	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
+		return;
+
+	aue_tick(sc);
+	sleepout_reset(&sc->sc_watchdog, hz, aue_watchdog, sc);
+}
Index: if_auereg.h
===================================================================
--- if_auereg.h	(revision 214568)
+++ if_auereg.h	(working copy)
@@ -183,7 +183,7 @@ enum {
 #define	AUE_RXSTAT_DRIBBLE	0x10
 #define	AUE_RXSTAT_MASK		0x1E
 
-#define	GET_MII(sc)		uether_getmii(&(sc)->sc_ue)
+#define	GET_MII(sc)		(device_get_softc(sc->sc_miibus))
 
 struct aue_intrpkt {
 	uint8_t	aue_txstat0;
@@ -202,10 +202,16 @@ struct aue_rxpkt {
 } __packed;
 
 struct aue_softc {
-	struct usb_ether	sc_ue;
+	struct ifnet		*sc_ifp;
+	device_t		sc_dev;
+	device_t		sc_miibus;
+	struct usb_device	*sc_udev; /* used by uether_do_request() */
+	struct usb_xfer		*sc_xfer[AUE_N_TRANSFER];
 	struct mtx		sc_mtx;
-	struct usb_xfer	*sc_xfer[AUE_N_TRANSFER];
-
+	struct sx		sc_sx;
+	struct ifqueue		sc_rxq;
+	/* ethernet address from eeprom */
+	uint8_t			sc_eaddr[ETHER_ADDR_LEN];
 	int			sc_flags;
 #define	AUE_FLAG_LSYS		0x0001	/* use Linksys reset */
 #define	AUE_FLAG_PNA		0x0002	/* has Home PNA */
@@ -213,8 +219,16 @@ struct aue_softc {
 #define	AUE_FLAG_LINK		0x0008	/* wait for link to come up */
 #define	AUE_FLAG_VER_2		0x0200	/* chip is version 2 */
 #define	AUE_FLAG_DUAL_PHY	0x0400	/* chip has two transcivers */
+	int			sc_unit;
+
+	struct sleepout		sc_sleepout;
+	struct sleepout_task	sc_watchdog;
+	struct task		sc_setmulti;
+	struct task		sc_setpromisc;
 };
 
+#define	AUE_SXLOCK(_sc)		sx_xlock(&(_sc)->sc_sx)
+#define	AUE_SXUNLOCK(_sc)	sx_xunlock(&(_sc)->sc_sx)
 #define	AUE_LOCK(_sc)		mtx_lock(&(_sc)->sc_mtx)
 #define	AUE_UNLOCK(_sc)		mtx_unlock(&(_sc)->sc_mtx)
 #define	AUE_LOCK_ASSERT(_sc, t)	mtx_assert(&(_sc)->sc_mtx, t)
Index: usb_ethernet.h
===================================================================
--- usb_ethernet.h	(revision 214568)
+++ usb_ethernet.h	(working copy)
@@ -119,4 +119,7 @@ int		uether_rxbuf(struct usb_ether *,
 		    unsigned int, unsigned int);
 void		uether_rxflush(struct usb_ether *);
 uint8_t		uether_is_gone(struct usb_ether *);
+int		uether_alloc_unr(void);
+void		uether_free_unr(int);
+
 #endif					/* _USB_ETHERNET_H_ */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20101031214704.GA3918>