Module Name: src
Committed By: martin
Date: Fri Nov 3 10:04:56 UTC 2023
Modified Files:
src/sys/dev/ic [netbsd-10]: dwc_eqos.c dwc_eqos_var.h
Log Message:
Pull up following revision(s) (requested by riastradh in ticket #453):
sys/dev/ic/dwc_eqos_var.h: revision 1.7
sys/dev/ic/dwc_eqos_var.h: revision 1.8
sys/dev/ic/dwc_eqos_var.h: revision 1.9
sys/dev/ic/dwc_eqos.c: revision 1.30
sys/dev/ic/dwc_eqos.c: revision 1.31
sys/dev/ic/dwc_eqos.c: revision 1.32
sys/dev/ic/dwc_eqos.c: revision 1.33
eqos(4): Wait for callout to halt and make sure it stays halted.
eqos(4): Don't touch if_flags in tx path.
Can't touch this without IFNET_LOCK.
eqos(4): Fix locking around multicast filter updates.
- Can't touch if_flags without IFNET_LOCK.
- Can't take IFNET_LOCK in SIOCADDMULTI/SIOCDELMULTI path.
Instead, cache IFF_PROMISC and IFF_ALLMULTI on if_init under a lock we
can take in this path.
XXX Is IFF_ALLMULTI relevant any more? Hasn't it been moved to
ethercom flags?
XXX Should not take sc_lock around if_init/stop -- IFNET_LOCK is
enough. Should narrow scope of sc_lock to be just tick/mii/multi
stuff.
eqos(4): Fix multicast filter updates.
1. Don't touch the obsolete IFF_ALLMULTI.
2. Set ETHER_F_ALLMULTI if we're accepting all multicast addresses.
3. If any multicast entry range is not a single address, accept all
multicast addresses.
To generate a diff of this commit:
cvs rdiff -u -r1.16.4.1 -r1.16.4.2 src/sys/dev/ic/dwc_eqos.c
cvs rdiff -u -r1.4.4.1 -r1.4.4.2 src/sys/dev/ic/dwc_eqos_var.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/dev/ic/dwc_eqos.c
diff -u src/sys/dev/ic/dwc_eqos.c:1.16.4.1 src/sys/dev/ic/dwc_eqos.c:1.16.4.2
--- src/sys/dev/ic/dwc_eqos.c:1.16.4.1 Fri Nov 3 08:56:36 2023
+++ src/sys/dev/ic/dwc_eqos.c Fri Nov 3 10:04:55 2023
@@ -1,4 +1,4 @@
-/* $NetBSD: dwc_eqos.c,v 1.16.4.1 2023/11/03 08:56:36 martin Exp $ */
+/* $NetBSD: dwc_eqos.c,v 1.16.4.2 2023/11/03 10:04:55 martin Exp $ */
/*-
* Copyright (c) 2022 Jared McNeill <[email protected]>
@@ -38,7 +38,7 @@
#include "opt_net_mpsafe.h"
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: dwc_eqos.c,v 1.16.4.1 2023/11/03 08:56:36 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: dwc_eqos.c,v 1.16.4.2 2023/11/03 10:04:55 martin Exp $");
#include <sys/param.h>
#include <sys/bus.h>
@@ -468,7 +468,8 @@ eqos_tick(void *softc)
EQOS_LOCK(sc);
mii_tick(mii);
- callout_schedule(&sc->sc_stat_ch, hz);
+ if (sc->sc_running)
+ callout_schedule(&sc->sc_stat_ch, hz);
EQOS_UNLOCK(sc);
#ifndef EQOS_MPSAFE
@@ -508,17 +509,29 @@ eqos_setup_rxfilter(struct eqos_softc *s
GMAC_MAC_PACKET_FILTER_PCF_MASK);
hash[0] = hash[1] = ~0U;
- if ((ifp->if_flags & IFF_PROMISC) != 0) {
+ ETHER_LOCK(ec);
+ if (sc->sc_promisc) {
+ ec->ec_flags |= ETHER_F_ALLMULTI;
pfil |= GMAC_MAC_PACKET_FILTER_PR |
GMAC_MAC_PACKET_FILTER_PCF_ALL;
- } else if ((ifp->if_flags & IFF_ALLMULTI) != 0) {
- pfil |= GMAC_MAC_PACKET_FILTER_PM;
} else {
- hash[0] = hash[1] = 0;
pfil |= GMAC_MAC_PACKET_FILTER_HMC;
- ETHER_LOCK(ec);
+ hash[0] = hash[1] = 0;
+ ec->ec_flags &= ~ETHER_F_ALLMULTI;
ETHER_FIRST_MULTI(step, ec, enm);
while (enm != NULL) {
+ if (memcmp(enm->enm_addrlo, enm->enm_addrhi,
+ ETHER_ADDR_LEN) != 0) {
+ ec->ec_flags |= ETHER_F_ALLMULTI;
+ pfil &= ~GMAC_MAC_PACKET_FILTER_HMC;
+ pfil |= GMAC_MAC_PACKET_FILTER_PM;
+ /*
+ * Shouldn't matter if we clear HMC but
+ * let's avoid using different values.
+ */
+ hash[0] = hash[1] = 0xffffffff;
+ break;
+ }
crc = ether_crc32_le(enm->enm_addrlo, ETHER_ADDR_LEN);
crc &= 0x7f;
crc = eqos_bitrev32(~crc) >> 26;
@@ -527,8 +540,8 @@ eqos_setup_rxfilter(struct eqos_softc *s
hash[hashreg] |= (1 << hashbit);
ETHER_NEXT_MULTI(step, enm);
}
- ETHER_UNLOCK(ec);
}
+ ETHER_UNLOCK(ec);
/* Write our unicast address */
eaddr = CLLADDR(ifp->if_sadl);
@@ -616,6 +629,7 @@ eqos_init_locked(struct eqos_softc *sc)
eqos_init_rings(sc, 0);
/* Setup RX filter */
+ sc->sc_promisc = ifp->if_flags & IFF_PROMISC;
eqos_setup_rxfilter(sc);
WR4(sc, GMAC_MAC_1US_TIC_COUNTER, (sc->sc_csr_clock / 1000000) - 1);
@@ -697,6 +711,10 @@ eqos_init_locked(struct eqos_softc *sc)
/* Enable interrupts */
eqos_enable_intr(sc);
+ EQOS_ASSERT_TXLOCKED(sc);
+ sc->sc_txrunning = true;
+
+ sc->sc_running = true;
ifp->if_flags |= IFF_RUNNING;
mii_mediachg(mii);
@@ -729,7 +747,12 @@ eqos_stop_locked(struct eqos_softc *sc,
EQOS_ASSERT_LOCKED(sc);
- callout_stop(&sc->sc_stat_ch);
+ EQOS_TXLOCK(sc);
+ sc->sc_txrunning = false;
+ EQOS_TXUNLOCK(sc);
+
+ sc->sc_running = false;
+ callout_halt(&sc->sc_stat_ch, &sc->sc_lock);
mii_down(&sc->sc_mii);
@@ -1007,7 +1030,7 @@ eqos_start_locked(struct eqos_softc *sc)
EQOS_ASSERT_TXLOCKED(sc);
- if ((ifp->if_flags & IFF_RUNNING) == 0)
+ if (!sc->sc_txrunning)
return;
for (cnt = 0, start = sc->sc_tx.cur; ; cnt++) {
@@ -1222,9 +1245,10 @@ eqos_ioctl(struct ifnet *ifp, u_long cmd
error = (*ifp->if_init)(ifp);
else if (cmd != SIOCADDMULTI && cmd != SIOCDELMULTI)
;
- else if ((ifp->if_flags & IFF_RUNNING) != 0) {
+ else {
EQOS_LOCK(sc);
- eqos_setup_rxfilter(sc);
+ if (sc->sc_running)
+ eqos_setup_rxfilter(sc);
EQOS_UNLOCK(sc);
}
break;
Index: src/sys/dev/ic/dwc_eqos_var.h
diff -u src/sys/dev/ic/dwc_eqos_var.h:1.4.4.1 src/sys/dev/ic/dwc_eqos_var.h:1.4.4.2
--- src/sys/dev/ic/dwc_eqos_var.h:1.4.4.1 Fri Nov 3 08:56:36 2023
+++ src/sys/dev/ic/dwc_eqos_var.h Fri Nov 3 10:04:55 2023
@@ -1,4 +1,4 @@
-/* $NetBSD: dwc_eqos_var.h,v 1.4.4.1 2023/11/03 08:56:36 martin Exp $ */
+/* $NetBSD: dwc_eqos_var.h,v 1.4.4.2 2023/11/03 10:04:55 martin Exp $ */
/*-
* Copyright (c) 2022 Jared McNeill <[email protected]>
@@ -70,6 +70,10 @@ struct eqos_softc {
callout_t sc_stat_ch;
kmutex_t sc_lock;
kmutex_t sc_txlock;
+ bool sc_running;
+ bool sc_txrunning;
+ bool sc_promisc;
+ bool sc_allmulti;
struct eqos_ring sc_tx;
struct eqos_ring sc_rx;