Module Name: src Committed By: skrll Date: Mon Dec 12 13:15:39 UTC 2016
Modified Files: src/sys/dev/usb [nick-nhusb]: if_aue.c if_auereg.h if_axe.c if_axen.c if_axenreg.h if_axereg.h if_cdce.c if_cdcereg.h if_cue.c if_cuereg.h if_udav.c if_udavreg.h Log Message: WIP MPification To generate a diff of this commit: cvs rdiff -u -r1.132.4.13 -r1.132.4.14 src/sys/dev/usb/if_aue.c cvs rdiff -u -r1.25.24.3 -r1.25.24.4 src/sys/dev/usb/if_auereg.h cvs rdiff -u -r1.67.4.12 -r1.67.4.13 src/sys/dev/usb/if_axe.c cvs rdiff -u -r1.3.6.12 -r1.3.6.13 src/sys/dev/usb/if_axen.c cvs rdiff -u -r1.1.12.2 -r1.1.12.3 src/sys/dev/usb/if_axenreg.h cvs rdiff -u -r1.16.6.4 -r1.16.6.5 src/sys/dev/usb/if_axereg.h cvs rdiff -u -r1.38.14.9 -r1.38.14.10 src/sys/dev/usb/if_cdce.c cvs rdiff -u -r1.7.24.4 -r1.7.24.5 src/sys/dev/usb/if_cdcereg.h cvs rdiff -u -r1.68.4.12 -r1.68.4.13 src/sys/dev/usb/if_cue.c cvs rdiff -u -r1.18.24.4 -r1.18.24.5 src/sys/dev/usb/if_cuereg.h cvs rdiff -u -r1.43.4.11 -r1.43.4.12 src/sys/dev/usb/if_udav.c cvs rdiff -u -r1.9.16.4 -r1.9.16.5 src/sys/dev/usb/if_udavreg.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_aue.c diff -u src/sys/dev/usb/if_aue.c:1.132.4.13 src/sys/dev/usb/if_aue.c:1.132.4.14 --- src/sys/dev/usb/if_aue.c:1.132.4.13 Mon Dec 5 10:55:18 2016 +++ src/sys/dev/usb/if_aue.c Mon Dec 12 13:15:39 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: if_aue.c,v 1.132.4.13 2016/12/05 10:55:18 skrll Exp $ */ +/* $NetBSD: if_aue.c,v 1.132.4.14 2016/12/12 13:15:39 skrll Exp $ */ /* * Copyright (c) 1997, 1998, 1999, 2000 @@ -71,14 +71,13 @@ * TODO: * better error messages from rxstat * split out if_auevar.h - * add thread to avoid register reads from interrupt context * more error checks * investigate short rx problem * proper cleanup on errors */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_aue.c,v 1.132.4.13 2016/12/05 10:55:18 skrll Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_aue.c,v 1.132.4.14 2016/12/12 13:15:39 skrll Exp $"); #ifdef _KERNEL_OPT #include "opt_usb.h" @@ -217,11 +216,11 @@ extern struct cfdriver aue_cd; CFATTACH_DECL_NEW(aue, sizeof(struct aue_softc), aue_match, aue_attach, aue_detach, aue_activate); -Static void aue_multithread(void *); - Static void aue_reset_pegasus_II(struct aue_softc *); Static int aue_tx_list_init(struct aue_softc *); +Static void aue_tx_list_free(struct aue_softc *); Static int aue_rx_list_init(struct aue_softc *); +Static void aue_rx_list_free(struct aue_softc *); Static int aue_newbuf(struct aue_softc *, struct aue_chain *, struct mbuf *); Static int aue_send(struct aue_softc *, struct mbuf *, int); Static void aue_intr(struct usbd_xfer *, void *, usbd_status); @@ -230,11 +229,14 @@ Static void aue_txeof(struct usbd_xfer * Static void aue_tick(void *); Static void aue_tick_task(void *); Static void aue_start(struct ifnet *); +Static void aue_start_locked(struct ifnet *); Static int aue_ioctl(struct ifnet *, u_long, void *); -Static void aue_init(void *); -Static void aue_stop(struct aue_softc *); +Static int aue_ifflags_cb(struct ethercom *); +Static int aue_init(struct ifnet *); +Static int aue_init_locked(struct ifnet *); +Static void aue_stop(struct ifnet *, int); +Static void aue_stop_locked(struct ifnet *, int); Static void aue_watchdog(struct ifnet *); -Static int aue_openpipes(struct aue_softc *); Static int aue_ifmedia_upd(struct ifnet *); Static int aue_eeprom_getword(struct aue_softc *, int); @@ -723,7 +725,6 @@ aue_attach(device_t parent, device_t sel struct aue_softc *sc = device_private(self); struct usb_attach_arg *uaa = aux; char *devinfop; - int s; u_char eaddr[ETHER_ADDR_LEN]; struct ifnet *ifp; struct mii_data *mii; @@ -755,6 +756,9 @@ aue_attach(device_t parent, device_t sel usb_init_task(&sc->aue_tick_task, aue_tick_task, sc, 0); usb_init_task(&sc->aue_stop_task, (void (*)(void *))aue_stop, sc, 0); mutex_init(&sc->aue_mii_lock, MUTEX_DEFAULT, IPL_NONE); + mutex_init(&sc->aue_lock, MUTEX_DEFAULT, IPL_NONE); + mutex_init(&sc->aue_txlock, MUTEX_DEFAULT, IPL_SOFTUSB); + mutex_init(&sc->aue_rxlock, MUTEX_DEFAULT, IPL_SOFTUSB); err = usbd_device2interface_handle(dev, AUE_IFACE_IDX, &iface); if (err) { @@ -764,13 +768,8 @@ aue_attach(device_t parent, device_t sel sc->aue_closing = 0; mutex_init(&sc->aue_mcmtx, MUTEX_DRIVER, IPL_NET); - cv_init(&sc->aue_domc, "auemc"); cv_init(&sc->aue_closemc, "auemccl"); - err = kthread_create(PRI_NONE, 0, NULL, - aue_multithread, sc, &sc->aue_thread, - "%s-mc", device_xname(sc->aue_dev)); - if (err) { aprint_error_dev(self, "creating multicast configuration thread\n"); @@ -813,7 +812,6 @@ aue_attach(device_t parent, device_t sel } - s = splnet(); /* Reset the adapter. */ aue_reset(sc); @@ -833,6 +831,8 @@ aue_attach(device_t parent, device_t sel ifp->if_softc = sc; ifp->if_mtu = ETHERMTU; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_extflags = IFEF_START_MPSAFE; + ifp->if_init = aue_init; ifp->if_ioctl = aue_ioctl; ifp->if_start = aue_start; ifp->if_watchdog = aue_watchdog; @@ -857,15 +857,17 @@ aue_attach(device_t parent, device_t sel ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_AUTO); /* Attach the interface. */ - if_attach(ifp); + if_initialize(ifp); + sc->aue_ipq = if_percpuq_create(&sc->aue_ec.ec_if); ether_ifattach(ifp, eaddr); + if_register(ifp); + ether_set_ifflags_cb(&sc->aue_ec, aue_ifflags_cb); rnd_attach_source(&sc->rnd_source, device_xname(sc->aue_dev), RND_TYPE_NET, RND_FLAG_DEFAULT); callout_init(&(sc->aue_stat_ch), 0); sc->aue_attached = 1; - splx(s); usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->aue_udev, sc->aue_dev); @@ -895,20 +897,18 @@ aue_detach(device_t self, int flags) usb_rem_task(sc->aue_udev, &sc->aue_stop_task); sc->aue_closing = 1; - cv_signal(&sc->aue_domc); mutex_enter(&sc->aue_mcmtx); cv_wait(&sc->aue_closemc,&sc->aue_mcmtx); mutex_exit(&sc->aue_mcmtx); mutex_destroy(&sc->aue_mcmtx); - cv_destroy(&sc->aue_domc); cv_destroy(&sc->aue_closemc); s = splusb(); if (ifp->if_flags & IFF_RUNNING) - aue_stop(sc); + aue_stop(ifp, 1); rnd_detach_source(&sc->rnd_source); mii_detach(&sc->aue_mii, MII_PHY_ANY, MII_OFFSET_ANY); @@ -1025,6 +1025,22 @@ aue_rx_list_init(struct aue_softc *sc) return 0; } +Static void +aue_rx_list_free(struct aue_softc *sc) +{ + /* Free RX resources. */ + for (int i = 0; i < AUE_RX_LIST_CNT; i++) { + if (sc->aue_cdata.aue_rx_chain[i].aue_mbuf != NULL) { + m_freem(sc->aue_cdata.aue_rx_chain[i].aue_mbuf); + sc->aue_cdata.aue_rx_chain[i].aue_mbuf = NULL; + } + if (sc->aue_cdata.aue_rx_chain[i].aue_xfer != NULL) { + usbd_destroy_xfer(sc->aue_cdata.aue_rx_chain[i].aue_xfer); + sc->aue_cdata.aue_rx_chain[i].aue_xfer = NULL; + } + } +} + Static int aue_tx_list_init(struct aue_softc *sc) { @@ -1054,6 +1070,22 @@ aue_tx_list_init(struct aue_softc *sc) } Static void +aue_tx_list_free(struct aue_softc *sc) +{ + /* Free TX resources. */ + for (int i = 0; i < AUE_TX_LIST_CNT; i++) { + if (sc->aue_cdata.aue_tx_chain[i].aue_mbuf != NULL) { + m_freem(sc->aue_cdata.aue_tx_chain[i].aue_mbuf); + sc->aue_cdata.aue_tx_chain[i].aue_mbuf = NULL; + } + if (sc->aue_cdata.aue_tx_chain[i].aue_xfer != NULL) { + usbd_destroy_xfer(sc->aue_cdata.aue_tx_chain[i].aue_xfer); + sc->aue_cdata.aue_tx_chain[i].aue_xfer = NULL; + } + } +} + +Static void aue_intr(struct usbd_xfer *xfer, void *priv, usbd_status status) { @@ -1346,6 +1378,17 @@ aue_send(struct aue_softc *sc, struct mb Static void aue_start(struct ifnet *ifp) { + struct aue_softc *sc = ifp->if_softc; + KASSERT(ifp->if_extflags & IFEF_START_MPSAFE); + + mutex_enter(&sc->aue_txlock); + aue_start_locked(ifp); + mutex_exit(&sc->aue_txlock); +} + +Static void +aue_start_locked(struct ifnet *ifp) +{ struct aue_softc *sc = ifp->if_softc; struct mbuf *m_head = NULL; @@ -1366,7 +1409,6 @@ aue_start(struct ifnet *ifp) return; if (aue_send(sc, m_head, 0)) { - ifp->if_flags |= IFF_OACTIVE; return; } @@ -1386,24 +1428,33 @@ aue_start(struct ifnet *ifp) ifp->if_timer = 5; } -Static void -aue_init(void *xsc) +Static int +aue_init(struct ifnet *ifp) { - struct aue_softc *sc = xsc; - struct ifnet *ifp = GET_IFP(sc); + struct aue_softc *sc = ifp->if_softc; + + mutex_enter(&sc->aue_lock); + int ret = aue_init_locked(ifp); + mutex_exit(&sc->aue_lock); + + return ret; +} + +Static int +aue_init_locked(struct ifnet *ifp) +{ + struct aue_softc *sc = ifp->if_softc; struct mii_data *mii = GET_MII(sc); - int i, s; + int i; const u_char *eaddr; + usbd_status err; DPRINTFN(5,("%s: %s: enter\n", device_xname(sc->aue_dev), __func__)); if (sc->aue_dying) - return; - - if (ifp->if_flags & IFF_RUNNING) - return; + return EIO; - s = splnet(); + aue_stop_locked(ifp, 1); /* * Cancel pending I/O and free all RX/TX buffers. @@ -1421,23 +1472,41 @@ aue_init(void *xsc) AUE_CLRBIT(sc, AUE_CTL2, AUE_CTL2_RX_PROMISC); if (sc->aue_ep[AUE_ENDPT_RX] == NULL) { - if (aue_openpipes(sc)) { - splx(s); - return; + /* Open RX and TX pipes. */ + err = usbd_open_pipe(sc->aue_iface, sc->aue_ed[AUE_ENDPT_RX], + USBD_EXCLUSIVE_USE, &sc->aue_ep[AUE_ENDPT_RX]); + if (err) { + aprint_error_dev(sc->aue_dev, "open rx pipe failed: %s\n", + usbd_errstr(err)); + goto fail; + } + err = usbd_open_pipe(sc->aue_iface, sc->aue_ed[AUE_ENDPT_TX], + USBD_EXCLUSIVE_USE, &sc->aue_ep[AUE_ENDPT_TX]); + if (err) { + aprint_error_dev(sc->aue_dev, "open tx pipe failed: %s\n", + usbd_errstr(err)); + goto fail1; + } + err = usbd_open_pipe_intr(sc->aue_iface, sc->aue_ed[AUE_ENDPT_INTR], + USBD_EXCLUSIVE_USE, &sc->aue_ep[AUE_ENDPT_INTR], sc, + &sc->aue_cdata.aue_ibuf, AUE_INTR_PKTLEN, aue_intr, + AUE_INTR_INTERVAL); + if (err) { + aprint_error_dev(sc->aue_dev, "open intr pipe failed: %s\n", + usbd_errstr(err)); + goto fail2; } } /* Init TX ring. */ if (aue_tx_list_init(sc)) { aprint_error_dev(sc->aue_dev, "tx list init failed\n"); - splx(s); - return; + goto fail3; } /* Init RX ring. */ if (aue_rx_list_init(sc)) { aprint_error_dev(sc->aue_dev, "rx list init failed\n"); - splx(s); - return; + goto fail4; } /* Start up the receive pipe. */ @@ -1465,42 +1534,19 @@ aue_init(void *xsc) ifp->if_flags |= IFF_RUNNING; ifp->if_flags &= ~IFF_OACTIVE; - splx(s); - callout_reset(&(sc->aue_stat_ch), (hz), (aue_tick), (sc)); -} - -Static int -aue_openpipes(struct aue_softc *sc) -{ - usbd_status err; - - /* Open RX and TX pipes. */ - err = usbd_open_pipe(sc->aue_iface, sc->aue_ed[AUE_ENDPT_RX], - USBD_EXCLUSIVE_USE, &sc->aue_ep[AUE_ENDPT_RX]); - if (err) { - aprint_error_dev(sc->aue_dev, "open rx pipe failed: %s\n", - usbd_errstr(err)); - return EIO; - } - err = usbd_open_pipe(sc->aue_iface, sc->aue_ed[AUE_ENDPT_TX], - USBD_EXCLUSIVE_USE, &sc->aue_ep[AUE_ENDPT_TX]); - if (err) { - aprint_error_dev(sc->aue_dev, "open tx pipe failed: %s\n", - usbd_errstr(err)); - return EIO; - } - err = usbd_open_pipe_intr(sc->aue_iface, sc->aue_ed[AUE_ENDPT_INTR], - USBD_EXCLUSIVE_USE, &sc->aue_ep[AUE_ENDPT_INTR], sc, - &sc->aue_cdata.aue_ibuf, AUE_INTR_PKTLEN, aue_intr, - AUE_INTR_INTERVAL); - if (err) { - aprint_error_dev(sc->aue_dev, "open intr pipe failed: %s\n", - usbd_errstr(err)); - return EIO; - } - return 0; + +fail4: + aue_tx_list_free(sc); +fail3: + usbd_close_pipe(sc->aue_ep[AUE_ENDPT_INTR]); +fail2: + usbd_close_pipe(sc->aue_ep[AUE_ENDPT_TX]); +fail1: + usbd_close_pipe(sc->aue_ep[AUE_ENDPT_RX]); +fail: + return EIO; } /* @@ -1529,76 +1575,42 @@ Static int aue_ioctl(struct ifnet *ifp, u_long command, void *data) { struct aue_softc *sc = ifp->if_softc; - struct ifaddr *ifa = (struct ifaddr *)data; - struct ifreq *ifr = (struct ifreq *)data; int s, error = 0; if (sc->aue_dying) return EIO; s = splnet(); + error = ether_ioctl(ifp, command, data); + splx(s); - switch(command) { - case SIOCINITIFADDR: - ifp->if_flags |= IFF_UP; - aue_init(sc); + return error; +} - switch (ifa->ifa_addr->sa_family) { -#ifdef INET - case AF_INET: - arp_ifinit(ifp, ifa); - break; -#endif /* INET */ - } - break; +Static int +aue_ifflags_cb(struct ethercom *ec) +{ + struct ifnet *ifp = &ec->ec_if; + struct aue_softc *sc = ifp->if_softc; - case SIOCSIFMTU: - if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > ETHERMTU) - error = EINVAL; - else if ((error = ifioctl_common(ifp, command, data)) == ENETRESET) - error = 0; - break; + mutex_enter(&sc->aue_lock); - case SIOCSIFFLAGS: - if ((error = ifioctl_common(ifp, command, data)) != 0) - break; - if (ifp->if_flags & IFF_UP) { - if (ifp->if_flags & IFF_RUNNING && - ifp->if_flags & IFF_PROMISC && - !(sc->aue_if_flags & IFF_PROMISC)) { - AUE_SETBIT(sc, AUE_CTL2, AUE_CTL2_RX_PROMISC); - } else if (ifp->if_flags & IFF_RUNNING && - !(ifp->if_flags & IFF_PROMISC) && - sc->aue_if_flags & IFF_PROMISC) { - AUE_CLRBIT(sc, AUE_CTL2, AUE_CTL2_RX_PROMISC); - } else if (!(ifp->if_flags & IFF_RUNNING)) - aue_init(sc); - } else { - if (ifp->if_flags & IFF_RUNNING) - aue_stop(sc); - } - sc->aue_if_flags = ifp->if_flags; - error = 0; - break; - case SIOCADDMULTI: - case SIOCDELMULTI: - case SIOCGIFMEDIA: - case SIOCSIFMEDIA: - if ((error = ether_ioctl(ifp, command, data)) == ENETRESET) { - if (ifp->if_flags & IFF_RUNNING) { - cv_signal(&sc->aue_domc); - } - error = 0; + if (ifp->if_flags & IFF_UP) { + if (ifp->if_flags & IFF_RUNNING && + ifp->if_flags & IFF_PROMISC && + !(sc->aue_if_flags & IFF_PROMISC)) { + AUE_SETBIT(sc, AUE_CTL2, AUE_CTL2_RX_PROMISC); + } else if (ifp->if_flags & IFF_RUNNING && + !(ifp->if_flags & IFF_PROMISC) && + sc->aue_if_flags & IFF_PROMISC) { + AUE_CLRBIT(sc, AUE_CTL2, AUE_CTL2_RX_PROMISC); } - break; - default: - error = ether_ioctl(ifp, command, data); - break; } + sc->aue_if_flags = ifp->if_flags; + aue_setmulti(sc); + mutex_exit(&sc->aue_lock); - splx(s); - - return error; + return 0; } Static void @@ -1629,15 +1641,23 @@ aue_watchdog(struct ifnet *ifp) * RX and TX lists. */ Static void -aue_stop(struct aue_softc *sc) +aue_stop(struct ifnet *ifp, int disable) +{ + struct aue_softc *sc = ifp->if_softc; + + mutex_enter(&sc->aue_lock); + aue_stop_locked(ifp, disable); + mutex_exit(&sc->aue_lock); +} + +Static void +aue_stop_locked(struct ifnet *ifp, int disable) { usbd_status err; - struct ifnet *ifp; - int i; + struct aue_softc *sc = ifp->if_softc; DPRINTFN(5,("%s: %s: enter\n", device_xname(sc->aue_dev), __func__)); - ifp = GET_IFP(sc); ifp->if_timer = 0; aue_csr_write_1(sc, AUE_CTL0, 0); @@ -1676,29 +1696,9 @@ aue_stop(struct aue_softc *sc) } } - /* Free RX resources. */ - for (i = 0; i < AUE_RX_LIST_CNT; i++) { - if (sc->aue_cdata.aue_rx_chain[i].aue_mbuf != NULL) { - m_freem(sc->aue_cdata.aue_rx_chain[i].aue_mbuf); - sc->aue_cdata.aue_rx_chain[i].aue_mbuf = NULL; - } - if (sc->aue_cdata.aue_rx_chain[i].aue_xfer != NULL) { - usbd_destroy_xfer(sc->aue_cdata.aue_rx_chain[i].aue_xfer); - sc->aue_cdata.aue_rx_chain[i].aue_xfer = NULL; - } - } + aue_rx_list_free(sc); - /* Free TX resources. */ - for (i = 0; i < AUE_TX_LIST_CNT; i++) { - if (sc->aue_cdata.aue_tx_chain[i].aue_mbuf != NULL) { - m_freem(sc->aue_cdata.aue_tx_chain[i].aue_mbuf); - sc->aue_cdata.aue_tx_chain[i].aue_mbuf = NULL; - } - if (sc->aue_cdata.aue_tx_chain[i].aue_xfer != NULL) { - usbd_destroy_xfer(sc->aue_cdata.aue_tx_chain[i].aue_xfer); - sc->aue_cdata.aue_tx_chain[i].aue_xfer = NULL; - } - } + aue_tx_list_free(sc); /* Close pipes */ if (sc->aue_ep[AUE_ENDPT_TX] != NULL) { @@ -1724,30 +1724,3 @@ aue_stop(struct aue_softc *sc) ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); } -Static void -aue_multithread(void *arg) -{ - struct aue_softc *sc; - int s; - - sc = (struct aue_softc *)arg; - - while (1) { - mutex_enter(&sc->aue_mcmtx); - cv_wait(&sc->aue_domc,&sc->aue_mcmtx); - mutex_exit(&sc->aue_mcmtx); - - if (sc->aue_closing) - break; - - s = splnet(); - aue_init(sc); - /* XXX called by aue_init, but rc ifconfig hangs without it: */ - aue_setmulti(sc); - splx(s); - } - - cv_signal(&sc->aue_closemc); - - kthread_exit(0); -} Index: src/sys/dev/usb/if_auereg.h diff -u src/sys/dev/usb/if_auereg.h:1.25.24.3 src/sys/dev/usb/if_auereg.h:1.25.24.4 --- src/sys/dev/usb/if_auereg.h:1.25.24.3 Sat Jun 6 14:40:13 2015 +++ src/sys/dev/usb/if_auereg.h Mon Dec 12 13:15:39 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: if_auereg.h,v 1.25.24.3 2015/06/06 14:40:13 skrll Exp $ */ +/* $NetBSD: if_auereg.h,v 1.25.24.4 2016/12/12 13:15:39 skrll Exp $ */ /* * Copyright (c) 1997, 1998, 1999 * Bill Paul <wp...@ee.columbia.edu>. All rights reserved. @@ -233,7 +233,6 @@ struct aue_softc { krndsource_t rnd_source; struct lwp *aue_thread; int aue_closing; - kcondvar_t aue_domc; kcondvar_t aue_closemc; kmutex_t aue_mcmtx; #define GET_IFP(sc) (&(sc)->aue_ec.ec_if) @@ -264,6 +263,11 @@ struct aue_softc { struct usb_task aue_stop_task; kmutex_t aue_mii_lock; + kmutex_t aue_lock; + kmutex_t aue_txlock; + kmutex_t aue_rxlock; + + struct if_percpuq *aue_ipq; }; #define AUE_TIMEOUT 1000 Index: src/sys/dev/usb/if_axe.c diff -u src/sys/dev/usb/if_axe.c:1.67.4.12 src/sys/dev/usb/if_axe.c:1.67.4.13 --- src/sys/dev/usb/if_axe.c:1.67.4.12 Mon Dec 5 10:55:18 2016 +++ src/sys/dev/usb/if_axe.c Mon Dec 12 13:15:39 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: if_axe.c,v 1.67.4.12 2016/12/05 10:55:18 skrll Exp $ */ +/* $NetBSD: if_axe.c,v 1.67.4.13 2016/12/12 13:15:39 skrll 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.67.4.12 2016/12/05 10:55:18 skrll Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_axe.c,v 1.67.4.13 2016/12/12 13:15:39 skrll Exp $"); #ifdef _KERNEL_OPT #include "opt_inet.h" @@ -246,16 +246,23 @@ CFATTACH_DECL_NEW(axe, sizeof(struct axe axe_match, axe_attach, axe_detach, axe_activate); static int axe_tx_list_init(struct axe_softc *); +#if 0 +static void axe_tx_list_free(struct axe_softc *); +#endif static int axe_rx_list_init(struct axe_softc *); +static void axe_rx_list_free(struct axe_softc *); static int axe_encap(struct axe_softc *, struct mbuf *, int); static void axe_rxeof(struct usbd_xfer *, void *, usbd_status); static void axe_txeof(struct usbd_xfer *, void *, usbd_status); static void axe_tick(void *); static void axe_tick_task(void *); static void axe_start(struct ifnet *); +static void axe_start_locked(struct ifnet *); static int axe_ioctl(struct ifnet *, u_long, void *); static int axe_init(struct ifnet *); +static int axe_init_locked(struct ifnet *); static void axe_stop(struct ifnet *, int); +static void axe_stop_locked(struct ifnet *, int); static void axe_watchdog(struct ifnet *); static int axe_miibus_readreg_locked(device_t, int, int); static int axe_miibus_readreg(device_t, int, int); @@ -741,6 +748,32 @@ axe_ax88772_init(struct axe_softc *sc) axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL); } +static int +axe_ifflags_cb(struct ethercom *ec) +{ + struct ifnet *ifp = &ec->ec_if; + struct axe_softc *sc = ifp->if_softc; + int rc = 0; + + mutex_enter(&sc->axe_lock); + int change = ifp->if_flags ^ sc->axe_if_flags; + sc->axe_if_flags = ifp->if_flags; + + if ((change & ~(IFF_CANTCHANGE | IFF_DEBUG)) != 0) { + rc = ENETRESET; + goto out; + } + + if ((change & IFF_PROMISC) != 0) { + axe_setmulti(sc); + } + +out: + mutex_exit(&sc->axe_lock); + + return rc; +} + static void axe_ax88772_phywake(struct axe_softc *sc) { @@ -887,6 +920,9 @@ axe_attach(device_t parent, device_t sel sc->axe_flags = axe_lookup(uaa->uaa_vendor, uaa->uaa_product)->axe_flags; + mutex_init(&sc->axe_lock, MUTEX_DEFAULT, IPL_NONE); + mutex_init(&sc->axe_txlock, MUTEX_DEFAULT, IPL_SOFTUSB); + mutex_init(&sc->axe_rxlock, MUTEX_DEFAULT, IPL_SOFTUSB); mutex_init(&sc->axe_mii_lock, MUTEX_DEFAULT, IPL_NONE); usb_init_task(&sc->axe_tick_task, axe_tick_task, sc, 0); @@ -990,6 +1026,7 @@ axe_attach(device_t parent, device_t sel ifp->if_softc = sc; strncpy(ifp->if_xname, devname, IFNAMSIZ); ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_extflags = IFEF_START_MPSAFE; ifp->if_ioctl = axe_ioctl; ifp->if_start = axe_start; ifp->if_init = axe_init; @@ -1043,8 +1080,12 @@ axe_attach(device_t parent, device_t sel ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_AUTO); /* Attach the interface. */ - if_attach(ifp); + if_initialize(ifp); + sc->axe_ipq = if_percpuq_create(&sc->axe_ec.ec_if); ether_ifattach(ifp, sc->axe_enaddr); + if_register(ifp); + ether_set_ifflags_cb(&sc->axe_ec, axe_ifflags_cb); + rnd_attach_source(&sc->rnd_source, device_xname(sc->axe_dev), RND_TYPE_NET, RND_FLAG_DEFAULT); @@ -1101,6 +1142,9 @@ axe_detach(device_t self, int flags) } callout_destroy(&sc->axe_stat_ch); + mutex_destroy(&sc->axe_lock); + mutex_destroy(&sc->axe_txlock); + mutex_destroy(&sc->axe_rxlock); mutex_destroy(&sc->axe_mii_lock); rnd_detach_source(&sc->rnd_source); mii_detach(&sc->axe_mii, MII_PHY_ANY, MII_OFFSET_ANY); @@ -1166,6 +1210,18 @@ axe_rx_list_init(struct axe_softc *sc) return 0; } +static void +axe_rx_list_free(struct axe_softc *sc) +{ + /* Free RX resources */ + for (size_t i = 0; i < AXE_RX_LIST_CNT; i++) { + if (sc->axe_cdata.axe_rx_chain[i].axe_xfer != NULL) { + usbd_destroy_xfer(sc->axe_cdata.axe_rx_chain[i].axe_xfer); + sc->axe_cdata.axe_rx_chain[i].axe_xfer = NULL; + } + } +} + static int axe_tx_list_init(struct axe_softc *sc) { @@ -1192,6 +1248,18 @@ axe_tx_list_init(struct axe_softc *sc) return 0; } +static void +axe_tx_list_free(struct axe_softc *sc) +{ + /* Free TX resources */ + for (size_t i = 0; i < AXE_TX_LIST_CNT; i++) { + if (sc->axe_cdata.axe_tx_chain[i].axe_xfer != NULL) { + usbd_destroy_xfer(sc->axe_cdata.axe_tx_chain[i].axe_xfer); + sc->axe_cdata.axe_tx_chain[i].axe_xfer = NULL; + } + } +} + /* * A frame has been uploaded: pass the resulting mbuf chain up to * the higher level protocols. @@ -1206,7 +1274,6 @@ axe_rxeof(struct usbd_xfer *xfer, void * uint8_t *buf; uint32_t total_len; struct mbuf *m; - int s; c = (struct axe_chain *)priv; sc = c->axe_sc; @@ -1374,13 +1441,9 @@ axe_rxeof(struct usbd_xfer *xfer, void * DPRINTFN(10, "deliver %d (%#x)", m->m_len, m->m_len, 0, 0); - s = splnet(); - bpf_mtap(ifp, m); - if_percpuq_enqueue((ifp)->if_percpuq, (m)); - - splx(s); + if_percpuq_enqueue(sc->axe_ipq, (m)); } while (total_len > 0); @@ -1587,10 +1650,18 @@ axe_csum_cfg(struct axe_softc *sc) static void axe_start(struct ifnet *ifp) { - struct axe_softc *sc; - struct mbuf *m; + struct axe_softc *sc = ifp->if_softc; - sc = ifp->if_softc; + mutex_enter(&sc->axe_txlock); + axe_start_locked(ifp); + mutex_exit(&sc->axe_txlock); +} + +static void +axe_start_locked(struct ifnet *ifp) +{ + struct axe_softc *sc = ifp->if_softc; + struct mbuf *m; if ((ifp->if_flags & (IFF_OACTIVE|IFF_RUNNING)) != IFF_RUNNING) return; @@ -1601,7 +1672,6 @@ axe_start(struct ifnet *ifp) } if (axe_encap(sc, m, 0)) { - ifp->if_flags |= IFF_OACTIVE; return; } IFQ_DEQUEUE(&ifp->if_snd, m); @@ -1626,17 +1696,25 @@ axe_start(struct ifnet *ifp) static int axe_init(struct ifnet *ifp) { + struct axe_softc *sc = ifp->if_softc; + + mutex_enter(&sc->axe_lock); + int ret = axe_init_locked(ifp); + mutex_exit(&sc->axe_lock); + + return ret; +} + +static int +axe_init_locked(struct ifnet *ifp) +{ AXEHIST_FUNC(); AXEHIST_CALLED(); struct axe_softc *sc = ifp->if_softc; - struct axe_chain *c; usbd_status err; int rxmode; - int i, s; + int i, error; - s = splnet(); - - if (ifp->if_flags & IFF_RUNNING) - axe_stop(ifp, 0); + axe_stop_locked(ifp, 0); /* * Cancel pending I/O and free all RX/TX buffers. @@ -1735,8 +1813,8 @@ axe_init(struct ifnet *ifp) if (err) { aprint_error_dev(sc->axe_dev, "open rx pipe failed: %s\n", usbd_errstr(err)); - splx(s); - return EIO; + error = EIO; + goto fail; } err = usbd_open_pipe(sc->axe_iface, sc->axe_ed[AXE_ENDPT_TX], @@ -1744,27 +1822,27 @@ axe_init(struct ifnet *ifp) if (err) { aprint_error_dev(sc->axe_dev, "open tx pipe failed: %s\n", usbd_errstr(err)); - splx(s); - return EIO; + error = EIO; + goto fail1; } /* Init RX ring. */ if (axe_rx_list_init(sc) != 0) { aprint_error_dev(sc->axe_dev, "rx list init failed\n"); - splx(s); - return ENOBUFS; + error = ENOBUFS; + goto fail2; } /* Init TX ring. */ if (axe_tx_list_init(sc) != 0) { aprint_error_dev(sc->axe_dev, "tx list init failed\n"); - splx(s); - return ENOBUFS; + error = ENOBUFS; + goto fail3; } /* Start up the receive pipe. */ for (i = 0; i < AXE_RX_LIST_CNT; i++) { - c = &sc->axe_cdata.axe_rx_chain[i]; + struct axe_chain *c = &sc->axe_cdata.axe_rx_chain[i]; usbd_setup_xfer(c->axe_xfer, c, c->axe_buf, sc->axe_bufsz, USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, axe_rxeof); usbd_transfer(c->axe_xfer); @@ -1773,10 +1851,17 @@ axe_init(struct ifnet *ifp) ifp->if_flags |= IFF_RUNNING; ifp->if_flags &= ~IFF_OACTIVE; - splx(s); - callout_schedule(&sc->axe_stat_ch, hz); + return 0; +fail3: + axe_rx_list_free(sc); +fail2: + usbd_close_pipe(sc->axe_ep[AXE_ENDPT_TX]); +fail1: + usbd_close_pipe(sc->axe_ep[AXE_ENDPT_RX]); +fail: + return error; } static int @@ -1787,40 +1872,19 @@ axe_ioctl(struct ifnet *ifp, u_long cmd, 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; - - switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) { - case IFF_RUNNING: - axe_stop(ifp, 1); - break; - case IFF_UP: - axe_init(ifp); - break; - case IFF_UP | IFF_RUNNING: - if ((ifp->if_flags ^ sc->axe_if_flags) == IFF_PROMISC) - axe_setmulti(sc); - else - axe_init(ifp); - break; - } - sc->axe_if_flags = ifp->if_flags; - break; - - default: - if ((error = ether_ioctl(ifp, cmd, data)) != ENETRESET) - break; - + if (error == ENETRESET) { error = 0; - - if (cmd == SIOCADDMULTI || cmd == SIOCDELMULTI) + if (cmd != SIOCADDMULTI && cmd != SIOCDELMULTI) + ; + else if (ifp->if_flags & IFF_RUNNING) { + mutex_enter(&sc->axe_lock); axe_setmulti(sc); - + mutex_exit(&sc->axe_lock); + } } - splx(s); return error; } @@ -1852,12 +1916,22 @@ axe_watchdog(struct ifnet *ifp) * Stop the adapter and free any mbufs allocated to the * RX and TX lists. */ + static void axe_stop(struct ifnet *ifp, int disable) { struct axe_softc *sc = ifp->if_softc; + + mutex_enter(&sc->axe_lock); + axe_stop_locked(ifp, disable); + mutex_exit(&sc->axe_lock); +} + +static void +axe_stop_locked(struct ifnet *ifp, int disable) +{ + struct axe_softc *sc = ifp->if_softc; usbd_status err; - int i; ifp->if_timer = 0; ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); @@ -1891,21 +1965,9 @@ axe_stop(struct ifnet *ifp, int disable) axe_reset(sc); - /* Free RX resources. */ - for (i = 0; i < AXE_RX_LIST_CNT; i++) { - if (sc->axe_cdata.axe_rx_chain[i].axe_xfer != NULL) { - usbd_destroy_xfer(sc->axe_cdata.axe_rx_chain[i].axe_xfer); - sc->axe_cdata.axe_rx_chain[i].axe_xfer = NULL; - } - } + axe_rx_list_free(sc); - /* Free TX resources. */ - for (i = 0; i < AXE_TX_LIST_CNT; i++) { - if (sc->axe_cdata.axe_tx_chain[i].axe_xfer != NULL) { - usbd_destroy_xfer(sc->axe_cdata.axe_tx_chain[i].axe_xfer); - sc->axe_cdata.axe_tx_chain[i].axe_xfer = NULL; - } - } + axe_tx_list_free(sc); /* Close pipes. */ if (sc->axe_ep[AXE_ENDPT_RX] != NULL) { Index: src/sys/dev/usb/if_axen.c diff -u src/sys/dev/usb/if_axen.c:1.3.6.12 src/sys/dev/usb/if_axen.c:1.3.6.13 --- src/sys/dev/usb/if_axen.c:1.3.6.12 Mon Dec 5 10:55:18 2016 +++ src/sys/dev/usb/if_axen.c Mon Dec 12 13:15:39 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: if_axen.c,v 1.3.6.12 2016/12/05 10:55:18 skrll Exp $ */ +/* $NetBSD: if_axen.c,v 1.3.6.13 2016/12/12 13:15:39 skrll 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.3.6.12 2016/12/05 10:55:18 skrll Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_axen.c,v 1.3.6.13 2016/12/12 13:15:39 skrll Exp $"); #ifdef _KERNEL_OPT #include "opt_inet.h" @@ -93,7 +93,9 @@ 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(struct usbd_xfer *, void *, usbd_status); @@ -101,9 +103,13 @@ static void axen_txeof(struct usbd_xfer 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); @@ -654,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"); @@ -678,6 +684,10 @@ axen_attach(device_t parent, device_t se 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"); @@ -721,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)); @@ -756,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; @@ -792,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); @@ -801,7 +813,6 @@ 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); @@ -908,13 +919,12 @@ 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; @@ -932,6 +942,17 @@ axen_rx_list_init(struct axen_softc *sc) 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) { @@ -959,6 +980,17 @@ axen_tx_list_init(struct axen_softc *sc) 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. @@ -977,7 +1009,6 @@ axen_rxeof(struct usbd_xfer *xfer, void 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__)); @@ -1105,10 +1136,8 @@ axen_rxeof(struct usbd_xfer *xfer, void memcpy(mtod(m, char *), buf + 2, pkt_len - 6); /* push the packet up */ - s = splnet(); bpf_mtap(ifp, m); - if_percpuq_enqueue((ifp)->if_percpuq, (m)); - splx(s); + if_percpuq_enqueue(sc->axen_ipq, (m)); nextpkt: /* @@ -1278,6 +1307,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; @@ -1294,7 +1334,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); @@ -1318,17 +1357,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. @@ -1359,8 +1407,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], @@ -1368,22 +1415,19 @@ 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"); - splx(s); - return ENOBUFS; + goto fail2; } /* Init TX ring. */ if (axen_tx_list_init(sc)) { aprint_error_dev(sc->axen_dev, "tx list init failed\n"); - splx(s); - return ENOBUFS; + goto fail3; } /* Start up the receive pipe. */ @@ -1398,56 +1442,52 @@ axen_init(struct ifnet *ifp) 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 @@ -1480,11 +1520,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); @@ -1517,21 +1566,9 @@ axen_stop(struct ifnet *ifp, int disable } } - /* Free RX resources. */ - for (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; - } - } + axen_rx_list_free(sc); - /* Free TX resources. */ - for (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; - } - } + axen_tx_list_free(sc); /* Close pipes. */ if (sc->axen_ep[AXEN_ENDPT_RX] != NULL) { @@ -1562,6 +1599,9 @@ axen_stop(struct ifnet *ifp, int disable } sc->axen_link = 0; + + ifp->if_timer = 0; + ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); } MODULE(MODULE_CLASS_DRIVER, if_axen, "bpf"); Index: src/sys/dev/usb/if_axenreg.h diff -u src/sys/dev/usb/if_axenreg.h:1.1.12.2 src/sys/dev/usb/if_axenreg.h:1.1.12.3 --- src/sys/dev/usb/if_axenreg.h:1.1.12.2 Sat Jun 6 14:40:13 2015 +++ src/sys/dev/usb/if_axenreg.h Mon Dec 12 13:15:39 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: if_axenreg.h,v 1.1.12.2 2015/06/06 14:40:13 skrll Exp $ */ +/* $NetBSD: if_axenreg.h,v 1.1.12.3 2016/12/12 13:15:39 skrll Exp $ */ /* $OpenBSD: if_axenreg.h,v 1.1 2013/10/07 05:37:41 yuo Exp $ */ /* @@ -276,6 +276,8 @@ struct axen_softc { uint16_t axen_vendor; uint16_t axen_product; uint16_t axen_flags; + + struct if_percpuq *axen_ipq; int axen_ed[AXEN_ENDPT_MAX]; struct usbd_pipe *axen_ep[AXEN_ENDPT_MAX]; @@ -289,6 +291,9 @@ struct axen_softc { struct usb_task axen_tick_task; + kmutex_t axen_lock; + kmutex_t axen_txlock; + kmutex_t axen_rxlock; krwlock_t axen_mii_lock; int axen_link; Index: src/sys/dev/usb/if_axereg.h diff -u src/sys/dev/usb/if_axereg.h:1.16.6.4 src/sys/dev/usb/if_axereg.h:1.16.6.5 --- src/sys/dev/usb/if_axereg.h:1.16.6.4 Mon Dec 5 10:55:18 2016 +++ src/sys/dev/usb/if_axereg.h Mon Dec 12 13:15:39 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: if_axereg.h,v 1.16.6.4 2016/12/05 10:55:18 skrll Exp $ */ +/* $NetBSD: if_axereg.h,v 1.16.6.5 2016/12/12 13:15:39 skrll Exp $ */ /* * Copyright (c) 1997, 1998, 1999, 2000-2003 @@ -435,8 +435,13 @@ struct axe_softc { struct usb_task axe_tick_task; + kmutex_t axe_lock; + kmutex_t axe_txlock; + kmutex_t axe_rxlock; kmutex_t axe_mii_lock; + struct if_percpuq *axe_ipq; + int axe_link; uint8_t axe_ipgs[3]; Index: src/sys/dev/usb/if_cdce.c diff -u src/sys/dev/usb/if_cdce.c:1.38.14.9 src/sys/dev/usb/if_cdce.c:1.38.14.10 --- src/sys/dev/usb/if_cdce.c:1.38.14.9 Sat Jul 9 20:25:15 2016 +++ src/sys/dev/usb/if_cdce.c Mon Dec 12 13:15:39 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: if_cdce.c,v 1.38.14.9 2016/07/09 20:25:15 skrll Exp $ */ +/* $NetBSD: if_cdce.c,v 1.38.14.10 2016/12/12 13:15:39 skrll Exp $ */ /* * Copyright (c) 1997, 1998, 1999, 2000-2003 Bill Paul <wp...@windriver.com> @@ -41,7 +41,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_cdce.c,v 1.38.14.9 2016/07/09 20:25:15 skrll Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_cdce.c,v 1.38.14.10 2016/12/12 13:15:39 skrll Exp $"); #ifdef _KERNEL_OPT #include "opt_inet.h" @@ -79,17 +79,22 @@ __KERNEL_RCSID(0, "$NetBSD: if_cdce.c,v #include <dev/usb/if_cdcereg.h> Static int cdce_tx_list_init(struct cdce_softc *); +Static void cdce_tx_list_free(struct cdce_softc *); Static int cdce_rx_list_init(struct cdce_softc *); +Static void cdce_rx_list_free(struct cdce_softc *); Static int cdce_newbuf(struct cdce_softc *, struct cdce_chain *, struct mbuf *); Static int cdce_encap(struct cdce_softc *, struct mbuf *, int); Static void cdce_rxeof(struct usbd_xfer *, void *, usbd_status); Static void cdce_txeof(struct usbd_xfer *, void *, usbd_status); Static void cdce_start(struct ifnet *); +Static void cdce_start_locked(struct ifnet *); Static int cdce_ioctl(struct ifnet *, u_long, void *); -Static void cdce_init(void *); +Static int cdce_init(struct ifnet *); +Static int cdce_init_locked(struct ifnet *); Static void cdce_watchdog(struct ifnet *); -Static void cdce_stop(struct cdce_softc *); +Static void cdce_stop(struct ifnet *, int); +Static void cdce_stop_locked(struct ifnet *, int); Static const struct cdce_type cdce_devs[] = { {{ USB_VENDOR_ACERLABS, USB_PRODUCT_ACERLABS_M5632 }, CDCE_NO_UNION }, @@ -136,7 +141,6 @@ cdce_attach(device_t parent, device_t se struct cdce_softc *sc = device_private(self); struct usbif_attach_arg *uiaa = aux; char *devinfop; - int s; struct ifnet *ifp; struct usbd_device *dev = uiaa->uiaa_device; const struct cdce_type *t; @@ -159,6 +163,10 @@ cdce_attach(device_t parent, device_t se aprint_normal_dev(self, "%s\n", devinfop); usbd_devinfo_free(devinfop); + mutex_init(&sc->cdce_lock, MUTEX_DEFAULT, IPL_NONE); + mutex_init(&sc->cdce_txlock, MUTEX_DEFAULT, IPL_SOFTUSB); + mutex_init(&sc->cdce_rxlock, MUTEX_DEFAULT, IPL_SOFTUSB); + sc->cdce_udev = uiaa->uiaa_device; sc->cdce_ctl_iface = uiaa->uiaa_iface; @@ -271,13 +279,13 @@ cdce_attach(device_t parent, device_t se eaddr[5] = (uint8_t)(device_unit(sc->cdce_dev)); } - s = splnet(); - aprint_normal_dev(self, "address %s\n", ether_sprintf(eaddr)); ifp = GET_IFP(sc); ifp->if_softc = sc; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_extflags = IFEF_START_MPSAFE; + ifp->if_init = cdce_init; ifp->if_ioctl = cdce_ioctl; ifp->if_start = cdce_start; ifp->if_watchdog = cdce_watchdog; @@ -285,11 +293,12 @@ cdce_attach(device_t parent, device_t se IFQ_SET_READY(&ifp->if_snd); - if_attach(ifp); + if_initialize(ifp); + sc->cdce_ipq = if_percpuq_create(&sc->cdce_ec.ec_if); ether_ifattach(ifp, eaddr); + if_register(ifp); sc->cdce_attached = 1; - splx(s); usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->cdce_udev, sc->cdce_dev); @@ -317,7 +326,7 @@ cdce_detach(device_t self, int flags) } if (ifp->if_flags & IFF_RUNNING) - cdce_stop(sc); + cdce_stop(ifp, 1); ether_ifdetach(ifp); @@ -333,6 +342,17 @@ Static void cdce_start(struct ifnet *ifp) { struct cdce_softc *sc = ifp->if_softc; + KASSERT(ifp->if_extflags & IFEF_START_MPSAFE); + + mutex_enter(&sc->cdce_txlock); + cdce_start_locked(ifp); + mutex_exit(&sc->cdce_txlock); +} + +Static void +cdce_start_locked(struct ifnet *ifp) +{ + struct cdce_softc *sc = ifp->if_softc; struct mbuf *m_head = NULL; if (sc->cdce_dying || (ifp->if_flags & IFF_OACTIVE)) @@ -343,7 +363,6 @@ cdce_start(struct ifnet *ifp) return; if (cdce_encap(sc, m_head, 0)) { - ifp->if_flags |= IFF_OACTIVE; return; } @@ -359,12 +378,9 @@ cdce_start(struct ifnet *ifp) Static int cdce_encap(struct cdce_softc *sc, struct mbuf *m, int idx) { - struct cdce_chain *c; - usbd_status err; + struct cdce_chain *c = &sc->cdce_cdata.cdce_tx_chain[idx]; int extra = 0; - c = &sc->cdce_cdata.cdce_tx_chain[idx]; - m_copydata(m, 0, m->m_pkthdr.len, c->cdce_buf); if (sc->cdce_flags & CDCE_ZAURUS) { /* Zaurus wants a 32-bit CRC appended to every frame */ @@ -378,9 +394,9 @@ cdce_encap(struct cdce_softc *sc, struct usbd_setup_xfer(c->cdce_xfer, c, c->cdce_buf, m->m_pkthdr.len + extra, USBD_FORCE_SHORT_XFER, 10000, cdce_txeof); - err = usbd_transfer(c->cdce_xfer); + usbd_status err = usbd_transfer(c->cdce_xfer); if (err != USBD_IN_PROGRESS) { - cdce_stop(sc); + cdce_stop(GET_IFP(sc), 0); return EIO; } @@ -390,11 +406,20 @@ cdce_encap(struct cdce_softc *sc, struct } Static void -cdce_stop(struct cdce_softc *sc) +cdce_stop(struct ifnet *ifp, int disable) { + struct cdce_softc * const sc = ifp->if_softc; + + mutex_enter(&sc->cdce_lock); + cdce_stop_locked(ifp, disable); + mutex_exit(&sc->cdce_lock); +} + +Static void +cdce_stop_locked(struct ifnet *ifp, int disable) +{ + struct cdce_softc * const sc = ifp->if_softc; usbd_status err; - struct ifnet *ifp = GET_IFP(sc); - int i; ifp->if_timer = 0; @@ -412,29 +437,9 @@ cdce_stop(struct cdce_softc *sc) device_xname(sc->cdce_dev), usbd_errstr(err)); } - for (i = 0; i < CDCE_RX_LIST_CNT; i++) { - if (sc->cdce_cdata.cdce_rx_chain[i].cdce_mbuf != NULL) { - m_freem(sc->cdce_cdata.cdce_rx_chain[i].cdce_mbuf); - sc->cdce_cdata.cdce_rx_chain[i].cdce_mbuf = NULL; - } - if (sc->cdce_cdata.cdce_rx_chain[i].cdce_xfer != NULL) { - usbd_destroy_xfer - (sc->cdce_cdata.cdce_rx_chain[i].cdce_xfer); - sc->cdce_cdata.cdce_rx_chain[i].cdce_xfer = NULL; - } - } + cdce_rx_list_free(sc); - for (i = 0; i < CDCE_TX_LIST_CNT; i++) { - if (sc->cdce_cdata.cdce_tx_chain[i].cdce_mbuf != NULL) { - m_freem(sc->cdce_cdata.cdce_tx_chain[i].cdce_mbuf); - sc->cdce_cdata.cdce_tx_chain[i].cdce_mbuf = NULL; - } - if (sc->cdce_cdata.cdce_tx_chain[i].cdce_xfer != NULL) { - usbd_destroy_xfer( - sc->cdce_cdata.cdce_tx_chain[i].cdce_xfer); - sc->cdce_cdata.cdce_tx_chain[i].cdce_xfer = NULL; - } - } + cdce_tx_list_free(sc); if (sc->cdce_bulkin_pipe != NULL) { err = usbd_close_pipe(sc->cdce_bulkin_pipe); @@ -452,6 +457,7 @@ cdce_stop(struct cdce_softc *sc) sc->cdce_bulkout_pipe = NULL; } + ifp->if_timer = 0; ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); } @@ -459,56 +465,13 @@ Static int cdce_ioctl(struct ifnet *ifp, u_long command, void *data) { struct cdce_softc *sc = ifp->if_softc; - struct ifaddr *ifa = (struct ifaddr *)data; - struct ifreq *ifr = (struct ifreq *)data; int s, error = 0; if (sc->cdce_dying) return EIO; s = splnet(); - - switch(command) { - case SIOCINITIFADDR: - ifp->if_flags |= IFF_UP; - cdce_init(sc); - switch (ifa->ifa_addr->sa_family) { -#ifdef INET - case AF_INET: - arp_ifinit(ifp, ifa); - break; -#endif /* INET */ - } - break; - - case SIOCSIFMTU: - if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > ETHERMTU) - error = EINVAL; - else if ((error = ifioctl_common(ifp, command, data)) == ENETRESET) - error = 0; - break; - - case SIOCSIFFLAGS: - if ((error = ifioctl_common(ifp, command, data)) != 0) - break; - /* XXX re-use ether_ioctl() */ - switch (ifp->if_flags & (IFF_UP|IFF_RUNNING)) { - case IFF_UP: - cdce_init(sc); - break; - case IFF_RUNNING: - cdce_stop(sc); - break; - default: - break; - } - break; - - default: - error = ether_ioctl(ifp, command, data); - break; - } - + error = ether_ioctl(ifp, command, data); splx(s); if (error == ENETRESET) @@ -529,29 +492,32 @@ cdce_watchdog(struct ifnet *ifp) printf("%s: watchdog timeout\n", device_xname(sc->cdce_dev)); } -Static void -cdce_init(void *xsc) +Static int +cdce_init(struct ifnet *ifp) { - struct cdce_softc *sc = xsc; - struct ifnet *ifp = GET_IFP(sc); - struct cdce_chain *c; - usbd_status err; - int s, i; + struct cdce_softc * const sc = ifp->if_softc; - if (ifp->if_flags & IFF_RUNNING) - return; + mutex_enter(&sc->cdce_lock); + int ret = cdce_init_locked(ifp); + mutex_exit(&sc->cdce_lock); - s = splnet(); + return ret; +} - /* Maybe set multicast / broadcast here??? */ +Static int +cdce_init_locked(struct ifnet *ifp) +{ + struct cdce_softc * const sc = ifp->if_softc; + struct cdce_chain *c; + usbd_status err; + int i; err = usbd_open_pipe(sc->cdce_data_iface, sc->cdce_bulkin_no, USBD_EXCLUSIVE_USE, &sc->cdce_bulkin_pipe); if (err) { printf("%s: open rx pipe failed: %s\n", device_xname(sc->cdce_dev), usbd_errstr(err)); - splx(s); - return; + goto fail; } err = usbd_open_pipe(sc->cdce_data_iface, sc->cdce_bulkout_no, @@ -559,20 +525,17 @@ cdce_init(void *xsc) if (err) { printf("%s: open tx pipe failed: %s\n", device_xname(sc->cdce_dev), usbd_errstr(err)); - splx(s); - return; + goto fail1; } if (cdce_tx_list_init(sc)) { printf("%s: tx list init failed\n", device_xname(sc->cdce_dev)); - splx(s); - return; + goto fail2; } if (cdce_rx_list_init(sc)) { printf("%s: rx list init failed\n", device_xname(sc->cdce_dev)); - splx(s); - return; + goto fail3; } for (i = 0; i < CDCE_RX_LIST_CNT; i++) { @@ -586,7 +549,16 @@ cdce_init(void *xsc) ifp->if_flags |= IFF_RUNNING; ifp->if_flags &= ~IFF_OACTIVE; - splx(s); + return 0; + +fail3: + cdce_tx_list_free(sc); +fail2: + usbd_close_pipe(sc->cdce_bulkout_pipe); +fail1: + usbd_close_pipe(sc->cdce_bulkin_pipe); +fail: + return EIO; } Static int @@ -621,11 +593,10 @@ cdce_newbuf(struct cdce_softc *sc, struc Static int cdce_rx_list_init(struct cdce_softc *sc) { - struct cdce_cdata *cd; + struct cdce_cdata *cd = &sc->cdce_cdata; struct cdce_chain *c; int i; - cd = &sc->cdce_cdata; for (i = 0; i < CDCE_RX_LIST_CNT; i++) { c = &cd->cdce_rx_chain[i]; c->cdce_sc = sc; @@ -644,14 +615,29 @@ cdce_rx_list_init(struct cdce_softc *sc) return 0; } +Static void +cdce_rx_list_free(struct cdce_softc *sc) +{ + /* Free RX resources */ + for (size_t i = 0; i < CDCE_RX_LIST_CNT; i++) { + if (sc->cdce_cdata.cdce_rx_chain[i].cdce_mbuf != NULL) { + m_freem(sc->cdce_cdata.cdce_rx_chain[i].cdce_mbuf); + sc->cdce_cdata.cdce_rx_chain[i].cdce_mbuf = NULL; + } + if (sc->cdce_cdata.cdce_rx_chain[i].cdce_xfer != NULL) { + usbd_destroy_xfer(sc->cdce_cdata.cdce_rx_chain[i].cdce_xfer); + sc->cdce_cdata.cdce_rx_chain[i].cdce_xfer = NULL; + } + } +} + Static int cdce_tx_list_init(struct cdce_softc *sc) { - struct cdce_cdata *cd; + struct cdce_cdata *cd = &sc->cdce_cdata; struct cdce_chain *c; int i; - cd = &sc->cdce_cdata; for (i = 0; i < CDCE_TX_LIST_CNT; i++) { c = &cd->cdce_tx_chain[i]; c->cdce_sc = sc; @@ -671,6 +657,22 @@ cdce_tx_list_init(struct cdce_softc *sc) } Static void +cdce_tx_list_free(struct cdce_softc *sc) +{ + /* Free TX resources */ + for (size_t i = 0; i < CDCE_TX_LIST_CNT; i++) { + if (sc->cdce_cdata.cdce_tx_chain[i].cdce_mbuf != NULL) { + m_freem(sc->cdce_cdata.cdce_tx_chain[i].cdce_mbuf); + sc->cdce_cdata.cdce_tx_chain[i].cdce_mbuf = NULL; + } + if (sc->cdce_cdata.cdce_tx_chain[i].cdce_xfer != NULL) { + usbd_destroy_xfer(sc->cdce_cdata.cdce_tx_chain[i].cdce_xfer); + sc->cdce_cdata.cdce_tx_chain[i].cdce_xfer = NULL; + } + } +} + +Static void cdce_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status) { struct cdce_chain *c = priv; @@ -678,7 +680,6 @@ cdce_rxeof(struct usbd_xfer *xfer, void struct ifnet *ifp = GET_IFP(sc); struct mbuf *m; int total_len = 0; - int s; if (sc->cdce_dying || !(ifp->if_flags & IFF_RUNNING)) return; @@ -716,19 +717,14 @@ cdce_rxeof(struct usbd_xfer *xfer, void m->m_pkthdr.len = m->m_len = total_len; m_set_rcvif(m, ifp); - s = splnet(); - if (cdce_newbuf(sc, c, NULL) == ENOBUFS) { ifp->if_ierrors++; - goto done1; + goto done; } bpf_mtap(ifp, m); - if_percpuq_enqueue((ifp)->if_percpuq, (m)); - -done1: - splx(s); + if_percpuq_enqueue(sc->cdce_ipq, (m)); done: /* Setup new transfer. */ @@ -745,12 +741,11 @@ cdce_txeof(struct usbd_xfer *xfer, void struct cdce_softc *sc = c->cdce_sc; struct ifnet *ifp = GET_IFP(sc); usbd_status err; - int s; if (sc->cdce_dying) return; - s = splnet(); + int s = splnet(); ifp->if_timer = 0; ifp->if_flags &= ~IFF_OACTIVE; Index: src/sys/dev/usb/if_cdcereg.h diff -u src/sys/dev/usb/if_cdcereg.h:1.7.24.4 src/sys/dev/usb/if_cdcereg.h:1.7.24.5 --- src/sys/dev/usb/if_cdcereg.h:1.7.24.4 Sun Mar 20 08:42:19 2016 +++ src/sys/dev/usb/if_cdcereg.h Mon Dec 12 13:15:39 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: if_cdcereg.h,v 1.7.24.4 2016/03/20 08:42:19 skrll Exp $ */ +/* $NetBSD: if_cdcereg.h,v 1.7.24.5 2016/12/12 13:15:39 skrll Exp $ */ /* * Copyright (c) 1997, 1998, 1999, 2000-2003 Bill Paul <wp...@windriver.com> @@ -70,7 +70,7 @@ struct cdce_cdata { struct cdce_softc { device_t cdce_dev; struct ethercom cdce_ec; - krndsource_t rnd_source; + krndsource_t rnd_source; #define GET_IFP(sc) (&(sc)->cdce_ec.ec_if) struct usbd_device * cdce_udev; struct usbd_interface * cdce_ctl_iface; @@ -85,4 +85,10 @@ struct cdce_softc { int cdce_rxeof_errors; uint16_t cdce_flags; char cdce_attached; + + struct if_percpuq *cdce_ipq; + + kmutex_t cdce_lock; + kmutex_t cdce_txlock; + kmutex_t cdce_rxlock; }; Index: src/sys/dev/usb/if_cue.c diff -u src/sys/dev/usb/if_cue.c:1.68.4.12 src/sys/dev/usb/if_cue.c:1.68.4.13 --- src/sys/dev/usb/if_cue.c:1.68.4.12 Mon Dec 5 10:55:18 2016 +++ src/sys/dev/usb/if_cue.c Mon Dec 12 13:15:39 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: if_cue.c,v 1.68.4.12 2016/12/05 10:55:18 skrll Exp $ */ +/* $NetBSD: if_cue.c,v 1.68.4.13 2016/12/12 13:15:39 skrll Exp $ */ /* * Copyright (c) 1997, 1998, 1999, 2000 * Bill Paul <wp...@ee.columbia.edu>. All rights reserved. @@ -56,7 +56,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_cue.c,v 1.68.4.12 2016/12/05 10:55:18 skrll Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_cue.c,v 1.68.4.13 2016/12/12 13:15:39 skrll Exp $"); #ifdef _KERNEL_OPT #include "opt_inet.h" @@ -120,9 +120,12 @@ extern struct cfdriver cue_cd; CFATTACH_DECL_NEW(cue, sizeof(struct cue_softc), cue_match, cue_attach, cue_detach, cue_activate); -Static int cue_open_pipes(struct cue_softc *); Static int cue_tx_list_init(struct cue_softc *); +Static void cue_tx_list_free(struct cue_softc *); Static int cue_rx_list_init(struct cue_softc *); +#if 0 +Static void cue_rx_list_free(struct cue_softc *); +#endif Static int cue_newbuf(struct cue_softc *, struct cue_chain *, struct mbuf *); Static int cue_send(struct cue_softc *, struct mbuf *, int); Static void cue_rxeof(struct usbd_xfer *, void *, usbd_status); @@ -130,9 +133,13 @@ Static void cue_txeof(struct usbd_xfer * Static void cue_tick(void *); Static void cue_tick_task(void *); Static void cue_start(struct ifnet *); +Static void cue_start_locked(struct ifnet *); Static int cue_ioctl(struct ifnet *, u_long, void *); -Static void cue_init(void *); +Static int cue_ifflags_cb(struct ethercom *); +Static int cue_init(struct ifnet *); +Static int cue_init_locked(struct ifnet *); Static void cue_stop(struct cue_softc *); +Static void cue_stop_locked(struct cue_softc *); Static void cue_watchdog(struct ifnet *); Static void cue_setmulti(struct cue_softc *); @@ -455,7 +462,6 @@ cue_attach(device_t parent, device_t sel struct cue_softc *sc = device_private(self); struct usb_attach_arg *uaa = aux; char *devinfop; - int s; u_char eaddr[ETHER_ADDR_LEN]; struct usbd_device * dev = uaa->uaa_device; struct usbd_interface * iface; @@ -490,6 +496,10 @@ cue_attach(device_t parent, device_t sel usb_init_task(&sc->cue_tick_task, cue_tick_task, sc, 0); usb_init_task(&sc->cue_stop_task, (void (*)(void *))cue_stop, sc, 0); + mutex_init(&sc->cue_lock, MUTEX_DEFAULT, IPL_NONE); + mutex_init(&sc->cue_txlock, MUTEX_DEFAULT, IPL_SOFTUSB); + mutex_init(&sc->cue_rxlock, MUTEX_DEFAULT, IPL_SOFTUSB); + err = usbd_device2interface_handle(dev, CUE_IFACE_IDX, &iface); if (err) { aprint_error_dev(self, "getting interface handle failed\n"); @@ -527,8 +537,6 @@ cue_attach(device_t parent, device_t sel */ cue_getmac(sc, &eaddr); - s = splnet(); - /* * A CATC chip was detected. Inform the world. */ @@ -539,6 +547,8 @@ cue_attach(device_t parent, device_t sel ifp->if_softc = sc; ifp->if_mtu = ETHERMTU; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_extflags = IFEF_START_MPSAFE; + ifp->if_init = cue_init; ifp->if_ioctl = cue_ioctl; ifp->if_start = cue_start; ifp->if_watchdog = cue_watchdog; @@ -547,15 +557,17 @@ cue_attach(device_t parent, device_t sel IFQ_SET_READY(&ifp->if_snd); /* Attach the interface. */ - if_attach(ifp); + if_initialize(ifp); + sc->cue_ipq = if_percpuq_create(&sc->cue_ec.ec_if); ether_ifattach(ifp, eaddr); + if_register(ifp); + ether_set_ifflags_cb(&sc->cue_ec, cue_ifflags_cb); rnd_attach_source(&sc->rnd_source, device_xname(sc->cue_dev), RND_TYPE_NET, RND_FLAG_DEFAULT); callout_init(&(sc->cue_stat_ch), 0); sc->cue_attached = 1; - splx(s); usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->cue_udev, sc->cue_dev); @@ -688,7 +700,19 @@ cue_rx_list_init(struct cue_softc *sc) return 0; } - +#if 0 +Static void +cue_rx_list_free(struct cue_softc *sc) +{ + /* Free RX resources. */ + for (int i = 0; i < CUE_RX_LIST_CNT; i++) { + if (sc->cue_cdata.cue_rx_chain[i].cue_xfer != NULL) { + usbd_destroy_xfer(sc->cue_cdata.cue_rx_chain[i].cue_xfer); + sc->cue_cdata.cue_rx_chain[i].cue_xfer = NULL; + } + } +} +#endif Static int cue_tx_list_init(struct cue_softc *sc) { @@ -714,6 +738,22 @@ cue_tx_list_init(struct cue_softc *sc) return 0; } +Static void +cue_tx_list_free(struct cue_softc *sc) +{ + /* Free TX resources. */ + for (int i = 0; i < CUE_TX_LIST_CNT; i++) { + if (sc->cue_cdata.cue_tx_chain[i].cue_mbuf != NULL) { + m_freem(sc->cue_cdata.cue_tx_chain[i].cue_mbuf); + sc->cue_cdata.cue_tx_chain[i].cue_mbuf = NULL; + } + if (sc->cue_cdata.cue_tx_chain[i].cue_xfer != NULL) { + usbd_destroy_xfer(sc->cue_cdata.cue_tx_chain[i].cue_xfer); + sc->cue_cdata.cue_tx_chain[i].cue_xfer = NULL; + } + } +} + /* * A frame has been uploaded: pass the resulting mbuf chain up to * the higher level protocols. @@ -727,7 +767,6 @@ cue_rxeof(struct usbd_xfer *xfer, void * struct mbuf *m; int total_len = 0; uint16_t len; - int s; DPRINTFN(10,("%s: %s: enter status=%d\n", device_xname(sc->cue_dev), __func__, status)); @@ -774,12 +813,10 @@ cue_rxeof(struct usbd_xfer *xfer, void * m_set_rcvif(m, ifp); - s = splnet(); - /* XXX ugly */ if (cue_newbuf(sc, c, NULL) == ENOBUFS) { ifp->if_ierrors++; - goto done1; + goto done; } /* @@ -792,9 +829,7 @@ cue_rxeof(struct usbd_xfer *xfer, void * DPRINTFN(10,("%s: %s: deliver %d\n", device_xname(sc->cue_dev), __func__, m->m_len)); - if_percpuq_enqueue(ifp->if_percpuq, m); - done1: - splx(s); + if_percpuq_enqueue(sc->cue_ipq, m); done: @@ -942,6 +977,17 @@ cue_send(struct cue_softc *sc, struct mb Static void cue_start(struct ifnet *ifp) { + struct cue_softc *sc = ifp->if_softc; + KASSERT(ifp->if_extflags & IFEF_START_MPSAFE); + + mutex_enter(&sc->cue_txlock); + cue_start_locked(ifp); + mutex_exit(&sc->cue_txlock); +} + +Static void +cue_start_locked(struct ifnet *ifp) +{ struct cue_softc *sc = ifp->if_softc; struct mbuf *m_head = NULL; @@ -978,23 +1024,32 @@ cue_start(struct ifnet *ifp) ifp->if_timer = 5; } -Static void -cue_init(void *xsc) +Static int +cue_init(struct ifnet *ifp) { - struct cue_softc *sc = xsc; - struct ifnet *ifp = GET_IFP(sc); - int i, s, ctl; + struct cue_softc *sc = ifp->if_softc; + + mutex_enter(&sc->cue_lock); + int ret = cue_init_locked(ifp); + mutex_exit(&sc->cue_lock); + + return ret; +} + +Static int +cue_init_locked(struct ifnet *ifp) +{ + struct cue_softc *sc = ifp->if_softc; + int i, ctl, err = 0; const u_char *eaddr; if (sc->cue_dying) - return; + return EIO; DPRINTFN(10,("%s: %s: enter\n", device_xname(sc->cue_dev),__func__)); if (ifp->if_flags & IFF_RUNNING) - return; - - s = splnet(); + return 0; /* * Cancel pending I/O and free all RX/TX buffers. @@ -1036,139 +1091,113 @@ cue_init(void *xsc) cue_csr_write_1(sc, CUE_LEDCTL, CUE_LEDCTL_FOLLOW_LINK); if (sc->cue_ep[CUE_ENDPT_RX] == NULL) { - if (cue_open_pipes(sc)) { - splx(s); - return; + /* Open RX and TX pipes. */ + err = usbd_open_pipe(sc->cue_iface, sc->cue_ed[CUE_ENDPT_RX], + USBD_EXCLUSIVE_USE, &sc->cue_ep[CUE_ENDPT_RX]); + if (err) { + printf("%s: open rx pipe failed: %s\n", + device_xname(sc->cue_dev), usbd_errstr(err)); + goto fail; + } + err = usbd_open_pipe(sc->cue_iface, sc->cue_ed[CUE_ENDPT_TX], + USBD_EXCLUSIVE_USE, &sc->cue_ep[CUE_ENDPT_TX]); + if (err) { + printf("%s: open tx pipe failed: %s\n", + device_xname(sc->cue_dev), usbd_errstr(err)); + goto fail1; } } /* Init TX ring. */ if (cue_tx_list_init(sc)) { printf("%s: tx list init failed\n", device_xname(sc->cue_dev)); - splx(s); - return; + goto fail2; } /* Init RX ring. */ if (cue_rx_list_init(sc)) { printf("%s: rx list init failed\n", device_xname(sc->cue_dev)); - splx(s); - return; + goto fail3; } + /* Start up the receive pipe. */ + for (i = 0; i < CUE_RX_LIST_CNT; i++) { + struct cue_chain *c = &sc->cue_cdata.cue_rx_chain[i]; + usbd_setup_xfer(c->cue_xfer, c, c->cue_buf, CUE_BUFSZ, + USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, cue_rxeof); + usbd_transfer(c->cue_xfer); + } ifp->if_flags |= IFF_RUNNING; ifp->if_flags &= ~IFF_OACTIVE; - splx(s); - callout_reset(&(sc->cue_stat_ch), (hz), (cue_tick), (sc)); + + return 0; + +fail3: + cue_tx_list_free(sc); +fail2: + usbd_close_pipe(sc->cue_ep[CUE_ENDPT_TX]); +fail1: + usbd_close_pipe(sc->cue_ep[CUE_ENDPT_RX]); +fail: + return EIO; } Static int -cue_open_pipes(struct cue_softc *sc) +cue_ioctl(struct ifnet *ifp, u_long cmd, void *data) { - struct cue_chain *c; - usbd_status err; - int i; + struct cue_softc *sc = ifp->if_softc; + int s, error = 0; - /* Open RX and TX pipes. */ - err = usbd_open_pipe(sc->cue_iface, sc->cue_ed[CUE_ENDPT_RX], - USBD_EXCLUSIVE_USE, &sc->cue_ep[CUE_ENDPT_RX]); - if (err) { - printf("%s: open rx pipe failed: %s\n", - device_xname(sc->cue_dev), usbd_errstr(err)); - return EIO; - } - err = usbd_open_pipe(sc->cue_iface, sc->cue_ed[CUE_ENDPT_TX], - USBD_EXCLUSIVE_USE, &sc->cue_ep[CUE_ENDPT_TX]); - if (err) { - printf("%s: open tx pipe failed: %s\n", - device_xname(sc->cue_dev), usbd_errstr(err)); + if (sc->cue_dying) return EIO; - } - /* Start up the receive pipe. */ - for (i = 0; i < CUE_RX_LIST_CNT; i++) { - c = &sc->cue_cdata.cue_rx_chain[i]; + s = splnet(); + error = ether_ioctl(ifp, cmd, data); + splx(s); - usbd_setup_xfer(c->cue_xfer, c, c->cue_buf, CUE_BUFSZ, - USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, cue_rxeof); - usbd_transfer(c->cue_xfer); + if (error == ENETRESET) { + error = 0; + if (cmd == SIOCADDMULTI || cmd == SIOCDELMULTI) { + mutex_enter(&sc->cue_lock); + cue_setmulti(sc); + mutex_exit(&sc->cue_lock); + } } - - return 0; + return error; } Static int -cue_ioctl(struct ifnet *ifp, u_long command, void *data) +cue_ifflags_cb(struct ethercom *ec) { - struct cue_softc *sc = ifp->if_softc; - struct ifaddr *ifa = (struct ifaddr *)data; - struct ifreq *ifr = (struct ifreq *)data; - int s, error = 0; + struct ifnet *ifp = &ec->ec_if; + struct cue_softc *sc = ifp->if_softc; + int rc = 0; - if (sc->cue_dying) - return EIO; + mutex_enter(&sc->cue_lock); - s = splnet(); + int change = ifp->if_flags ^ sc->cue_if_flags; + sc->cue_if_flags = ifp->if_flags; - switch(command) { - case SIOCINITIFADDR: - ifp->if_flags |= IFF_UP; - cue_init(sc); + if ((change & ~(IFF_CANTCHANGE | IFF_DEBUG)) != 0) { + rc = ENETRESET; + goto out; + } - switch (ifa->ifa_addr->sa_family) { -#ifdef INET - case AF_INET: - arp_ifinit(ifp, ifa); - break; -#endif /* INET */ - } - break; - - case SIOCSIFMTU: - if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > ETHERMTU) - error = EINVAL; - else if ((error = ifioctl_common(ifp, command, data)) == ENETRESET) - error = 0; - break; - - case SIOCSIFFLAGS: - if ((error = ifioctl_common(ifp, command, data)) != 0) - break; - if (ifp->if_flags & IFF_UP) { - if (ifp->if_flags & IFF_RUNNING && - ifp->if_flags & IFF_PROMISC && - !(sc->cue_if_flags & IFF_PROMISC)) { - CUE_SETBIT(sc, CUE_ETHCTL, CUE_ETHCTL_PROMISC); - cue_setmulti(sc); - } else if (ifp->if_flags & IFF_RUNNING && - !(ifp->if_flags & IFF_PROMISC) && - sc->cue_if_flags & IFF_PROMISC) { - CUE_CLRBIT(sc, CUE_ETHCTL, CUE_ETHCTL_PROMISC); - cue_setmulti(sc); - } else if (!(ifp->if_flags & IFF_RUNNING)) - cue_init(sc); - } else { - if (ifp->if_flags & IFF_RUNNING) - cue_stop(sc); + if ((change & IFF_PROMISC) != 0) { + if (ifp->if_flags & IFF_PROMISC) { + CUE_SETBIT(sc, CUE_ETHCTL, CUE_ETHCTL_PROMISC); + } else if (!(ifp->if_flags & IFF_PROMISC)) { + CUE_CLRBIT(sc, CUE_ETHCTL, CUE_ETHCTL_PROMISC); } - sc->cue_if_flags = ifp->if_flags; - error = 0; - break; - case SIOCADDMULTI: - case SIOCDELMULTI: cue_setmulti(sc); - error = 0; - break; - default: - error = ether_ioctl(ifp, command, data); - break; } - splx(s); +out: + mutex_exit(&sc->cue_lock); - return error; + return rc; } Static void @@ -1204,9 +1233,16 @@ cue_watchdog(struct ifnet *ifp) Static void cue_stop(struct cue_softc *sc) { + mutex_enter(&sc->cue_lock); + cue_stop_locked(sc); + mutex_exit(&sc->cue_lock); +} + +Static void +cue_stop_locked(struct cue_softc *sc) +{ usbd_status err; struct ifnet *ifp; - int i; DPRINTFN(10,("%s: %s: enter\n", device_xname(sc->cue_dev),__func__)); @@ -1242,26 +1278,6 @@ cue_stop(struct cue_softc *sc) } } - /* Free RX resources. */ - for (i = 0; i < CUE_RX_LIST_CNT; i++) { - if (sc->cue_cdata.cue_rx_chain[i].cue_xfer != NULL) { - usbd_destroy_xfer(sc->cue_cdata.cue_rx_chain[i].cue_xfer); - sc->cue_cdata.cue_rx_chain[i].cue_xfer = NULL; - } - } - - /* Free TX resources. */ - for (i = 0; i < CUE_TX_LIST_CNT; i++) { - if (sc->cue_cdata.cue_tx_chain[i].cue_mbuf != NULL) { - m_freem(sc->cue_cdata.cue_tx_chain[i].cue_mbuf); - sc->cue_cdata.cue_tx_chain[i].cue_mbuf = NULL; - } - if (sc->cue_cdata.cue_tx_chain[i].cue_xfer != NULL) { - usbd_destroy_xfer(sc->cue_cdata.cue_tx_chain[i].cue_xfer); - sc->cue_cdata.cue_tx_chain[i].cue_xfer = NULL; - } - } - /* Stop transfers. */ if (sc->cue_ep[CUE_ENDPT_RX] != NULL) { err = usbd_close_pipe(sc->cue_ep[CUE_ENDPT_RX]); Index: src/sys/dev/usb/if_cuereg.h diff -u src/sys/dev/usb/if_cuereg.h:1.18.24.4 src/sys/dev/usb/if_cuereg.h:1.18.24.5 --- src/sys/dev/usb/if_cuereg.h:1.18.24.4 Sun Mar 20 08:42:19 2016 +++ src/sys/dev/usb/if_cuereg.h Mon Dec 12 13:15:39 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: if_cuereg.h,v 1.18.24.4 2016/03/20 08:42:19 skrll Exp $ */ +/* $NetBSD: if_cuereg.h,v 1.18.24.5 2016/12/12 13:15:39 skrll Exp $ */ /* * Copyright (c) 1997, 1998, 1999, 2000 * Bill Paul <wp...@ee.columbia.edu>. All rights reserved. @@ -185,6 +185,12 @@ struct cue_softc { uint16_t cue_rxfilt; struct cue_cdata cue_cdata; + kmutex_t cue_lock; + kmutex_t cue_txlock; + kmutex_t cue_rxlock; + + struct if_percpuq *cue_ipq; + char cue_dying; char cue_attached; u_int cue_rx_errs; Index: src/sys/dev/usb/if_udav.c diff -u src/sys/dev/usb/if_udav.c:1.43.4.11 src/sys/dev/usb/if_udav.c:1.43.4.12 --- src/sys/dev/usb/if_udav.c:1.43.4.11 Mon Dec 5 10:55:18 2016 +++ src/sys/dev/usb/if_udav.c Mon Dec 12 13:15:39 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: if_udav.c,v 1.43.4.11 2016/12/05 10:55:18 skrll Exp $ */ +/* $NetBSD: if_udav.c,v 1.43.4.12 2016/12/12 13:15:39 skrll 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.43.4.11 2016/12/05 10:55:18 skrll Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_udav.c,v 1.43.4.12 2016/12/12 13:15:39 skrll Exp $"); #ifdef _KERNEL_OPT #include "opt_inet.h" @@ -96,9 +96,12 @@ CFATTACH_DECL_NEW(udav, sizeof(struct ud Static int udav_openpipes(struct udav_softc *); Static int udav_rx_list_init(struct udav_softc *); +Static void udav_rx_list_free(struct udav_softc *); Static int udav_tx_list_init(struct udav_softc *); +Static void udav_tx_list_free(struct udav_softc *); Static int udav_newbuf(struct udav_softc *, struct udav_chain *, struct mbuf *); Static void udav_start(struct ifnet *); +Static void udav_start_locked(struct ifnet *); Static int udav_send(struct udav_softc *, struct mbuf *, int); Static void udav_txeof(struct usbd_xfer *, void *, usbd_status); Static void udav_rxeof(struct usbd_xfer *, void *, usbd_status); @@ -107,6 +110,7 @@ Static void udav_tick_task(void *); Static int udav_ioctl(struct ifnet *, u_long, void *); Static void udav_stop_task(struct udav_softc *); Static void udav_stop(struct ifnet *, int); +Static void udav_stop_locked(struct ifnet *, int); Static void udav_watchdog(struct ifnet *); Static int udav_ifmedia_change(struct ifnet *); Static void udav_ifmedia_status(struct ifnet *, struct ifmediareq *); @@ -116,6 +120,7 @@ Static int udav_miibus_readreg(device_t, Static void udav_miibus_writereg(device_t, int, int, int); Static void udav_miibus_statchg(struct ifnet *); Static int udav_init(struct ifnet *); +Static int udav_init_locked(struct ifnet *); Static void udav_setmulti(struct udav_softc *); Static void udav_reset(struct udav_softc *); @@ -198,7 +203,7 @@ udav_attach(device_t parent, device_t se struct ifnet *ifp; struct mii_data *mii; u_char eaddr[ETHER_ADDR_LEN]; - int i, s; + int i; sc->sc_dev = self; @@ -219,6 +224,9 @@ udav_attach(device_t parent, device_t se usb_init_task(&sc->sc_tick_task, udav_tick_task, sc, 0); mutex_init(&sc->sc_mii_lock, MUTEX_DEFAULT, IPL_NONE); + mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); + mutex_init(&sc->sc_txlock, MUTEX_DEFAULT, IPL_SOFTUSB); + mutex_init(&sc->sc_rxlock, MUTEX_DEFAULT, IPL_SOFTUSB); usb_init_task(&sc->sc_stop_task, (void (*)(void *))udav_stop_task, sc, 0); @@ -263,8 +271,6 @@ udav_attach(device_t parent, device_t se goto bad; } - s = splnet(); - /* reset the adapter */ udav_reset(sc); @@ -272,7 +278,6 @@ udav_attach(device_t parent, device_t se err = udav_csr_read(sc, UDAV_PAR, (void *)eaddr, ETHER_ADDR_LEN); if (err) { aprint_error_dev(self, "read MAC address failed\n"); - splx(s); goto bad; } @@ -285,6 +290,7 @@ udav_attach(device_t parent, device_t se ifp->if_mtu = ETHERMTU; strncpy(ifp->if_xname, device_xname(self), IFNAMSIZ); ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_extflags = IFEF_START_MPSAFE; ifp->if_start = udav_start; ifp->if_ioctl = udav_ioctl; ifp->if_watchdog = udav_watchdog; @@ -319,15 +325,16 @@ udav_attach(device_t parent, device_t se skipmii: /* attach the interface */ - if_attach(ifp); + if_initialize(ifp); + sc->sc_ipq = if_percpuq_create(&sc->sc_ec.ec_if); ether_ifattach(ifp, eaddr); + if_register(ifp); rnd_attach_source(&sc->rnd_source, device_xname(self), RND_TYPE_NET, RND_FLAG_DEFAULT); callout_init(&sc->sc_stat_ch, 0); sc->sc_attached = 1; - splx(s); usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, dev, sc->sc_dev); @@ -635,19 +642,29 @@ Static int udav_init(struct ifnet *ifp) { struct udav_softc *sc = ifp->if_softc; + + mutex_enter(&sc->sc_lock); + int ret = udav_init_locked(ifp); + mutex_exit(&sc->sc_lock); + + return ret; +} + +Static int +udav_init_locked(struct ifnet *ifp) +{ + struct udav_softc *sc = ifp->if_softc; struct mii_data *mii = GET_MII(sc); uint8_t eaddr[ETHER_ADDR_LEN]; - int rc, s; + int rc; DPRINTF(("%s: %s: enter\n", device_xname(sc->sc_dev), __func__)); if (sc->sc_dying) return EIO; - s = splnet(); - /* Cancel pending I/O and free all TX/RX buffers */ - udav_stop(ifp, 1); + udav_stop_locked(ifp, 1); memcpy(eaddr, CLLADDR(ifp->if_sadl), sizeof(eaddr)); udav_csr_write(sc, UDAV_PAR, eaddr, ETHER_ADDR_LEN); @@ -678,11 +695,10 @@ udav_init(struct ifnet *ifp) if ((rc = mii_mediachg(mii)) == ENXIO) rc = 0; else if (rc != 0) - goto out; + return rc; if (sc->sc_pipe_tx == NULL || sc->sc_pipe_rx == NULL) { if (udav_openpipes(sc)) { - splx(s); return EIO; } } @@ -690,15 +706,13 @@ udav_init(struct ifnet *ifp) /* Initialize transmit ring */ if (udav_tx_list_init(sc)) { printf("%s: tx list init failed\n", device_xname(sc->sc_dev)); - splx(s); - return EIO; + goto fail; } /* Initialize receive ring */ if (udav_rx_list_init(sc)) { printf("%s: rx list init failed\n", device_xname(sc->sc_dev)); - splx(s); - return EIO; + goto fail1; } /* Start up the receive pipe. */ @@ -716,9 +730,11 @@ udav_init(struct ifnet *ifp) callout_reset(&sc->sc_stat_ch, hz, udav_tick, sc); -out: - splx(s); return rc; +fail1: + udav_tx_list_free(sc); +fail: + return EIO; } Static void @@ -861,6 +877,7 @@ udav_openpipes(struct udav_softc *sc) err = usbd_open_pipe(sc->sc_ctl_iface, sc->sc_bulkout_no, USBD_EXCLUSIVE_USE, &sc->sc_pipe_tx); if (err) { + usbd_close_pipe(sc->sc_pipe_rx); printf("%s: open tx pipe failed: %s\n", device_xname(sc->sc_dev), usbd_errstr(err)); error = EIO; @@ -951,6 +968,21 @@ udav_rx_list_init(struct udav_softc *sc) return 0; } +Static void +udav_rx_list_free(struct udav_softc *sc) +{ + for (int i = 0; i < UDAV_RX_LIST_CNT; i++) { + if (sc->sc_cdata.udav_rx_chain[i].udav_mbuf != NULL) { + m_freem(sc->sc_cdata.udav_rx_chain[i].udav_mbuf); + sc->sc_cdata.udav_rx_chain[i].udav_mbuf = NULL; + } + if (sc->sc_cdata.udav_rx_chain[i].udav_xfer != NULL) { + usbd_destroy_xfer(sc->sc_cdata.udav_rx_chain[i].udav_xfer); + sc->sc_cdata.udav_rx_chain[i].udav_xfer = NULL; + } + } +} + Static int udav_tx_list_init(struct udav_softc *sc) { @@ -979,8 +1011,34 @@ udav_tx_list_init(struct udav_softc *sc) } Static void +udav_tx_list_free(struct udav_softc *sc) +{ + for (int i = 0; i < UDAV_TX_LIST_CNT; i++) { + if (sc->sc_cdata.udav_tx_chain[i].udav_mbuf != NULL) { + m_freem(sc->sc_cdata.udav_tx_chain[i].udav_mbuf); + sc->sc_cdata.udav_tx_chain[i].udav_mbuf = NULL; + } + if (sc->sc_cdata.udav_tx_chain[i].udav_xfer != NULL) { + usbd_destroy_xfer(sc->sc_cdata.udav_tx_chain[i].udav_xfer); + sc->sc_cdata.udav_tx_chain[i].udav_xfer = NULL; + } + } +} + +Static void udav_start(struct ifnet *ifp) { + struct udav_softc * const sc = ifp->if_softc; + KASSERT(ifp->if_extflags & IFEF_START_MPSAFE); + + mutex_enter(&sc->sc_txlock); + udav_start_locked(ifp); + mutex_exit(&sc->sc_txlock); +} + +Static void +udav_start_locked(struct ifnet *ifp) +{ struct udav_softc *sc = ifp->if_softc; struct mbuf *m_head = NULL; @@ -1001,7 +1059,6 @@ udav_start(struct ifnet *ifp) return; if (udav_send(sc, m_head, 0)) { - ifp->if_flags |= IFF_OACTIVE; return; } @@ -1124,7 +1181,6 @@ udav_rxeof(struct usbd_xfer *xfer, void struct mbuf *m; uint32_t total_len; uint8_t *pktstat; - int s; DPRINTF(("%s: %s: enter\n", device_xname(sc->sc_dev),__func__)); @@ -1182,21 +1238,16 @@ udav_rxeof(struct usbd_xfer *xfer, void m->m_pkthdr.len = m->m_len = total_len; m_set_rcvif(m, ifp); - s = splnet(); - if (udav_newbuf(sc, c, NULL) == ENOBUFS) { ifp->if_ierrors++; - goto done1; + goto done; } bpf_mtap(ifp, m); DPRINTF(("%s: %s: deliver %d\n", device_xname(sc->sc_dev), __func__, m->m_len)); - if_percpuq_enqueue((ifp)->if_percpuq, (m)); - - done1: - splx(s); + if_percpuq_enqueue(sc->sc_ipq, (m)); done: /* Setup new transfer */ @@ -1270,19 +1321,28 @@ udav_stop_task(struct udav_softc *sc) udav_stop(GET_IFP(sc), 1); } -/* Stop the adapter and free any mbufs allocated to the RX and TX lists. */ Static void udav_stop(struct ifnet *ifp, int disable) { + struct udav_softc * const sc = ifp->if_softc; + + mutex_enter(&sc->sc_lock); + udav_stop_locked(ifp, disable); + mutex_exit(&sc->sc_lock); +} + +/* Stop the adapter and free any mbufs allocated to the RX and TX lists. */ +Static void +udav_stop_locked(struct ifnet *ifp, int disable) +{ struct udav_softc *sc = ifp->if_softc; usbd_status err; - int i; DPRINTF(("%s: %s: enter\n", device_xname(sc->sc_dev), __func__)); ifp->if_timer = 0; - udav_reset(sc); +// udav_reset(sc); callout_stop(&sc->sc_stat_ch); @@ -1319,29 +1379,9 @@ udav_stop(struct ifnet *ifp, int disable } #endif - /* Free RX resources. */ - for (i = 0; i < UDAV_RX_LIST_CNT; i++) { - if (sc->sc_cdata.udav_rx_chain[i].udav_mbuf != NULL) { - m_freem(sc->sc_cdata.udav_rx_chain[i].udav_mbuf); - sc->sc_cdata.udav_rx_chain[i].udav_mbuf = NULL; - } - if (sc->sc_cdata.udav_rx_chain[i].udav_xfer != NULL) { - usbd_destroy_xfer(sc->sc_cdata.udav_rx_chain[i].udav_xfer); - sc->sc_cdata.udav_rx_chain[i].udav_xfer = NULL; - } - } + udav_rx_list_free(sc); - /* Free TX resources. */ - for (i = 0; i < UDAV_TX_LIST_CNT; i++) { - if (sc->sc_cdata.udav_tx_chain[i].udav_mbuf != NULL) { - m_freem(sc->sc_cdata.udav_tx_chain[i].udav_mbuf); - sc->sc_cdata.udav_tx_chain[i].udav_mbuf = NULL; - } - if (sc->sc_cdata.udav_tx_chain[i].udav_xfer != NULL) { - usbd_destroy_xfer(sc->sc_cdata.udav_tx_chain[i].udav_xfer); - sc->sc_cdata.udav_tx_chain[i].udav_xfer = NULL; - } - } + udav_tx_list_free(sc); /* Close pipes */ /* RX endpoint */ Index: src/sys/dev/usb/if_udavreg.h diff -u src/sys/dev/usb/if_udavreg.h:1.9.16.4 src/sys/dev/usb/if_udavreg.h:1.9.16.5 --- src/sys/dev/usb/if_udavreg.h:1.9.16.4 Sun Mar 20 08:42:19 2016 +++ src/sys/dev/usb/if_udavreg.h Mon Dec 12 13:15:39 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: if_udavreg.h,v 1.9.16.4 2016/03/20 08:42:19 skrll Exp $ */ +/* $NetBSD: if_udavreg.h,v 1.9.16.5 2016/12/12 13:15:39 skrll Exp $ */ /* $nabe: if_udavreg.h,v 1.2 2003/08/21 16:26:40 nabe Exp $ */ /* * Copyright (c) 2003 @@ -189,6 +189,9 @@ struct udav_softc { struct ethercom sc_ec; /* ethernet common */ struct mii_data sc_mii; kmutex_t sc_mii_lock; + kmutex_t sc_lock; + kmutex_t sc_txlock; + kmutex_t sc_rxlock; int sc_link; #define sc_media udav_mii.mii_media krndsource_t rnd_source; @@ -202,4 +205,6 @@ struct udav_softc { struct usb_task sc_stop_task; uint16_t sc_flags; + + struct if_percpuq * sc_ipq; };