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