Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/sys/dev/usb/if_axen.c,v rcsdiff: /ftp/cvs/cvsroot/src/sys/dev/usb/if_axen.c,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.3 retrieving revision 1.3.6.14 diff -u -p -r1.3 -r1.3.6.14 --- src/sys/dev/usb/if_axen.c 2014/08/10 16:44:36 1.3 +++ src/sys/dev/usb/if_axen.c 2016/12/28 09:45:16 1.3.6.14 @@ -1,4 +1,4 @@ -/* $NetBSD: if_axen.c,v 1.3 2014/08/10 16:44:36 tls Exp $ */ +/* $NetBSD: if_axen.c,v 1.3.6.14 2016/12/28 09:45:16 skrll Exp $ */ /* $OpenBSD: if_axen.c,v 1.3 2013/10/21 10:10:22 yuo Exp $ */ /* @@ -19,14 +19,15 @@ /* * ASIX Electronics AX88178a USB 2.0 ethernet and AX88179 USB 3.0 Ethernet - * driver. + * driver. */ #include -__KERNEL_RCSID(0, "$NetBSD: if_axen.c,v 1.3 2014/08/10 16:44:36 tls Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_axen.c,v 1.3.6.14 2016/12/28 09:45:16 skrll Exp $"); #ifdef _KERNEL_OPT #include "opt_inet.h" +#include "opt_usb.h" #endif #include @@ -40,7 +41,7 @@ __KERNEL_RCSID(0, "$NetBSD: if_axen.c,v #include #include -#include +#include #include #include @@ -92,17 +93,23 @@ CFATTACH_DECL_NEW(axen, sizeof(struct ax axen_match, axen_attach, axen_detach, axen_activate); static int axen_tx_list_init(struct axen_softc *); +static void axen_tx_list_free(struct axen_softc *); static int axen_rx_list_init(struct axen_softc *); +static void axen_rx_list_free(struct axen_softc *); static struct mbuf *axen_newbuf(void); static int axen_encap(struct axen_softc *, struct mbuf *, int); -static void axen_rxeof(usbd_xfer_handle, usbd_private_handle, usbd_status); -static void axen_txeof(usbd_xfer_handle, usbd_private_handle, usbd_status); +static void axen_rxeof(struct usbd_xfer *, void *, usbd_status); +static void axen_txeof(struct usbd_xfer *, void *, usbd_status); static void axen_tick(void *); static void axen_tick_task(void *); static void axen_start(struct ifnet *); +static void axen_start_locked(struct ifnet *); static int axen_ioctl(struct ifnet *, u_long, void *); +static int axen_ifflags_cb(struct ethercom *ec); static int axen_init(struct ifnet *); +static int axen_init_locked(struct ifnet *); static void axen_stop(struct ifnet *, int); +static void axen_stop_locked(struct ifnet *, int); static void axen_watchdog(struct ifnet *); static int axen_miibus_readreg(device_t, int, int); static void axen_miibus_writereg(device_t, int, int, int); @@ -110,14 +117,14 @@ static void axen_miibus_statchg(struct i static int axen_cmd(struct axen_softc *, int, int, int, void *); static int axen_ifmedia_upd(struct ifnet *); static void axen_ifmedia_sts(struct ifnet *, struct ifmediareq *); -static void axen_reset(struct axen_softc *sc); +static void axen_reset(struct axen_softc *); #if 0 static int axen_ax88179_eeprom(struct axen_softc *, void *); #endif static void axen_iff(struct axen_softc *); -static void axen_lock_mii(struct axen_softc *sc); -static void axen_unlock_mii(struct axen_softc *sc); +static void axen_lock_mii(struct axen_softc *); +static void axen_unlock_mii(struct axen_softc *); static void axen_ax88179_init(struct axen_softc *); @@ -433,7 +440,7 @@ axen_ax88179_eeprom(struct axen_softc *s } while ((le16toh(buf) & 0xff) & AXEN_EEPROM_BUSY); /* read data */ - axen_cmd(sc, AXEN_CMD_MAC_READ2, 2, AXEN_EEPROM_READ, + axen_cmd(sc, AXEN_CMD_MAC_READ2, 2, AXEN_EEPROM_READ, &eeprom[i * 2]); /* sanity check */ @@ -635,7 +642,7 @@ axen_match(device_t parent, cfdata_t mat { struct usb_attach_arg *uaa = aux; - return axen_lookup(uaa->vendor, uaa->product) != NULL ? + return axen_lookup(uaa->uaa_vendor, uaa->uaa_product) != NULL ? UMATCH_VENDOR_PRODUCT : UMATCH_NONE; } @@ -644,7 +651,7 @@ axen_attach(device_t parent, device_t se { struct axen_softc *sc = device_private(self); struct usb_attach_arg *uaa = aux; - struct usbd_device *dev = uaa->device; + struct usbd_device *dev = uaa->uaa_device; usbd_status err; usb_interface_descriptor_t *id; usb_endpoint_descriptor_t *ed; @@ -653,7 +660,7 @@ axen_attach(device_t parent, device_t se char *devinfop; const char *devname = device_xname(self); struct ifnet *ifp; - int i, s; + int i; aprint_naive("\n"); aprint_normal("\n"); @@ -672,26 +679,38 @@ axen_attach(device_t parent, device_t se return; } - sc->axen_flags = axen_lookup(uaa->vendor, uaa->product)->axen_flags; + sc->axen_flags = axen_lookup(uaa->uaa_vendor, uaa->uaa_product)->axen_flags; rw_init(&sc->axen_mii_lock); usb_init_task(&sc->axen_tick_task, axen_tick_task, sc, 0); + mutex_init(&sc->axen_lock, MUTEX_DEFAULT, IPL_NONE); + mutex_init(&sc->axen_txlock, MUTEX_DEFAULT, IPL_SOFTUSB); + mutex_init(&sc->axen_rxlock, MUTEX_DEFAULT, IPL_SOFTUSB); + err = usbd_device2interface_handle(dev, AXEN_IFACE_IDX,&sc->axen_iface); if (err) { aprint_error_dev(self, "getting interface handle failed\n"); return; } - sc->axen_product = uaa->product; - sc->axen_vendor = uaa->vendor; + sc->axen_product = uaa->uaa_product; + sc->axen_vendor = uaa->uaa_vendor; id = usbd_get_interface_descriptor(sc->axen_iface); - /* XXX fix when USB3.0 HC is supported */ /* decide on what our bufsize will be */ - sc->axen_bufsz = (sc->axen_udev->speed == USB_SPEED_HIGH) ? - AXEN_BUFSZ_HS * 1024 : AXEN_BUFSZ_LS * 1024; + switch (sc->axen_udev->ud_speed) { + case USB_SPEED_SUPER: + sc->axen_bufsz = AXEN_BUFSZ_SS * 1024; + break; + case USB_SPEED_HIGH: + sc->axen_bufsz = AXEN_BUFSZ_HS * 1024; + break; + default: + sc->axen_bufsz = AXEN_BUFSZ_LS * 1024; + break; + } /* Find endpoints. */ for (i = 0; i < id->bNumEndpoints; i++) { @@ -712,8 +731,6 @@ axen_attach(device_t parent, device_t se } } - s = splnet(); - sc->axen_phyno = AXEN_PHY_ID; DPRINTF(("%s: phyno %d\n", device_xname(self), sc->axen_phyno)); @@ -747,6 +764,7 @@ axen_attach(device_t parent, device_t se ifp->if_softc = sc; strlcpy(ifp->if_xname, devname, IFNAMSIZ); ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_extflags = IFEF_START_MPSAFE; ifp->if_ioctl = axen_ioctl; ifp->if_start = axen_start; ifp->if_init = axen_init; @@ -783,8 +801,11 @@ axen_attach(device_t parent, device_t se ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_AUTO); /* Attach the interface. */ - if_attach(ifp); + if_initialize(ifp); + sc->axen_ipq = if_percpuq_create(&sc->axen_ec.ec_if); ether_ifattach(ifp, eaddr); + if_register(ifp); + ether_set_ifflags_cb(&sc->axen_ec, axen_ifflags_cb); rnd_attach_source(&sc->rnd_source, device_xname(sc->axen_dev), RND_TYPE_NET, RND_FLAG_DEFAULT); @@ -792,9 +813,11 @@ axen_attach(device_t parent, device_t se callout_setfunc(&sc->axen_stat_ch, axen_tick, sc); sc->axen_attached = true; - splx(s); usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->axen_udev,sc->axen_dev); + + if (!pmf_device_register(self, NULL, NULL)) + aprint_error_dev(self, "couldn't establish power handler\n"); } static int @@ -810,6 +833,8 @@ axen_detach(device_t self, int flags) if (!sc->axen_attached) return 0; + pmf_device_deregister(self); + sc->axen_dying = true; /* @@ -849,6 +874,10 @@ axen_detach(device_t self, int flags) rw_destroy(&sc->axen_mii_lock); + mutex_destroy(&sc->axen_txlock); + mutex_destroy(&sc->axen_rxlock); + mutex_destroy(&sc->axen_lock); + return 0; } @@ -894,33 +923,40 @@ axen_newbuf(void) static int axen_rx_list_init(struct axen_softc *sc) { - struct axen_cdata *cd; + struct axen_cdata *cd = &sc->axen_cdata; struct axen_chain *c; int i; DPRINTF(("%s: %s: enter\n", device_xname(sc->axen_dev), __func__)); - cd = &sc->axen_cdata; for (i = 0; i < AXEN_RX_LIST_CNT; i++) { c = &cd->axen_rx_chain[i]; c->axen_sc = sc; c->axen_idx = i; if (c->axen_xfer == NULL) { - c->axen_xfer = usbd_alloc_xfer(sc->axen_udev); - if (c->axen_xfer == NULL) - return ENOBUFS; - c->axen_buf = usbd_alloc_buffer(c->axen_xfer, - sc->axen_bufsz); - if (c->axen_buf == NULL) { - usbd_free_xfer(c->axen_xfer); - return ENOBUFS; - } + int err = usbd_create_xfer(sc->axen_ep[AXEN_ENDPT_RX], + sc->axen_bufsz, USBD_SHORT_XFER_OK, 0, + &c->axen_xfer); + if (err) + return err; + c->axen_buf = usbd_get_buffer(c->axen_xfer); } } return 0; } +static void +axen_rx_list_free(struct axen_softc *sc) +{ + for (size_t i = 0; i < AXEN_RX_LIST_CNT; i++) { + if (sc->axen_cdata.axen_rx_chain[i].axen_xfer != NULL) { + usbd_destroy_xfer(sc->axen_cdata.axen_rx_chain[i].axen_xfer); + sc->axen_cdata.axen_rx_chain[i].axen_xfer = NULL; + } + } +} + static int axen_tx_list_init(struct axen_softc *sc) { @@ -936,27 +972,35 @@ axen_tx_list_init(struct axen_softc *sc) c->axen_sc = sc; c->axen_idx = i; if (c->axen_xfer == NULL) { - c->axen_xfer = usbd_alloc_xfer(sc->axen_udev); - if (c->axen_xfer == NULL) - return ENOBUFS; - c->axen_buf = usbd_alloc_buffer(c->axen_xfer, - sc->axen_bufsz); - if (c->axen_buf == NULL) { - usbd_free_xfer(c->axen_xfer); - return ENOBUFS; - } + int err = usbd_create_xfer(sc->axen_ep[AXEN_ENDPT_TX], + sc->axen_bufsz, USBD_FORCE_SHORT_XFER, 0, + &c->axen_xfer); + if (err) + return err; + c->axen_buf = usbd_get_buffer(c->axen_xfer); } } return 0; } +static void +axen_tx_list_free(struct axen_softc *sc) +{ + for (size_t i = 0; i < AXEN_TX_LIST_CNT; i++) { + if (sc->axen_cdata.axen_tx_chain[i].axen_xfer != NULL) { + usbd_destroy_xfer(sc->axen_cdata.axen_tx_chain[i].axen_xfer); + sc->axen_cdata.axen_tx_chain[i].axen_xfer = NULL; + } + } +} + /* * A frame has been uploaded: pass the resulting mbuf chain up to * the higher level protocols. */ static void -axen_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status) +axen_rxeof(struct usbd_xfer *xfer, void * priv, usbd_status status) { struct axen_chain *c = (struct axen_chain *)priv; struct axen_softc *sc = c->axen_sc; @@ -969,7 +1013,6 @@ axen_rxeof(usbd_xfer_handle xfer, usbd_p uint16_t hdr_offset, pkt_count; size_t pkt_len; size_t temp; - int s; DPRINTFN(10,("%s: %s: enter\n", device_xname(sc->axen_dev), __func__)); @@ -998,7 +1041,7 @@ axen_rxeof(usbd_xfer_handle xfer, usbd_p goto done; } - /* + /* * buffer map * [packet #0]...[packet #n][pkt hdr#0]..[pkt hdr#n][recv_hdr] * each packet has 0xeeee as psuedo header.. @@ -1012,7 +1055,7 @@ axen_rxeof(usbd_xfer_handle xfer, usbd_p aprint_error_dev(sc->axen_dev, "rxeof: too large transfer\n"); goto done; } - + /* sanity check */ if (hdr_offset > total_len) { ifp->if_ierrors++; @@ -1029,9 +1072,9 @@ axen_rxeof(usbd_xfer_handle xfer, usbd_p */ #if 1 /* XXX: paranoiac check. need to remove later */ -#define AXEN_MAX_PACKED_PACKET 200 +#define AXEN_MAX_PACKED_PACKET 200 if (pkt_count > AXEN_MAX_PACKED_PACKET) { - DPRINTF(("%s: Too many packets (%d) in a transaction, discard.\n", + DPRINTF(("%s: Too many packets (%d) in a transaction, discard.\n", device_xname(sc->axen_dev), pkt_count)); goto done; } @@ -1048,7 +1091,7 @@ axen_rxeof(usbd_xfer_handle xfer, usbd_p pkt_hdr = le32toh(*hdr_p); pkt_len = (pkt_hdr >> 16) & 0x1fff; DPRINTFN(10, - ("%s: rxeof: packet#%d, pkt_hdr 0x%08x, pkt_len %zu\n", + ("%s: rxeof: packet#%d, pkt_hdr 0x%08x, pkt_len %zu\n", device_xname(sc->axen_dev), pkt_count, pkt_hdr, pkt_len)); if ((pkt_hdr & AXEN_RXHDR_CRC_ERR) || @@ -1070,12 +1113,12 @@ axen_rxeof(usbd_xfer_handle xfer, usbd_p /* skip pseudo header (2byte) */ ifp->if_ipackets++; - m->m_pkthdr.rcvif = ifp; - m->m_pkthdr.len = m->m_len = pkt_len - 2; + m_set_rcvif(m, ifp); + m->m_pkthdr.len = m->m_len = pkt_len - 6; #ifdef AXEN_TOE /* cheksum err */ - if ((pkt_hdr & AXEN_RXHDR_L3CSUM_ERR) || + if ((pkt_hdr & AXEN_RXHDR_L3CSUM_ERR) || (pkt_hdr & AXEN_RXHDR_L4CSUM_ERR)) { aprint_error_dev(sc->axen_dev, "checksum err (pkt#%d)\n", pkt_count); @@ -1084,7 +1127,7 @@ axen_rxeof(usbd_xfer_handle xfer, usbd_p m->m_pkthdr.csum_flags |= M_CSUM_IPv4; } - int l4_type = (pkt_hdr & AXEN_RXHDR_L4_TYPE_MASK) >> + int l4_type = (pkt_hdr & AXEN_RXHDR_L4_TYPE_MASK) >> AXEN_RXHDR_L4_TYPE_OFFSET; if ((l4_type == AXEN_RXHDR_L4_TYPE_TCP) || @@ -1094,17 +1137,15 @@ axen_rxeof(usbd_xfer_handle xfer, usbd_p } #endif - memcpy(mtod(m, char *), buf + 2, pkt_len - 2); + memcpy(mtod(m, char *), buf + 2, pkt_len - 6); /* push the packet up */ - s = splnet(); bpf_mtap(ifp, m); - (*(ifp)->if_input)((ifp), (m)); - splx(s); + if_percpuq_enqueue(sc->axen_ipq, (m)); nextpkt: /* - * prepare next packet + * prepare next packet * as each packet will be aligned 8byte boundary, * need to fix up the start point of the buffer. */ @@ -1119,10 +1160,8 @@ done: memset(c->axen_buf, 0, sc->axen_bufsz); /* Setup new transfer. */ - usbd_setup_xfer(xfer, sc->axen_ep[AXEN_ENDPT_RX], - c, c->axen_buf, sc->axen_bufsz, - USBD_SHORT_XFER_OK | USBD_NO_COPY, - USBD_NO_TIMEOUT, axen_rxeof); + usbd_setup_xfer(xfer, c, c->axen_buf, sc->axen_bufsz, + USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, axen_rxeof); usbd_transfer(xfer); DPRINTFN(10,("%s: %s: start rx\n",device_xname(sc->axen_dev),__func__)); @@ -1133,7 +1172,7 @@ done: * the list buffers. */ static void -axen_txeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status) +axen_txeof(struct usbd_xfer *xfer, void * priv, usbd_status status) { struct axen_chain *c = (struct axen_chain *)priv; struct axen_softc *sc = c->axen_sc; @@ -1236,7 +1275,7 @@ axen_encap(struct axen_softc *sc, struct c = &sc->axen_cdata.axen_tx_chain[idx]; - boundary = (sc->axen_udev->speed == USB_SPEED_HIGH) ? 512 : 64; + boundary = (sc->axen_udev->ud_speed == USB_SPEED_HIGH) ? 512 : 64; hdr.plen = htole32(m->m_pkthdr.len); hdr.gso = 0; /* disable segmentation offloading */ @@ -1254,9 +1293,8 @@ axen_encap(struct axen_softc *sc, struct length += sizeof(hdr); } - usbd_setup_xfer(c->axen_xfer, sc->axen_ep[AXEN_ENDPT_TX], - c, c->axen_buf, length, USBD_FORCE_SHORT_XFER | USBD_NO_COPY, - 10000, axen_txeof); + usbd_setup_xfer(c->axen_xfer, c, c->axen_buf, length, + USBD_FORCE_SHORT_XFER, 10000, axen_txeof); /* Transmit */ err = usbd_transfer(c->axen_xfer); @@ -1273,6 +1311,17 @@ axen_encap(struct axen_softc *sc, struct static void axen_start(struct ifnet *ifp) { + struct axen_softc * const sc = ifp->if_softc; + KASSERT(ifp->if_extflags & IFEF_START_MPSAFE); + + mutex_enter(&sc->axen_txlock); + axen_start_locked(ifp); + mutex_exit(&sc->axen_txlock); +} + +static void +axen_start_locked(struct ifnet *ifp) +{ struct axen_softc *sc; struct mbuf *m; @@ -1289,7 +1338,6 @@ axen_start(struct ifnet *ifp) return; if (axen_encap(sc, m, 0)) { - ifp->if_flags |= IFF_OACTIVE; return; } IFQ_DEQUEUE(&ifp->if_snd, m); @@ -1313,17 +1361,26 @@ static int axen_init(struct ifnet *ifp) { struct axen_softc *sc = ifp->if_softc; + + mutex_enter(&sc->axen_lock); + int ret = axen_init_locked(ifp); + mutex_exit(&sc->axen_lock); + + return ret; +} + +static int +axen_init_locked(struct ifnet *ifp) +{ + struct axen_softc *sc = ifp->if_softc; struct axen_chain *c; usbd_status err; - int i, s; + int i; uint16_t rxmode; uint16_t wval; uint8_t bval; - s = splnet(); - - if (ifp->if_flags & IFF_RUNNING) - axen_stop(ifp, 0); + axen_stop_locked(ifp, 1); /* * Cancel pending I/O and free all RX/TX buffers. @@ -1336,22 +1393,6 @@ axen_init(struct ifnet *ifp) axen_cmd(sc, AXEN_CMD_MAC_WRITE, 1, AXEN_UNK_28, &bval); axen_unlock_mii(sc); - /* Init RX ring. */ - if (axen_rx_list_init(sc) == ENOBUFS) { - aprint_error_dev(sc->axen_dev, "rx list init failed\n"); - axen_unlock_mii(sc); - splx(s); - return ENOBUFS; - } - - /* Init TX ring. */ - if (axen_tx_list_init(sc) == ENOBUFS) { - aprint_error_dev(sc->axen_dev, "tx list init failed\n"); - axen_unlock_mii(sc); - splx(s); - return ENOBUFS; - } - /* Program promiscuous mode and multicast filters. */ axen_iff(sc); @@ -1370,8 +1411,7 @@ axen_init(struct ifnet *ifp) if (err) { aprint_error_dev(sc->axen_dev, "open rx pipe failed: %s\n", usbd_errstr(err)); - splx(s); - return EIO; + goto fail; } err = usbd_open_pipe(sc->axen_iface, sc->axen_ed[AXEN_ENDPT_TX], @@ -1379,73 +1419,79 @@ axen_init(struct ifnet *ifp) if (err) { aprint_error_dev(sc->axen_dev, "open tx pipe failed: %s\n", usbd_errstr(err)); - splx(s); - return EIO; + goto fail1; + } + + /* Init RX ring. */ + if (axen_rx_list_init(sc)) { + aprint_error_dev(sc->axen_dev, "rx list init failed\n"); + goto fail2; + } + + /* Init TX ring. */ + if (axen_tx_list_init(sc)) { + aprint_error_dev(sc->axen_dev, "tx list init failed\n"); + goto fail3; } /* Start up the receive pipe. */ for (i = 0; i < AXEN_RX_LIST_CNT; i++) { c = &sc->axen_cdata.axen_rx_chain[i]; - usbd_setup_xfer(c->axen_xfer, sc->axen_ep[AXEN_ENDPT_RX], - c, c->axen_buf, sc->axen_bufsz, - USBD_SHORT_XFER_OK | USBD_NO_COPY, - USBD_NO_TIMEOUT, axen_rxeof); + + usbd_setup_xfer(c->axen_xfer, c, c->axen_buf, sc->axen_bufsz, + USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, axen_rxeof); usbd_transfer(c->axen_xfer); } ifp->if_flags |= IFF_RUNNING; ifp->if_flags &= ~IFF_OACTIVE; - splx(s); - callout_schedule(&sc->axen_stat_ch, hz); return 0; + +fail3: + axen_rx_list_free(sc); +fail2: + usbd_close_pipe(sc->axen_ep[AXEN_ENDPT_TX]); +fail1: + usbd_close_pipe(sc->axen_ep[AXEN_ENDPT_RX]); +fail: + return EIO; } static int axen_ioctl(struct ifnet *ifp, u_long cmd, void *data) { - struct axen_softc *sc = ifp->if_softc; int s; int error = 0; s = splnet(); + error = ether_ioctl(ifp, cmd, data); + splx(s); - switch (cmd) { - case SIOCSIFFLAGS: - if ((error = ifioctl_common(ifp, cmd, data)) != 0) - break; + return error; +} - switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) { - case IFF_RUNNING: - axen_stop(ifp, 1); - break; - case IFF_UP: - axen_init(ifp); - break; - case IFF_UP | IFF_RUNNING: - if ((ifp->if_flags ^ sc->axen_if_flags) == IFF_PROMISC) - axen_iff(sc); - else - axen_init(ifp); - break; - } - sc->axen_if_flags = ifp->if_flags; - break; +static int +axen_ifflags_cb(struct ethercom *ec) +{ + struct ifnet *ifp = &ec->ec_if; + struct axen_softc *sc = ifp->if_softc; + int ret; - default: - if ((error = ether_ioctl(ifp, cmd, data)) != ENETRESET) - break; + mutex_enter(&sc->axen_lock); - error = 0; + int change = ifp->if_flags ^ sc->axen_if_flags; + sc->axen_if_flags = ifp->if_flags; - if (cmd == SIOCADDMULTI || cmd == SIOCDELMULTI) - axen_iff(sc); - break; + if ((change & IFF_PROMISC) == 0) { + ret = ENETRESET; + } else { + axen_iff(sc); + ret = 0; } - splx(s); - - return error; + mutex_exit(&sc->axen_lock); + return ret; } static void @@ -1478,11 +1524,20 @@ axen_watchdog(struct ifnet *ifp) static void axen_stop(struct ifnet *ifp, int disable) { + struct axen_softc * const sc = ifp->if_softc; + + mutex_enter(&sc->axen_lock); + axen_stop_locked(ifp, disable); + mutex_exit(&sc->axen_lock); +} + +static void +axen_stop_locked(struct ifnet *ifp, int disable) +{ struct axen_softc *sc = ifp->if_softc; usbd_status err; - int i; - axen_reset(sc); +// axen_reset(sc); ifp->if_timer = 0; ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); @@ -1497,12 +1552,6 @@ axen_stop(struct ifnet *ifp, int disable "abort rx pipe failed: %s\n", usbd_errstr(err)); } - err = usbd_close_pipe(sc->axen_ep[AXEN_ENDPT_RX]); - if (err) { - aprint_error_dev(sc->axen_dev, - "close rx pipe failed: %s\n", usbd_errstr(err)); - } - sc->axen_ep[AXEN_ENDPT_RX] = NULL; } if (sc->axen_ep[AXEN_ENDPT_TX] != NULL) { @@ -1511,12 +1560,6 @@ axen_stop(struct ifnet *ifp, int disable aprint_error_dev(sc->axen_dev, "abort tx pipe failed: %s\n", usbd_errstr(err)); } - err = usbd_close_pipe(sc->axen_ep[AXEN_ENDPT_TX]); - if (err) { - aprint_error_dev(sc->axen_dev, - "close tx pipe failed: %s\n", usbd_errstr(err)); - } - sc->axen_ep[AXEN_ENDPT_TX] = NULL; } if (sc->axen_ep[AXEN_ENDPT_INTR] != NULL) { @@ -1525,31 +1568,44 @@ axen_stop(struct ifnet *ifp, int disable aprint_error_dev(sc->axen_dev, "abort intr pipe failed: %s\n", usbd_errstr(err)); } - err = usbd_close_pipe(sc->axen_ep[AXEN_ENDPT_INTR]); + } + + axen_rx_list_free(sc); + + axen_tx_list_free(sc); + + /* Close pipes. */ + if (sc->axen_ep[AXEN_ENDPT_RX] != NULL) { + err = usbd_close_pipe(sc->axen_ep[AXEN_ENDPT_RX]); if (err) { aprint_error_dev(sc->axen_dev, - "close intr pipe failed: %s\n", usbd_errstr(err)); + "close rx pipe failed: %s\n", usbd_errstr(err)); } - sc->axen_ep[AXEN_ENDPT_INTR] = NULL; + sc->axen_ep[AXEN_ENDPT_RX] = NULL; } - /* Free RX resources. */ - for (i = 0; i < AXEN_RX_LIST_CNT; i++) { - if (sc->axen_cdata.axen_rx_chain[i].axen_xfer != NULL) { - usbd_free_xfer(sc->axen_cdata.axen_rx_chain[i].axen_xfer); - sc->axen_cdata.axen_rx_chain[i].axen_xfer = NULL; + if (sc->axen_ep[AXEN_ENDPT_TX] != NULL) { + err = usbd_close_pipe(sc->axen_ep[AXEN_ENDPT_TX]); + if (err) { + aprint_error_dev(sc->axen_dev, + "close tx pipe failed: %s\n", usbd_errstr(err)); } + sc->axen_ep[AXEN_ENDPT_TX] = NULL; } - /* Free TX resources. */ - for (i = 0; i < AXEN_TX_LIST_CNT; i++) { - if (sc->axen_cdata.axen_tx_chain[i].axen_xfer != NULL) { - usbd_free_xfer(sc->axen_cdata.axen_tx_chain[i].axen_xfer); - sc->axen_cdata.axen_tx_chain[i].axen_xfer = NULL; + if (sc->axen_ep[AXEN_ENDPT_INTR] != NULL) { + err = usbd_close_pipe(sc->axen_ep[AXEN_ENDPT_INTR]); + if (err) { + aprint_error_dev(sc->axen_dev, + "close intr pipe failed: %s\n", usbd_errstr(err)); } + sc->axen_ep[AXEN_ENDPT_INTR] = NULL; } sc->axen_link = 0; + + ifp->if_timer = 0; + ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); } MODULE(MODULE_CLASS_DRIVER, if_axen, "bpf");