Re: if_bfe and > 1 GB of ram is now fixed (fwd)
Mike Silbersack <[email protected]>
| Newsgroups | gmane.os.freebsd.devel.mobile |
|---|---|
| Message-ID | <[email protected]> |
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 _______________________________________________ [email protected] mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-mobile To unsubscribe, send any mail to "[email protected]"
if_bfe.c.wip1.patch
(text/plain, 3.6 KB)
--- 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;