[CFR 3/n] removes uther dependency of axe(4)

Weongyo Jeong weongyo.jeong at gmail.com
Sun Oct 31 22:43:09 UTC 2010


Hello,

As one of patch series it's for patching axe(4) without dependency of
uether module.  The change log would be almost same like the previous
patch log.

regards,
Weongyo Jeong

Index: if_axereg.h
===================================================================
--- if_axereg.h	(revision 214604)
+++ if_axereg.h	(working copy)
@@ -185,7 +185,7 @@ struct axe_sframe_hdr {
 	uint16_t ilen;
 } __packed;
 
-#define	GET_MII(sc)		uether_getmii(&(sc)->sc_ue)
+#define	GET_MII(sc)		(device_get_softc(sc->sc_miibus))
 
 /* The interrupt endpoint is currently unused by the ASIX part. */
 enum {
@@ -195,20 +195,35 @@ enum {
 };
 
 struct axe_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 mtx		sc_mtx;
-	struct usb_xfer	*sc_xfer[AXE_N_TRANSFER];
+	struct sx		sc_sx;
+	struct usb_xfer		*sc_xfer[AXE_N_TRANSFER];
+
+	/* ethernet address from eeprom */
+	uint8_t			sc_eaddr[ETHER_ADDR_LEN];
+	struct ifqueue		sc_rxq;
+
+	struct sleepout		sc_sleepout;
+	struct sleepout_task	sc_watchdog;
+	struct task		sc_setmulti;
+	struct task		sc_setpromisc;
+
+	int			sc_unit;
 	int			sc_phyno;
-
 	int			sc_flags;
 #define	AXE_FLAG_LINK		0x0001
 #define	AXE_FLAG_772		0x1000	/* AX88772 */
 #define	AXE_FLAG_178		0x2000	/* AX88178 */
-
 	uint8_t			sc_ipgs[3];
 	uint8_t			sc_phyaddrs[2];
 };
 
+#define	AXE_SXLOCK(_sc)		sx_xlock(&(_sc)->sc_sx)
+#define	AXE_SXUNLOCK(_sc)	sx_xunlock(&(_sc)->sc_sx)
 #define	AXE_LOCK(_sc)		mtx_lock(&(_sc)->sc_mtx)
 #define	AXE_UNLOCK(_sc)		mtx_unlock(&(_sc)->sc_mtx)
 #define	AXE_LOCK_ASSERT(_sc, t)	mtx_assert(&(_sc)->sc_mtx, t)
Index: if_axe.c
===================================================================
--- if_axe.c	(revision 214604)
+++ if_axe.c	(working copy)
@@ -89,6 +89,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>
@@ -96,6 +98,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>
@@ -104,6 +119,7 @@ __FBSDID("$FreeBSD$");
 #define	USB_DEBUG_VAR axe_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_axereg.h>
@@ -178,23 +194,26 @@ static miibus_readreg_t axe_miibus_readreg;
 static miibus_writereg_t axe_miibus_writereg;
 static miibus_statchg_t axe_miibus_statchg;
 
-static uether_fn_t axe_attach_post;
-static uether_fn_t axe_init;
-static uether_fn_t axe_stop;
-static uether_fn_t axe_start;
-static uether_fn_t axe_tick;
-static uether_fn_t axe_setmulti;
-static uether_fn_t axe_setpromisc;
-
 static int	axe_ifmedia_upd(struct ifnet *);
 static void	axe_ifmedia_sts(struct ifnet *, struct ifmediareq *);
 static int	axe_cmd(struct axe_softc *, int, int, int, void *);
 static void	axe_ax88178_init(struct axe_softc *);
 static void	axe_ax88772_init(struct axe_softc *);
 static int	axe_get_phyno(struct axe_softc *, int);
+static void	axe_watchdog(void *);
+static void	axe_init(void *);
+static void	axe_init_locked(struct axe_softc *);
+static int	axe_ioctl(struct ifnet *, u_long, caddr_t);
+static void	axe_start(struct ifnet *);
+static void	axe_start_locked(struct ifnet *);
+static void	axe_tick(struct axe_softc *);
+static void	axe_stop(struct axe_softc *);
+static void	axe_stop_locked(struct axe_softc *);
+static void	axe_setmulti_locked(struct axe_softc *);
+static void	axe_setpromisc(void *, int);
+static void	axe_setpromisc_locked(struct axe_softc *);
 
 static const struct usb_config axe_config[AXE_N_TRANSFER] = {
-
 	[AXE_BULK_DT_WR] = {
 		.type = UE_BULK,
 		.endpoint = UE_ADDR_ANY,
@@ -250,18 +269,14 @@ MODULE_DEPEND(axe, ether, 1, 1, 1);
 MODULE_DEPEND(axe, miibus, 1, 1, 1);
 MODULE_VERSION(axe, 1);
 
-static const struct usb_ether_methods axe_ue_methods = {
-	.ue_attach_post = axe_attach_post,
-	.ue_start = axe_start,
-	.ue_init = axe_init,
-	.ue_stop = axe_stop,
-	.ue_tick = axe_tick,
-	.ue_setmulti = axe_setmulti,
-	.ue_setpromisc = axe_setpromisc,
-	.ue_mii_upd = axe_ifmedia_upd,
-	.ue_mii_sts = axe_ifmedia_sts,
-};
+static uint8_t
+axe_pause(struct axe_softc *sc, unsigned int _ticks)
+{
 
+	usb_pause_mtx(&sc->sc_mtx, _ticks);
+	return (0);
+}
+
 static int
 axe_cmd(struct axe_softc *sc, int cmd, int index, int val, void *buf)
 {
@@ -278,7 +293,8 @@ axe_cmd(struct axe_softc *sc, int cmd, int index,
 	USETW(req.wIndex, index);
 	USETW(req.wLength, AXE_CMD_LEN(cmd));
 
-	err = uether_do_request(&sc->sc_ue, &req, buf, 1000);
+	err = usbd_do_request_flags(sc->sc_udev, &sc->sc_mtx, &req, buf, 0,
+	    NULL, 1000);
 
 	return (err);
 }
@@ -354,7 +370,7 @@ axe_miibus_statchg(device_t dev)
 	if (!locked)
 		AXE_LOCK(sc);
 
-	ifp = uether_getifp(&sc->sc_ue);
+	ifp = sc->sc_ifp;
 	if (mii == NULL || ifp == NULL ||
 	    (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
 		goto done;
@@ -418,8 +434,7 @@ axe_ifmedia_upd(struct ifnet *ifp)
 	struct mii_data *mii = GET_MII(sc);
 	int error;
 
-	AXE_LOCK_ASSERT(sc, MA_OWNED);
-
+	AXE_LOCK(sc);
 	if (mii->mii_instance) {
 		struct mii_softc *miisc;
 
@@ -427,6 +442,7 @@ axe_ifmedia_upd(struct ifnet *ifp)
 			mii_phy_reset(miisc);
 	}
 	error = mii_mediachg(mii);
+	AXE_UNLOCK(sc);
 	return (error);
 }
 
@@ -447,10 +463,19 @@ axe_ifmedia_sts(struct ifnet *ifp, struct ifmediar
 }
 
 static void
-axe_setmulti(struct usb_ether *ue)
+axe_setmulti(void *arg, int npending)
 {
-	struct axe_softc *sc = uether_getsc(ue);
-	struct ifnet *ifp = uether_getifp(ue);
+	struct axe_softc *sc = arg;
+
+	AXE_LOCK(sc);
+	axe_setmulti_locked(sc);
+	AXE_UNLOCK(sc);
+}
+
+static void
+axe_setmulti_locked(struct axe_softc *sc)
+{
+	struct ifnet *ifp = sc->sc_ifp;
 	struct ifmultiaddr *ifma;
 	uint32_t h = 0;
 	uint16_t rxmode;
@@ -509,17 +534,15 @@ axe_get_phyno(struct axe_softc *sc, int sel)
 
 #define	AXE_GPIO_WRITE(x, y)	do {				\
 	axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, (x), NULL);		\
-	uether_pause(ue, (y));					\
+	axe_pause(sc, (y));					\
 } while (0)
 
 static void
 axe_ax88178_init(struct axe_softc *sc)
 {
-	struct usb_ether *ue;
 	int gpio0, phymode;
 	uint16_t eeprom, val;
 
-	ue = &sc->sc_ue;
 	axe_cmd(sc, AXE_CMD_SROM_WR_ENABLE, 0, 0, NULL);
 	/* XXX magic */
 	axe_cmd(sc, AXE_CMD_SROM_READ, 0, 0x0017, &eeprom);
@@ -536,7 +559,7 @@ axe_ax88178_init(struct axe_softc *sc)
 	}
 
 	if (bootverbose)
-		device_printf(sc->sc_ue.ue_dev, "EEPROM data : 0x%04x\n",
+		device_printf(sc->sc_dev, "EEPROM data : 0x%04x\n",
 		    eeprom);
 	/* Program GPIOs depending on PHY hardware. */
 	switch (phymode) {
@@ -580,15 +603,15 @@ axe_ax88178_init(struct axe_softc *sc)
 		AXE_GPIO_WRITE(val | AXE_GPIO2_EN, hz / 4);
 		AXE_GPIO_WRITE(val | AXE_GPIO2 | AXE_GPIO2_EN, hz / 32);
 		if (phymode == AXE_PHY_MODE_REALTEK_8211CL) {
-			axe_miibus_writereg(ue->ue_dev, sc->sc_phyno,
+			axe_miibus_writereg(sc->sc_dev, sc->sc_phyno,
 			    0x1F, 0x0005);
-			axe_miibus_writereg(ue->ue_dev, sc->sc_phyno,
+			axe_miibus_writereg(sc->sc_dev, sc->sc_phyno,
 			    0x0C, 0x0000);
-			val = axe_miibus_readreg(ue->ue_dev, sc->sc_phyno,
+			val = axe_miibus_readreg(sc->sc_dev, sc->sc_phyno,
 			    0x0001);
-			axe_miibus_writereg(ue->ue_dev, sc->sc_phyno,
+			axe_miibus_writereg(sc->sc_dev, sc->sc_phyno,
 			    0x01, val | 0x0080);
-			axe_miibus_writereg(ue->ue_dev, sc->sc_phyno,
+			axe_miibus_writereg(sc->sc_dev, sc->sc_phyno,
 			    0x1F, 0x0000);
 		}
 		break;
@@ -599,14 +622,14 @@ axe_ax88178_init(struct axe_softc *sc)
 
 	/* soft reset */
 	axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_CLEAR, NULL);
-	uether_pause(ue, hz / 4);
+	axe_pause(sc, hz / 4);
 
 	axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0,
 	    AXE_SW_RESET_PRL | AXE_178_RESET_MAGIC, NULL);
-	uether_pause(ue, hz / 4);
+	axe_pause(sc, hz / 4);
 	/* Enable MII/GMII/RGMII interface to work with external PHY. */
 	axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, 0, NULL);
-	uether_pause(ue, hz / 4);
+	axe_pause(sc, hz / 4);
 
 	axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL);
 }
@@ -615,23 +638,24 @@ axe_ax88178_init(struct axe_softc *sc)
 static void
 axe_ax88772_init(struct axe_softc *sc)
 {
+
 	axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x00b0, NULL);
-	uether_pause(&sc->sc_ue, hz / 16);
+	axe_pause(sc, hz / 16);
 
 	if (sc->sc_phyno == AXE_772_PHY_NO_EPHY) {
 		/* ask for the embedded PHY */
 		axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, 0x01, NULL);
-		uether_pause(&sc->sc_ue, hz / 64);
+		axe_pause(sc, hz / 64);
 
 		/* power down and reset state, pin reset state */
 		axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0,
 		    AXE_SW_RESET_CLEAR, NULL);
-		uether_pause(&sc->sc_ue, hz / 16);
+		axe_pause(sc, hz / 16);
 
 		/* power down/reset state, pin operating state */
 		axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0,
 		    AXE_SW_RESET_IPPD | AXE_SW_RESET_PRL, NULL);
-		uether_pause(&sc->sc_ue, hz / 4);
+		axe_pause(sc, hz / 4);
 
 		/* power up, reset */
 		axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_PRL, NULL);
@@ -642,14 +666,14 @@ axe_ax88772_init(struct axe_softc *sc)
 	} else {
 		/* ask for external PHY */
 		axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, 0x00, NULL);
-		uether_pause(&sc->sc_ue, hz / 64);
+		axe_pause(sc, hz / 64);
 
 		/* power down internal PHY */
 		axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0,
 		    AXE_SW_RESET_IPPD | AXE_SW_RESET_PRL, NULL);
 	}
 
-	uether_pause(&sc->sc_ue, hz / 4);
+	axe_pause(sc, hz / 4);
 	axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL);
 }
 
@@ -659,34 +683,33 @@ axe_reset(struct axe_softc *sc)
 	struct usb_config_descriptor *cd;
 	usb_error_t err;
 
-	cd = usbd_get_config_descriptor(sc->sc_ue.ue_udev);
+	cd = usbd_get_config_descriptor(sc->sc_udev);
 
-	err = usbd_req_set_config(sc->sc_ue.ue_udev, &sc->sc_mtx,
+	err = usbd_req_set_config(sc->sc_udev, &sc->sc_mtx,
 	    cd->bConfigurationValue);
 	if (err)
 		DPRINTF("reset failed (ignored)\n");
 
 	/* Wait a little while for the chip to get its brains in order. */
-	uether_pause(&sc->sc_ue, hz / 100);
+	axe_pause(sc, hz / 100);
 }
 
 static void
-axe_attach_post(struct usb_ether *ue)
+axe_attach_post(struct axe_softc *sc)
 {
-	struct axe_softc *sc = uether_getsc(ue);
 
 	/*
 	 * Load PHY indexes first. Needed by axe_xxx_init().
 	 */
 	axe_cmd(sc, AXE_CMD_READ_PHYID, 0, 0, sc->sc_phyaddrs);
 	if (bootverbose)
-		device_printf(sc->sc_ue.ue_dev, "PHYADDR 0x%02x:0x%02x\n",
+		device_printf(sc->sc_dev, "PHYADDR 0x%02x:0x%02x\n",
 		    sc->sc_phyaddrs[0], sc->sc_phyaddrs[1]);
 	sc->sc_phyno = axe_get_phyno(sc, AXE_PHY_SEL_PRI);
 	if (sc->sc_phyno == -1)
 		sc->sc_phyno = axe_get_phyno(sc, AXE_PHY_SEL_SEC);
 	if (sc->sc_phyno == -1) {
-		device_printf(sc->sc_ue.ue_dev,
+		device_printf(sc->sc_dev,
 		    "no valid PHY address found, assuming PHY address 0\n");
 		sc->sc_phyno = 0;
 	}
@@ -700,9 +723,9 @@ static void
 	 * Get station address.
 	 */
 	if (sc->sc_flags & (AXE_FLAG_178 | AXE_FLAG_772))
-		axe_cmd(sc, AXE_178_CMD_READ_NODEID, 0, 0, ue->ue_eaddr);
+		axe_cmd(sc, AXE_178_CMD_READ_NODEID, 0, 0, sc->sc_eaddr);
 	else
-		axe_cmd(sc, AXE_172_CMD_READ_NODEID, 0, 0, ue->ue_eaddr);
+		axe_cmd(sc, AXE_172_CMD_READ_NODEID, 0, 0, sc->sc_eaddr);
 
 	/*
 	 * Fetch IPG values.
@@ -728,6 +751,19 @@ axe_probe(device_t dev)
 	return (usbd_lookup_id_by_uaa(axe_devs, sizeof(axe_devs), uaa));
 }
 
+static void
+axe_watchdog(void *arg)
+{
+	struct axe_softc *sc = arg;
+	struct ifnet *ifp = sc->sc_ifp;
+
+	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
+		return;
+
+	axe_tick(sc);
+	sleepout_reset(&sc->sc_watchdog, hz, axe_watchdog, sc);
+}
+
 /*
  * Attach the interface. Allocate softc structures, do ifmedia
  * setup and ethernet/BPF attach.
@@ -737,15 +773,23 @@ axe_attach(device_t dev)
 {
 	struct usb_attach_arg *uaa = device_get_ivars(dev);
 	struct axe_softc *sc = device_get_softc(dev);
-	struct usb_ether *ue = &sc->sc_ue;
+	struct ifnet *ifp;
 	uint8_t iface_index;
 	int error;
 
 	sc->sc_flags = USB_GET_DRIVER_INFO(uaa);
+	sc->sc_dev = dev;
+	sc->sc_udev = uaa->device;
+	sc->sc_unit = uether_alloc_unr();
 
 	device_set_usb_desc(dev);
 
 	mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
+	sx_init(&sc->sc_sx, "axe sxlock");
+	sleepout_create(&sc->sc_sleepout, "axe sleepout");
+	sleepout_init_mtx(&sc->sc_sleepout, &sc->sc_watchdog, &sc->sc_mtx, 0);
+	TASK_INIT(&sc->sc_setmulti, 0, axe_setmulti, sc);
+	TASK_INIT(&sc->sc_setpromisc, 0, axe_setpromisc, sc);
 
 	iface_index = AXE_IFACE_IDX;
 	error = usbd_transfer_setup(uaa->device, &iface_index, sc->sc_xfer,
@@ -755,19 +799,39 @@ axe_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 = &axe_ue_methods;
+	AXE_LOCK(sc);
+	axe_attach_post(sc);
+	AXE_UNLOCK(sc);
 
-	error = uether_ifattach(ue);
-	if (error) {
-		device_printf(dev, "could not attach interface\n");
+	sc->sc_ifp = ifp = if_alloc(IFT_ETHER);
+	if (ifp == NULL) {
+		device_printf(sc->sc_dev, "could not allocate ifnet\n");
 		goto detach;
 	}
-	return (0);			/* success */
 
+	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 = axe_ioctl;
+	ifp->if_start = axe_start;
+	ifp->if_init = axe_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,
+	    axe_ifmedia_upd, axe_ifmedia_sts,
+	    BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, 0);
+	if (error) {
+		device_printf(sc->sc_dev, "MII without any PHY\n");
+		goto error2;
+	}
+
+	if_printf(ifp, "<USB Ethernet> on %s\n",
+	    device_get_nameunit(sc->sc_dev));
+	ether_ifattach(ifp, sc->sc_eaddr);
+	return (0);
 detach:
 	axe_detach(dev);
 	return (ENXIO);			/* failure */
@@ -777,15 +841,96 @@ static int
 axe_detach(device_t dev)
 {
 	struct axe_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, AXE_N_TRANSFER);
-	uether_ifdetach(ue);
+
+	if (sc->sc_miibus != NULL)
+		device_delete_child(sc->sc_dev, sc->sc_miibus);
+	if (ifp != NULL) {
+		AXE_LOCK(sc);
+		ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
+		AXE_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);
 }
 
+static void
+axe_rxflush(struct axe_softc *sc)
+{
+	struct ifnet *ifp = sc->sc_ifp;
+	struct mbuf *m;
+
+	AXE_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.
+		 */
+		AXE_UNLOCK(sc);
+		ifp->if_input(ifp, m);
+		AXE_LOCK(sc);
+	}
+}
+
+static struct mbuf *
+axe_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
+axe_rxbuf(struct axe_softc *sc, struct usb_page_cache *pc, 
+    unsigned int offset, unsigned int len)
+{
+	struct ifnet *ifp = sc->sc_ifp;
+	struct mbuf *m;
+
+	AXE_LOCK_ASSERT(sc, MA_OWNED);
+
+	if (len < ETHER_HDR_LEN || len > MCLBYTES - ETHER_ALIGN)
+		return (1);
+
+	m = axe_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);
+}
+
 #if (AXE_BULK_BUF_SIZE >= 0x10000)
 #error "Please update axe_bulk_read_callback()!"
 #endif
@@ -794,8 +939,7 @@ static void
 axe_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error)
 {
 	struct axe_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 axe_sframe_hdr hdr;
 	struct usb_page_cache *pc;
 	int err, pos, len;
@@ -832,24 +976,22 @@ axe_bulk_read_callback(struct usb_xfer *xfer, usb_
 					err = EINVAL;
 					break;
 				}
-				uether_rxbuf(ue, pc, pos, len);
+				err = axe_rxbuf(sc, pc, pos, len);
 
 				pos += len + (len % 2);
 			}
 		} else
-			uether_rxbuf(ue, pc, 0, actlen);
+			err = axe_rxbuf(sc, pc, 0, actlen);
 
 		if (err != 0)
 			ifp->if_ierrors++;
-
 		/* 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);
+		axe_rxflush(sc);
 		return;
-
 	default:			/* Error */
 		DPRINTF("bulk read error, %s\n", usbd_errstr(error));
 
@@ -859,7 +1001,6 @@ tr_setup:
 			goto tr_setup;
 		}
 		return;
-
 	}
 }
 
@@ -872,7 +1013,7 @@ axe_bulk_write_callback(struct usb_xfer *xfer, usb
 {
 	struct axe_softc *sc = usbd_xfer_softc(xfer);
 	struct axe_sframe_hdr hdr;
-	struct ifnet *ifp = uether_getifp(&sc->sc_ue);
+	struct ifnet *ifp = sc->sc_ifp;
 	struct usb_page_cache *pc;
 	struct mbuf *m;
 	int pos;
@@ -896,7 +1037,6 @@ tr_setup:
 		pc = usbd_xfer_get_frame(xfer, 0);
 
 		while (1) {
-
 			IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
 
 			if (m == NULL) {
@@ -904,11 +1044,9 @@ tr_setup:
 					break;	/* send out data */
 				return;
 			}
-			if (m->m_pkthdr.len > MCLBYTES) {
+			if (m->m_pkthdr.len > MCLBYTES)
 				m->m_pkthdr.len = MCLBYTES;
-			}
 			if (sc->sc_flags & (AXE_FLAG_772 | AXE_FLAG_178)) {
-
 				hdr.len = htole16(m->m_pkthdr.len);
 				hdr.ilen = ~hdr.len;
 
@@ -961,7 +1099,6 @@ tr_setup:
 		usbd_transfer_submit(xfer);
 		ifp->if_drv_flags |= IFF_DRV_OACTIVE;
 		return;
-
 	default:			/* Error */
 		DPRINTFN(11, "transfer error, %s\n",
 		    usbd_errstr(error));
@@ -975,31 +1112,41 @@ tr_setup:
 			goto tr_setup;
 		}
 		return;
-
 	}
 }
 
 static void
-axe_tick(struct usb_ether *ue)
+axe_tick(struct axe_softc *sc)
 {
-	struct axe_softc *sc = uether_getsc(ue);
 	struct mii_data *mii = GET_MII(sc);
 
 	AXE_LOCK_ASSERT(sc, MA_OWNED);
 
 	mii_tick(mii);
 	if ((sc->sc_flags & AXE_FLAG_LINK) == 0) {
-		axe_miibus_statchg(ue->ue_dev);
+		axe_miibus_statchg(sc->sc_dev);
 		if ((sc->sc_flags & AXE_FLAG_LINK) != 0)
-			axe_start(ue);
+			axe_start_locked(sc->sc_ifp);
 	}
 }
 
 static void
-axe_start(struct usb_ether *ue)
+axe_start(struct ifnet *ifp)
 {
-	struct axe_softc *sc = uether_getsc(ue);
+	struct axe_softc *sc = ifp->if_softc;
 
+	AXE_LOCK(sc);
+	axe_start_locked(ifp);
+	AXE_UNLOCK(sc);
+}
+
+static void
+axe_start_locked(struct ifnet *ifp)
+{
+	struct axe_softc *sc = ifp->if_softc;
+
+	AXE_LOCK_ASSERT(sc, MA_OWNED);
+
 	/*
 	 * start the USB transfers, if not already started:
 	 */
@@ -1008,16 +1155,27 @@ static void
 }
 
 static void
-axe_init(struct usb_ether *ue)
+axe_init(void *arg)
 {
-	struct axe_softc *sc = uether_getsc(ue);
-	struct ifnet *ifp = uether_getifp(ue);
+	struct axe_softc *sc = arg;
+
+	AXE_SXLOCK(sc);
+	AXE_LOCK(sc);
+	axe_init_locked(sc);
+	AXE_UNLOCK(sc);
+	AXE_SXUNLOCK(sc);
+}
+
+static void
+axe_init_locked(struct axe_softc *sc)
+{
+	struct ifnet *ifp = sc->sc_ifp;
 	uint16_t rxmode;
 
 	AXE_LOCK_ASSERT(sc, MA_OWNED);
 
 	/* Cancel pending I/O */
-	axe_stop(ue);
+	axe_stop_locked(sc);
 
 	/* Set MAC address. */
 	if (sc->sc_flags & (AXE_FLAG_178 | AXE_FLAG_772))
@@ -1047,9 +1205,8 @@ static void
 		 */
 		rxmode |= AXE_178_RXCMD_MFB_16384;
 #endif
-	} else {
+	} else
 		rxmode |= AXE_172_RXCMD_UNICAST;
-	}
 
 	/* If we want promiscuous mode, set the allframes bit. */
 	if (ifp->if_flags & IFF_PROMISC)
@@ -1061,44 +1218,65 @@ static void
 	axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, rxmode, NULL);
 
 	/* Load the multicast filter. */
-	axe_setmulti(ue);
+	axe_setmulti_locked(sc);
 
 	usbd_xfer_set_stall(sc->sc_xfer[AXE_BULK_DT_WR]);
 
 	ifp->if_drv_flags |= IFF_DRV_RUNNING;
-	axe_start(ue);
+	sleepout_reset(&sc->sc_watchdog, hz, axe_watchdog, sc);
+	axe_start_locked(sc->sc_ifp);
 }
 
 static void
-axe_setpromisc(struct usb_ether *ue)
+axe_setpromisc(void *arg, int npending)
 {
-	struct axe_softc *sc = uether_getsc(ue);
-	struct ifnet *ifp = uether_getifp(ue);
+	struct axe_softc *sc = arg;
+
+	AXE_LOCK(sc);
+	axe_setpromisc_locked(sc);
+	AXE_UNLOCK(sc);
+}
+
+static void
+axe_setpromisc_locked(struct axe_softc *sc)
+{
+	struct ifnet *ifp = sc->sc_ifp;
 	uint16_t rxmode;
 
 	axe_cmd(sc, AXE_CMD_RXCTL_READ, 0, 0, &rxmode);
 
 	rxmode = le16toh(rxmode);
 
-	if (ifp->if_flags & IFF_PROMISC) {
+	if (ifp->if_flags & IFF_PROMISC)
 		rxmode |= AXE_RXCMD_PROMISC;
-	} else {
+	else
 		rxmode &= ~AXE_RXCMD_PROMISC;
-	}
 
 	axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, rxmode, NULL);
 
-	axe_setmulti(ue);
+	axe_setmulti_locked(sc);
 }
 
 static void
-axe_stop(struct usb_ether *ue)
+axe_stop(struct axe_softc *sc)
 {
-	struct axe_softc *sc = uether_getsc(ue);
-	struct ifnet *ifp = uether_getifp(ue);
 
+	AXE_SXLOCK(sc);
+	AXE_LOCK(sc);
+	axe_stop_locked(sc);
+	AXE_UNLOCK(sc);
+	AXE_SXUNLOCK(sc);
+}
+
+static void
+axe_stop_locked(struct axe_softc *sc)
+{
+	struct ifnet *ifp = sc->sc_ifp;
+
 	AXE_LOCK_ASSERT(sc, MA_OWNED);
 
+	sleepout_stop(&sc->sc_watchdog);
+
 	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
 	sc->sc_flags &= ~AXE_FLAG_LINK;
 
@@ -1110,3 +1288,46 @@ static void
 
 	axe_reset(sc);
 }
+
+static int
+axe_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
+{
+	struct axe_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. */
+		AXE_LOCK(sc);
+		flags = ifp->if_flags;
+		drv_flags = ifp->if_drv_flags;
+		AXE_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
+				axe_init(sc);
+		} else
+			axe_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);
+}


More information about the freebsd-usb mailing list