Module Name: src
Committed By: mlelstv
Date: Sat Sep 8 13:10:08 UTC 2018
Modified Files:
src/sys/dev/usb: if_smsc.c if_smscvar.h
Log Message:
Make smsc(4) MPSAFE. Patch from skrll@.
To generate a diff of this commit:
cvs rdiff -u -r1.37 -r1.38 src/sys/dev/usb/if_smsc.c
cvs rdiff -u -r1.5 -r1.6 src/sys/dev/usb/if_smscvar.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_smsc.c
diff -u src/sys/dev/usb/if_smsc.c:1.37 src/sys/dev/usb/if_smsc.c:1.38
--- src/sys/dev/usb/if_smsc.c:1.37 Sun Aug 12 06:02:38 2018
+++ src/sys/dev/usb/if_smsc.c Sat Sep 8 13:10:08 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: if_smsc.c,v 1.37 2018/08/12 06:02:38 rin Exp $ */
+/* $NetBSD: if_smsc.c,v 1.38 2018/09/08 13:10:08 mlelstv Exp $ */
/* $OpenBSD: if_smsc.c,v 1.4 2012/09/27 12:38:11 jsg Exp $ */
/* $FreeBSD: src/sys/dev/usb/net/if_smsc.c,v 1.1 2012/08/15 04:03:55 gonzo Exp $ */
@@ -61,7 +61,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_smsc.c,v 1.37 2018/08/12 06:02:38 rin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_smsc.c,v 1.38 2018/09/08 13:10:08 mlelstv Exp $");
#ifdef _KERNEL_OPT
#include "opt_usb.h"
@@ -70,17 +70,15 @@ __KERNEL_RCSID(0, "$NetBSD: if_smsc.c,v
#include <sys/param.h>
#include <sys/bus.h>
-#include <sys/systm.h>
-#include <sys/sockio.h>
+#include <sys/device.h>
+#include <sys/kernel.h>
#include <sys/mbuf.h>
#include <sys/mutex.h>
-#include <sys/kernel.h>
#include <sys/proc.h>
-#include <sys/socket.h>
-
-#include <sys/device.h>
-
#include <sys/rndsource.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/systm.h>
#include <net/if.h>
#include <net/if_dl.h>
@@ -164,9 +162,12 @@ int smsc_detach(device_t, int);
int smsc_activate(device_t, enum devact);
int smsc_init(struct ifnet *);
+int smsc_init_locked(struct ifnet *);
void smsc_start(struct ifnet *);
+void smsc_start_locked(struct ifnet *);
int smsc_ioctl(struct ifnet *, u_long, void *);
void smsc_stop(struct ifnet *, int);
+void smsc_stop_locked(struct ifnet *, int);
void smsc_reset(struct smsc_softc *);
struct mbuf *smsc_newbuf(void);
@@ -174,6 +175,7 @@ struct mbuf *smsc_newbuf(void);
void smsc_tick(void *);
void smsc_tick_task(void *);
void smsc_miibus_statchg(struct ifnet *);
+void smsc_miibus_statchg_locked(struct ifnet *);
int smsc_miibus_readreg(device_t, int, int);
void smsc_miibus_writereg(device_t, int, int, int);
int smsc_ifmedia_upd(struct ifnet *);
@@ -182,7 +184,9 @@ void smsc_lock_mii(struct smsc_softc *
void smsc_unlock_mii(struct smsc_softc *);
int smsc_tx_list_init(struct smsc_softc *);
+void smsc_tx_list_free(struct smsc_softc *);
int smsc_rx_list_init(struct smsc_softc *);
+void smsc_rx_list_free(struct smsc_softc *);
int smsc_encap(struct smsc_softc *, struct mbuf *, int);
void smsc_rxeof(struct usbd_xfer *, void *, usbd_status);
void smsc_txeof(struct usbd_xfer *, void *, usbd_status);
@@ -259,7 +263,7 @@ smsc_wait_for_bits(struct smsc_softc *sc
int
smsc_miibus_readreg(device_t dev, int phy, int reg)
{
- struct smsc_softc *sc = device_private(dev);
+ struct smsc_softc * const sc = device_private(dev);
uint32_t addr;
uint32_t val = 0;
@@ -286,7 +290,7 @@ done:
void
smsc_miibus_writereg(device_t dev, int phy, int reg, int val)
{
- struct smsc_softc *sc = device_private(dev);
+ struct smsc_softc * const sc = device_private(dev);
uint32_t addr;
if (sc->sc_phyno != phy)
@@ -312,15 +316,37 @@ smsc_miibus_writereg(device_t dev, int p
void
smsc_miibus_statchg(struct ifnet *ifp)
{
- struct smsc_softc *sc = ifp->if_softc;
- struct mii_data *mii = &sc->sc_mii;
+ if (ifp == NULL)
+ return;
+
+ struct smsc_softc * const sc = ifp->if_softc;
+
+ mutex_enter(&sc->sc_lock);
+ if (sc->sc_dying) {
+ mutex_exit(&sc->sc_lock);
+ return;
+ }
+ smsc_miibus_statchg_locked(ifp);
+
+ mutex_exit(&sc->sc_lock);
+}
+
+
+void
+smsc_miibus_statchg_locked(struct ifnet *ifp)
+{
+ struct smsc_softc * const sc = ifp->if_softc;
+ struct mii_data * const mii = &sc->sc_mii;
int err;
uint32_t flow;
uint32_t afc_cfg;
- if (mii == NULL || ifp == NULL ||
- (ifp->if_flags & IFF_RUNNING) == 0)
+ KASSERT(mutex_owned(&sc->sc_lock));
+
+ if ((ifp->if_flags & IFF_RUNNING) == 0) {
+ smsc_dbg_printf(sc, "%s: not running\n", __func__);
return;
+ }
/* Use the MII status to determine link status */
sc->sc_flags &= ~SMSC_FLAG_LINK;
@@ -386,8 +412,8 @@ smsc_miibus_statchg(struct ifnet *ifp)
int
smsc_ifmedia_upd(struct ifnet *ifp)
{
- struct smsc_softc *sc = ifp->if_softc;
- struct mii_data *mii = &sc->sc_mii;
+ struct smsc_softc * const sc = ifp->if_softc;
+ struct mii_data * const mii = &sc->sc_mii;
int err;
if (mii->mii_instance) {
@@ -403,13 +429,17 @@ smsc_ifmedia_upd(struct ifnet *ifp)
void
smsc_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
{
- struct smsc_softc *sc = ifp->if_softc;
- struct mii_data *mii = &sc->sc_mii;
+ struct smsc_softc * const sc = ifp->if_softc;
+ struct mii_data * const mii = &sc->sc_mii;
+
+ /* SMSC_LOCK */
mii_pollstat(mii);
ifmr->ifm_active = mii->mii_media_active;
ifmr->ifm_status = mii->mii_media_status;
+
+ /* SMSC_UNLOCK */
}
static inline uint32_t
@@ -422,11 +452,13 @@ smsc_hash(uint8_t addr[ETHER_ADDR_LEN])
void
smsc_setmulti(struct smsc_softc *sc)
{
- struct ifnet *ifp = &sc->sc_ec.ec_if;
- struct ether_multi *enm;
- struct ether_multistep step;
- uint32_t hashtbl[2] = { 0, 0 };
- uint32_t hash;
+ struct ifnet * const ifp = &sc->sc_ec.ec_if;
+ struct ether_multi *enm;
+ struct ether_multistep step;
+ uint32_t hashtbl[2] = { 0, 0 };
+ uint32_t hash;
+
+ KASSERT(mutex_owned(&sc->sc_lock));
if (sc->sc_dying)
return;
@@ -443,16 +475,19 @@ allmulti:
sc->sc_mac_csr &= ~(SMSC_MAC_CSR_PRMS | SMSC_MAC_CSR_MCPAS);
}
+ ETHER_LOCK(&sc->sc_ec);
ETHER_FIRST_MULTI(step, &sc->sc_ec, enm);
while (enm != NULL) {
- if (memcmp(enm->enm_addrlo, enm->enm_addrhi,
- ETHER_ADDR_LEN) != 0)
+ if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) {
+ ETHER_UNLOCK(&sc->sc_ec);
goto allmulti;
+ }
hash = smsc_hash(enm->enm_addrlo);
hashtbl[hash >> 5] |= 1 << (hash & 0x1F);
ETHER_NEXT_MULTI(step, enm);
}
+ ETHER_UNLOCK(&sc->sc_ec);
/* Debug */
if (sc->sc_mac_csr & SMSC_MAC_CSR_HPFILT) {
@@ -471,13 +506,10 @@ allmulti:
int
smsc_sethwcsum(struct smsc_softc *sc)
{
- struct ifnet *ifp = &sc->sc_ec.ec_if;
+ struct ifnet * const ifp = &sc->sc_ec.ec_if;
uint32_t val;
int err;
- if (!ifp)
- return EIO;
-
err = smsc_read_reg(sc, SMSC_COE_CTRL, &val);
if (err != 0) {
smsc_warn_printf(sc, "failed to read SMSC_COE_CTRL (err=%d)\n",
@@ -533,6 +565,7 @@ done:
void
smsc_reset(struct smsc_softc *sc)
{
+ KASSERT(mutex_owned(&sc->sc_lock));
if (sc->sc_dying)
return;
@@ -546,19 +579,26 @@ smsc_reset(struct smsc_softc *sc)
int
smsc_init(struct ifnet *ifp)
{
- struct smsc_softc *sc = ifp->if_softc;
- struct smsc_chain *c;
- usbd_status err;
- int s, i;
+ struct smsc_softc * const sc = ifp->if_softc;
+
+ mutex_enter(&sc->sc_lock);
+ int ret = smsc_init_locked(ifp);
+ mutex_exit(&sc->sc_lock);
+
+ return ret;
+}
+
+int
+smsc_init_locked(struct ifnet *ifp)
+{
+ struct smsc_softc * const sc = ifp->if_softc;
+ usbd_status err;
if (sc->sc_dying)
return EIO;
- s = splnet();
-
/* Cancel pending I/O */
- if (ifp->if_flags & IFF_RUNNING)
- smsc_stop(ifp, 1);
+ smsc_stop_locked(ifp, 1);
/* Reset the ethernet interface. */
smsc_reset(sc);
@@ -571,83 +611,122 @@ smsc_init(struct ifnet *ifp)
/* Open RX and TX pipes. */
err = usbd_open_pipe(sc->sc_iface, sc->sc_ed[SMSC_ENDPT_RX],
- USBD_EXCLUSIVE_USE, &sc->sc_ep[SMSC_ENDPT_RX]);
+ USBD_EXCLUSIVE_USE | USBD_MPSAFE, &sc->sc_ep[SMSC_ENDPT_RX]);
if (err) {
printf("%s: open rx pipe failed: %s\n",
device_xname(sc->sc_dev), usbd_errstr(err));
- splx(s);
- return EIO;
+ goto fail;
}
err = usbd_open_pipe(sc->sc_iface, sc->sc_ed[SMSC_ENDPT_TX],
- USBD_EXCLUSIVE_USE, &sc->sc_ep[SMSC_ENDPT_TX]);
+ USBD_EXCLUSIVE_USE | USBD_MPSAFE, &sc->sc_ep[SMSC_ENDPT_TX]);
if (err) {
printf("%s: open tx pipe failed: %s\n",
device_xname(sc->sc_dev), usbd_errstr(err));
- splx(s);
- return EIO;
+ goto fail1;
}
/* Init RX ring. */
if (smsc_rx_list_init(sc)) {
aprint_error_dev(sc->sc_dev, "rx list init failed\n");
- splx(s);
- return EIO;
+ goto fail2;
}
/* Init TX ring. */
if (smsc_tx_list_init(sc)) {
aprint_error_dev(sc->sc_dev, "tx list init failed\n");
- splx(s);
- return EIO;
+ goto fail3;
}
+ mutex_enter(&sc->sc_rxlock);
+ mutex_enter(&sc->sc_txlock);
+ sc->sc_stopping = false;
+
/* Start up the receive pipe. */
- for (i = 0; i < SMSC_RX_LIST_CNT; i++) {
- c = &sc->sc_cdata.rx_chain[i];
+ for (size_t i = 0; i < SMSC_RX_LIST_CNT; i++) {
+ struct smsc_chain * const c = &sc->sc_cdata.rx_chain[i];
usbd_setup_xfer(c->sc_xfer, c, c->sc_buf, sc->sc_bufsz,
USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, smsc_rxeof);
usbd_transfer(c->sc_xfer);
}
+ mutex_exit(&sc->sc_txlock);
+ mutex_exit(&sc->sc_rxlock);
+
/* Indicate we are up and running. */
ifp->if_flags |= IFF_RUNNING;
ifp->if_flags &= ~IFF_OACTIVE;
- splx(s);
-
callout_reset(&sc->sc_stat_ch, hz, smsc_tick, sc);
return 0;
+
+fail3:
+ smsc_rx_list_free(sc);
+fail2:
+ usbd_close_pipe(sc->sc_ep[SMSC_ENDPT_TX]);
+fail1:
+ usbd_close_pipe(sc->sc_ep[SMSC_ENDPT_RX]);
+fail:
+ return EIO;
}
void
smsc_start(struct ifnet *ifp)
{
- struct smsc_softc *sc = ifp->if_softc;
- struct mbuf *m_head = NULL;
+ struct smsc_softc * const sc = ifp->if_softc;
+ KASSERT(ifp->if_extflags & IFEF_MPSAFE);
+
+ mutex_enter(&sc->sc_txlock);
+ if (!sc->sc_stopping)
+ smsc_start_locked(ifp);
+ mutex_exit(&sc->sc_txlock);
+}
+
+void
+smsc_start_locked(struct ifnet *ifp)
+{
+ struct smsc_softc * const sc = ifp->if_softc;
+ struct mbuf *m_head = NULL;
+
+ KASSERT(mutex_owned(&sc->sc_txlock));
/* Don't send anything if there is no link or controller is busy. */
if ((sc->sc_flags & SMSC_FLAG_LINK) == 0) {
+ smsc_dbg_printf(sc, "%s: no link\n", __func__);
+ return;
+ }
+
+ /* Any free USB transfers? */
+ if (sc->sc_cdata.tx_free == 0) {
+ smsc_dbg_printf(sc, "%s: all USB transfers in use\n", __func__);
return;
}
- if ((ifp->if_flags & (IFF_OACTIVE|IFF_RUNNING)) != IFF_RUNNING)
+ if ((ifp->if_flags & (IFF_OACTIVE|IFF_RUNNING)) != IFF_RUNNING) {
+ smsc_dbg_printf(sc, "%s: not running\n", __func__);
return;
+ }
IFQ_POLL(&ifp->if_snd, m_head);
if (m_head == NULL)
return;
- if (smsc_encap(sc, m_head, 0)) {
- ifp->if_flags |= IFF_OACTIVE;
+ sc->sc_cdata.tx_free--;
+
+ IFQ_DEQUEUE(&ifp->if_snd, m_head);
+ if (smsc_encap(sc, m_head, sc->sc_cdata.tx_next)) {
+ m_free(m_head);
+ sc->sc_cdata.tx_free++;
return;
}
- IFQ_DEQUEUE(&ifp->if_snd, m_head);
+
+ sc->sc_cdata.tx_next = (sc->sc_cdata.tx_next + 1) % SMSC_TX_LIST_CNT;
bpf_mtap(ifp, m_head, BPF_D_OUT);
- ifp->if_flags |= IFF_OACTIVE;
+ if (sc->sc_cdata.tx_free == 0)
+ ifp->if_flags |= IFF_OACTIVE;
/*
* Set a timeout in case the chip goes out to lunch.
@@ -658,29 +737,48 @@ smsc_start(struct ifnet *ifp)
void
smsc_tick(void *xsc)
{
- struct smsc_softc *sc = xsc;
+ struct smsc_softc * const sc = xsc;
if (sc == NULL)
return;
- if (sc->sc_dying)
+ mutex_enter(&sc->sc_lock);
+
+ if (sc->sc_dying) {
+ mutex_exit(&sc->sc_lock);
return;
+ }
- usb_add_task(sc->sc_udev, &sc->sc_tick_task, USB_TASKQ_DRIVER);
+ if (!sc->sc_ttpending) {
+ sc->sc_ttpending = true;
+ usb_add_task(sc->sc_udev, &sc->sc_tick_task, USB_TASKQ_DRIVER);
+ }
+
+ mutex_exit(&sc->sc_lock);
}
void
smsc_stop(struct ifnet *ifp, int disable)
{
- usbd_status err;
- struct smsc_softc *sc = ifp->if_softc;
- int i;
+ struct smsc_softc * const sc = ifp->if_softc;
- smsc_reset(sc);
+ mutex_enter(&sc->sc_lock);
+ smsc_stop_locked(ifp, disable);
+ mutex_exit(&sc->sc_lock);
+}
- ifp = &sc->sc_ec.ec_if;
- ifp->if_timer = 0;
- ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+void
+smsc_stop_locked(struct ifnet *ifp, int disable)
+{
+ struct smsc_softc * const sc = ifp->if_softc;
+ usbd_status err;
+
+ KASSERT(mutex_owned(&sc->sc_lock));
+ mutex_enter(&sc->sc_rxlock);
+ mutex_enter(&sc->sc_txlock);
+ sc->sc_stopping = true;
+ mutex_exit(&sc->sc_txlock);
+ mutex_exit(&sc->sc_rxlock);
callout_stop(&sc->sc_stat_ch);
@@ -709,29 +807,10 @@ smsc_stop(struct ifnet *ifp, int disable
}
}
- /* Free RX resources. */
- for (i = 0; i < SMSC_RX_LIST_CNT; i++) {
- if (sc->sc_cdata.rx_chain[i].sc_mbuf != NULL) {
- m_freem(sc->sc_cdata.rx_chain[i].sc_mbuf);
- sc->sc_cdata.rx_chain[i].sc_mbuf = NULL;
- }
- if (sc->sc_cdata.rx_chain[i].sc_xfer != NULL) {
- usbd_destroy_xfer(sc->sc_cdata.rx_chain[i].sc_xfer);
- sc->sc_cdata.rx_chain[i].sc_xfer = NULL;
- }
- }
+ smsc_rx_list_free(sc);
+
+ smsc_tx_list_free(sc);
- /* Free TX resources. */
- for (i = 0; i < SMSC_TX_LIST_CNT; i++) {
- if (sc->sc_cdata.tx_chain[i].sc_mbuf != NULL) {
- m_freem(sc->sc_cdata.tx_chain[i].sc_mbuf);
- sc->sc_cdata.tx_chain[i].sc_mbuf = NULL;
- }
- if (sc->sc_cdata.tx_chain[i].sc_xfer != NULL) {
- usbd_destroy_xfer(sc->sc_cdata.tx_chain[i].sc_xfer);
- sc->sc_cdata.tx_chain[i].sc_xfer = NULL;
- }
- }
/* Close pipes */
if (sc->sc_ep[SMSC_ENDPT_RX] != NULL) {
err = usbd_close_pipe(sc->sc_ep[SMSC_ENDPT_RX]);
@@ -759,6 +838,13 @@ smsc_stop(struct ifnet *ifp, int disable
}
sc->sc_ep[SMSC_ENDPT_INTR] = NULL;
}
+
+ ifp->if_timer = 0;
+ ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+
+ if (disable) {
+ /* drain */
+ }
}
int
@@ -790,7 +876,7 @@ smsc_chip_init(struct smsc_softc *sc)
usbd_delay_ms(sc->sc_udev, 40);
/* Set the mac address */
- struct ifnet *ifp = &sc->sc_ec.ec_if;
+ struct ifnet * const ifp = &sc->sc_ec.ec_if;
const char *eaddr = CLLADDR(ifp->if_sadl);
if ((err = smsc_setmacaddress(sc, eaddr)) != 0) {
smsc_warn_printf(sc, "failed to set the MAC address\n");
@@ -909,67 +995,64 @@ init_failed:
return err;
}
-int
-smsc_ioctl(struct ifnet *ifp, u_long cmd, void *data)
+static int
+smsc_ifflags_cb(struct ethercom *ec)
{
- struct smsc_softc *sc = ifp->if_softc;
- struct ifreq /*const*/ *ifr = data;
- int s, error = 0;
+ struct ifnet *ifp = &ec->ec_if;
+ struct smsc_softc *sc = ifp->if_softc;
- if (sc->sc_dying)
- return EIO;
+ mutex_enter(&sc->sc_lock);
- s = splnet();
+ const int change = ifp->if_flags ^ sc->sc_if_flags;
+ if ((change & ~(IFF_CANTCHANGE | IFF_DEBUG)) != 0) {
+ mutex_exit(&sc->sc_lock);
+ return ENETRESET;
+ }
- switch(cmd) {
- case SIOCSIFFLAGS:
- if ((error = ifioctl_common(ifp, cmd, data)) != 0)
- break;
-
- switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
- case IFF_RUNNING:
- smsc_stop(ifp, 1);
- break;
- case IFF_UP:
- smsc_init(ifp);
- break;
- case IFF_UP | IFF_RUNNING:
- if (ifp->if_flags & IFF_PROMISC &&
- !(sc->sc_if_flags & IFF_PROMISC)) {
- sc->sc_mac_csr |= SMSC_MAC_CSR_PRMS;
- smsc_write_reg(sc, SMSC_MAC_CSR,
- sc->sc_mac_csr);
- smsc_setmulti(sc);
- } else if (!(ifp->if_flags & IFF_PROMISC) &&
- sc->sc_if_flags & IFF_PROMISC) {
- sc->sc_mac_csr &= ~SMSC_MAC_CSR_PRMS;
- smsc_write_reg(sc, SMSC_MAC_CSR,
- sc->sc_mac_csr);
- smsc_setmulti(sc);
- } else {
- smsc_init(ifp);
- }
- break;
+ smsc_dbg_printf(sc, "%s: change %x\n", __func__, change);
+
+ if ((change & IFF_PROMISC) != 0) {
+ if (ifp->if_flags & IFF_PROMISC) {
+ sc->sc_mac_csr |= SMSC_MAC_CSR_PRMS;
+ smsc_write_reg(sc, SMSC_MAC_CSR, sc->sc_mac_csr);
+ } else if (!(ifp->if_flags & IFF_PROMISC)) {
+ sc->sc_mac_csr &= ~SMSC_MAC_CSR_PRMS;
+ smsc_write_reg(sc, SMSC_MAC_CSR, sc->sc_mac_csr);
}
- sc->sc_if_flags = ifp->if_flags;
- break;
+ smsc_setmulti(sc);
+ }
- case SIOCGIFMEDIA:
- case SIOCSIFMEDIA:
- error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, cmd);
- break;
+ mutex_exit(&sc->sc_lock);
- default:
- if ((error = ether_ioctl(ifp, cmd, data)) != ENETRESET)
- break;
+ return 0;
+}
- error = 0;
- if (cmd == SIOCADDMULTI || cmd == SIOCDELMULTI)
- smsc_setmulti(sc);
+int
+smsc_ioctl(struct ifnet *ifp, u_long cmd, void *data)
+{
+ struct smsc_softc * const sc = ifp->if_softc;
+
+ smsc_dbg_printf(sc, "%s: cmd %0lx data %p\n", __func__, cmd, data);
+
+ int error = ether_ioctl(ifp, cmd, data);
+ if (error == ENETRESET) {
+ error = 0;
+ if (cmd == SIOCADDMULTI || cmd == SIOCDELMULTI) {
+ if (ifp->if_flags & IFF_RUNNING) {
+ mutex_enter(&sc->sc_lock);
+ smsc_setmulti(sc);
+ mutex_exit(&sc->sc_lock);
+ }
+ }
}
- splx(s);
+
+ mutex_enter(&sc->sc_rxlock);
+ mutex_enter(&sc->sc_txlock);
+ sc->sc_if_flags = ifp->if_flags;
+ mutex_exit(&sc->sc_txlock);
+ mutex_exit(&sc->sc_rxlock);
return error;
}
@@ -994,11 +1077,12 @@ smsc_attach(device_t parent, device_t se
char *devinfop;
struct mii_data *mii;
struct ifnet *ifp;
- int err, s, i;
+ int err, i;
uint32_t mac_h, mac_l;
sc->sc_dev = self;
sc->sc_udev = dev;
+ sc->sc_stopping = false;
aprint_naive("\n");
aprint_normal("\n");
@@ -1013,11 +1097,8 @@ smsc_attach(device_t parent, device_t se
", err=%s\n", usbd_errstr(err));
return;
}
- /* Setup the endpoints for the SMSC LAN95xx device(s) */
- usb_init_task(&sc->sc_tick_task, smsc_tick_task, sc, 0);
- usb_init_task(&sc->sc_stop_task, (void (*)(void *))smsc_stop, sc, 0);
- mutex_init(&sc->sc_mii_lock, MUTEX_DEFAULT, IPL_NONE);
+ /* Setup the endpoints for the SMSC LAN95xx device(s) */
err = usbd_device2interface_handle(dev, SMSC_IFACE_IDX, &sc->sc_iface);
if (err) {
aprint_error_dev(self, "getting interface handle failed\n");
@@ -1050,12 +1131,18 @@ smsc_attach(device_t parent, device_t se
}
}
- s = splnet();
+ usb_init_task(&sc->sc_tick_task, smsc_tick_task, sc, USB_TASKQ_MPSAFE);
+
+ 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);
+ mutex_init(&sc->sc_mii_lock, MUTEX_DEFAULT, IPL_NONE);
ifp = &sc->sc_ec.ec_if;
ifp->if_softc = sc;
strlcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ);
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifp->if_extflags = IFEF_MPSAFE;
ifp->if_init = smsc_init;
ifp->if_ioctl = smsc_ioctl;
ifp->if_start = smsc_start;
@@ -1090,19 +1177,21 @@ smsc_attach(device_t parent, device_t se
KASSERT(prop_data_size(eaprop) == ETHER_ADDR_LEN);
memcpy(sc->sc_enaddr, prop_data_data_nocopy(eaprop),
ETHER_ADDR_LEN);
- } else
- /* Check if there is already a MAC address in the register */
- if ((smsc_read_reg(sc, SMSC_MAC_ADDRL, &mac_l) == 0) &&
- (smsc_read_reg(sc, SMSC_MAC_ADDRH, &mac_h) == 0)) {
- sc->sc_enaddr[5] = (uint8_t)((mac_h >> 8) & 0xff);
- sc->sc_enaddr[4] = (uint8_t)((mac_h) & 0xff);
- sc->sc_enaddr[3] = (uint8_t)((mac_l >> 24) & 0xff);
- sc->sc_enaddr[2] = (uint8_t)((mac_l >> 16) & 0xff);
- sc->sc_enaddr[1] = (uint8_t)((mac_l >> 8) & 0xff);
- sc->sc_enaddr[0] = (uint8_t)((mac_l) & 0xff);
+ } else {
+ /* Check if there is already a MAC address in the register */
+ if ((smsc_read_reg(sc, SMSC_MAC_ADDRL, &mac_l) == 0) &&
+ (smsc_read_reg(sc, SMSC_MAC_ADDRH, &mac_h) == 0)) {
+ sc->sc_enaddr[5] = (uint8_t)((mac_h >> 8) & 0xff);
+ sc->sc_enaddr[4] = (uint8_t)((mac_h) & 0xff);
+ sc->sc_enaddr[3] = (uint8_t)((mac_l >> 24) & 0xff);
+ sc->sc_enaddr[2] = (uint8_t)((mac_l >> 16) & 0xff);
+ sc->sc_enaddr[1] = (uint8_t)((mac_l >> 8) & 0xff);
+ sc->sc_enaddr[0] = (uint8_t)((mac_l) & 0xff);
+ }
}
- aprint_normal_dev(self, "Ethernet address %s\n", ether_sprintf(sc->sc_enaddr));
+ aprint_normal_dev(self, "Ethernet address %s\n",
+ ether_sprintf(sc->sc_enaddr));
IFQ_SET_READY(&ifp->if_snd);
@@ -1123,16 +1212,17 @@ smsc_attach(device_t parent, device_t se
} else
ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_AUTO);
- if_attach(ifp);
+ callout_init(&sc->sc_stat_ch, CALLOUT_MPSAFE);
+
+ if_initialize(ifp);
+ sc->sc_ipq = if_percpuq_create(&sc->sc_ec.ec_if);
ether_ifattach(ifp, sc->sc_enaddr);
+ ether_set_ifflags_cb(&sc->sc_ec, smsc_ifflags_cb);
+ if_register(ifp);
rnd_attach_source(&sc->sc_rnd_source, device_xname(sc->sc_dev),
RND_TYPE_NET, RND_FLAG_DEFAULT);
- callout_init(&sc->sc_stat_ch, 0);
-
- splx(s);
-
usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, sc->sc_dev);
}
@@ -1141,38 +1231,28 @@ smsc_detach(device_t self, int flags)
{
struct smsc_softc *sc = device_private(self);
struct ifnet *ifp = &sc->sc_ec.ec_if;
- int s;
+
+ mutex_enter(&sc->sc_lock);
+ sc->sc_dying = true;
+ mutex_exit(&sc->sc_lock);
callout_halt(&sc->sc_stat_ch, NULL);
- if (sc->sc_ep[SMSC_ENDPT_TX] != NULL)
- usbd_abort_pipe(sc->sc_ep[SMSC_ENDPT_TX]);
- if (sc->sc_ep[SMSC_ENDPT_RX] != NULL)
- usbd_abort_pipe(sc->sc_ep[SMSC_ENDPT_RX]);
- if (sc->sc_ep[SMSC_ENDPT_INTR] != NULL)
- usbd_abort_pipe(sc->sc_ep[SMSC_ENDPT_INTR]);
+ if (ifp->if_flags & IFF_RUNNING)
+ smsc_stop_locked(ifp, 1);
+ /*
+ * Remove any pending tasks. They cannot be executing because they run
+ * in the same thread as detach.
+ */
usb_rem_task_wait(sc->sc_udev, &sc->sc_tick_task, USB_TASKQ_DRIVER,
NULL);
- usb_rem_task_wait(sc->sc_udev, &sc->sc_stop_task, USB_TASKQ_DRIVER,
- NULL);
- s = splusb();
-
- if (--sc->sc_refcnt >= 0) {
+ mutex_enter(&sc->sc_lock);
+ sc->sc_refcnt--;
+ while (sc->sc_refcnt > 0) {
/* Wait for processes to go away */
- usb_detach_waitold(sc->sc_dev);
- }
-
- if (ifp->if_flags & IFF_RUNNING)
- smsc_stop(ifp ,1);
-
- rnd_detach_source(&sc->sc_rnd_source);
- mii_detach(&sc->sc_mii, MII_PHY_ANY, MII_OFFSET_ANY);
- ifmedia_delete_instance(&sc->sc_mii.mii_media, IFM_INST_ANY);
- if (ifp->if_softc != NULL) {
- ether_ifdetach(ifp);
- if_detach(ifp);
+ cv_wait(&sc->sc_detachcv, &sc->sc_lock);
}
#ifdef DIAGNOSTIC
@@ -1183,15 +1263,23 @@ smsc_detach(device_t self, int flags)
device_xname(sc->sc_dev));
#endif
- if (--sc->sc_refcnt >= 0) {
- /* Wait for processes to go away. */
- usb_detach_waitold(sc->sc_dev);
+ mutex_exit(&sc->sc_lock);
+
+ rnd_detach_source(&sc->sc_rnd_source);
+ mii_detach(&sc->sc_mii, MII_PHY_ANY, MII_OFFSET_ANY);
+ ifmedia_delete_instance(&sc->sc_mii.mii_media, IFM_INST_ANY);
+ if (ifp->if_softc != NULL) {
+ ether_ifdetach(ifp);
+ if_detach(ifp);
}
- splx(s);
usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, sc->sc_dev);
+ cv_destroy(&sc->sc_detachcv);
mutex_destroy(&sc->sc_mii_lock);
+ mutex_destroy(&sc->sc_rxlock);
+ mutex_destroy(&sc->sc_txlock);
+ mutex_destroy(&sc->sc_lock);
return 0;
}
@@ -1199,29 +1287,41 @@ smsc_detach(device_t self, int flags)
void
smsc_tick_task(void *xsc)
{
- int s;
- struct smsc_softc *sc = xsc;
- struct ifnet *ifp;
- struct mii_data *mii;
+ struct smsc_softc * const sc = xsc;
if (sc == NULL)
return;
- if (sc->sc_dying)
- return;
- ifp = &sc->sc_ec.ec_if;
- mii = &sc->sc_mii;
- if (mii == NULL)
+ mutex_enter(&sc->sc_lock);
+
+ if (sc->sc_dying) {
+ mutex_exit(&sc->sc_lock);
return;
+ }
+
+ struct ifnet * const ifp = &sc->sc_ec.ec_if;
+ struct mii_data * const mii = &sc->sc_mii;
- s = splnet();
+ sc->sc_refcnt++;
+ mutex_exit(&sc->sc_lock);
mii_tick(mii);
if ((sc->sc_flags & SMSC_FLAG_LINK) == 0)
smsc_miibus_statchg(ifp);
+
+ mutex_enter(&sc->sc_lock);
+ sc->sc_ttpending = false;
+
+ if (--sc->sc_refcnt < 0)
+ cv_broadcast(&sc->sc_detachcv);
+
+ if (sc->sc_dying) {
+ mutex_exit(&sc->sc_lock);
+ return;
+ }
callout_reset(&sc->sc_stat_ch, hz, smsc_tick, sc);
- splx(s);
+ mutex_exit(&sc->sc_lock);
}
int
@@ -1232,7 +1332,17 @@ smsc_activate(device_t self, enum devact
switch (act) {
case DVACT_DEACTIVATE:
if_deactivate(&sc->sc_ec.ec_if);
- sc->sc_dying = 1;
+
+ mutex_enter(&sc->sc_lock);
+ sc->sc_dying = true;
+
+ mutex_enter(&sc->sc_rxlock);
+ mutex_enter(&sc->sc_txlock);
+ sc->sc_stopping = true;
+ mutex_exit(&sc->sc_txlock);
+ mutex_exit(&sc->sc_rxlock);
+
+ mutex_exit(&sc->sc_lock);
return 0;
default:
return EOPNOTSUPP;
@@ -1243,40 +1353,52 @@ smsc_activate(device_t self, enum devact
void
smsc_lock_mii(struct smsc_softc *sc)
{
+
+ mutex_enter(&sc->sc_lock);
sc->sc_refcnt++;
+ mutex_exit(&sc->sc_lock);
+
mutex_enter(&sc->sc_mii_lock);
}
void
smsc_unlock_mii(struct smsc_softc *sc)
{
+
mutex_exit(&sc->sc_mii_lock);
+ mutex_enter(&sc->sc_lock);
if (--sc->sc_refcnt < 0)
- usb_detach_wakeupold(sc->sc_dev);
+ cv_broadcast(&sc->sc_detachcv);
+ mutex_exit(&sc->sc_lock);
}
void
smsc_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
{
- struct smsc_chain *c = (struct smsc_chain *)priv;
- struct smsc_softc *sc = c->sc_sc;
- struct ifnet *ifp = &sc->sc_ec.ec_if;
- u_char *buf = c->sc_buf;
- uint32_t total_len;
- uint32_t rxhdr;
- uint16_t pktlen;
- struct mbuf *m;
- int s;
-
- if (sc->sc_dying)
+ struct smsc_chain * const c = (struct smsc_chain *)priv;
+ struct smsc_softc * const sc = c->sc_sc;
+ struct ifnet * const ifp = &sc->sc_ec.ec_if;
+ u_char *buf = c->sc_buf;
+ uint32_t total_len;
+
+ mutex_enter(&sc->sc_rxlock);
+ if (sc->sc_stopping) {
+ smsc_dbg_printf(sc, "%s: stopping\n", __func__);
+ mutex_exit(&sc->sc_rxlock);
return;
+ }
- if (!(ifp->if_flags & IFF_RUNNING))
+ if (!(sc->sc_if_flags & IFF_RUNNING)) {
+ smsc_dbg_printf(sc, "%s: not running\n", __func__);
+ mutex_exit(&sc->sc_rxlock);
return;
+ }
if (status != USBD_NORMAL_COMPLETION) {
- if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
+ if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
+ mutex_exit(&sc->sc_rxlock);
return;
+ }
if (usbd_ratecheck(&sc->sc_rx_notice)) {
printf("%s: usb errors on rx: %s\n",
device_xname(sc->sc_dev), usbd_errstr(status));
@@ -1290,6 +1412,7 @@ smsc_rxeof(struct usbd_xfer *xfer, void
smsc_dbg_printf(sc, "xfer status total_len %d\n", total_len);
while (total_len != 0) {
+ uint32_t rxhdr;
if (total_len < sizeof(rxhdr)) {
smsc_dbg_printf(sc, "total_len %d < sizeof(rxhdr) %zu\n",
total_len, sizeof(rxhdr));
@@ -1313,7 +1436,7 @@ smsc_rxeof(struct usbd_xfer *xfer, void
goto done;
}
- pktlen = (uint16_t)SMSC_RX_STAT_FRM_LENGTH(rxhdr);
+ uint16_t pktlen = (uint16_t)SMSC_RX_STAT_FRM_LENGTH(rxhdr);
smsc_dbg_printf(sc, "rxeof total_len %d pktlen %d rxhdr "
"0x%08x\n", total_len, pktlen, rxhdr);
@@ -1340,7 +1463,7 @@ smsc_rxeof(struct usbd_xfer *xfer, void
goto done;
}
- m = smsc_newbuf();
+ struct mbuf *m = smsc_newbuf();
if (m == NULL) {
smsc_dbg_printf(sc, "smc_newbuf returned NULL\n");
ifp->if_ierrors++;
@@ -1414,13 +1537,22 @@ smsc_rxeof(struct usbd_xfer *xfer, void
buf += pktlen;
total_len -= pktlen;
+ mutex_exit(&sc->sc_rxlock);
+
/* push the packet up */
- s = splnet();
- if_percpuq_enqueue(ifp->if_percpuq, m);
- splx(s);
+ if_percpuq_enqueue(sc->sc_ipq, m);
+
+ mutex_enter(&sc->sc_rxlock);
+ if (sc->sc_stopping) {
+ smsc_dbg_printf(sc, "%s: stopping\n", __func__);
+ mutex_exit(&sc->sc_rxlock);
+ return;
+ }
}
done:
+ mutex_exit(&sc->sc_rxlock);
+
/* Setup new transfer. */
usbd_setup_xfer(xfer, c, c->sc_buf, sc->sc_bufsz, USBD_SHORT_XFER_OK,
USBD_NO_TIMEOUT, smsc_rxeof);
@@ -1432,26 +1564,24 @@ done:
void
smsc_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
{
- struct smsc_softc *sc;
- struct smsc_chain *c;
- struct ifnet *ifp;
- int s;
-
- c = priv;
- sc = c->sc_sc;
- ifp = &sc->sc_ec.ec_if;
+ struct smsc_chain *c = priv;
+ struct smsc_softc *sc = c->sc_sc;
+ struct ifnet *ifp = &sc->sc_ec.ec_if;
- if (sc->sc_dying)
+ mutex_enter(&sc->sc_txlock);
+ if (sc->sc_stopping) {
+ smsc_dbg_printf(sc, "%s: stopping\n", __func__);
+ mutex_exit(&sc->sc_txlock);
return;
+ }
- s = splnet();
-
+ sc->sc_cdata.tx_free++;
ifp->if_timer = 0;
ifp->if_flags &= ~IFF_OACTIVE;
if (status != USBD_NORMAL_COMPLETION) {
if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
- splx(s);
+ mutex_exit(&sc->sc_txlock);
return;
}
ifp->if_oerrors++;
@@ -1459,7 +1589,7 @@ smsc_txeof(struct usbd_xfer *xfer, void
usbd_errstr(status));
if (status == USBD_STALLED)
usbd_clear_endpoint_stall_async(sc->sc_ep[SMSC_ENDPT_TX]);
- splx(s);
+ mutex_exit(&sc->sc_txlock);
return;
}
ifp->if_opackets++;
@@ -1468,19 +1598,18 @@ smsc_txeof(struct usbd_xfer *xfer, void
c->sc_mbuf = NULL;
if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
- smsc_start(ifp);
+ smsc_start_locked(ifp);
- splx(s);
+ mutex_exit(&sc->sc_txlock);
}
int
smsc_tx_list_init(struct smsc_softc *sc)
{
- struct smsc_cdata *cd;
+ struct smsc_cdata *cd = &sc->sc_cdata;
struct smsc_chain *c;
int i;
- cd = &sc->sc_cdata;
for (i = 0; i < SMSC_TX_LIST_CNT; i++) {
c = &cd->tx_chain[i];
c->sc_sc = sc;
@@ -1496,17 +1625,35 @@ smsc_tx_list_init(struct smsc_softc *sc)
}
}
+ cd->tx_free = SMSC_TX_LIST_CNT;
+ cd->tx_next = 0;
+
return 0;
}
+void
+smsc_tx_list_free(struct smsc_softc *sc)
+{
+ /* Free TX resources. */
+ for (size_t i = 0; i < SMSC_TX_LIST_CNT; i++) {
+ if (sc->sc_cdata.tx_chain[i].sc_mbuf != NULL) {
+ m_freem(sc->sc_cdata.tx_chain[i].sc_mbuf);
+ sc->sc_cdata.tx_chain[i].sc_mbuf = NULL;
+ }
+ if (sc->sc_cdata.tx_chain[i].sc_xfer != NULL) {
+ usbd_destroy_xfer(sc->sc_cdata.tx_chain[i].sc_xfer);
+ sc->sc_cdata.tx_chain[i].sc_xfer = NULL;
+ }
+ }
+}
+
int
smsc_rx_list_init(struct smsc_softc *sc)
{
- struct smsc_cdata *cd;
+ struct smsc_cdata *cd = &sc->sc_cdata;
struct smsc_chain *c;
int i;
- cd = &sc->sc_cdata;
for (i = 0; i < SMSC_RX_LIST_CNT; i++) {
c = &cd->rx_chain[i];
c->sc_sc = sc;
@@ -1514,7 +1661,7 @@ smsc_rx_list_init(struct smsc_softc *sc)
c->sc_mbuf = NULL;
if (c->sc_xfer == NULL) {
int error = usbd_create_xfer(sc->sc_ep[SMSC_ENDPT_RX],
- sc->sc_bufsz, 0, 0, &c->sc_xfer);
+ sc->sc_bufsz, USBD_SHORT_XFER_OK, 0, &c->sc_xfer);
if (error)
return error;
c->sc_buf = usbd_get_buffer(c->sc_xfer);
@@ -1524,10 +1671,26 @@ smsc_rx_list_init(struct smsc_softc *sc)
return 0;
}
+void
+smsc_rx_list_free(struct smsc_softc *sc)
+{
+ /* Free RX resources. */
+ for (size_t i = 0; i < SMSC_RX_LIST_CNT; i++) {
+ if (sc->sc_cdata.rx_chain[i].sc_mbuf != NULL) {
+ m_freem(sc->sc_cdata.rx_chain[i].sc_mbuf);
+ sc->sc_cdata.rx_chain[i].sc_mbuf = NULL;
+ }
+ if (sc->sc_cdata.rx_chain[i].sc_xfer != NULL) {
+ usbd_destroy_xfer(sc->sc_cdata.rx_chain[i].sc_xfer);
+ sc->sc_cdata.rx_chain[i].sc_xfer = NULL;
+ }
+ }
+}
+
struct mbuf *
smsc_newbuf(void)
{
- struct mbuf *m;
+ struct mbuf *m;
MGETHDR(m, M_DONTWAIT, MT_DATA);
if (m == NULL)
@@ -1545,20 +1708,16 @@ smsc_newbuf(void)
int
smsc_encap(struct smsc_softc *sc, struct mbuf *m, int idx)
{
- struct ifnet *ifp = &sc->sc_ec.ec_if;
- struct smsc_chain *c;
- usbd_status err;
- uint32_t txhdr;
- uint32_t frm_len = 0;
-
- c = &sc->sc_cdata.tx_chain[idx];
+ struct smsc_chain * const c = &sc->sc_cdata.tx_chain[idx];
+ uint32_t txhdr;
+ uint32_t frm_len = 0;
/*
* Each frame is prefixed with two 32-bit values describing the
* length of the packet and buffer.
*/
txhdr = SMSC_TX_CTRL_0_BUF_SIZE(m->m_pkthdr.len) |
- SMSC_TX_CTRL_0_FIRST_SEG | SMSC_TX_CTRL_0_LAST_SEG;
+ SMSC_TX_CTRL_0_FIRST_SEG | SMSC_TX_CTRL_0_LAST_SEG;
txhdr = htole32(txhdr);
memcpy(c->sc_buf, &txhdr, sizeof(txhdr));
@@ -1577,14 +1736,10 @@ smsc_encap(struct smsc_softc *sc, struct
usbd_setup_xfer(c->sc_xfer, c, c->sc_buf, frm_len,
USBD_FORCE_SHORT_XFER, 10000, smsc_txeof);
- err = usbd_transfer(c->sc_xfer);
- /* XXXNH get task to stop interface */
+ usbd_status err = usbd_transfer(c->sc_xfer);
if (err != USBD_IN_PROGRESS) {
- smsc_stop(ifp, 0);
return EIO;
}
- sc->sc_cdata.tx_cnt++;
-
return 0;
}
Index: src/sys/dev/usb/if_smscvar.h
diff -u src/sys/dev/usb/if_smscvar.h:1.5 src/sys/dev/usb/if_smscvar.h:1.6
--- src/sys/dev/usb/if_smscvar.h:1.5 Sat Apr 23 10:15:31 2016
+++ src/sys/dev/usb/if_smscvar.h Sat Sep 8 13:10:08 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: if_smscvar.h,v 1.5 2016/04/23 10:15:31 skrll Exp $ */
+/* $NetBSD: if_smscvar.h,v 1.6 2018/09/08 13:10:08 mlelstv Exp $ */
/* $OpenBSD: if_smscreg.h,v 1.2 2012/09/27 12:38:11 jsg Exp $ */
/*-
@@ -46,16 +46,17 @@ struct smsc_chain {
struct smsc_cdata {
struct smsc_chain tx_chain[SMSC_TX_LIST_CNT];
struct smsc_chain rx_chain[SMSC_RX_LIST_CNT];
- int tx_prod;
- int tx_cons;
- int tx_cnt;
- int rx_prod;
+ int tx_free;
+ int tx_next;
+ int rx_next;
};
struct smsc_softc {
device_t sc_dev;
struct usbd_device * sc_udev;
bool sc_dying;
+ bool sc_stopping;
+ bool sc_ttpending;
uint8_t sc_enaddr[ETHER_ADDR_LEN];
struct ethercom sc_ec;
@@ -77,12 +78,15 @@ struct smsc_softc {
int sc_refcnt;
struct usb_task sc_tick_task;
- struct usb_task sc_stop_task;
int sc_ed[SMSC_ENDPT_MAX];
struct usbd_pipe * sc_ep[SMSC_ENDPT_MAX];
+ kmutex_t sc_lock;
+ kmutex_t sc_txlock;
+ kmutex_t sc_rxlock;
kmutex_t sc_mii_lock;
+ kcondvar_t sc_detachcv;
struct smsc_cdata sc_cdata;
callout_t sc_stat_ch;
@@ -92,6 +96,9 @@ struct smsc_softc {
uint32_t sc_flags;
#define SMSC_FLAG_LINK 0x0001
+
+ struct if_percpuq *sc_ipq; /* softint-based input queues */
+
};
#define SMSC_MIN_BUFSZ 2048