From cdf7a928d94624fd7b9f7faa48b097370d79f86e Mon Sep 17 00:00:00 2001 From: kettenis Date: Sat, 10 Jan 2015 14:55:29 +0000 Subject: [PATCH] Properly stop DMA and tear down the rings when taking the interface down. --- sys/dev/pci/if_nep.c | 98 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 97 insertions(+), 1 deletion(-) diff --git a/sys/dev/pci/if_nep.c b/sys/dev/pci/if_nep.c index 60747f302fc..09b137e9384 100644 --- a/sys/dev/pci/if_nep.c +++ b/sys/dev/pci/if_nep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_nep.c,v 1.10 2015/01/03 23:14:33 kettenis Exp $ */ +/* $OpenBSD: if_nep.c,v 1.11 2015/01/10 14:55:29 kettenis Exp $ */ /* * Copyright (c) 2014, 2015 Mark Kettenis * @@ -361,6 +361,8 @@ extern void myetheraddr(u_char *); #define TX_CS_PKT_CNT_MASK (0xfffULL << 48) #define TX_CS_PKT_CNT_SHIFT 48 #define TX_CS_RST (1ULL << 31) +#define TX_CS_STOP_N_GO (1ULL << 28) +#define TX_CS_SNG_STATE (1ULL << 27) #define TDMC_INTR_DBG(chan) (DMC + 0x40060 + (chan) * 0x00200) #define TXDMA_MBH(chan) (DMC + 0x40030 + (chan) * 0x00200) #define TXDMA_MBL(chan) (DMC + 0x40038 + (chan) * 0x00200) @@ -487,6 +489,7 @@ void nep_init_tx_mac(struct nep_softc *); void nep_init_tx_xmac(struct nep_softc *); void nep_init_tx_bmac(struct nep_softc *); void nep_init_tx_channel(struct nep_softc *, int); +void nep_stop_dma(struct nep_softc *); void nep_fill_rx_ring(struct nep_softc *); @@ -1178,6 +1181,8 @@ nep_init_rx_channel(struct nep_softc *sc, int chan) val |= RBR_CFIG_B_BUFSZ1_8K | RBR_CFIG_B_VLD1; nep_write(sc, RBR_CFIG_B(chan), val); + nep_write(sc, RBR_KICK(chan), 0); + val = NEP_DMA_DVA(sc->sc_rcring); val |= (uint64_t)NEP_NRCDESC << RCRCFIG_A_LEN_SHIFT; nep_write(sc, RCRCFIG_A(chan), val); @@ -1320,6 +1325,39 @@ nep_init_tx_channel(struct nep_softc *sc, int chan) nep_write(sc, TX_CS(chan), 0); } +void +nep_stop_dma(struct nep_softc *sc) +{ + uint64_t val; + int n; + + val = nep_read(sc, TX_CS(sc->sc_port)); + val |= TX_CS_STOP_N_GO; + nep_write(sc, TX_CS(sc->sc_port), val); + + n = 1000; + while (--n) { + val = nep_read(sc, TX_CS(sc->sc_port)); + if (val & TX_CS_SNG_STATE) + break; + } + if (n == 0) + printf("timeout stopping Tx DMA\n"); + + val = nep_read(sc, RXDMA_CFIG1(sc->sc_port)); + val &= ~RXDMA_CFIG1_EN; + nep_write(sc, RXDMA_CFIG1(sc->sc_port), val); + + n = 1000; + while (--n) { + val = nep_read(sc, RXDMA_CFIG1(sc->sc_port)); + if (val & RXDMA_CFIG1_QST) + break; + } + if (n == 0) + printf("timeout stopping Rx DMA\n"); +} + void nep_up(struct nep_softc *sc) { @@ -1353,6 +1391,8 @@ nep_up(struct nep_softc *sc) goto free_rbring; sc->sc_rcdesc = NEP_DMA_KVA(sc->sc_rcring); + sc->sc_rx_cons = 0; + /* Allocate Rx mailbox. */ sc->sc_rxmbox = nep_dmamem_alloc(sc, 64); if (sc->sc_rxmbox == NULL) @@ -1454,7 +1494,63 @@ free_rbring: void nep_down(struct nep_softc *sc) { + struct ifnet *ifp = &sc->sc_ac.ac_if; + struct nep_buf *txb; + struct nep_block *rb; + uint64_t val; + int i; + timeout_del(&sc->sc_tick); + + ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); + ifp->if_timer = 0; + + if (sc->sc_port < 2) { + val = nep_read(sc, XMAC_CONFIG(sc->sc_port)); + val &= ~XMAC_CONFIG_RX_MAC_ENABLE; + nep_write(sc, XMAC_CONFIG(sc->sc_port), val); + } else { + val = nep_read(sc, RXMAC_CONFIG(sc->sc_port)); + val &= ~RXMAC_CONFIG_RX_ENABLE; + nep_write(sc, RXMAC_CONFIG(sc->sc_port), val); + } + + val = nep_read(sc, IPP_CFIG(sc->sc_port)); + val &= ~IPP_CFIG_IPP_ENABLE; + nep_write(sc, IPP_CFIG(sc->sc_port), val); + + nep_stop_dma(sc); + + for (i = 0; i < NEP_NTXDESC; i++) { + txb = &sc->sc_txbuf[i]; + if (txb->nb_m) { + bus_dmamap_sync(sc->sc_dmat, txb->nb_map, 0, + txb->nb_map->dm_mapsize, BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(sc->sc_dmat, txb->nb_map); + m_freem(txb->nb_m); + } + bus_dmamap_destroy(sc->sc_dmat, txb->nb_map); + } + + nep_dmamem_free(sc, sc->sc_txring); + free(sc->sc_txbuf, M_DEVBUF, sizeof(struct nep_buf) * NEP_NTXDESC); + + nep_dmamem_free(sc, sc->sc_rxmbox); + nep_dmamem_free(sc, sc->sc_rcring); + + for (i = 0; i < NEP_NRBDESC; i++) { + rb = &sc->sc_rb[i]; + if (rb->nb_block) { + bus_dmamap_sync(sc->sc_dmat, rb->nb_map, 0, + rb->nb_map->dm_mapsize, BUS_DMASYNC_POSTREAD); + bus_dmamap_unload(sc->sc_dmat, rb->nb_map); + pool_put(nep_block_pool, rb->nb_block); + } + bus_dmamap_destroy(sc->sc_dmat, rb->nb_map); + } + + nep_dmamem_free(sc, sc->sc_rbring); + free(sc->sc_rb, M_DEVBUF, sizeof(struct nep_block) * NEP_NRBDESC); } void -- 2.20.1