summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/dev/ic/xl.c154
1 files changed, 38 insertions, 116 deletions
diff --git a/sys/dev/ic/xl.c b/sys/dev/ic/xl.c
index 2f1a6793624..cb165826d2a 100644
--- a/sys/dev/ic/xl.c
+++ b/sys/dev/ic/xl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: xl.c,v 1.69 2006/01/11 04:19:42 brad Exp $ */
+/* $OpenBSD: xl.c,v 1.70 2006/01/20 05:49:32 brad Exp $ */
/*
* Copyright (c) 1997, 1998, 1999
@@ -153,8 +153,6 @@ int xl_newbuf(struct xl_softc *, struct xl_chain_onefrag *);
void xl_stats_update(void *);
int xl_encap(struct xl_softc *, struct xl_chain *,
struct mbuf * );
-int xl_encap_90xB(struct xl_softc *, struct xl_chain *,
- struct mbuf * );
void xl_rxeof(struct xl_softc *);
int xl_rx_resync(struct xl_softc *);
void xl_txeof(struct xl_softc *);
@@ -1493,12 +1491,16 @@ xl_txeoc(sc)
CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_TX_RESET);
xl_wait(sc);
if (sc->xl_type == XL_TYPE_905B) {
- int i;
- struct xl_chain *c;
- i = sc->xl_cdata.xl_tx_cons;
- c = &sc->xl_cdata.xl_tx_chain[i];
- CSR_WRITE_4(sc, XL_DOWNLIST_PTR, c->xl_phys);
- CSR_WRITE_1(sc, XL_DOWN_POLL, 64);
+ if (sc->xl_cdata.xl_tx_cnt) {
+ int i;
+ struct xl_chain *c;
+
+ i = sc->xl_cdata.xl_tx_cons;
+ c = &sc->xl_cdata.xl_tx_chain[i];
+ CSR_WRITE_4(sc, XL_DOWNLIST_PTR,
+ c->xl_phys);
+ CSR_WRITE_1(sc, XL_DOWN_POLL, 64);
+ }
} else {
if (sc->xl_cdata.xl_tx_head != NULL)
CSR_WRITE_4(sc, XL_DOWNLIST_PTR,
@@ -1667,15 +1669,20 @@ xl_encap(sc, c, m_head)
struct xl_chain *c;
struct mbuf *m_head;
{
- int frag, total_len;
+ int error, frag, total_len;
+ u_int32_t status;
bus_dmamap_t map;
map = sc->sc_tx_sparemap;
reload:
- if (bus_dmamap_load_mbuf(sc->sc_dmat, map,
- m_head, BUS_DMA_NOWAIT) != 0)
- return (ENOBUFS);
+ error = bus_dmamap_load_mbuf(sc->sc_dmat, map,
+ m_head, BUS_DMA_NOWAIT);
+
+ if (error && error != EFBIG) {
+ m_freem(m_head);
+ return (1);
+ }
/*
* Start packing the mbufs in this chain into
@@ -1683,8 +1690,6 @@ reload:
* of fragments or hit the end of the mbuf chain.
*/
for (frag = 0, total_len = 0; frag < map->dm_nsegs; frag++) {
- if ((XL_TX_LIST_CNT - (sc->xl_cdata.xl_tx_cnt + frag)) < 3)
- return (ENOBUFS);
if (frag == XL_MAXFRAGS)
break;
total_len += map->dm_segs[frag].ds_len;
@@ -1702,7 +1707,7 @@ reload:
* pointers/counters; it wouldn't gain us anything,
* and would waste cycles.
*/
- if (frag != map->dm_nsegs) {
+ if (error) {
struct mbuf *m_new = NULL;
MGETHDR(m_new, M_DONTWAIT, MT_DATA);
@@ -1742,6 +1747,22 @@ reload:
c->xl_ptr->xl_status = htole32(total_len);
c->xl_ptr->xl_next = 0;
+ if (sc->xl_type == XL_TYPE_905B) {
+ status = XL_TXSTAT_RND_DEFEAT;
+
+#ifndef XL905B_TXCSUM_BROKEN
+ if (m_head->m_pkthdr.csum_flags) {
+ if (m_head->m_pkthdr.csum_flags & M_IPV4_CSUM_OUT)
+ status |= XL_TXSTAT_IPCKSUM;
+ if (m_head->m_pkthdr.csum_flags & M_TCPV4_CSUM_OUT)
+ status |= XL_TXSTAT_TCPCKSUM;
+ if (m_head->m_pkthdr.csum_flags & M_UDPV4_CSUM_OUT)
+ status |= XL_TXSTAT_UDPCKSUM;
+ }
+#endif
+ c->xl_ptr->xl_status = htole32(status);
+ }
+
bus_dmamap_sync(sc->sc_dmat, sc->sc_listmap,
offsetof(struct xl_list_data, xl_tx_list[0]),
sizeof(struct xl_list) * XL_TX_LIST_CNT,
@@ -1890,105 +1911,6 @@ xl_start(ifp)
return;
}
-int
-xl_encap_90xB(sc, c, m_head)
- struct xl_softc *sc;
- struct xl_chain *c;
- struct mbuf *m_head;
-{
- struct xl_frag *f = NULL;
- struct xl_list *d;
- int frag;
- bus_dmamap_t map;
-
- /*
- * Start packing the mbufs in this chain into
- * the fragment pointers. Stop when we run out
- * of fragments or hit the end of the mbuf chain.
- */
- map = sc->sc_tx_sparemap;
- d = c->xl_ptr;
- d->xl_status = htole32(0);
- d->xl_next = 0;
-
-reload:
- if (bus_dmamap_load_mbuf(sc->sc_dmat, map,
- m_head, BUS_DMA_NOWAIT) != 0)
- return (ENOBUFS);
-
- for (frag = 0; frag < map->dm_nsegs; frag++) {
- if (frag == XL_MAXFRAGS)
- break;
- f = &d->xl_frag[frag];
- f->xl_addr = htole32(map->dm_segs[frag].ds_addr);
- f->xl_len = htole32(map->dm_segs[frag].ds_len);
- }
-
- /*
- * Handle special case: we used up all 63 fragments,
- * but we have more mbufs left in the chain. Copy the
- * data into an mbuf cluster. Note that we don't
- * bother clearing the values in the other fragment
- * pointers/counters; it wouldn't gain us anything,
- * and would waste cycles.
- */
- if (frag != map->dm_nsegs) {
- struct mbuf *m_new = NULL;
-
- MGETHDR(m_new, M_DONTWAIT, MT_DATA);
- if (m_new == NULL) {
- m_freem(m_head);
- return (1);
- }
- if (m_head->m_pkthdr.len > MHLEN) {
- MCLGET(m_new, M_DONTWAIT);
- if (!(m_new->m_flags & M_EXT)) {
- m_freem(m_new);
- m_freem(m_head);
- return (1);
- }
- }
- m_copydata(m_head, 0, m_head->m_pkthdr.len,
- mtod(m_new, caddr_t));
- m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len;
- m_freem(m_head);
- m_head = m_new;
- goto reload;
- }
-
- bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
- BUS_DMASYNC_PREWRITE);
-
- /* sync the old map, and unload it (if necessary) */
- if (c->map->dm_nsegs != 0) {
- bus_dmamap_sync(sc->sc_dmat, c->map, 0, c->map->dm_mapsize,
- BUS_DMASYNC_POSTWRITE);
- bus_dmamap_unload(sc->sc_dmat, c->map);
- }
-
- c->xl_mbuf = m_head;
- sc->sc_tx_sparemap = c->map;
- c->map = map;
- c->xl_ptr->xl_frag[frag - 1].xl_len |= htole32(XL_LAST_FRAG);
- c->xl_ptr->xl_status = htole32(XL_TXSTAT_RND_DEFEAT);
-
-#ifndef XL905B_TXCSUM_BROKEN
- if (m_head->m_pkthdr.csum & M_IPV4_CSUM_OUT)
- c->xl_ptr->xl_status |= htole32(XL_TXSTAT_IPCKSUM);
- if (m_head->m_pkthdr.csum & M_TCPV4_CSUM_OUT)
- c->xl_ptr->xl_status |= htole32(XL_TXSTAT_TCPCKSUM);
- if (m_head->m_pkthdr.csum & M_UDPV4_CSUM_OUT)
- c->xl_ptr->xl_status |= htole32(XL_TXSTAT_UDPCKSUM);
-#endif
-
- bus_dmamap_sync(sc->sc_dmat, sc->sc_listmap,
- offsetof(struct xl_list_data, xl_tx_list[0]),
- sizeof(struct xl_list) * XL_TX_LIST_CNT,
- BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
-
- return(0);
-}
-
void
xl_start_90xB(ifp)
struct ifnet *ifp;
@@ -2022,7 +1944,7 @@ xl_start_90xB(ifp)
cur_tx = &sc->xl_cdata.xl_tx_chain[idx];
/* Pack the data into the descriptor. */
- error = xl_encap_90xB(sc, cur_tx, m_head);
+ error = xl_encap(sc, cur_tx, m_head);
if (error) {
cur_tx = prev_tx;
continue;