NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: kern/58584: bge(4) locking issues
Attached patch series (pr58584.patch) and giant diff (pr58584.diff)
aims to address these problems, but I don't have any bge(4) to test.
# HG changeset patch
# User Taylor R Campbell <riastradh%NetBSD.org@localhost>
# Date 1723483765 0
# Mon Aug 12 17:29:25 2024 +0000
# Branch trunk
# Node ID 3b02c14478dd88afdd6539071e42f2d3025358d3
# Parent 26b25ed27d2f6bf0ad5e4df6a9ae9713f10ee32e
# EXP-Topic riastradh-pr58584-bgelocking
bge(4): Avoid freeing never-allocated resources if attach failed.
PR kern/58584
diff -r 26b25ed27d2f -r 3b02c14478dd sys/dev/pci/if_bge.c
--- a/sys/dev/pci/if_bge.c Sun Aug 11 18:33:13 2024 +0000
+++ b/sys/dev/pci/if_bge.c Mon Aug 12 17:29:25 2024 +0000
@@ -4078,6 +4078,8 @@ again:
#ifdef BGE_DEBUG
bge_debug_info(sc);
#endif
+
+ sc->bge_attached = true;
}
/*
@@ -4090,6 +4092,9 @@ bge_detach(device_t self, int flags __un
struct bge_softc * const sc = device_private(self);
struct ifnet * const ifp = &sc->ethercom.ec_if;
+ if (!sc->bge_attached)
+ return;
+
IFNET_LOCK(ifp);
/* Stop the interface. Callouts are stopped in it. */
diff -r 26b25ed27d2f -r 3b02c14478dd sys/dev/pci/if_bgevar.h
--- a/sys/dev/pci/if_bgevar.h Sun Aug 11 18:33:13 2024 +0000
+++ b/sys/dev/pci/if_bgevar.h Mon Aug 12 17:29:25 2024 +0000
@@ -349,6 +349,7 @@ struct bge_softc {
int bge_txcnt;
struct callout bge_timeout;
bool bge_pending_rxintr_change;
+ bool bge_attached;
bool bge_detaching;
SLIST_HEAD(, txdmamap_pool_entry) txdma_list;
struct txdmamap_pool_entry *txdma[BGE_TX_RING_CNT];
# HG changeset patch
# User Taylor R Campbell <riastradh%NetBSD.org@localhost>
# Date 1723485119 0
# Mon Aug 12 17:51:59 2024 +0000
# Branch trunk
# Node ID acdf8ea65621599e86692e4caa30dc52d6d61865
# Parent 3b02c14478dd88afdd6539071e42f2d3025358d3
# EXP-Topic riastradh-pr58584-bgelocking
bge(4): Fix various locking issues.
1. Add missing mutex_obj_free.
2. Add missing callout_destroy.
3. Nix core lock. Instead, new mcast lock serializes
SIOCADDMULTI/SIOCDELMULTI and multicast filter updates.
4. Use sc_intr_lock for SIOCIFMEDIA, to exclude concurrent ifmedia
business, not sc_core_lock, which doesn't exclude that.
5. Nix bge_stopping. Already handled by callout_halt.
(Note: PR says bge_detaching can be nixed too but I think that's
wrong; after our final if_stop, nothing else prevents if_init
again, which we must prevent before freeing resources.)
6. Serialize access to the coal ticks business, even during
if_init/stop, to exclude concurrent sysctl.
Sprinkle locking notes while here.
PR kern/58584
diff -r 3b02c14478dd -r acdf8ea65621 sys/dev/pci/if_bge.c
--- a/sys/dev/pci/if_bge.c Mon Aug 12 17:29:25 2024 +0000
+++ b/sys/dev/pci/if_bge.c Mon Aug 12 17:51:59 2024 +0000
@@ -203,9 +203,7 @@ static void bge_start_locked(struct ifne
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_stop_locked(struct ifnet *, bool);
static bool bge_watchdog_tick(struct ifnet *);
static int bge_ifmedia_upd(struct ifnet *);
static void bge_ifmedia_sts(struct ifnet *, struct ifmediareq *);
@@ -1091,6 +1089,8 @@ bge_miibus_readreg(device_t dev, int phy
int rv = 0;
int i;
+ KASSERT(mutex_owned(sc->sc_intr_lock));
+
if (bge_ape_lock(sc, sc->bge_phy_ape_lock) != 0)
return -1;
@@ -1144,6 +1144,8 @@ bge_miibus_writereg(device_t dev, int ph
int rv = 0;
int i;
+ KASSERT(mutex_owned(sc->sc_intr_lock));
+
if (BGE_ASICREV(sc->bge_chipid) == BGE_ASICREV_BCM5906 &&
(reg == MII_GTCR || reg == BRGPHY_MII_AUXCTL))
return 0;
@@ -1198,6 +1200,8 @@ bge_miibus_statchg(struct ifnet *ifp)
struct mii_data *mii = &sc->bge_mii;
uint32_t mac_mode, rx_mode, tx_mode;
+ KASSERT(mutex_owned(sc->sc_intr_lock));
+
/*
* Get flow control negotiation result.
*/
@@ -1838,7 +1842,7 @@ bge_setmulti(struct bge_softc *sc)
uint32_t h;
int i;
- KASSERT(mutex_owned(sc->sc_core_lock));
+ KASSERT(mutex_owned(sc->sc_mcast_lock));
if (sc->bge_if_flags & IFF_PROMISC)
goto allmulti;
@@ -2766,10 +2770,16 @@ bge_blockinit(struct bge_softc *sc)
/* 5718 step 35, 36, 37 */
/* Set up host coalescing defaults */
- CSR_WRITE_4(sc, BGE_HCC_RX_COAL_TICKS, sc->bge_rx_coal_ticks);
- CSR_WRITE_4(sc, BGE_HCC_TX_COAL_TICKS, sc->bge_tx_coal_ticks);
- CSR_WRITE_4(sc, BGE_HCC_RX_MAX_COAL_BDS, sc->bge_rx_max_coal_bds);
- CSR_WRITE_4(sc, BGE_HCC_TX_MAX_COAL_BDS, sc->bge_tx_max_coal_bds);
+ mutex_enter(sc->sc_intr_lock);
+ const uint32_t rx_coal_ticks = sc->bge_rx_coal_ticks;
+ const uint32_t tx_coal_ticks = sc->bge_tx_coal_ticks;
+ const uint32_t rx_max_coal_bds = sc->bge_rx_max_coal_bds;
+ const uint32_t tx_max_coal_bds = sc->bge_tx_max_coal_bds;
+ mutex_exit(sc->sc_intr_lock);
+ CSR_WRITE_4(sc, BGE_HCC_RX_COAL_TICKS, rx_coal_ticks);
+ CSR_WRITE_4(sc, BGE_HCC_TX_COAL_TICKS, tx_coal_ticks);
+ CSR_WRITE_4(sc, BGE_HCC_RX_MAX_COAL_BDS, rx_max_coal_bds);
+ CSR_WRITE_4(sc, BGE_HCC_TX_MAX_COAL_BDS, tx_max_coal_bds);
if (!(BGE_IS_5705_PLUS(sc))) {
CSR_WRITE_4(sc, BGE_HCC_RX_COAL_TICKS_INT, 0);
CSR_WRITE_4(sc, BGE_HCC_TX_COAL_TICKS_INT, 0);
@@ -3295,7 +3305,6 @@ bge_attach(device_t parent, device_t sel
return;
}
- sc->bge_stopping = false;
sc->bge_txrx_stopping = false;
/* Save various chip information. */
@@ -3869,7 +3878,7 @@ bge_attach(device_t parent, device_t sel
else
sc->bge_return_ring_cnt = BGE_RETURN_RING_CNT;
- sc->sc_core_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NONE);
+ sc->sc_mcast_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_SOFTNET);
sc->sc_intr_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NET);
/* Set up ifnet structure */
@@ -4124,6 +4133,8 @@ bge_release_resources(struct bge_softc *
if (sc->bge_log != NULL)
sysctl_teardown(&sc->bge_log);
+ callout_destroy(&sc->bge_timeout);
+
#ifdef BGE_EVENT_COUNTERS
/* Detach event counters. */
evcnt_detach(&sc->bge_ev_intr);
@@ -4137,6 +4148,9 @@ bge_release_resources(struct bge_softc *
evcnt_detach(&sc->bge_ev_xoffentered);
#endif /* BGE_EVENT_COUNTERS */
+ mutex_obj_free(sc->sc_intr_lock);
+ mutex_obj_free(sc->sc_mcast_lock);
+
/* Disestablish the interrupt handler */
if (sc->bge_intrhand != NULL) {
pci_intr_disestablish(sc->sc_pc, sc->bge_intrhand);
@@ -4466,6 +4480,8 @@ bge_rxeof(struct bge_softc *sc)
bus_size_t tlen;
int tosync;
+ KASSERT(mutex_owned(sc->sc_intr_lock));
+
bus_dmamap_sync(sc->bge_dmatag, sc->bge_ring_map,
offsetof(struct bge_ring_data, bge_status_block),
sizeof(struct bge_status_block),
@@ -4636,6 +4652,8 @@ bge_txeof(struct bge_softc *sc)
int tosync;
struct mbuf *m;
+ KASSERT(mutex_owned(sc->sc_intr_lock));
+
bus_dmamap_sync(sc->bge_dmatag, sc->bge_ring_map,
offsetof(struct bge_ring_data, bge_status_block),
sizeof(struct bge_status_block),
@@ -4833,11 +4851,7 @@ bge_tick(void *xsc)
struct ifnet * const ifp = &sc->ethercom.ec_if;
struct mii_data * const mii = &sc->bge_mii;
- mutex_enter(sc->sc_core_lock);
- if (sc->bge_stopping) {
- mutex_exit(sc->sc_core_lock);
- return;
- }
+ mutex_enter(sc->sc_intr_lock);
if (BGE_IS_5705_PLUS(sc))
bge_stats_update_regs(sc);
@@ -4859,9 +4873,7 @@ bge_tick(void *xsc)
* (extra input errors was reported for bcm5701 & bcm5704).
*/
if (!BGE_STS_BIT(sc, BGE_STS_LINK)) {
- mutex_enter(sc->sc_intr_lock);
mii_tick(mii);
- mutex_exit(sc->sc_intr_lock);
}
}
@@ -4870,8 +4882,7 @@ bge_tick(void *xsc)
const bool ok = bge_watchdog_tick(ifp);
if (ok)
callout_schedule(&sc->bge_timeout, hz);
-
- mutex_exit(sc->sc_core_lock);
+ mutex_exit(sc->sc_intr_lock);
}
static void
@@ -5155,6 +5166,8 @@ bge_encap(struct bge_softc *sc, struct m
uint16_t vtag;
bool remap;
+ KASSERT(mutex_owned(sc->sc_intr_lock));
+
if (m_head->m_pkthdr.csum_flags) {
if (m_head->m_pkthdr.csum_flags & M_CSUM_IPv4)
csum_flags |= BGE_TXBDFLAG_IP_CSUM;
@@ -5568,35 +5581,19 @@ static int
bge_init(struct ifnet *ifp)
{
struct bge_softc * const sc = ifp->if_softc;
-
- KASSERT(IFNET_LOCKED(ifp));
-
- if (sc->bge_detaching)
- return ENXIO;
-
- mutex_enter(sc->sc_core_lock);
- int ret = bge_init_locked(ifp);
- mutex_exit(sc->sc_core_lock);
-
- return ret;
-}
-
-
-static int
-bge_init_locked(struct ifnet *ifp)
-{
- struct bge_softc * const sc = ifp->if_softc;
const uint16_t *m;
uint32_t mode, reg;
int error = 0;
ASSERT_SLEEPABLE();
KASSERT(IFNET_LOCKED(ifp));
- KASSERT(mutex_owned(sc->sc_core_lock));
KASSERT(ifp == &sc->ethercom.ec_if);
+ if (sc->bge_detaching)
+ return ENXIO;
+
/* Cancel pending I/O and flush buffers. */
- bge_stop_locked(ifp, false);
+ bge_stop(ifp, 0);
bge_stop_fw(sc);
bge_sig_pre_reset(sc, BGE_RESET_START);
@@ -5768,7 +5765,6 @@ bge_init_locked(struct ifnet *ifp)
mutex_enter(sc->sc_intr_lock);
if ((error = bge_ifmedia_upd(ifp)) == 0) {
- sc->bge_stopping = false;
sc->bge_txrx_stopping = false;
/* IFNET_LOCKED asserted above */
@@ -5778,7 +5774,9 @@ bge_init_locked(struct ifnet *ifp)
}
mutex_exit(sc->sc_intr_lock);
+ mutex_enter(sc->sc_mcast_lock);
sc->bge_if_flags = ifp->if_flags;
+ mutex_exit(sc->sc_mcast_lock);
return error;
}
@@ -5924,7 +5922,7 @@ bge_ifflags_cb(struct ethercom *ec)
int ret = 0;
KASSERT(IFNET_LOCKED(ifp));
- mutex_enter(sc->sc_core_lock);
+ mutex_enter(sc->sc_mcast_lock);
u_short change = ifp->if_flags ^ sc->bge_if_flags;
@@ -5940,7 +5938,7 @@ bge_ifflags_cb(struct ethercom *ec)
}
sc->bge_if_flags = ifp->if_flags;
- mutex_exit(sc->sc_core_lock);
+ mutex_exit(sc->sc_mcast_lock);
return ret;
}
@@ -5964,7 +5962,7 @@ bge_ioctl(struct ifnet *ifp, u_long comm
switch (command) {
case SIOCSIFMEDIA:
- mutex_enter(sc->sc_core_lock);
+ mutex_enter(sc->sc_intr_lock);
/* XXX Flow control is not supported for 1000BASE-SX */
if (sc->bge_flags & BGEF_FIBER_TBI) {
ifr->ifr_media &= ~IFM_ETH_FMASK;
@@ -5984,7 +5982,7 @@ bge_ioctl(struct ifnet *ifp, u_long comm
}
sc->bge_flowflags = ifr->ifr_media & IFM_ETH_FMASK;
}
- mutex_exit(sc->sc_core_lock);
+ mutex_exit(sc->sc_intr_lock);
if (sc->bge_flags & BGEF_FIBER_TBI) {
error = ifmedia_ioctl(ifp, ifr, &sc->bge_ifmedia,
@@ -6002,11 +6000,11 @@ bge_ioctl(struct ifnet *ifp, u_long comm
error = 0;
if (command == SIOCADDMULTI || command == SIOCDELMULTI) {
- mutex_enter(sc->sc_core_lock);
+ mutex_enter(sc->sc_mcast_lock);
if (sc->bge_if_flags & IFF_RUNNING) {
bge_setmulti(sc);
}
- mutex_exit(sc->sc_core_lock);
+ mutex_exit(sc->sc_mcast_lock);
}
break;
}
@@ -6020,7 +6018,7 @@ static bool
bge_watchdog_check(struct bge_softc * const sc)
{
- KASSERT(mutex_owned(sc->sc_core_lock));
+ KASSERT(mutex_owned(sc->sc_intr_lock));
if (!sc->bge_tx_sending)
return true;
@@ -6063,7 +6061,7 @@ bge_watchdog_tick(struct ifnet *ifp)
{
struct bge_softc * const sc = ifp->if_softc;
- KASSERT(mutex_owned(sc->sc_core_lock));
+ KASSERT(mutex_owned(sc->sc_intr_lock));
if (!sc->sc_trigger_reset && bge_watchdog_check(sc))
return true;
@@ -6126,7 +6124,10 @@ bge_stop_block(struct bge_softc *sc, bus
(u_long)reg, bit);
}
-
+/*
+ * Stop the adapter and free any mbufs allocated to the
+ * RX and TX lists.
+ */
static void
bge_stop(struct ifnet *ifp, int disable)
{
@@ -6135,31 +6136,11 @@ bge_stop(struct ifnet *ifp, int disable)
ASSERT_SLEEPABLE();
KASSERT(IFNET_LOCKED(ifp));
- mutex_enter(sc->sc_core_lock);
- bge_stop_locked(ifp, disable ? true : false);
- mutex_exit(sc->sc_core_lock);
-}
-
-/*
- * Stop the adapter and free any mbufs allocated to the
- * RX and TX lists.
- */
-static void
-bge_stop_locked(struct ifnet *ifp, bool disable)
-{
- struct bge_softc * const sc = ifp->if_softc;
-
- ASSERT_SLEEPABLE();
- KASSERT(IFNET_LOCKED(ifp));
- KASSERT(mutex_owned(sc->sc_core_lock));
-
- sc->bge_stopping = true;
-
mutex_enter(sc->sc_intr_lock);
sc->bge_txrx_stopping = true;
mutex_exit(sc->sc_intr_lock);
- callout_halt(&sc->bge_timeout, sc->sc_core_lock);
+ callout_halt(&sc->bge_timeout, NULL);
/* Disable host interrupts. */
BGE_SETBIT(sc, BGE_PCI_MISC_CTL, BGE_PCIMISCCTL_MASK_PCI_INTR);
@@ -6257,7 +6238,9 @@ bge_stop_locked(struct ifnet *ifp, bool
ifp->if_flags &= ~IFF_RUNNING;
+ mutex_enter(sc->sc_mcast_lock);
sc->bge_if_flags = ifp->if_flags;
+ mutex_exit(sc->sc_mcast_lock);
}
static void
diff -r 3b02c14478dd -r acdf8ea65621 sys/dev/pci/if_bgevar.h
--- a/sys/dev/pci/if_bgevar.h Mon Aug 12 17:29:25 2024 +0000
+++ b/sys/dev/pci/if_bgevar.h Mon Aug 12 17:51:59 2024 +0000
@@ -261,6 +261,21 @@ struct txdmamap_pool_entry {
#define ASF_NEW_HANDSHAKE 2
#define ASF_STACKUP 4
+/*
+ * Locking notes:
+ *
+ * n IFNET_LOCK
+ * m sc_mcast_lock
+ * i sc_intr_lock
+ * i/n while down, IFNET_LOCK; while up, sc_intr_lock
+ *
+ * Otherwise, stable from attach to detach.
+ *
+ * Lock order:
+ *
+ * IFNET_LOCK -> sc_intr_lock
+ * IFNET_LOCK -> sc_mcast_lock
+ */
struct bge_softc {
device_t bge_dev;
struct ethercom ethercom; /* interface info */
@@ -276,10 +291,10 @@ struct bge_softc {
pcitag_t sc_pcitag;
struct pci_attach_args bge_pa;
- struct mii_data bge_mii;
- struct ifmedia bge_ifmedia; /* media info */
+ struct mii_data bge_mii; /* i: mii data */
+ struct ifmedia bge_ifmedia; /* i: media info */
uint32_t bge_return_ring_cnt;
- uint32_t bge_tx_prodidx;
+ uint32_t bge_tx_prodidx; /* i: tx producer idx */
bus_dma_tag_t bge_dmatag;
bus_dma_tag_t bge_dmatag32;
bool bge_dma64;
@@ -287,7 +302,7 @@ struct bge_softc {
uint32_t bge_pciecap;
uint16_t bge_mps;
int bge_expmrq;
- uint32_t bge_lasttag;
+ uint32_t bge_lasttag; /* i: last status tag */
uint32_t bge_mfw_flags; /* Management F/W flags */
#define BGE_MFW_ON_RXCPU __BIT(0)
#define BGE_MFW_ON_APE __BIT(1)
@@ -297,74 +312,82 @@ struct bge_softc {
int bge_phy_addr;
uint32_t bge_chipid;
uint8_t bge_asf_mode;
- uint8_t bge_asf_count;
+ uint8_t bge_asf_count; /* i: XXX ??? */
struct bge_ring_data *bge_rdata; /* rings */
struct bge_chain_data bge_cdata; /* mbufs */
bus_dmamap_t bge_ring_map;
bus_dma_segment_t bge_ring_seg;
int bge_ring_rseg;
- uint16_t bge_tx_saved_considx;
- uint16_t bge_rx_saved_considx;
- uint16_t bge_std; /* current std ring head */
- uint16_t bge_std_cnt;
- uint16_t bge_jumbo; /* current jumbo ring head */
+ uint16_t bge_tx_saved_considx; /* i: tx consumer idx */
+ uint16_t bge_rx_saved_considx; /* i: rx consumer idx */
+ uint16_t bge_std; /* i: current std ring head */
+ uint16_t bge_std_cnt; /* i: number of std mbufs */
+ uint16_t bge_jumbo;
+ /* i: current jumbo ring head */
SLIST_HEAD(__bge_jfreehead, bge_jpool_entry) bge_jfree_listhead;
+ /* i: list of free jumbo mbufs */
SLIST_HEAD(__bge_jinusehead, bge_jpool_entry) bge_jinuse_listhead;
+ /* i: list of jumbo mbufs in use */
uint32_t bge_stat_ticks;
- uint32_t bge_rx_coal_ticks;
- uint32_t bge_tx_coal_ticks;
- uint32_t bge_rx_max_coal_bds;
- uint32_t bge_tx_max_coal_bds;
- uint32_t bge_sts;
+ uint32_t bge_rx_coal_ticks; /* i */
+ uint32_t bge_tx_coal_ticks; /* i */
+ uint32_t bge_rx_max_coal_bds; /* i */
+ uint32_t bge_tx_max_coal_bds; /* i */
+ uint32_t bge_sts; /* i/n: link status */
#define BGE_STS_LINK __BIT(0) /* MAC link status */
#define BGE_STS_LINK_EVT __BIT(1) /* pending link event */
#define BGE_STS_AUTOPOLL __BIT(2) /* PHY auto-polling */
#define BGE_STS_BIT(sc, x) ((sc)->bge_sts & (x))
#define BGE_STS_SETBIT(sc, x) ((sc)->bge_sts |= (x))
#define BGE_STS_CLRBIT(sc, x) ((sc)->bge_sts &= ~(x))
- u_short bge_if_flags;
- uint32_t bge_flags;
+ u_short bge_if_flags; /* m: if_flags cache */
+ uint32_t bge_flags; /* i/n */
uint32_t bge_phy_flags;
- int bge_flowflags;
+ int bge_flowflags; /* i */
time_t bge_tx_lastsent;
- bool bge_stopping;
+ /* i: time of last tx */
bool bge_txrx_stopping;
- bool bge_tx_sending;
+ /* i: true when going down */
+ bool bge_tx_sending; /* i: XXX ??? */
#ifdef BGE_EVENT_COUNTERS
/*
* Event counters.
*/
- struct evcnt bge_ev_intr; /* interrupts */
- struct evcnt bge_ev_intr_spurious; /* spurious intr. (tagged status)*/
- struct evcnt bge_ev_intr_spurious2; /* spurious interrupts */
- struct evcnt bge_ev_tx_xoff; /* send PAUSE(len>0) packets */
- struct evcnt bge_ev_tx_xon; /* send PAUSE(len=0) packets */
- struct evcnt bge_ev_rx_xoff; /* receive PAUSE(len>0) packets */
- struct evcnt bge_ev_rx_xon; /* receive PAUSE(len=0) packets */
- struct evcnt bge_ev_rx_macctl; /* receive MAC control packets */
- struct evcnt bge_ev_xoffentered;/* XOFF state entered */
+ struct evcnt bge_ev_intr; /* i: interrupts */
+ struct evcnt bge_ev_intr_spurious;
+ /* i: spurious intr. (tagged status) */
+ struct evcnt bge_ev_intr_spurious2; /* i: spurious interrupts */
+ struct evcnt bge_ev_tx_xoff; /* i: send PAUSE(len>0) packets */
+ struct evcnt bge_ev_tx_xon; /* i: send PAUSE(len=0) packets */
+ struct evcnt bge_ev_rx_xoff; /* i: receive PAUSE(len>0) packets */
+ struct evcnt bge_ev_rx_xon; /* i: receive PAUSE(len=0) packets */
+ struct evcnt bge_ev_rx_macctl; /* i: receive MAC control packets */
+ struct evcnt bge_ev_xoffentered;/* i: XOFF state entered */
#endif /* BGE_EVENT_COUNTERS */
- uint64_t bge_if_collisions;
- int bge_txcnt;
- struct callout bge_timeout;
+ uint64_t bge_if_collisions; /* i */
+ int bge_txcnt; /* i: # tx descs in use */
+ struct callout bge_timeout; /* i: tx timeout */
bool bge_pending_rxintr_change;
+ /* i: change pending to
+ * rx_coal_ticks and
+ * rx_max_coal_bds */
bool bge_attached;
- bool bge_detaching;
- SLIST_HEAD(, txdmamap_pool_entry) txdma_list;
- struct txdmamap_pool_entry *txdma[BGE_TX_RING_CNT];
+ bool bge_detaching; /* n */
+ SLIST_HEAD(, txdmamap_pool_entry) txdma_list; /* i */
+ struct txdmamap_pool_entry *txdma[BGE_TX_RING_CNT]; /* i */
struct sysctllog *bge_log;
krndsource_t rnd_source; /* random source */
- kmutex_t *sc_core_lock; /* lock for softc operations */
- kmutex_t *sc_intr_lock; /* lock for interrupt operations */
+ kmutex_t *sc_mcast_lock; /* m: lock for SIOCADD/DELMULTI */
+ kmutex_t *sc_intr_lock; /* i: lock for interrupt operations */
struct workqueue *sc_reset_wq;
- struct work sc_reset_work;
+ struct work sc_reset_work; /* i */
volatile unsigned sc_reset_pending;
- bool sc_trigger_reset;
+ bool sc_trigger_reset; /* i */
};
#endif /* _DEV_PCI_IF_BGEVAR_H_ */
diff -r 26b25ed27d2f sys/dev/pci/if_bge.c
--- a/sys/dev/pci/if_bge.c Sun Aug 11 18:33:13 2024 +0000
+++ b/sys/dev/pci/if_bge.c Mon Aug 12 18:32:16 2024 +0000
@@ -203,9 +203,7 @@ static void bge_start_locked(struct ifne
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_stop_locked(struct ifnet *, bool);
static bool bge_watchdog_tick(struct ifnet *);
static int bge_ifmedia_upd(struct ifnet *);
static void bge_ifmedia_sts(struct ifnet *, struct ifmediareq *);
@@ -1091,6 +1089,8 @@ bge_miibus_readreg(device_t dev, int phy
int rv = 0;
int i;
+ KASSERT(mutex_owned(sc->sc_intr_lock));
+
if (bge_ape_lock(sc, sc->bge_phy_ape_lock) != 0)
return -1;
@@ -1144,6 +1144,8 @@ bge_miibus_writereg(device_t dev, int ph
int rv = 0;
int i;
+ KASSERT(mutex_owned(sc->sc_intr_lock));
+
if (BGE_ASICREV(sc->bge_chipid) == BGE_ASICREV_BCM5906 &&
(reg == MII_GTCR || reg == BRGPHY_MII_AUXCTL))
return 0;
@@ -1198,6 +1200,8 @@ bge_miibus_statchg(struct ifnet *ifp)
struct mii_data *mii = &sc->bge_mii;
uint32_t mac_mode, rx_mode, tx_mode;
+ KASSERT(mutex_owned(sc->sc_intr_lock));
+
/*
* Get flow control negotiation result.
*/
@@ -1838,7 +1842,7 @@ bge_setmulti(struct bge_softc *sc)
uint32_t h;
int i;
- KASSERT(mutex_owned(sc->sc_core_lock));
+ KASSERT(mutex_owned(sc->sc_mcast_lock));
if (sc->bge_if_flags & IFF_PROMISC)
goto allmulti;
@@ -2766,10 +2770,16 @@ bge_blockinit(struct bge_softc *sc)
/* 5718 step 35, 36, 37 */
/* Set up host coalescing defaults */
- CSR_WRITE_4(sc, BGE_HCC_RX_COAL_TICKS, sc->bge_rx_coal_ticks);
- CSR_WRITE_4(sc, BGE_HCC_TX_COAL_TICKS, sc->bge_tx_coal_ticks);
- CSR_WRITE_4(sc, BGE_HCC_RX_MAX_COAL_BDS, sc->bge_rx_max_coal_bds);
- CSR_WRITE_4(sc, BGE_HCC_TX_MAX_COAL_BDS, sc->bge_tx_max_coal_bds);
+ mutex_enter(sc->sc_intr_lock);
+ const uint32_t rx_coal_ticks = sc->bge_rx_coal_ticks;
+ const uint32_t tx_coal_ticks = sc->bge_tx_coal_ticks;
+ const uint32_t rx_max_coal_bds = sc->bge_rx_max_coal_bds;
+ const uint32_t tx_max_coal_bds = sc->bge_tx_max_coal_bds;
+ mutex_exit(sc->sc_intr_lock);
+ CSR_WRITE_4(sc, BGE_HCC_RX_COAL_TICKS, rx_coal_ticks);
+ CSR_WRITE_4(sc, BGE_HCC_TX_COAL_TICKS, tx_coal_ticks);
+ CSR_WRITE_4(sc, BGE_HCC_RX_MAX_COAL_BDS, rx_max_coal_bds);
+ CSR_WRITE_4(sc, BGE_HCC_TX_MAX_COAL_BDS, tx_max_coal_bds);
if (!(BGE_IS_5705_PLUS(sc))) {
CSR_WRITE_4(sc, BGE_HCC_RX_COAL_TICKS_INT, 0);
CSR_WRITE_4(sc, BGE_HCC_TX_COAL_TICKS_INT, 0);
@@ -3295,7 +3305,6 @@ bge_attach(device_t parent, device_t sel
return;
}
- sc->bge_stopping = false;
sc->bge_txrx_stopping = false;
/* Save various chip information. */
@@ -3869,7 +3878,7 @@ bge_attach(device_t parent, device_t sel
else
sc->bge_return_ring_cnt = BGE_RETURN_RING_CNT;
- sc->sc_core_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NONE);
+ sc->sc_mcast_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_SOFTNET);
sc->sc_intr_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NET);
/* Set up ifnet structure */
@@ -4078,6 +4087,8 @@ again:
#ifdef BGE_DEBUG
bge_debug_info(sc);
#endif
+
+ sc->bge_attached = true;
}
/*
@@ -4090,6 +4101,9 @@ bge_detach(device_t self, int flags __un
struct bge_softc * const sc = device_private(self);
struct ifnet * const ifp = &sc->ethercom.ec_if;
+ if (!sc->bge_attached)
+ return;
+
IFNET_LOCK(ifp);
/* Stop the interface. Callouts are stopped in it. */
@@ -4119,6 +4133,8 @@ bge_release_resources(struct bge_softc *
if (sc->bge_log != NULL)
sysctl_teardown(&sc->bge_log);
+ callout_destroy(&sc->bge_timeout);
+
#ifdef BGE_EVENT_COUNTERS
/* Detach event counters. */
evcnt_detach(&sc->bge_ev_intr);
@@ -4132,6 +4148,9 @@ bge_release_resources(struct bge_softc *
evcnt_detach(&sc->bge_ev_xoffentered);
#endif /* BGE_EVENT_COUNTERS */
+ mutex_obj_free(sc->sc_intr_lock);
+ mutex_obj_free(sc->sc_mcast_lock);
+
/* Disestablish the interrupt handler */
if (sc->bge_intrhand != NULL) {
pci_intr_disestablish(sc->sc_pc, sc->bge_intrhand);
@@ -4461,6 +4480,8 @@ bge_rxeof(struct bge_softc *sc)
bus_size_t tlen;
int tosync;
+ KASSERT(mutex_owned(sc->sc_intr_lock));
+
bus_dmamap_sync(sc->bge_dmatag, sc->bge_ring_map,
offsetof(struct bge_ring_data, bge_status_block),
sizeof(struct bge_status_block),
@@ -4631,6 +4652,8 @@ bge_txeof(struct bge_softc *sc)
int tosync;
struct mbuf *m;
+ KASSERT(mutex_owned(sc->sc_intr_lock));
+
bus_dmamap_sync(sc->bge_dmatag, sc->bge_ring_map,
offsetof(struct bge_ring_data, bge_status_block),
sizeof(struct bge_status_block),
@@ -4828,11 +4851,7 @@ bge_tick(void *xsc)
struct ifnet * const ifp = &sc->ethercom.ec_if;
struct mii_data * const mii = &sc->bge_mii;
- mutex_enter(sc->sc_core_lock);
- if (sc->bge_stopping) {
- mutex_exit(sc->sc_core_lock);
- return;
- }
+ mutex_enter(sc->sc_intr_lock);
if (BGE_IS_5705_PLUS(sc))
bge_stats_update_regs(sc);
@@ -4854,9 +4873,7 @@ bge_tick(void *xsc)
* (extra input errors was reported for bcm5701 & bcm5704).
*/
if (!BGE_STS_BIT(sc, BGE_STS_LINK)) {
- mutex_enter(sc->sc_intr_lock);
mii_tick(mii);
- mutex_exit(sc->sc_intr_lock);
}
}
@@ -4865,8 +4882,7 @@ bge_tick(void *xsc)
const bool ok = bge_watchdog_tick(ifp);
if (ok)
callout_schedule(&sc->bge_timeout, hz);
-
- mutex_exit(sc->sc_core_lock);
+ mutex_exit(sc->sc_intr_lock);
}
static void
@@ -5150,6 +5166,8 @@ bge_encap(struct bge_softc *sc, struct m
uint16_t vtag;
bool remap;
+ KASSERT(mutex_owned(sc->sc_intr_lock));
+
if (m_head->m_pkthdr.csum_flags) {
if (m_head->m_pkthdr.csum_flags & M_CSUM_IPv4)
csum_flags |= BGE_TXBDFLAG_IP_CSUM;
@@ -5563,35 +5581,19 @@ static int
bge_init(struct ifnet *ifp)
{
struct bge_softc * const sc = ifp->if_softc;
-
- KASSERT(IFNET_LOCKED(ifp));
-
- if (sc->bge_detaching)
- return ENXIO;
-
- mutex_enter(sc->sc_core_lock);
- int ret = bge_init_locked(ifp);
- mutex_exit(sc->sc_core_lock);
-
- return ret;
-}
-
-
-static int
-bge_init_locked(struct ifnet *ifp)
-{
- struct bge_softc * const sc = ifp->if_softc;
const uint16_t *m;
uint32_t mode, reg;
int error = 0;
ASSERT_SLEEPABLE();
KASSERT(IFNET_LOCKED(ifp));
- KASSERT(mutex_owned(sc->sc_core_lock));
KASSERT(ifp == &sc->ethercom.ec_if);
+ if (sc->bge_detaching)
+ return ENXIO;
+
/* Cancel pending I/O and flush buffers. */
- bge_stop_locked(ifp, false);
+ bge_stop(ifp, 0);
bge_stop_fw(sc);
bge_sig_pre_reset(sc, BGE_RESET_START);
@@ -5763,7 +5765,6 @@ bge_init_locked(struct ifnet *ifp)
mutex_enter(sc->sc_intr_lock);
if ((error = bge_ifmedia_upd(ifp)) == 0) {
- sc->bge_stopping = false;
sc->bge_txrx_stopping = false;
/* IFNET_LOCKED asserted above */
@@ -5773,7 +5774,9 @@ bge_init_locked(struct ifnet *ifp)
}
mutex_exit(sc->sc_intr_lock);
+ mutex_enter(sc->sc_mcast_lock);
sc->bge_if_flags = ifp->if_flags;
+ mutex_exit(sc->sc_mcast_lock);
return error;
}
@@ -5919,7 +5922,7 @@ bge_ifflags_cb(struct ethercom *ec)
int ret = 0;
KASSERT(IFNET_LOCKED(ifp));
- mutex_enter(sc->sc_core_lock);
+ mutex_enter(sc->sc_mcast_lock);
u_short change = ifp->if_flags ^ sc->bge_if_flags;
@@ -5935,7 +5938,7 @@ bge_ifflags_cb(struct ethercom *ec)
}
sc->bge_if_flags = ifp->if_flags;
- mutex_exit(sc->sc_core_lock);
+ mutex_exit(sc->sc_mcast_lock);
return ret;
}
@@ -5959,7 +5962,7 @@ bge_ioctl(struct ifnet *ifp, u_long comm
switch (command) {
case SIOCSIFMEDIA:
- mutex_enter(sc->sc_core_lock);
+ mutex_enter(sc->sc_intr_lock);
/* XXX Flow control is not supported for 1000BASE-SX */
if (sc->bge_flags & BGEF_FIBER_TBI) {
ifr->ifr_media &= ~IFM_ETH_FMASK;
@@ -5979,7 +5982,7 @@ bge_ioctl(struct ifnet *ifp, u_long comm
}
sc->bge_flowflags = ifr->ifr_media & IFM_ETH_FMASK;
}
- mutex_exit(sc->sc_core_lock);
+ mutex_exit(sc->sc_intr_lock);
if (sc->bge_flags & BGEF_FIBER_TBI) {
error = ifmedia_ioctl(ifp, ifr, &sc->bge_ifmedia,
@@ -5997,11 +6000,11 @@ bge_ioctl(struct ifnet *ifp, u_long comm
error = 0;
if (command == SIOCADDMULTI || command == SIOCDELMULTI) {
- mutex_enter(sc->sc_core_lock);
+ mutex_enter(sc->sc_mcast_lock);
if (sc->bge_if_flags & IFF_RUNNING) {
bge_setmulti(sc);
}
- mutex_exit(sc->sc_core_lock);
+ mutex_exit(sc->sc_mcast_lock);
}
break;
}
@@ -6015,7 +6018,7 @@ static bool
bge_watchdog_check(struct bge_softc * const sc)
{
- KASSERT(mutex_owned(sc->sc_core_lock));
+ KASSERT(mutex_owned(sc->sc_intr_lock));
if (!sc->bge_tx_sending)
return true;
@@ -6058,7 +6061,7 @@ bge_watchdog_tick(struct ifnet *ifp)
{
struct bge_softc * const sc = ifp->if_softc;
- KASSERT(mutex_owned(sc->sc_core_lock));
+ KASSERT(mutex_owned(sc->sc_intr_lock));
if (!sc->sc_trigger_reset && bge_watchdog_check(sc))
return true;
@@ -6121,7 +6124,10 @@ bge_stop_block(struct bge_softc *sc, bus
(u_long)reg, bit);
}
-
+/*
+ * Stop the adapter and free any mbufs allocated to the
+ * RX and TX lists.
+ */
static void
bge_stop(struct ifnet *ifp, int disable)
{
@@ -6130,31 +6136,11 @@ bge_stop(struct ifnet *ifp, int disable)
ASSERT_SLEEPABLE();
KASSERT(IFNET_LOCKED(ifp));
- mutex_enter(sc->sc_core_lock);
- bge_stop_locked(ifp, disable ? true : false);
- mutex_exit(sc->sc_core_lock);
-}
-
-/*
- * Stop the adapter and free any mbufs allocated to the
- * RX and TX lists.
- */
-static void
-bge_stop_locked(struct ifnet *ifp, bool disable)
-{
- struct bge_softc * const sc = ifp->if_softc;
-
- ASSERT_SLEEPABLE();
- KASSERT(IFNET_LOCKED(ifp));
- KASSERT(mutex_owned(sc->sc_core_lock));
-
- sc->bge_stopping = true;
-
mutex_enter(sc->sc_intr_lock);
sc->bge_txrx_stopping = true;
mutex_exit(sc->sc_intr_lock);
- callout_halt(&sc->bge_timeout, sc->sc_core_lock);
+ callout_halt(&sc->bge_timeout, NULL);
/* Disable host interrupts. */
BGE_SETBIT(sc, BGE_PCI_MISC_CTL, BGE_PCIMISCCTL_MASK_PCI_INTR);
@@ -6252,7 +6238,9 @@ bge_stop_locked(struct ifnet *ifp, bool
ifp->if_flags &= ~IFF_RUNNING;
+ mutex_enter(sc->sc_mcast_lock);
sc->bge_if_flags = ifp->if_flags;
+ mutex_exit(sc->sc_mcast_lock);
}
static void
diff -r 26b25ed27d2f sys/dev/pci/if_bgevar.h
--- a/sys/dev/pci/if_bgevar.h Sun Aug 11 18:33:13 2024 +0000
+++ b/sys/dev/pci/if_bgevar.h Mon Aug 12 18:32:16 2024 +0000
@@ -261,6 +261,21 @@ struct txdmamap_pool_entry {
#define ASF_NEW_HANDSHAKE 2
#define ASF_STACKUP 4
+/*
+ * Locking notes:
+ *
+ * n IFNET_LOCK
+ * m sc_mcast_lock
+ * i sc_intr_lock
+ * i/n while down, IFNET_LOCK; while up, sc_intr_lock
+ *
+ * Otherwise, stable from attach to detach.
+ *
+ * Lock order:
+ *
+ * IFNET_LOCK -> sc_intr_lock
+ * IFNET_LOCK -> sc_mcast_lock
+ */
struct bge_softc {
device_t bge_dev;
struct ethercom ethercom; /* interface info */
@@ -276,10 +291,10 @@ struct bge_softc {
pcitag_t sc_pcitag;
struct pci_attach_args bge_pa;
- struct mii_data bge_mii;
- struct ifmedia bge_ifmedia; /* media info */
+ struct mii_data bge_mii; /* i: mii data */
+ struct ifmedia bge_ifmedia; /* i: media info */
uint32_t bge_return_ring_cnt;
- uint32_t bge_tx_prodidx;
+ uint32_t bge_tx_prodidx; /* i: tx producer idx */
bus_dma_tag_t bge_dmatag;
bus_dma_tag_t bge_dmatag32;
bool bge_dma64;
@@ -287,7 +302,7 @@ struct bge_softc {
uint32_t bge_pciecap;
uint16_t bge_mps;
int bge_expmrq;
- uint32_t bge_lasttag;
+ uint32_t bge_lasttag; /* i: last status tag */
uint32_t bge_mfw_flags; /* Management F/W flags */
#define BGE_MFW_ON_RXCPU __BIT(0)
#define BGE_MFW_ON_APE __BIT(1)
@@ -297,73 +312,82 @@ struct bge_softc {
int bge_phy_addr;
uint32_t bge_chipid;
uint8_t bge_asf_mode;
- uint8_t bge_asf_count;
+ uint8_t bge_asf_count; /* i: XXX ??? */
struct bge_ring_data *bge_rdata; /* rings */
struct bge_chain_data bge_cdata; /* mbufs */
bus_dmamap_t bge_ring_map;
bus_dma_segment_t bge_ring_seg;
int bge_ring_rseg;
- uint16_t bge_tx_saved_considx;
- uint16_t bge_rx_saved_considx;
- uint16_t bge_std; /* current std ring head */
- uint16_t bge_std_cnt;
- uint16_t bge_jumbo; /* current jumbo ring head */
+ uint16_t bge_tx_saved_considx; /* i: tx consumer idx */
+ uint16_t bge_rx_saved_considx; /* i: rx consumer idx */
+ uint16_t bge_std; /* i: current std ring head */
+ uint16_t bge_std_cnt; /* i: number of std mbufs */
+ uint16_t bge_jumbo;
+ /* i: current jumbo ring head */
SLIST_HEAD(__bge_jfreehead, bge_jpool_entry) bge_jfree_listhead;
+ /* i: list of free jumbo mbufs */
SLIST_HEAD(__bge_jinusehead, bge_jpool_entry) bge_jinuse_listhead;
+ /* i: list of jumbo mbufs in use */
uint32_t bge_stat_ticks;
- uint32_t bge_rx_coal_ticks;
- uint32_t bge_tx_coal_ticks;
- uint32_t bge_rx_max_coal_bds;
- uint32_t bge_tx_max_coal_bds;
- uint32_t bge_sts;
+ uint32_t bge_rx_coal_ticks; /* i */
+ uint32_t bge_tx_coal_ticks; /* i */
+ uint32_t bge_rx_max_coal_bds; /* i */
+ uint32_t bge_tx_max_coal_bds; /* i */
+ uint32_t bge_sts; /* i/n: link status */
#define BGE_STS_LINK __BIT(0) /* MAC link status */
#define BGE_STS_LINK_EVT __BIT(1) /* pending link event */
#define BGE_STS_AUTOPOLL __BIT(2) /* PHY auto-polling */
#define BGE_STS_BIT(sc, x) ((sc)->bge_sts & (x))
#define BGE_STS_SETBIT(sc, x) ((sc)->bge_sts |= (x))
#define BGE_STS_CLRBIT(sc, x) ((sc)->bge_sts &= ~(x))
- u_short bge_if_flags;
- uint32_t bge_flags;
+ u_short bge_if_flags; /* m: if_flags cache */
+ uint32_t bge_flags; /* i/n */
uint32_t bge_phy_flags;
- int bge_flowflags;
+ int bge_flowflags; /* i */
time_t bge_tx_lastsent;
- bool bge_stopping;
+ /* i: time of last tx */
bool bge_txrx_stopping;
- bool bge_tx_sending;
+ /* i: true when going down */
+ bool bge_tx_sending; /* i: XXX ??? */
#ifdef BGE_EVENT_COUNTERS
/*
* Event counters.
*/
- struct evcnt bge_ev_intr; /* interrupts */
- struct evcnt bge_ev_intr_spurious; /* spurious intr. (tagged status)*/
- struct evcnt bge_ev_intr_spurious2; /* spurious interrupts */
- struct evcnt bge_ev_tx_xoff; /* send PAUSE(len>0) packets */
- struct evcnt bge_ev_tx_xon; /* send PAUSE(len=0) packets */
- struct evcnt bge_ev_rx_xoff; /* receive PAUSE(len>0) packets */
- struct evcnt bge_ev_rx_xon; /* receive PAUSE(len=0) packets */
- struct evcnt bge_ev_rx_macctl; /* receive MAC control packets */
- struct evcnt bge_ev_xoffentered;/* XOFF state entered */
+ struct evcnt bge_ev_intr; /* i: interrupts */
+ struct evcnt bge_ev_intr_spurious;
+ /* i: spurious intr. (tagged status) */
+ struct evcnt bge_ev_intr_spurious2; /* i: spurious interrupts */
+ struct evcnt bge_ev_tx_xoff; /* i: send PAUSE(len>0) packets */
+ struct evcnt bge_ev_tx_xon; /* i: send PAUSE(len=0) packets */
+ struct evcnt bge_ev_rx_xoff; /* i: receive PAUSE(len>0) packets */
+ struct evcnt bge_ev_rx_xon; /* i: receive PAUSE(len=0) packets */
+ struct evcnt bge_ev_rx_macctl; /* i: receive MAC control packets */
+ struct evcnt bge_ev_xoffentered;/* i: XOFF state entered */
#endif /* BGE_EVENT_COUNTERS */
- uint64_t bge_if_collisions;
- int bge_txcnt;
- struct callout bge_timeout;
+ uint64_t bge_if_collisions; /* i */
+ int bge_txcnt; /* i: # tx descs in use */
+ struct callout bge_timeout; /* i: tx timeout */
bool bge_pending_rxintr_change;
- bool bge_detaching;
- SLIST_HEAD(, txdmamap_pool_entry) txdma_list;
- struct txdmamap_pool_entry *txdma[BGE_TX_RING_CNT];
+ /* i: change pending to
+ * rx_coal_ticks and
+ * rx_max_coal_bds */
+ bool bge_attached;
+ bool bge_detaching; /* n */
+ SLIST_HEAD(, txdmamap_pool_entry) txdma_list; /* i */
+ struct txdmamap_pool_entry *txdma[BGE_TX_RING_CNT]; /* i */
struct sysctllog *bge_log;
krndsource_t rnd_source; /* random source */
- kmutex_t *sc_core_lock; /* lock for softc operations */
- kmutex_t *sc_intr_lock; /* lock for interrupt operations */
+ kmutex_t *sc_mcast_lock; /* m: lock for SIOCADD/DELMULTI */
+ kmutex_t *sc_intr_lock; /* i: lock for interrupt operations */
struct workqueue *sc_reset_wq;
- struct work sc_reset_work;
+ struct work sc_reset_work; /* i */
volatile unsigned sc_reset_pending;
- bool sc_trigger_reset;
+ bool sc_trigger_reset; /* i */
};
#endif /* _DEV_PCI_IF_BGEVAR_H_ */
Home |
Main Index |
Thread Index |
Old Index