Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/dev/pci Make if_wm MPSAFE
details: https://anonhg.NetBSD.org/src/rev/aabd67e5fb4c
branches: trunk
changeset: 330251:aabd67e5fb4c
user: ozaki-r <ozaki-r%NetBSD.org@localhost>
date: Tue Jul 01 10:35:18 2014 +0000
description:
Make if_wm MPSAFE
- Make it MPSAFE only when NET_MPSAFE
- otherwise, its instructions are almost same as before
- the only change is IFQ_POLL/IFQ_DEQUEUE which
is now single IFQ_DEQUEUE
- Protect driver operations with a lock
- further work would make it separate
- Apply MPSAFE flag to
- callout_init
- pci_intr_establish
- Stop proceeding packets when the driver is likely
to stop for graceful ifconfig down
Tested on Rangeley (I354) and KVM (e1000)
Reviewed by msaitoh@
diffstat:
sys/dev/pci/if_wm.c | 273 ++++++++++++++++++++++++++++++++++++++++++++-------
1 files changed, 234 insertions(+), 39 deletions(-)
diffs (truncated from 690 to 300 lines):
diff -r 41d974914889 -r aabd67e5fb4c sys/dev/pci/if_wm.c
--- a/sys/dev/pci/if_wm.c Tue Jul 01 10:16:02 2014 +0000
+++ b/sys/dev/pci/if_wm.c Tue Jul 01 10:35:18 2014 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: if_wm.c,v 1.271 2014/06/30 06:09:44 ozaki-r Exp $ */
+/* $NetBSD: if_wm.c,v 1.272 2014/07/01 10:35:18 ozaki-r Exp $ */
/*
* Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc.
@@ -76,7 +76,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.271 2014/06/30 06:09:44 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.272 2014/07/01 10:35:18 ozaki-r Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -141,6 +141,10 @@
#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
@@ -275,6 +279,7 @@
void *sc_ih; /* interrupt cookie */
callout_t sc_tick_ch; /* tick callout */
+ bool sc_stopping;
int sc_ee_addrbits; /* EEPROM address bits */
int sc_ich8_flash_base;
@@ -380,8 +385,21 @@
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_LOCKED(_sc) (!(_sc)->sc_txrx_lock || mutex_owned((_sc)->sc_txrx_lock))
+
+#ifdef WM_MPSAFE
+#define CALLOUT_FLAGS CALLOUT_MPSAFE
+#else
+#define CALLOUT_FLAGS 0
+#endif
+
#define WM_RXCHAIN_RESET(sc) \
do { \
(sc)->sc_rxtailp = &(sc)->sc_rxhead; \
@@ -495,12 +513,16 @@
} 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 *);
static int wm_init(struct ifnet *);
+static int wm_init_locked(struct ifnet *);
static void wm_stop(struct ifnet *, int);
+static void wm_stop_locked(struct ifnet *, int);
static bool wm_suspend(device_t, const pmf_qual_t *);
static bool wm_resume(device_t, const pmf_qual_t *);
@@ -1184,7 +1206,8 @@
char intrbuf[PCI_INTRSTR_LEN];
sc->sc_dev = self;
- callout_init(&sc->sc_tick_ch, 0);
+ callout_init(&sc->sc_tick_ch, CALLOUT_FLAGS);
+ sc->sc_stopping = false;
sc->sc_wmp = wmp = wm_lookup(pa);
if (wmp == NULL) {
@@ -1315,6 +1338,9 @@
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");
@@ -1354,7 +1380,7 @@
aprint_verbose_dev(sc->sc_dev,
"Communication Streaming Architecture\n");
if (sc->sc_type == WM_T_82547) {
- callout_init(&sc->sc_txfifo_ch, 0);
+ callout_init(&sc->sc_txfifo_ch, CALLOUT_FLAGS);
callout_setfunc(&sc->sc_txfifo_ch,
wm_82547_txfifo_stall, sc);
aprint_verbose_dev(sc->sc_dev,
@@ -2051,6 +2077,12 @@
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.
*/
@@ -2159,18 +2191,26 @@
{
struct wm_softc *sc = device_private(self);
struct ifnet *ifp = &sc->sc_ethercom.ec_if;
- int i, s;
+ int i;
+#ifndef WM_MPSAFE
+ int s;
s = splnet();
+#endif
/* Stop the interface. Callouts are stopped in it. */
wm_stop(ifp, 1);
+
+#ifndef WM_MPSAFE
splx(s);
+#endif
pmf_device_deregister(self);
/* Tell the firmware about the release */
+ WM_LOCK(sc);
wm_release_manageability(sc);
wm_release_hw_control(sc);
+ WM_UNLOCK(sc);
mii_detach(&sc->sc_mii, MII_PHY_ANY, MII_OFFSET_ANY);
@@ -2182,7 +2222,10 @@
/* Unload RX dmamaps and free mbufs */
+ WM_LOCK(sc);
wm_rxdrain(sc);
+ WM_UNLOCK(sc);
+ /* Must unlock here */
/* Free dmamap. It's the same as the end of the wm_attach() function */
for (i = 0; i < WM_NRXDESC; i++) {
@@ -2218,6 +2261,9 @@
sc->sc_ios = 0;
}
+ if (sc->sc_txrx_lock)
+ mutex_obj_free(sc->sc_txrx_lock);
+
return 0;
}
@@ -2441,9 +2487,15 @@
wm_82547_txfifo_stall(void *arg)
{
struct wm_softc *sc = arg;
+#ifndef WM_MPSAFE
int s;
s = splnet();
+#endif
+ WM_LOCK(sc);
+
+ if (sc->sc_stopping)
+ goto out;
if (sc->sc_txfifo_stall) {
if (CSR_READ(sc, WMREG_TDT) == CSR_READ(sc, WMREG_TDH) &&
@@ -2465,7 +2517,7 @@
sc->sc_txfifo_head = 0;
sc->sc_txfifo_stall = 0;
- wm_start(&sc->sc_ethercom.ec_if);
+ wm_start_locked(&sc->sc_ethercom.ec_if);
} else {
/*
* Still waiting for packets to drain; try again in
@@ -2475,7 +2527,11 @@
}
}
+out:
+ WM_UNLOCK(sc);
+#ifndef WM_MPSAFE
splx(s);
+#endif
}
static void
@@ -2546,6 +2602,17 @@
wm_start(struct ifnet *ifp)
{
struct wm_softc *sc = ifp->if_softc;
+
+ WM_LOCK(sc);
+ if (!sc->sc_stopping)
+ 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;
@@ -2556,6 +2623,8 @@
uint32_t cksumcmd;
uint8_t cksumfields;
+ KASSERT(WM_LOCKED(sc));
+
if ((ifp->if_flags & (IFF_RUNNING|IFF_OACTIVE)) != IFF_RUNNING)
return;
@@ -2570,14 +2639,7 @@
* descriptors.
*/
for (;;) {
- /* Grab a packet off the queue. */
- IFQ_POLL(&ifp->if_snd, m0);
- if (m0 == NULL)
- break;
-
- DPRINTF(WM_DEBUG_TX,
- ("%s: TX: have packet to transmit: %p\n",
- device_xname(sc->sc_dev), m0));
+ m0 = NULL;
/* Get a work queue entry. */
if (sc->sc_txsfree < WM_TXQUEUE_GC(sc)) {
@@ -2591,6 +2653,15 @@
}
}
+ /* Grab a packet off the queue. */
+ IFQ_DEQUEUE(&ifp->if_snd, m0);
+ if (m0 == NULL)
+ break;
+
+ DPRINTF(WM_DEBUG_TX,
+ ("%s: TX: have packet to transmit: %p\n",
+ device_xname(sc->sc_dev), m0));
+
txs = &sc->sc_txsoft[sc->sc_txsnext];
dmamap = txs->txs_dmamap;
@@ -2627,7 +2698,6 @@
log(LOG_ERR, "%s: Tx packet consumes too many "
"DMA segments, dropping...\n",
device_xname(sc->sc_dev));
- IFQ_DEQUEUE(&ifp->if_snd, m0);
wm_dump_mbuf_chain(sc, m0);
m_freem(m0);
continue;
@@ -2688,8 +2758,6 @@
break;
}
- IFQ_DEQUEUE(&ifp->if_snd, m0);
-
/*
* WE ARE NOW COMMITTED TO TRANSMITTING THE PACKET.
*/
@@ -2833,6 +2901,13 @@
bpf_mtap(ifp, m0);
}
+ if (m0 != NULL) {
+ ifp->if_flags |= IFF_OACTIVE;
+ WM_EVCNT_INCR(&sc->sc_ev_txdrop);
+ DPRINTF(WM_DEBUG_TX, ("%s: TX: error after IFQ_DEQUEUE\n", __func__));
+ m_freem(m0);
+ }
+
if (sc->sc_txsfree == 0 || sc->sc_txfree <= 2) {
/* No more slots; notify upper layer. */
ifp->if_flags |= IFF_OACTIVE;
@@ -3053,6 +3128,17 @@
wm_nq_start(struct ifnet *ifp)
{
struct wm_softc *sc = ifp->if_softc;
+
+ WM_LOCK(sc);
Home |
Main Index |
Thread Index |
Old Index