git: 8f45652b6bcc - main - genet: fix problems with interface down/up

From: Mike Karels <karels_at_FreeBSD.org>
Date: Thu, 14 Apr 2022 19:10:25 UTC
The branch main has been updated by karels:

URL: https://cgit.FreeBSD.org/src/commit/?id=8f45652b6bccc258eb58f8721dea10184f1aaa17

commit 8f45652b6bccc258eb58f8721dea10184f1aaa17
Author:     Mike Karels <karels@FreeBSD.org>
AuthorDate: 2022-04-11 19:44:49 +0000
Commit:     Mike Karels <karels@FreeBSD.org>
CommitDate: 2022-04-14 19:10:13 +0000

    genet: fix problems with interface down/up
    
    The genet interface did not resume operation correctly after doing
    ifconfig down then up.  The down/reset procedure did not clear the
    RUNNING flag, and did not reset enough of the hardware state.  This
    patch is modeled on OpenBSD code, with a call to gen_reset added
    to reset the controller completely.  Regularize the parameter to
    gen_dma_disable() while here.
    
    PR:             263091
    Submitted by:   jiahali@blackberry.com
---
 sys/arm64/broadcom/genet/if_genet.c | 86 ++++++++++++++++++++++++++++++++-----
 1 file changed, 75 insertions(+), 11 deletions(-)

diff --git a/sys/arm64/broadcom/genet/if_genet.c b/sys/arm64/broadcom/genet/if_genet.c
index 31fab0f9cf09..4532c8d32f90 100644
--- a/sys/arm64/broadcom/genet/if_genet.c
+++ b/sys/arm64/broadcom/genet/if_genet.c
@@ -216,7 +216,7 @@ static void gen_set_enaddr(struct gen_softc *sc);
 static void gen_setup_rxfilter(struct gen_softc *sc);
 static void gen_reset(struct gen_softc *sc);
 static void gen_enable(struct gen_softc *sc);
-static void gen_dma_disable(device_t dev);
+static void gen_dma_disable(struct gen_softc *sc);
 static int gen_bus_dma_init(struct gen_softc *sc);
 static void gen_bus_dma_teardown(struct gen_softc *sc);
 static void gen_enable_intr(struct gen_softc *sc);
@@ -289,7 +289,7 @@ gen_attach(device_t dev)
 	/* reset core */
 	gen_reset(sc);
 
-	gen_dma_disable(dev);
+	gen_dma_disable(sc);
 
 	/* Setup DMA */
 	error = gen_bus_dma_init(sc);
@@ -484,6 +484,12 @@ gen_reset(struct gen_softc *sc)
 	WR4(sc, GENET_UMAC_MIB_CTRL, GENET_UMAC_MIB_RESET_RUNT |
 	    GENET_UMAC_MIB_RESET_RX | GENET_UMAC_MIB_RESET_TX);
 	WR4(sc, GENET_UMAC_MIB_CTRL, 0);
+}
+
+static void
+gen_enable(struct gen_softc *sc)
+{
+	u_int val;
 
 	WR4(sc, GENET_UMAC_MAX_FRAME_LEN, 1536);
 
@@ -492,12 +498,6 @@ gen_reset(struct gen_softc *sc)
 	WR4(sc, GENET_RBUF_CTRL, val);
 
 	WR4(sc, GENET_RBUF_TBUF_SIZE_CTRL, 1);
-}
-
-static void
-gen_enable(struct gen_softc *sc)
-{
-	u_int val;
 
 	/* Enable transmitter and receiver */
 	val = RD4(sc, GENET_UMAC_CMD);
@@ -511,6 +511,33 @@ gen_enable(struct gen_softc *sc)
 	    GENET_IRQ_TXDMA_DONE | GENET_IRQ_RXDMA_DONE);
 }
 
+static void
+gen_disable_intr(struct gen_softc *sc)
+{
+	/* Disable interrupts */
+	WR4(sc, GENET_INTRL2_CPU_SET_MASK, 0xffffffff);
+	WR4(sc, GENET_INTRL2_CPU_CLEAR_MASK, 0xffffffff);
+}
+
+static void
+gen_disable(struct gen_softc *sc)
+{
+	uint32_t val;
+
+	/* Stop receiver */
+	val = RD4(sc, GENET_UMAC_CMD);
+	val &= ~GENET_UMAC_CMD_RXEN;
+	WR4(sc, GENET_UMAC_CMD, val);
+
+	/* Stop transmitter */
+	val = RD4(sc, GENET_UMAC_CMD);
+	val &= ~GENET_UMAC_CMD_TXEN;
+	WR4(sc, GENET_UMAC_CMD, val);
+
+	/* Disable Interrupt */
+	gen_disable_intr(sc);
+}
+
 static void
 gen_enable_offload(struct gen_softc *sc)
 {
@@ -538,9 +565,8 @@ gen_enable_offload(struct gen_softc *sc)
 }
 
 static void
-gen_dma_disable(device_t dev)
+gen_dma_disable(struct gen_softc *sc)
 {
-	struct gen_softc *sc = device_get_softc(dev);
 	int val;
 
 	val = RD4(sc, GENET_TX_DMA_CTRL);
@@ -808,6 +834,44 @@ gen_init_rxrings(struct gen_softc *sc)
 
 }
 
+static void
+gen_stop(struct gen_softc *sc)
+{
+	int i;
+	struct gen_ring_ent *ent;
+
+	GEN_ASSERT_LOCKED(sc);
+
+	callout_stop(&sc->stat_ch);
+	if_setdrvflagbits(sc->ifp, 0, IFF_DRV_RUNNING);
+	gen_reset(sc);
+	gen_disable(sc);
+	gen_dma_disable(sc);
+
+	/* Clear the tx/rx ring buffer */
+	for (i = 0; i < TX_DESC_COUNT; i++) {
+		ent = &sc->tx_ring_ent[i];
+		if (ent->mbuf != NULL) {
+			bus_dmamap_sync(sc->tx_buf_tag, ent->map,
+				BUS_DMASYNC_POSTWRITE);
+			bus_dmamap_unload(sc->tx_buf_tag, ent->map);
+			m_freem(ent->mbuf);
+			ent->mbuf = NULL;
+		}
+	}
+
+	for (i = 0; i < RX_DESC_COUNT; i++) {
+		ent = &sc->rx_ring_ent[i];
+		if (ent->mbuf != NULL) {
+			bus_dmamap_sync(sc->rx_buf_tag, ent->map,
+			    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+			bus_dmamap_unload(sc->rx_buf_tag, ent->map);
+			m_freem(ent->mbuf);
+			ent->mbuf = NULL;
+		}
+	}
+}
+
 static void
 gen_init_locked(struct gen_softc *sc)
 {
@@ -1498,7 +1562,7 @@ gen_ioctl(if_t ifp, u_long cmd, caddr_t data)
 				gen_init_locked(sc);
 		} else {
 			if (if_getdrvflags(ifp) & IFF_DRV_RUNNING)
-				gen_reset(sc);
+				gen_stop(sc);
 		}
 		sc->if_flags = if_getflags(ifp);
 		GEN_UNLOCK(sc);