diff options
author | tmm <tmm@FreeBSD.org> | 2003-01-19 00:23:59 +0000 |
---|---|---|
committer | tmm <tmm@FreeBSD.org> | 2003-01-19 00:23:59 +0000 |
commit | d52835b4ab057c3bfdf416502c82c4c0f7a22546 (patch) | |
tree | ff74f88b22b18ba7dfa8bdc3eee9d0814ba5c5c7 /sys | |
parent | 0c8d64a2c4ed9577970bc064bd9354ec7fa78297 (diff) | |
download | FreeBSD-src-d52835b4ab057c3bfdf416502c82c4c0f7a22546.zip FreeBSD-src-d52835b4ab057c3bfdf416502c82c4c0f7a22546.tar.gz |
Make the xl driver work on sparc64:
- Add conversions to/from little endian for fields that the NIC accesses
by DMA as required.
- Add some bus_dmamap_sync() calls, and correct some existing ones.
- Read the receiver information from the EEPROM in an endian-neutral
manner.
- Load all RX and TX descriptors in a single DMA map up front, and
get the bus addresses of individual descriptors by address arithmetic;
this fixes multiple use of the descriptor tags, which would have
undesired effects.
It seems that xl still does not work on e250 boxen, for reasons which
are not clear yet.
Reviewed by: mux
Diffstat (limited to 'sys')
-rw-r--r-- | sys/pci/if_xl.c | 166 | ||||
-rw-r--r-- | sys/pci/if_xlreg.h | 1 |
2 files changed, 100 insertions, 67 deletions
diff --git a/sys/pci/if_xl.c b/sys/pci/if_xl.c index 181e6dc..421d05a 100644 --- a/sys/pci/if_xl.c +++ b/sys/pci/if_xl.c @@ -106,6 +106,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> #include <sys/sockio.h> +#include <sys/endian.h> #include <sys/mbuf.h> #include <sys/malloc.h> #include <sys/kernel.h> @@ -346,12 +347,13 @@ xl_dma_map_txbuf(arg, segs, nseg, mapsize, error) l = arg; for (i = 0; i < nseg; i++) { KASSERT(segs[i].ds_len <= MCLBYTES, ("segment size too large")); - l->xl_frag[i].xl_addr = segs[i].ds_addr; - l->xl_frag[i].xl_len = segs[i].ds_len; + l->xl_frag[i].xl_addr = htole32(segs[i].ds_addr); + l->xl_frag[i].xl_len = htole32(segs[i].ds_len); total_len += segs[i].ds_len; } - l->xl_frag[nseg - 1].xl_len |= XL_LAST_FRAG; - l->xl_status = total_len; + l->xl_frag[nseg - 1].xl_len = htole32(segs[nseg - 1].ds_len | + XL_LAST_FRAG); + l->xl_status = htole32(total_len); l->xl_next = 0; } @@ -1295,6 +1297,7 @@ xl_attach(dev) { u_char eaddr[ETHER_ADDR_LEN]; u_int32_t command; + u_int16_t xcvr[2]; struct xl_softc *sc; struct ifnet *ifp; int media = IFM_ETHER|IFM_100_TX|IFM_FDX; @@ -1466,7 +1469,7 @@ xl_attach(dev) * All of our lists are allocated as a contiguous block * of memory. */ - error = bus_dma_tag_create(NULL, 1, 0, + error = bus_dma_tag_create(NULL, 8, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, XL_RX_LIST_SZ, 1, BUS_SPACE_MAXSIZE_32BIT, 0, &sc->xl_ldata.xl_rx_tag); @@ -1475,7 +1478,7 @@ xl_attach(dev) goto fail_irq_setup; } - error = bus_dma_tag_create(NULL, 1, 0, + error = bus_dma_tag_create(NULL, 8, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, XL_TX_LIST_SZ, 1, BUS_SPACE_MAXSIZE_32BIT, 0, &sc->xl_ldata.xl_tx_tag); @@ -1519,15 +1522,24 @@ xl_attach(dev) bzero(sc->xl_ldata.xl_rx_list, XL_RX_LIST_SZ); /* - * Obtain the DMA address of the RX ring which we'll need later. + * Obtain the DMA address of the RX and TX ring which we'll need later. */ + error = bus_dmamap_load(sc->xl_ldata.xl_tx_tag, + sc->xl_ldata.xl_tx_dmamap, sc->xl_ldata.xl_tx_list, + XL_TX_LIST_SZ, xl_dma_map_addr, + &sc->xl_ldata.xl_tx_dmaaddr, 0); + if (error) { + printf("xl%d: cannot get dma address of the tx ring!\n", unit); + goto fail_rxmem; + } + error = bus_dmamap_load(sc->xl_ldata.xl_rx_tag, - sc->xl_ldata.xl_rx_dmamap, &(sc->xl_ldata.xl_rx_list[0]), - sizeof(struct xl_list_onefrag), xl_dma_map_addr, + sc->xl_ldata.xl_rx_dmamap, sc->xl_ldata.xl_rx_list, + XL_RX_LIST_SZ, xl_dma_map_addr, &sc->xl_ldata.xl_rx_dmaaddr, 0); if (error) { printf("xl%d: cannot get dma address of the rx ring!\n", unit); - goto fail_rxmem; + goto fail_txmap; } /* @@ -1572,7 +1584,8 @@ xl_attach(dev) printf("xl%d: media options word: %x\n", sc->xl_unit, sc->xl_media); - xl_read_eeprom(sc, (char *)&sc->xl_xcvr, XL_EE_ICFG_0, 2, 0); + xl_read_eeprom(sc, (char *)&xcvr, XL_EE_ICFG_0, 2, 0); + sc->xl_xcvr = xcvr[0] | xcvr[1] << 16; sc->xl_xcvr &= XL_ICFG_CONNECTOR_MASK; sc->xl_xcvr >>= XL_ICFG_CONNECTOR_BITS; @@ -1586,7 +1599,7 @@ xl_attach(dev) if (mii_phy_probe(dev, &sc->xl_miibus, xl_ifmedia_upd, xl_ifmedia_sts)) { printf("xl%d: no PHY found!\n", sc->xl_unit); - goto fail_rxmem; + goto fail_rxmap; } goto done; @@ -1706,6 +1719,10 @@ done: XL_UNLOCK(sc); return(0); +fail_rxmap: + bus_dmamap_unload(sc->xl_ldata.xl_rx_tag, sc->xl_ldata.xl_rx_dmamap); +fail_txmap: + bus_dmamap_unload(sc->xl_ldata.xl_tx_tag, sc->xl_ldata.xl_tx_dmamap); fail_rxmem: bus_dmamem_free(sc->xl_ldata.xl_rx_tag, sc->xl_ldata.xl_rx_list, sc->xl_ldata.xl_rx_dmamap); @@ -1798,11 +1815,8 @@ xl_list_tx_init(sc) &cd->xl_tx_chain[i].xl_map); if (error) return(error); - error = bus_dmamap_load(ld->xl_tx_tag, ld->xl_tx_dmamap, - &ld->xl_tx_list[i], sizeof(struct xl_list), - xl_dma_map_addr, &cd->xl_tx_chain[i].xl_phys, 0); - if (error) - return(error); + cd->xl_tx_chain[i].xl_phys = ld->xl_tx_dmaaddr + + i * sizeof(struct xl_list); if (i == (XL_TX_LIST_CNT - 1)) cd->xl_tx_chain[i].xl_next = NULL; else @@ -1835,11 +1849,8 @@ xl_list_tx_init_90xB(sc) &cd->xl_tx_chain[i].xl_map); if (error) return(error); - error = bus_dmamap_load(ld->xl_tx_tag, ld->xl_tx_dmamap, - &ld->xl_tx_list[i], sizeof(struct xl_list), - xl_dma_map_addr, &cd->xl_tx_chain[i].xl_phys, 0); - if (error) - return(error); + cd->xl_tx_chain[i].xl_phys = ld->xl_tx_dmaaddr + + i * sizeof(struct xl_list); if (i == (XL_TX_LIST_CNT - 1)) cd->xl_tx_chain[i].xl_next = &cd->xl_tx_chain[0]; else @@ -1853,7 +1864,7 @@ xl_list_tx_init_90xB(sc) } bzero(ld->xl_tx_list, XL_TX_LIST_SZ); - ld->xl_tx_list[0].xl_status = XL_TXSTAT_EMPTY; + ld->xl_tx_list[0].xl_status = htole32(XL_TXSTAT_EMPTY); cd->xl_tx_prod = 1; cd->xl_tx_cons = 1; @@ -1874,7 +1885,8 @@ xl_list_rx_init(sc) { struct xl_chain_data *cd; struct xl_list_data *ld; - int error, i; + int error, i, next; + u_int32_t nextptr; cd = &sc->xl_cdata; ld = &sc->xl_ldata; @@ -1888,22 +1900,14 @@ xl_list_rx_init(sc) error = xl_newbuf(sc, &cd->xl_rx_chain[i]); if (error) return(error); - if (i == (XL_RX_LIST_CNT - 1)) { - cd->xl_rx_chain[i].xl_next = &cd->xl_rx_chain[0]; - error = bus_dmamap_load(ld->xl_rx_tag, ld->xl_rx_dmamap, - &ld->xl_rx_list[0], sizeof(struct xl_list_onefrag), - xl_dma_map_addr, &ld->xl_rx_list[i].xl_next, 0); - if (error) - return(error); - } else { - cd->xl_rx_chain[i].xl_next = &cd->xl_rx_chain[i + 1]; - error = bus_dmamap_load(ld->xl_rx_tag, ld->xl_rx_dmamap, - &ld->xl_rx_list[i + 1], - sizeof(struct xl_list_onefrag), xl_dma_map_addr, - &ld->xl_rx_list[i].xl_next, 0); - if (error) - return(error); - } + if (i == (XL_RX_LIST_CNT - 1)) + next = 0; + else + next = i + 1; + nextptr = ld->xl_rx_dmaaddr + + next * sizeof(struct xl_list_onefrag); + cd->xl_rx_chain[i].xl_next = &cd->xl_rx_chain[next]; + ld->xl_rx_list[i].xl_next = htole32(nextptr); } bus_dmamap_sync(ld->xl_rx_tag, ld->xl_rx_dmamap, BUS_DMASYNC_PREWRITE); @@ -1922,6 +1926,7 @@ xl_newbuf(sc, c) { struct mbuf *m_new = NULL; int error; + u_int32_t baddr; MGETHDR(m_new, M_DONTWAIT, MT_DATA); if (m_new == NULL) @@ -1939,17 +1944,18 @@ xl_newbuf(sc, c) m_adj(m_new, ETHER_ALIGN); c->xl_mbuf = m_new; - c->xl_ptr->xl_frag.xl_len = MCLBYTES | XL_LAST_FRAG; + c->xl_ptr->xl_frag.xl_len = htole32(m_new->m_len | XL_LAST_FRAG); c->xl_ptr->xl_status = 0; error = bus_dmamap_load(sc->xl_mtag, c->xl_map, mtod(m_new, void *), - MCLBYTES, xl_dma_map_addr, &c->xl_ptr->xl_frag.xl_addr, 0); + MCLBYTES, xl_dma_map_addr, &baddr, 0); if (error) { m_freem(m_new); printf("xl%d: can't map mbuf (error %d)\n", sc->xl_unit, error); return(error); } - bus_dmamap_sync(sc->xl_mtag, c->xl_map, BUS_DMASYNC_PREWRITE); + c->xl_ptr->xl_frag.xl_addr = htole32(baddr); + bus_dmamap_sync(sc->xl_mtag, c->xl_map, BUS_DMASYNC_PREREAD); return(0); } @@ -1994,7 +2000,9 @@ xl_rxeof(sc) again: - while((rxstat = sc->xl_cdata.xl_rx_head->xl_ptr->xl_status)) { + bus_dmamap_sync(sc->xl_ldata.xl_rx_tag, sc->xl_ldata.xl_rx_dmamap, + BUS_DMASYNC_POSTREAD); + while((rxstat = le32toh(sc->xl_cdata.xl_rx_head->xl_ptr->xl_status))) { cur_rx = sc->xl_cdata.xl_rx_head; sc->xl_cdata.xl_rx_head = cur_rx->xl_next; @@ -2007,6 +2015,8 @@ again: if (rxstat & XL_RXSTAT_UP_ERROR) { ifp->if_ierrors++; cur_rx->xl_ptr->xl_status = 0; + bus_dmamap_sync(sc->xl_ldata.xl_rx_tag, + sc->xl_ldata.xl_rx_dmamap, BUS_DMASYNC_PREWRITE); continue; } @@ -2020,15 +2030,18 @@ again: "packet dropped\n", sc->xl_unit); ifp->if_ierrors++; cur_rx->xl_ptr->xl_status = 0; + bus_dmamap_sync(sc->xl_ldata.xl_rx_tag, + sc->xl_ldata.xl_rx_dmamap, BUS_DMASYNC_PREWRITE); continue; } /* No errors; receive the packet. */ bus_dmamap_sync(sc->xl_mtag, cur_rx->xl_map, - BUS_DMASYNC_POSTWRITE); + BUS_DMASYNC_POSTREAD); bus_dmamap_unload(sc->xl_mtag, cur_rx->xl_map); m = cur_rx->xl_mbuf; - total_len = cur_rx->xl_ptr->xl_status & XL_RXSTAT_LENMASK; + total_len = le32toh(cur_rx->xl_ptr->xl_status) & + XL_RXSTAT_LENMASK; /* * Try to conjure up a new mbuf cluster. If that @@ -2040,8 +2053,12 @@ again: if (xl_newbuf(sc, cur_rx)) { ifp->if_ierrors++; cur_rx->xl_ptr->xl_status = 0; + bus_dmamap_sync(sc->xl_ldata.xl_rx_tag, + sc->xl_ldata.xl_rx_dmamap, BUS_DMASYNC_PREWRITE); continue; } + bus_dmamap_sync(sc->xl_ldata.xl_rx_tag, + sc->xl_ldata.xl_rx_dmamap, BUS_DMASYNC_PREWRITE); ifp->if_ipackets++; m->m_pkthdr.rcvif = ifp; @@ -2124,7 +2141,7 @@ xl_txeof(sc) sc->xl_cdata.xl_tx_head = cur_tx->xl_next; bus_dmamap_sync(sc->xl_mtag, cur_tx->xl_map, - BUS_DMASYNC_POSTREAD); + BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(sc->xl_mtag, cur_tx->xl_map); m_freem(cur_tx->xl_mbuf); cur_tx->xl_mbuf = NULL; @@ -2159,17 +2176,20 @@ xl_txeof_90xB(sc) ifp = &sc->arpcom.ac_if; + bus_dmamap_sync(sc->xl_ldata.xl_tx_tag, sc->xl_ldata.xl_tx_dmamap, + BUS_DMASYNC_POSTREAD); idx = sc->xl_cdata.xl_tx_cons; while(idx != sc->xl_cdata.xl_tx_prod) { cur_tx = &sc->xl_cdata.xl_tx_chain[idx]; - if (!(cur_tx->xl_ptr->xl_status & XL_TXSTAT_DL_COMPLETE)) + if (!(le32toh(cur_tx->xl_ptr->xl_status) & + XL_TXSTAT_DL_COMPLETE)) break; if (cur_tx->xl_mbuf != NULL) { bus_dmamap_sync(sc->xl_mtag, cur_tx->xl_map, - BUS_DMASYNC_POSTREAD); + BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(sc->xl_mtag, cur_tx->xl_map); m_freem(cur_tx->xl_mbuf); cur_tx->xl_mbuf = NULL; @@ -2382,6 +2402,7 @@ xl_encap(sc, c, m_head) { struct xl_frag *f = NULL; int error; + u_int32_t baddr, status; /* * Start packing the mbufs in this chain into @@ -2432,33 +2453,35 @@ xl_encap(sc, c, m_head) f = &c->xl_ptr->xl_frag[0]; error = bus_dmamap_load(sc->xl_mtag, c->xl_map, mtod(m_new, void *), MCLBYTES, xl_dma_map_addr, - &f->xl_addr, 0); + &baddr, 0); if (error) { m_freem(m_new); printf("xl%d: can't map mbuf (error %d)\n", sc->xl_unit, error); return(1); } - f->xl_len = m_new->m_len | XL_LAST_FRAG; - c->xl_ptr->xl_status = m_new->m_len; + f->xl_addr = htole32(baddr); + f->xl_len = htole32(m_new->m_len | XL_LAST_FRAG); + c->xl_ptr->xl_status = htole32(m_new->m_len); c->xl_ptr->xl_next = 0; } if (sc->xl_type == XL_TYPE_905B) { - c->xl_ptr->xl_status = XL_TXSTAT_RND_DEFEAT; + status = XL_TXSTAT_RND_DEFEAT; if (m_head->m_pkthdr.csum_flags) { if (m_head->m_pkthdr.csum_flags & CSUM_IP) - c->xl_ptr->xl_status |= XL_TXSTAT_IPCKSUM; + status |= XL_TXSTAT_IPCKSUM; if (m_head->m_pkthdr.csum_flags & CSUM_TCP) - c->xl_ptr->xl_status |= XL_TXSTAT_TCPCKSUM; + status |= XL_TXSTAT_TCPCKSUM; if (m_head->m_pkthdr.csum_flags & CSUM_UDP) - c->xl_ptr->xl_status |= XL_TXSTAT_UDPCKSUM; + status |= XL_TXSTAT_UDPCKSUM; } + c->xl_ptr->xl_status = htole32(status); } c->xl_mbuf = m_head; - bus_dmamap_sync(sc->xl_mtag, c->xl_map, BUS_DMASYNC_PREREAD); + bus_dmamap_sync(sc->xl_mtag, c->xl_map, BUS_DMASYNC_PREWRITE); return(0); } @@ -2475,6 +2498,7 @@ xl_start(ifp) struct xl_softc *sc; struct mbuf *m_head = NULL; struct xl_chain *prev = NULL, *cur_tx = NULL, *start_tx; + u_int32_t status; int error; sc = ifp->if_softc; @@ -2514,7 +2538,7 @@ xl_start(ifp) /* Chain it together. */ if (prev != NULL) { prev->xl_next = cur_tx; - prev->xl_ptr->xl_next = cur_tx->xl_phys; + prev->xl_ptr->xl_next = htole32(cur_tx->xl_phys); } prev = cur_tx; @@ -2540,7 +2564,10 @@ xl_start(ifp) * get an interupt once for the whole chain rather than * once for each packet. */ - cur_tx->xl_ptr->xl_status |= XL_TXSTAT_DL_INTR; + cur_tx->xl_ptr->xl_status = htole32(le32toh(cur_tx->xl_ptr->xl_status) | + XL_TXSTAT_DL_INTR); + bus_dmamap_sync(sc->xl_ldata.xl_tx_tag, sc->xl_ldata.xl_tx_dmamap, + BUS_DMASYNC_PREWRITE); /* * Queue the packets. If the TX channel is clear, update @@ -2551,9 +2578,11 @@ xl_start(ifp) if (sc->xl_cdata.xl_tx_head != NULL) { sc->xl_cdata.xl_tx_tail->xl_next = start_tx; - sc->xl_cdata.xl_tx_tail->xl_ptr->xl_next = start_tx->xl_phys; - sc->xl_cdata.xl_tx_tail->xl_ptr->xl_status &= - ~XL_TXSTAT_DL_INTR; + sc->xl_cdata.xl_tx_tail->xl_ptr->xl_next = + htole32(start_tx->xl_phys); + status = sc->xl_cdata.xl_tx_tail->xl_ptr->xl_status; + sc->xl_cdata.xl_tx_tail->xl_ptr->xl_status = + htole32(le32toh(status) & ~XL_TXSTAT_DL_INTR); sc->xl_cdata.xl_tx_tail = cur_tx; } else { sc->xl_cdata.xl_tx_head = start_tx; @@ -2633,7 +2662,7 @@ xl_start_90xB(ifp) /* Chain it together. */ if (prev != NULL) - prev->xl_ptr->xl_next = cur_tx->xl_phys; + prev->xl_ptr->xl_next = htole32(cur_tx->xl_phys); prev = cur_tx; /* @@ -2661,11 +2690,14 @@ xl_start_90xB(ifp) * get an interupt once for the whole chain rather than * once for each packet. */ - cur_tx->xl_ptr->xl_status |= XL_TXSTAT_DL_INTR; + cur_tx->xl_ptr->xl_status = htole32(le32toh(cur_tx->xl_ptr->xl_status) | + XL_TXSTAT_DL_INTR); + bus_dmamap_sync(sc->xl_ldata.xl_tx_tag, sc->xl_ldata.xl_tx_dmamap, + BUS_DMASYNC_PREWRITE); /* Start transmission */ sc->xl_cdata.xl_tx_prod = idx; - start_tx->xl_prev->xl_ptr->xl_next = start_tx->xl_phys; + start_tx->xl_prev->xl_ptr->xl_next = htole32(start_tx->xl_phys); /* * Set a timeout in case the chip goes out to lunch. @@ -3150,9 +3182,9 @@ xl_stop(sc) for (i = 0; i < XL_RX_LIST_CNT; i++) { if (sc->xl_cdata.xl_rx_chain[i].xl_mbuf != NULL) { bus_dmamap_unload(sc->xl_mtag, - sc->xl_cdata.xl_tx_chain[i].xl_map); + sc->xl_cdata.xl_rx_chain[i].xl_map); bus_dmamap_destroy(sc->xl_mtag, - sc->xl_cdata.xl_tx_chain[i].xl_map); + sc->xl_cdata.xl_rx_chain[i].xl_map); m_freem(sc->xl_cdata.xl_rx_chain[i].xl_mbuf); sc->xl_cdata.xl_rx_chain[i].xl_mbuf = NULL; } diff --git a/sys/pci/if_xlreg.h b/sys/pci/if_xlreg.h index 4f08afb..a035dc6 100644 --- a/sys/pci/if_xlreg.h +++ b/sys/pci/if_xlreg.h @@ -458,6 +458,7 @@ struct xl_list_data { u_int32_t xl_rx_dmaaddr; bus_dma_tag_t xl_rx_tag; bus_dmamap_t xl_rx_dmamap; + u_int32_t xl_tx_dmaaddr; bus_dma_tag_t xl_tx_tag; bus_dmamap_t xl_tx_dmamap; }; |