Diff below splits the functions that allocate memory for the various
ring to do it only once, in bge_attach(), instead of doing it every
time bge_init() is called, possibly in the watchdog function.
Tested with a "Broadcom BCM5714" rev 0xa3, BCM5715 A3 (0x9003).
Comments? Ok?
Index: if_bge.c
===================================================================
RCS file: /home/ncvs/src/sys/dev/pci/if_bge.c,v
retrieving revision 1.354
diff -u -p -r1.354 if_bge.c
--- if_bge.c 22 Apr 2014 11:54:46 -0000 1.354
+++ if_bge.c 21 May 2014 14:52:03 -0000
@@ -166,18 +166,24 @@ int bge_read_eeprom(struct bge_softc *,
void bge_iff(struct bge_softc *);
int bge_newbuf_jumbo(struct bge_softc *, int);
+int bge_alloc_rx_ring_jumbo(struct bge_softc *);
int bge_init_rx_ring_jumbo(struct bge_softc *);
void bge_fill_rx_ring_jumbo(struct bge_softc *);
void bge_free_rx_ring_jumbo(struct bge_softc *);
+void bge_drain_rx_ring_jumbo(struct bge_softc *);
int bge_newbuf(struct bge_softc *, int);
+int bge_alloc_rx_ring_std(struct bge_softc *);
int bge_init_rx_ring_std(struct bge_softc *);
void bge_rxtick(void *);
void bge_fill_rx_ring_std(struct bge_softc *);
void bge_free_rx_ring_std(struct bge_softc *);
+void bge_drain_rx_ring_std(struct bge_softc *);
+int bge_alloc_tx_ring(struct bge_softc *);
void bge_free_tx_ring(struct bge_softc *);
int bge_init_tx_ring(struct bge_softc *);
+void bge_drain_tx_ring(struct bge_softc *);
void bge_chipinit(struct bge_softc *);
int bge_blockinit(struct bge_softc *);
@@ -1238,13 +1244,10 @@ bge_newbuf_jumbo(struct bge_softc *sc, i
* the NIC.
*/
int
-bge_init_rx_ring_std(struct bge_softc *sc)
+bge_alloc_rx_ring_std(struct bge_softc *sc)
{
int i;
- if (ISSET(sc->bge_flags, BGE_RXRING_VALID))
- return (0);
-
for (i = 0; i < BGE_STD_RX_RING_CNT; i++) {
if (bus_dmamap_create(sc->bge_dmatag, MCLBYTES, 1, MCLBYTES, 0,
BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
@@ -1257,12 +1260,6 @@ bge_init_rx_ring_std(struct bge_softc *s
sizeof(struct bge_rx_bd));
}
- sc->bge_std = BGE_STD_RX_RING_CNT - 1;
- sc->bge_std_cnt = 0;
- bge_fill_rx_ring_std(sc);
-
- SET(sc->bge_flags, BGE_RXRING_VALID);
-
return (0);
uncreate:
@@ -1273,6 +1270,21 @@ uncreate:
return (1);
}
+int
+bge_init_rx_ring_std(struct bge_softc *sc)
+{
+ if (ISSET(sc->bge_flags, BGE_RXRING_VALID))
+ return (0);
+
+ sc->bge_std = BGE_STD_RX_RING_CNT - 1;
+ sc->bge_std_cnt = 0;
+ bge_fill_rx_ring_std(sc);
+
+ SET(sc->bge_flags, BGE_RXRING_VALID);
+
+ return (0);
+}
+
void
bge_rxtick(void *arg)
{
@@ -1321,6 +1333,21 @@ void
bge_free_rx_ring_std(struct bge_softc *sc)
{
bus_dmamap_t dmap;
+ int i;
+
+ for (i = 0; i < BGE_STD_RX_RING_CNT; i++) {
+ dmap = sc->bge_cdata.bge_rx_std_map[i];
+ bus_dmamap_destroy(sc->bge_dmatag, dmap);
+ sc->bge_cdata.bge_rx_std_map[i] = NULL;
+ bzero(&sc->bge_rdata->bge_rx_std_ring[i],
+ sizeof(struct bge_rx_bd));
+ }
+}
+
+void
+bge_drain_rx_ring_std(struct bge_softc *sc)
+{
+ bus_dmamap_t dmap;
struct mbuf *m;
int i;
@@ -1337,24 +1364,16 @@ bge_free_rx_ring_std(struct bge_softc *s
m_freem(m);
sc->bge_cdata.bge_rx_std_chain[i] = NULL;
}
- bus_dmamap_destroy(sc->bge_dmatag, dmap);
- sc->bge_cdata.bge_rx_std_map[i] = NULL;
- bzero(&sc->bge_rdata->bge_rx_std_ring[i],
- sizeof(struct bge_rx_bd));
}
CLR(sc->bge_flags, BGE_RXRING_VALID);
}
int
-bge_init_rx_ring_jumbo(struct bge_softc *sc)
+bge_alloc_rx_ring_jumbo(struct bge_softc *sc)
{
- volatile struct bge_rcb *rcb;
int i;
- if (ISSET(sc->bge_flags, BGE_JUMBO_RXRING_VALID))
- return (0);
-
for (i = 0; i < BGE_JUMBO_RX_RING_CNT; i++) {
if (bus_dmamap_create(sc->bge_dmatag, BGE_JLEN, 4, BGE_JLEN, 0,
BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
@@ -1367,6 +1386,24 @@ bge_init_rx_ring_jumbo(struct bge_softc
sizeof(struct bge_ext_rx_bd));
}
+ return (0);
+
+uncreate:
+ while (--i) {
+ bus_dmamap_destroy(sc->bge_dmatag,
+ sc->bge_cdata.bge_rx_jumbo_map[i]);
+ }
+ return (1);
+}
+
+int
+bge_init_rx_ring_jumbo(struct bge_softc *sc)
+{
+ volatile struct bge_rcb *rcb;
+
+ if (ISSET(sc->bge_flags, BGE_JUMBO_RXRING_VALID))
+ return (0);
+
sc->bge_jumbo = BGE_JUMBO_RX_RING_CNT - 1;
sc->bge_jumbo_cnt = 0;
bge_fill_rx_ring_jumbo(sc);
@@ -1379,13 +1416,6 @@ bge_init_rx_ring_jumbo(struct bge_softc
CSR_WRITE_4(sc, BGE_RX_JUMBO_RCB_MAXLEN_FLAGS, rcb->bge_maxlen_flags);
return (0);
-
-uncreate:
- while (--i) {
- bus_dmamap_destroy(sc->bge_dmatag,
- sc->bge_cdata.bge_rx_jumbo_map[i]);
- }
- return (1);
}
void
@@ -1420,6 +1450,21 @@ void
bge_free_rx_ring_jumbo(struct bge_softc *sc)
{
bus_dmamap_t dmap;
+ int i;
+
+ for (i = 0; i < BGE_JUMBO_RX_RING_CNT; i++) {
+ dmap = sc->bge_cdata.bge_rx_jumbo_map[i];
+ bus_dmamap_destroy(sc->bge_dmatag, dmap);
+ sc->bge_cdata.bge_rx_jumbo_map[i] = NULL;
+ bzero(&sc->bge_rdata->bge_rx_jumbo_ring[i],
+ sizeof(struct bge_ext_rx_bd));
+ }
+}
+
+void
+bge_drain_rx_ring_jumbo(struct bge_softc *sc)
+{
+ bus_dmamap_t dmap;
struct mbuf *m;
int i;
@@ -1436,20 +1481,15 @@ bge_free_rx_ring_jumbo(struct bge_softc
m_freem(m);
sc->bge_cdata.bge_rx_jumbo_chain[i] = NULL;
}
- bus_dmamap_destroy(sc->bge_dmatag, dmap);
- sc->bge_cdata.bge_rx_jumbo_map[i] = NULL;
- bzero(&sc->bge_rdata->bge_rx_jumbo_ring[i],
- sizeof(struct bge_ext_rx_bd));
}
CLR(sc->bge_flags, BGE_JUMBO_RXRING_VALID);
}
void
-bge_free_tx_ring(struct bge_softc *sc)
+bge_drain_tx_ring(struct bge_softc *sc)
{
int i;
- struct txdmamap_pool_entry *dma;
if (!(sc->bge_flags & BGE_TXRING_VALID))
return;
@@ -1466,39 +1506,28 @@ bge_free_tx_ring(struct bge_softc *sc)
sizeof(struct bge_tx_bd));
}
+ sc->bge_flags &= ~BGE_TXRING_VALID;
+}
+
+void
+bge_free_tx_ring(struct bge_softc *sc)
+{
+ struct txdmamap_pool_entry *dma;
+
while ((dma = SLIST_FIRST(&sc->txdma_list))) {
SLIST_REMOVE_HEAD(&sc->txdma_list, link);
bus_dmamap_destroy(sc->bge_dmatag, dma->dmamap);
free(dma, M_DEVBUF);
}
-
- sc->bge_flags &= ~BGE_TXRING_VALID;
}
int
-bge_init_tx_ring(struct bge_softc *sc)
+bge_alloc_tx_ring(struct bge_softc *sc)
{
int i;
bus_dmamap_t dmamap;
struct txdmamap_pool_entry *dma;
- if (sc->bge_flags & BGE_TXRING_VALID)
- return (0);
-
- sc->bge_txcnt = 0;
- sc->bge_tx_saved_considx = 0;
-
- /* Initialize transmit producer index for host-memory send ring. */
- sc->bge_tx_prodidx = 0;
- bge_writembx(sc, BGE_MBX_TX_HOST_PROD0_LO, sc->bge_tx_prodidx);
- if (BGE_CHIPREV(sc->bge_chipid) == BGE_CHIPREV_5700_BX)
- bge_writembx(sc, BGE_MBX_TX_HOST_PROD0_LO, sc->bge_tx_prodidx);
-
- /* NIC-memory send ring not used; initialize to zero. */
- bge_writembx(sc, BGE_MBX_TX_NIC_PROD0_LO, 0);
- if (BGE_CHIPREV(sc->bge_chipid) == BGE_CHIPREV_5700_BX)
- bge_writembx(sc, BGE_MBX_TX_NIC_PROD0_LO, 0);
-
SLIST_INIT(&sc->txdma_list);
for (i = 0; i < BGE_TX_RING_CNT; i++) {
if (bus_dmamap_create(sc->bge_dmatag, BGE_JLEN,
@@ -1506,7 +1535,7 @@ bge_init_tx_ring(struct bge_softc *sc)
&dmamap))
return (ENOBUFS);
if (dmamap == NULL)
- panic("dmamap NULL in bge_init_tx_ring");
+ panic("dmamap NULL in %s", __func__);
dma = malloc(sizeof(*dma), M_DEVBUF, M_NOWAIT);
if (dma == NULL) {
printf("%s: can't alloc txdmamap_pool_entry\n",
@@ -1518,6 +1547,29 @@ bge_init_tx_ring(struct bge_softc *sc)
SLIST_INSERT_HEAD(&sc->txdma_list, dma, link);
}
+ return (0);
+}
+
+int
+bge_init_tx_ring(struct bge_softc *sc)
+{
+ if (sc->bge_flags & BGE_TXRING_VALID)
+ return (0);
+
+ sc->bge_txcnt = 0;
+ sc->bge_tx_saved_considx = 0;
+
+ /* Initialize transmit producer index for host-memory send ring. */
+ sc->bge_tx_prodidx = 0;
+ bge_writembx(sc, BGE_MBX_TX_HOST_PROD0_LO, sc->bge_tx_prodidx);
+ if (BGE_CHIPREV(sc->bge_chipid) == BGE_CHIPREV_5700_BX)
+ bge_writembx(sc, BGE_MBX_TX_HOST_PROD0_LO, sc->bge_tx_prodidx);
+
+ /* NIC-memory send ring not used; initialize to zero. */
+ bge_writembx(sc, BGE_MBX_TX_NIC_PROD0_LO, 0);
+ if (BGE_CHIPREV(sc->bge_chipid) == BGE_CHIPREV_5700_BX)
+ bge_writembx(sc, BGE_MBX_TX_NIC_PROD0_LO, 0);
+
sc->bge_flags |= BGE_TXRING_VALID;
return (0);
@@ -3077,6 +3129,15 @@ bge_attach(struct device *parent, struct
goto fail_6;
}
+ if (bge_alloc_rx_ring_std(sc))
+ goto fail_6;
+
+ if (BGE_IS_JUMBO_CAPABLE(sc) && bge_alloc_rx_ring_jumbo(sc))
+ goto fail_7;
+
+ if (bge_alloc_tx_ring(sc))
+ goto fail_8;
+
/*
* A Broadcom chip was detected. Inform the world.
*/
@@ -3127,6 +3188,15 @@ bge_attach(struct device *parent, struct
timeout_set(&sc->bge_rxtimeout, bge_rxtick, sc);
return;
+fail_8:
+ bge_free_tx_ring(sc);
+
+ if (BGE_IS_JUMBO_CAPABLE(sc))
+ bge_free_rx_ring_jumbo(sc);
+
+fail_7:
+ bge_free_rx_ring_std(sc);
+
fail_6:
bus_dmamap_unload(sc->bge_dmatag, sc->bge_ring_map);
@@ -4586,15 +4656,15 @@ bge_stop(struct bge_softc *sc)
*/
BGE_CLRBIT(sc, BGE_MODE_CTL, BGE_MODECTL_STACKUP);
- /* Free the RX lists. */
- bge_free_rx_ring_std(sc);
+ /* Drain the RX lists. */
+ bge_drain_rx_ring_std(sc);
- /* Free jumbo RX list. */
+ /* Drain jumbo RX list. */
if (BGE_IS_JUMBO_CAPABLE(sc))
- bge_free_rx_ring_jumbo(sc);
+ bge_drain_rx_ring_jumbo(sc);
- /* Free TX buffers. */
- bge_free_tx_ring(sc);
+ /* Drain TX buffers. */
+ bge_drain_tx_ring(sc);
/*
* Isolate/power down the PHY, but leave the media selection