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 bge(4) MP safe
details: https://anonhg.NetBSD.org/src/rev/1c9b6c5c59d1
branches: trunk
changeset: 368949:1c9b6c5c59d1
user: skrll <skrll%NetBSD.org@localhost>
date: Sun Aug 14 09:01:25 2022 +0000
description:
Make bge(4) MP safe
This started out as a fix so that LOCKDEBUG wouldn't explode with kernel
lock spinout. LOCKDEBUG is too aggressive now and really should be
relaxed.
diffstat:
sys/dev/pci/if_bge.c | 320 ++++++++++++++++++++++++++++++++++-------------
sys/dev/pci/if_bgevar.h | 13 +-
2 files changed, 239 insertions(+), 94 deletions(-)
diffs (truncated from 793 to 300 lines):
diff -r b4dade607c14 -r 1c9b6c5c59d1 sys/dev/pci/if_bge.c
--- a/sys/dev/pci/if_bge.c Sun Aug 14 08:51:41 2022 +0000
+++ b/sys/dev/pci/if_bge.c Sun Aug 14 09:01:25 2022 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: if_bge.c,v 1.374 2022/08/14 08:42:33 skrll Exp $ */
+/* $NetBSD: if_bge.c,v 1.375 2022/08/14 09:01:25 skrll Exp $ */
/*
* Copyright (c) 2001 Wind River Systems
@@ -79,7 +79,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_bge.c,v 1.374 2022/08/14 08:42:33 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_bge.c,v 1.375 2022/08/14 09:01:25 skrll Exp $");
#include <sys/param.h>
#include <sys/types.h>
@@ -206,13 +206,17 @@
static int bge_intr(void *);
static void bge_start(struct ifnet *);
+static void bge_start_locked(struct ifnet *);
static int bge_ifflags_cb(struct ethercom *);
static int bge_ioctl(struct ifnet *, u_long, void *);
static int bge_init(struct ifnet *);
+static int bge_init_locked(struct ifnet *);
static void bge_stop(struct ifnet *, int);
-static void bge_watchdog(struct ifnet *);
+static void bge_stop_locked(struct ifnet *, int);
+static bool bge_watchdog(struct ifnet *);
static int bge_ifmedia_upd(struct ifnet *);
static void bge_ifmedia_sts(struct ifnet *, struct ifmediareq *);
+static void bge_handle_reset_work(struct work *, void *);
static uint8_t bge_nvram_getbyte(struct bge_softc *, int, uint8_t *);
static int bge_read_nvram(struct bge_softc *, uint8_t *, int, int);
@@ -529,6 +533,12 @@
static int bge_allow_asf = 1;
+#ifndef BGE_WATCHDOG_TIMEOUT
+#define BGE_WATCHDOG_TIMEOUT 5
+#endif
+static int bge_watchdog_timeout = BGE_WATCHDOG_TIMEOUT;
+
+
CFATTACH_DECL3_NEW(bge, sizeof(struct bge_softc),
bge_probe, bge_attach, bge_detach, NULL, NULL, NULL, DVF_DETACH_SHUTDOWN);
@@ -1247,7 +1257,6 @@
bge_set_thresh(struct ifnet *ifp, int lvl)
{
struct bge_softc * const sc = ifp->if_softc;
- int s;
/*
* For now, just save the new Rx-intr thresholds and record
@@ -1256,11 +1265,11 @@
* occasionally cause glitches where Rx-interrupts are not
* honoured for up to 10 seconds. jonathan%NetBSD.org@localhost, 2003-04-05
*/
- s = splnet();
+ mutex_enter(sc->sc_core_lock);
sc->bge_rx_coal_ticks = bge_rx_threshes[lvl].rx_ticks;
sc->bge_rx_max_coal_bds = bge_rx_threshes[lvl].rx_max_bds;
sc->bge_pending_rxintr_change = 1;
- splx(s);
+ mutex_exit(sc->sc_core_lock);
}
@@ -1311,8 +1320,8 @@
bge_alloc_jumbo_mem(struct bge_softc *sc)
{
char *ptr, *kva;
- int i, rseg, state, error;
- struct bge_jpool_entry *entry;
+ int i, rseg, state, error;
+ struct bge_jpool_entry *entry;
state = error = 0;
@@ -1325,8 +1334,7 @@
state = 1;
if (bus_dmamem_map(sc->bge_dmatag, &sc->bge_cdata.bge_rx_jumbo_seg,
- rseg, BGE_JMEM, (void **)&kva,
- BUS_DMA_NOWAIT)) {
+ rseg, BGE_JMEM, (void **)&kva, BUS_DMA_NOWAIT)) {
aprint_error_dev(sc->bge_dev,
"can't map DMA buffers (%d bytes)\n", (int)BGE_JMEM);
error = ENOBUFS;
@@ -1443,7 +1451,6 @@
{
struct bge_jpool_entry *entry;
struct bge_softc * const sc = arg;
- int s;
if (sc == NULL)
panic("bge_jfree: can't find softc pointer!");
@@ -1454,17 +1461,17 @@
if (i < 0 || i >= BGE_JSLOTS)
panic("bge_jfree: asked to free buffer that we don't manage!");
- s = splvm();
+ mutex_enter(sc->sc_core_lock);
entry = SLIST_FIRST(&sc->bge_jinuse_listhead);
if (entry == NULL)
panic("bge_jfree: buffer not in use!");
entry->slot = i;
SLIST_REMOVE_HEAD(&sc->bge_jinuse_listhead, jpool_entries);
SLIST_INSERT_HEAD(&sc->bge_jfree_listhead, entry, jpool_entries);
+ mutex_exit(sc->sc_core_lock);
if (__predict_true(m != NULL))
pool_cache_put(mb_cache, m);
- splx(s);
}
@@ -1576,6 +1583,7 @@
bus_dmamap_sync(sc->bge_dmatag, sc->bge_cdata.bge_rx_jumbo_map,
mtod(m_new, char *) - (char *)sc->bge_cdata.bge_jumbo_buf,
BGE_JLEN, BUS_DMASYNC_PREREAD);
+
/* Set up the descriptor. */
r = &sc->bge_rdata->bge_rx_jumbo_ring[i];
sc->bge_cdata.bge_rx_jumbo_chain[i] = m_new;
@@ -1810,14 +1818,14 @@
bge_setmulti(struct bge_softc *sc)
{
struct ethercom * const ec = &sc->ethercom;
- struct ifnet * const ifp = &ec->ec_if;
struct ether_multi *enm;
struct ether_multistep step;
uint32_t hashes[4] = { 0, 0, 0, 0 };
uint32_t h;
int i;
- if (ifp->if_flags & IFF_PROMISC)
+ KASSERT(mutex_owned(sc->sc_core_lock));
+ if (sc->bge_if_flags & IFF_PROMISC)
goto allmulti;
/* Now program new ones. */
@@ -1845,13 +1853,15 @@
hashes[(h & 0x60) >> 5] |= 1U << (h & 0x1F);
ETHER_NEXT_MULTI(step, enm);
}
+ ec->ec_flags &= ~ETHER_F_ALLMULTI;
ETHER_UNLOCK(ec);
- ifp->if_flags &= ~IFF_ALLMULTI;
goto setit;
allmulti:
- ifp->if_flags |= IFF_ALLMULTI;
+ ETHER_LOCK(ec);
+ ec->ec_flags |= ETHER_F_ALLMULTI;
+ ETHER_UNLOCK(ec);
hashes[0] = hashes[1] = hashes[2] = hashes[3] = 0xffffffff;
setit:
@@ -3631,6 +3641,18 @@
break;
}
+ char wqname[MAXCOMLEN];
+ snprintf(wqname, sizeof(wqname), "%sReset", device_xname(sc->bge_dev));
+ int error = workqueue_create(&sc->sc_reset_wq, wqname,
+ bge_handle_reset_work, sc, PRI_NONE, IPL_SOFTCLOCK,
+ WQ_MPSAFE);
+ if (error) {
+ aprint_error_dev(sc->bge_dev,
+ "unable to create reset workqueue\n");
+ return;
+ }
+
+
/*
* All controllers except BCM5700 supports tagged status but
* we use tagged status only for MSI case on BCM5717. Otherwise
@@ -3830,15 +3852,17 @@
else
sc->bge_return_ring_cnt = BGE_RETURN_RING_CNT;
+ sc->sc_core_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NET);
+
/* Set up ifnet structure */
ifp = &sc->ethercom.ec_if;
ifp->if_softc = sc;
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifp->if_extflags = IFEF_MPSAFE;
ifp->if_ioctl = bge_ioctl;
ifp->if_stop = bge_stop;
ifp->if_start = bge_start;
ifp->if_init = bge_init;
- ifp->if_watchdog = bge_watchdog;
IFQ_SET_MAXLEN(&ifp->if_snd, uimax(BGE_TX_RING_CNT - 1, IFQ_MAXLEN));
IFQ_SET_READY(&ifp->if_snd);
DPRINTFN(5, ("strcpy if_xname\n"));
@@ -3986,12 +4010,16 @@
/*
* Call MI attach routine.
*/
- DPRINTFN(5, ("if_attach\n"));
- if_attach(ifp);
+ DPRINTFN(5, ("if_initialize\n"));
+ if_initialize(ifp);
+ ifp->if_percpuq = if_percpuq_create(ifp);
if_deferred_start_init(ifp, NULL);
+ if_register(ifp);
+
DPRINTFN(5, ("ether_ifattach\n"));
ether_ifattach(ifp, eaddr);
ether_set_ifflags_cb(&sc->ethercom, bge_ifflags_cb);
+
rnd_attach_source(&sc->rnd_source, device_xname(sc->bge_dev),
RND_TYPE_NET, RND_FLAG_DEFAULT);
#ifdef BGE_EVENT_COUNTERS
@@ -4018,7 +4046,7 @@
NULL, device_xname(sc->bge_dev), "xoffentered");
#endif /* BGE_EVENT_COUNTERS */
DPRINTFN(5, ("callout_init\n"));
- callout_init(&sc->bge_timeout, 0);
+ callout_init(&sc->bge_timeout, CALLOUT_MPSAFE);
callout_setfunc(&sc->bge_timeout, bge_tick, sc);
if (pmf_device_register(self, NULL, NULL))
@@ -4042,12 +4070,9 @@
{
struct bge_softc * const sc = device_private(self);
struct ifnet * const ifp = &sc->ethercom.ec_if;
- int s;
-
- s = splnet();
+
/* Stop the interface. Callouts are stopped in it. */
bge_stop(ifp, 1);
- splx(s);
mii_detach(&sc->bge_mii, MII_PHY_ANY, MII_OFFSET_ANY);
@@ -4654,11 +4679,8 @@
}
sc->bge_txcnt--;
BGE_INC(sc->bge_tx_saved_considx, BGE_TX_RING_CNT);
- ifp->if_timer = 0;
- }
-
- if (cur_tx != NULL)
- ifp->if_flags &= ~IFF_OACTIVE;
+ sc->bge_tx_sending = false;
+ }
}
static int
@@ -4669,11 +4691,12 @@
uint32_t pcistate, statusword, statustag;
uint32_t intrmask = BGE_PCISTATE_INTR_NOT_ACTIVE;
-
/* 5717 and newer chips have no BGE_PCISTATE_INTR_NOT_ACTIVE bit */
if (BGE_IS_5717_PLUS(sc))
intrmask = 0;
+ mutex_enter(sc->sc_core_lock);
+
/*
* It is possible for the interrupt to arrive before
* the status block is updated prior to the interrupt.
@@ -4694,6 +4717,7 @@
if (sc->bge_lasttag == statustag &&
(~pcistate & intrmask)) {
BGE_EVCNT_INCR(sc->bge_ev_intr_spurious);
+ mutex_exit(sc->sc_core_lock);
return 0;
}
sc->bge_lasttag = statustag;
@@ -4701,6 +4725,7 @@
if (!(statusword & BGE_STATFLAG_UPDATED) &&
!(~pcistate & intrmask)) {
BGE_EVCNT_INCR(sc->bge_ev_intr_spurious2);
+ mutex_exit(sc->sc_core_lock);
return 0;
}
statustag = 0;
@@ -4722,7 +4747,7 @@
BGE_STS_BIT(sc, BGE_STS_LINK_EVT))
bge_link_upd(sc);
- if (ifp->if_flags & IFF_RUNNING) {
+ if (sc->bge_if_flags & IFF_RUNNING) {
/* Check RX return ring producer/consumer */
bge_rxeof(sc);
@@ -4749,9 +4774,11 @@
/* Re-enable interrupts. */
bge_writembx_flush(sc, BGE_MBX_IRQ0_LO, statustag);
Home |
Main Index |
Thread Index |
Old Index