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
This commit is contained in:
Mike Karels 2022-04-11 14:44:49 -05:00
parent d86cf44350
commit 8f45652b6b

View File

@ -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);