if_bfe and > 1 GB of ram is now fixed (fwd)

Mike Silbersack silby at silby.com
Mon May 1 06:27:49 UTC 2006


On Sun, 30 Apr 2006, Mikko Työläjärvi wrote:

> Verfied that limiting RAM still works.  I guess the code path that
> needs the locking isn't being triggered, as it seems to deal with
> bounce buffers.
>
> Actually, even with 2G I can get an address via DHCP, do DNS lookups,
> ping some hosts and even have a short telnet session without problems.
>
> But starting a web browser or running cvsup instantly results in the
> above panic.
>
>    /Mikko

Ok, I talked to Scott Long about the problem and he explained to me why 
it's happening.  Subsequently, I was able to cause it to happen to me if I 
told the system that my bfe card could only accept buffers from under the 
128MB mark.

Basically, what's happening is that there are not enough bounce buffers to 
go around, but the driver is assuming that there are - so when we hit the 
limit, it doesn't handle the error properly, and it panics.

Attached is my WIP patch - it stops the panics, but acts flakey at times - 
in other words, it needs more work.  I don't think I'll have a chance to 
get back to it until Thursday.  In the meantime, see if it helps you at 
all.

Mike "Silby" Silbersack
-------------- next part --------------
--- if_bfe.c	Mon May  1 01:20:05 2006
+++ if_bfe.c.wip	Mon May  1 01:20:00 2006
@@ -297,7 +298,7 @@
 	bzero(sc->bfe_rx_list, BFE_RX_LIST_SIZE);
 	error = bus_dmamap_load(sc->bfe_rx_tag, sc->bfe_rx_map,
 			sc->bfe_rx_list, sizeof(struct bfe_desc),
-			bfe_dma_map, &sc->bfe_rx_dma, 0);
+			bfe_dma_map, &sc->bfe_rx_dma, BUS_DMA_NOWAIT);
 
 	if(error)
 		return (ENOMEM);
@@ -312,7 +313,7 @@
 
 	error = bus_dmamap_load(sc->bfe_tx_tag, sc->bfe_tx_map,
 			sc->bfe_tx_list, sizeof(struct bfe_desc),
-			bfe_dma_map, &sc->bfe_tx_dma, 0);
+			bfe_dma_map, &sc->bfe_tx_dma, BUS_DMA_NOWAIT);
 	if(error)
 		return (ENOMEM);
 
@@ -574,6 +575,7 @@
 	struct bfe_desc *d;
 	struct bfe_data *r;
 	u_int32_t ctrl;
+	int error;
 
 	if ((c < 0) || (c >= BFE_RX_LIST_CNT))
 		return (EINVAL);
@@ -595,8 +597,10 @@
 	sc->bfe_rx_cnt = c;
 	d = &sc->bfe_rx_list[c];
 	r = &sc->bfe_rx_ring[c];
-	bus_dmamap_load(sc->bfe_tag, r->bfe_map, mtod(m, void *),
-			MCLBYTES, bfe_dma_map_desc, d, 0);
+	error = bus_dmamap_load(sc->bfe_tag, r->bfe_map, mtod(m, void *),
+			MCLBYTES, bfe_dma_map_desc, d, BUS_DMA_NOWAIT);
+	if (error)
+		printf("Error I can't handle!!!\n");
 	bus_dmamap_sync(sc->bfe_tag, r->bfe_map, BUS_DMASYNC_PREWRITE);
 
 	ctrl = ETHER_MAX_LEN + 32;
@@ -1241,13 +1245,14 @@
 }
 
 static int
-bfe_encap(struct bfe_softc *sc, struct mbuf *m_head, u_int32_t *txidx)
+bfe_encap(struct bfe_softc *sc, struct mbuf **m_head, u_int32_t *txidx)
 {
 	struct bfe_desc *d = NULL;
 	struct bfe_data *r = NULL;
 	struct mbuf	*m;
 	u_int32_t	   frag, cur, cnt = 0;
 	int chainlen = 0;
+	int error;
 
 	if(BFE_TX_LIST_CNT - sc->bfe_tx_cnt < 2)
 		return (ENOBUFS);
@@ -1258,16 +1263,16 @@
 	 * by all packets, we'll m_defrag long chains so that they
 	 * do not use up the entire list, even if they would fit.
 	 */
-	for(m = m_head; m != NULL; m = m->m_next)
+	for(m = *m_head; m != NULL; m = m->m_next) {
 		chainlen++;
-
+	}
 
 	if ((chainlen > BFE_TX_LIST_CNT / 4) ||
 			((BFE_TX_LIST_CNT - (chainlen + sc->bfe_tx_cnt)) < 2)) {
-		m = m_defrag(m_head, M_DONTWAIT);
+		m = m_defrag(*m_head, M_DONTWAIT);
 		if (m == NULL)
 			return (ENOBUFS);
-		m_head = m;
+		*m_head = m;
 	}
 
 	/*
@@ -1275,11 +1280,10 @@
 	 * the fragment pointers. Stop when we run out
 	 * of fragments or hit the end of the mbuf chain.
 	 */
-	m = m_head;
 	cur = frag = *txidx;
 	cnt = 0;
 
-	for(m = m_head; m != NULL; m = m->m_next) {
+	for(m = *m_head; m != NULL; m = m->m_next) {
 		if(m->m_len != 0) {
 			if((BFE_TX_LIST_CNT - (sc->bfe_tx_cnt + cnt)) < 2)
 				return (ENOBUFS);
@@ -1299,9 +1303,13 @@
 				 */
 				d->bfe_ctrl |= BFE_DESC_EOT;
 
-			bus_dmamap_load(sc->bfe_tag,
+			error = bus_dmamap_load(sc->bfe_tag,
 			    r->bfe_map, mtod(m, void*), m->m_len,
-			    bfe_dma_map_desc, d, 0);
+			    bfe_dma_map_desc, d, BUS_DMA_NOWAIT);
+			if (error) {
+				printf("dmamap_load error, ENOBUFS\n");
+				return (ENOBUFS);
+			}
 			bus_dmamap_sync(sc->bfe_tag, r->bfe_map,
 			    BUS_DMASYNC_PREWRITE);
 
@@ -1315,7 +1323,7 @@
 		return (ENOBUFS);
 
 	sc->bfe_tx_list[frag].bfe_ctrl |= BFE_DESC_EOF;
-	sc->bfe_tx_ring[frag].bfe_mbuf = m_head;
+	sc->bfe_tx_ring[frag].bfe_mbuf = *m_head;
 	bus_dmamap_sync(sc->bfe_tx_tag, sc->bfe_tx_map, BUS_DMASYNC_PREWRITE);
 
 	*txidx = cur;
@@ -1368,7 +1376,7 @@
 		 * Pack the data into the tx ring.  If we dont have
 		 * enough room, let the chip drain the ring.
 		 */
-		if(bfe_encap(sc, m_head, &idx)) {
+		if(bfe_encap(sc, &m_head, &idx)) {
 			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
 			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
 			break;


More information about the freebsd-mobile mailing list