diff --git a/sys/altq/if_altq.h b/sys/altq/if_altq.h index c441651..e48f0a6 100644 --- a/sys/altq/if_altq.h +++ b/sys/altq/if_altq.h @@ -45,6 +45,7 @@ struct ifaltq { int ifq_len; int ifq_maxlen; int ifq_drops; + kmutex_t *ifq_lock; /* alternate queueing related fields */ int altq_type; /* discipline type */ diff --git a/sys/dev/pci/if_wm.c b/sys/dev/pci/if_wm.c index 1c41f32..3b947ac 100644 --- a/sys/dev/pci/if_wm.c +++ b/sys/dev/pci/if_wm.c @@ -141,6 +141,10 @@ int wm_debug = WM_DEBUG_TX | WM_DEBUG_RX | WM_DEBUG_LINK | WM_DEBUG_GMII #define DPRINTF(x, y) /* nothing */ #endif /* WM_DEBUG */ +#ifdef NET_MPSAFE +#define WM_MPSAFE 1 +#endif + /* * Transmit descriptor list size. Due to errata, we can only have * 256 hardware descriptors in the ring on < 82544, but we use 4096 @@ -380,8 +384,14 @@ struct wm_softc { int sc_mchash_type; /* multicast filter offset */ krndsource_t rnd_source; /* random source */ + + kmutex_t *sc_txrx_lock; /* lock for tx/rx operations */ + /* XXX need separation? */ }; +#define WM_LOCK(_sc) if ((_sc)->sc_txrx_lock) mutex_enter((_sc)->sc_txrx_lock) +#define WM_UNLOCK(_sc) if ((_sc)->sc_txrx_lock) mutex_exit((_sc)->sc_txrx_lock) + #define WM_RXCHAIN_RESET(sc) \ do { \ (sc)->sc_rxtailp = &(sc)->sc_rxhead; \ @@ -495,7 +505,9 @@ do { \ } while (/*CONSTCOND*/0) static void wm_start(struct ifnet *); +static void wm_start_locked(struct ifnet *); static void wm_nq_start(struct ifnet *); +static void wm_nq_start_locked(struct ifnet *); static void wm_watchdog(struct ifnet *); static int wm_ifflags_cb(struct ethercom *); static int wm_ioctl(struct ifnet *, u_long, void *); @@ -1315,6 +1327,9 @@ wm_attach(device_t parent, device_t self, void *aux) return; } intrstr = pci_intr_string(pc, ih, intrbuf, sizeof(intrbuf)); +#ifdef WM_MPSAFE + pci_intr_setattr(pc, &ih, PCI_INTR_MPSAFE, true); +#endif sc->sc_ih = pci_intr_establish(pc, ih, IPL_NET, wm_intr, sc); if (sc->sc_ih == NULL) { aprint_error_dev(sc->sc_dev, "unable to establish interrupt"); @@ -2051,6 +2066,12 @@ wm_attach(device_t parent, device_t self, void *aux) ifp->if_capabilities |= IFCAP_TSOv6; } +#ifdef WM_MPSAFE + sc->sc_txrx_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NET); +#else + sc->sc_txrx_lock = NULL; +#endif + /* * Attach the interface. */ @@ -2218,6 +2239,9 @@ wm_detach(device_t self, int flags __unused) sc->sc_ios = 0; } + if (sc->sc_txrx_lock) + mutex_obj_free(sc->sc_txrx_lock); + return 0; } @@ -2546,6 +2570,16 @@ static void wm_start(struct ifnet *ifp) { struct wm_softc *sc = ifp->if_softc; + + WM_LOCK(sc); + wm_start_locked(ifp); + WM_UNLOCK(sc); +} + +static void +wm_start_locked(struct ifnet *ifp) +{ + struct wm_softc *sc = ifp->if_softc; struct mbuf *m0; struct m_tag *mtag; struct wm_txsoft *txs; @@ -3053,6 +3087,16 @@ static void wm_nq_start(struct ifnet *ifp) { struct wm_softc *sc = ifp->if_softc; + + WM_LOCK(sc); + wm_nq_start_locked(ifp); + WM_UNLOCK(sc); +} + +static void +wm_nq_start_locked(struct ifnet *ifp) +{ + struct wm_softc *sc = ifp->if_softc; struct mbuf *m0; struct m_tag *mtag; struct wm_txsoft *txs; @@ -3335,7 +3379,9 @@ wm_watchdog(struct ifnet *ifp) * Since we're using delayed interrupts, sweep up * before we report an error. */ + WM_LOCK(sc); wm_txintr(sc); + WM_UNLOCK(sc); if (sc->sc_txfree != WM_NTXDESC(sc)) { #ifdef WM_DEBUG @@ -3486,6 +3532,8 @@ wm_intr(void *arg) handled = 1; + WM_LOCK(sc); + #if defined(WM_DEBUG) || defined(WM_EVENT_COUNTERS) if (icr & (ICR_RXDMT0|ICR_RXT0)) { DPRINTF(WM_DEBUG_RX, @@ -3512,6 +3560,8 @@ wm_intr(void *arg) wm_linkintr(sc, icr); } + WM_UNLOCK(sc); + if (icr & ICR_RXO) { #if defined(WM_DEBUG) log(LOG_WARNING, "%s: Receive overrun\n", @@ -3818,7 +3868,9 @@ wm_rxintr(struct wm_softc *sc) bpf_mtap(ifp, m); /* Pass it on. */ + WM_UNLOCK(sc); (*ifp->if_input)(ifp, m); + WM_LOCK(sc); } /* Update the receive pointer. */ diff --git a/sys/net/if.c b/sys/net/if.c index 2a6fa0f..f8429b1 100644 --- a/sys/net/if.c +++ b/sys/net/if.c @@ -611,6 +611,12 @@ if_attach(ifnet_t *ifp) ifp->if_snd.altq_ifp = ifp; #endif +#ifdef NET_MPSAFE + ifp->if_snd.ifq_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NET); +#else + ifp->if_snd.ifq_lock = NULL; +#endif + ifp->if_pfil = pfil_head_create(PFIL_TYPE_IFNET, ifp); (void)pfil_run_hooks(if_pfil, (struct mbuf **)PFIL_IFNET_ATTACH, ifp, PFIL_IFNET); @@ -732,6 +738,9 @@ if_detach(struct ifnet *ifp) altq_detach(&ifp->if_snd); #endif + if (ifp->if_snd.ifq_lock) + mutex_obj_free(ifp->if_snd.ifq_lock); + sysctl_teardown(&ifp->if_sysctl_log); #if NCARP > 0 diff --git a/sys/net/if.h b/sys/net/if.h index bc2c240..ca5d11e 100644 --- a/sys/net/if.h +++ b/sys/net/if.h @@ -86,6 +86,8 @@ #include #endif +//#define NET_MPSAFE 1 + /* * Always include ALTQ glue here -- we use the ALTQ interface queue * structure even when ALTQ is not configured into the kernel so that @@ -198,11 +200,12 @@ struct if_data { * Structure defining a queue for a network interface. */ struct ifqueue { - struct mbuf *ifq_head; - struct mbuf *ifq_tail; - int ifq_len; - int ifq_maxlen; - int ifq_drops; + struct mbuf *ifq_head; + struct mbuf *ifq_tail; + int ifq_len; + int ifq_maxlen; + int ifq_drops; + kmutex_t *ifq_lock; }; struct ifnet_lock; @@ -230,6 +233,7 @@ struct ifnet_lock { * before they leave. */ }; + #endif /* _KERNEL */ /* @@ -424,6 +428,9 @@ typedef struct ifnet { "\23TSO6" \ "\24LRO" \ +#define IFQ_LOCK(_ifq) if ((_ifq)->ifq_lock) mutex_enter((_ifq)->ifq_lock) +#define IFQ_UNLOCK(_ifq) if ((_ifq)->ifq_lock) mutex_exit((_ifq)->ifq_lock) + /* * Output queues (ifp->if_snd) and internetwork datagram level (pup level 1) * input routines have queues of messages stored on ifqueue structures @@ -752,6 +759,7 @@ do { \ #define IFQ_ENQUEUE(ifq, m, pattr, err) \ do { \ + IFQ_LOCK((ifq)); \ if (ALTQ_IS_ENABLED((ifq))) \ ALTQ_ENQUEUE((ifq), (m), (pattr), (err)); \ else { \ @@ -765,34 +773,41 @@ do { \ } \ if ((err)) \ (ifq)->ifq_drops++; \ + IFQ_UNLOCK((ifq)); \ } while (/*CONSTCOND*/ 0) #define IFQ_DEQUEUE(ifq, m) \ do { \ + IFQ_LOCK((ifq)); \ if (TBR_IS_ENABLED((ifq))) \ (m) = tbr_dequeue((ifq), ALTDQ_REMOVE); \ else if (ALTQ_IS_ENABLED((ifq))) \ ALTQ_DEQUEUE((ifq), (m)); \ else \ IF_DEQUEUE((ifq), (m)); \ + IFQ_UNLOCK((ifq)); \ } while (/*CONSTCOND*/ 0) #define IFQ_POLL(ifq, m) \ do { \ + IFQ_LOCK((ifq)); \ if (TBR_IS_ENABLED((ifq))) \ (m) = tbr_dequeue((ifq), ALTDQ_POLL); \ else if (ALTQ_IS_ENABLED((ifq))) \ ALTQ_POLL((ifq), (m)); \ else \ IF_POLL((ifq), (m)); \ + IFQ_UNLOCK((ifq)); \ } while (/*CONSTCOND*/ 0) #define IFQ_PURGE(ifq) \ do { \ + IFQ_LOCK((ifq)); \ if (ALTQ_IS_ENABLED((ifq))) \ ALTQ_PURGE((ifq)); \ else \ IF_PURGE((ifq)); \ + IFQ_UNLOCK((ifq)); \ } while (/*CONSTCOND*/ 0) #define IFQ_SET_READY(ifq) \ @@ -802,6 +817,7 @@ do { \ #define IFQ_CLASSIFY(ifq, m, af, pattr) \ do { \ + IFQ_LOCK((ifq)); \ if (ALTQ_IS_ENABLED((ifq))) { \ if (ALTQ_NEEDS_CLASSIFY((ifq))) \ (pattr)->pattr_class = (*(ifq)->altq_classify) \ @@ -809,6 +825,7 @@ do { \ (pattr)->pattr_af = (af); \ (pattr)->pattr_hdr = mtod((m), void *); \ } \ + IFQ_UNLOCK((ifq)); \ } while (/*CONSTCOND*/ 0) #else /* ! ALTQ */ #define ALTQ_DECL(x) /* nothing */ @@ -816,6 +833,7 @@ do { \ #define IFQ_ENQUEUE(ifq, m, pattr, err) \ do { \ + IFQ_LOCK((ifq)); \ if (IF_QFULL((ifq))) { \ m_freem((m)); \ (err) = ENOBUFS; \ @@ -825,13 +843,29 @@ do { \ } \ if ((err)) \ (ifq)->ifq_drops++; \ + IFQ_UNLOCK((ifq)); \ } while (/*CONSTCOND*/ 0) -#define IFQ_DEQUEUE(ifq, m) IF_DEQUEUE((ifq), (m)) +#define IFQ_DEQUEUE(ifq, m) \ +do { \ + IFQ_LOCK((ifq)); \ + IF_DEQUEUE((ifq), (m)); \ + IFQ_UNLOCK((ifq)); \ +} while (/*CONSTCOND*/ 0) -#define IFQ_POLL(ifq, m) IF_POLL((ifq), (m)) +#define IFQ_POLL(ifq, m) \ +do { \ + IFQ_LOCK((ifq)); \ + IF_POLL((ifq), (m)); \ + IFQ_UNLOCK((ifq)); \ +} while (/*CONSTCOND*/ 0) -#define IFQ_PURGE(ifq) IF_PURGE((ifq)) +#define IFQ_PURGE(ifq) \ +do { \ + IFQ_LOCK((ifq)); \ + IF_PURGE((ifq)); \ + IFQ_UNLOCK((ifq)); \ +} while (/*CONSTCOND*/ 0) #define IFQ_SET_READY(ifq) /* nothing */