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); +} _______________________________________________ freebsd-usb@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-usb To unsubscribe, send any mail to "freebsd-usb-unsubscr...@freebsd.org"