From 5ef6b21b784867c039fba3dd4e5a3ab761435792 Mon Sep 17 00:00:00 2001 From: yamt Date: Sat, 12 Mar 2005 08:01:51 +0000 Subject: [PATCH] re(4) driver: - TSO support. - fix some error handling. - remove mysterious RTK_NTXSEGS and use more appropriate values for bus_dmamap_create. - if we need more than all of our tx descriptors in order to transmit a packet, just drop it rather than retrying infinitely. --- sys/dev/ic/rtl8169.c | 85 +++++++++++++++++++++++++++++++---------- sys/dev/ic/rtl81x9reg.h | 5 +-- 2 files changed, 66 insertions(+), 24 deletions(-) diff --git a/sys/dev/ic/rtl8169.c b/sys/dev/ic/rtl8169.c index fe85692bfa63..1c95bfcda6a7 100644 --- a/sys/dev/ic/rtl8169.c +++ b/sys/dev/ic/rtl8169.c @@ -1,4 +1,4 @@ -/* $NetBSD: rtl8169.c,v 1.12 2005/02/27 00:27:02 perry Exp $ */ +/* $NetBSD: rtl8169.c,v 1.13 2005/03/12 08:01:51 yamt Exp $ */ /* * Copyright (c) 1997, 1998-2003 @@ -130,6 +130,10 @@ #include #include +#include /* XXX for IP_MAXPACKET */ +#include /* XXX for IP_MAXPACKET */ +#include /* XXX for IP_MAXPACKET */ + #if NBPFILTER > 0 #include #endif @@ -659,8 +663,10 @@ re_attach(struct rtk_softc *sc) /* Create DMA maps for TX buffers */ for (i = 0; i < RTK_TX_DESC_CNT; i++) { - error = bus_dmamap_create(sc->sc_dmat, MCLBYTES * RTK_NTXSEGS, - RTK_NTXSEGS, MCLBYTES, 0, BUS_DMA_ALLOCNOW, + error = bus_dmamap_create(sc->sc_dmat, + round_page(IP_MAXPACKET), + RTK_TX_DESC_CNT - 4, RTK_TDESC_CMD_FRAGLEN, + 0, BUS_DMA_ALLOCNOW, &sc->rtk_ldata.rtk_tx_dmamap[i]); if (error) { aprint_error("%s: can't create DMA map for TX\n", @@ -732,7 +738,8 @@ re_attach(struct rtk_softc *sc) ifp->if_start = re_start; ifp->if_stop = re_stop; ifp->if_capabilities |= - IFCAP_CSUM_IPv4 | IFCAP_CSUM_TCPv4 | IFCAP_CSUM_UDPv4; + IFCAP_CSUM_IPv4 | IFCAP_CSUM_TCPv4 | IFCAP_CSUM_UDPv4 | + IFCAP_TSOv4; ifp->if_watchdog = re_watchdog; ifp->if_init = re_init; if (sc->rtk_type == RTK_8169) @@ -1485,7 +1492,7 @@ done: } static int -re_encap(struct rtk_softc *sc, struct mbuf *m_head, int *idx) +re_encap(struct rtk_softc *sc, struct mbuf *m, int *idx) { bus_dmamap_t map; int error, i, curidx; @@ -1503,27 +1510,42 @@ re_encap(struct rtk_softc *sc, struct mbuf *m_head, int *idx) * chip. I'm not sure if this is a requirement or a bug.) */ - rtk_flags = 0; + if ((m->m_pkthdr.csum_flags & M_CSUM_TSOv4) != 0) { + u_int32_t segsz = m->m_pkthdr.segsz; - if (m_head->m_pkthdr.csum_flags & M_CSUM_IPv4) - rtk_flags |= RTK_TDESC_CMD_IPCSUM; - if (m_head->m_pkthdr.csum_flags & M_CSUM_TCPv4) - rtk_flags |= RTK_TDESC_CMD_TCPCSUM; - if (m_head->m_pkthdr.csum_flags & M_CSUM_UDPv4) - rtk_flags |= RTK_TDESC_CMD_UDPCSUM; + rtk_flags = RTK_TDESC_CMD_LGSEND | + (segsz << RTK_TDESC_CMD_MSSVAL_SHIFT); + } else { + rtk_flags = 0; + if (m->m_pkthdr.csum_flags & M_CSUM_IPv4) + rtk_flags |= RTK_TDESC_CMD_IPCSUM; + if (m->m_pkthdr.csum_flags & M_CSUM_TCPv4) + rtk_flags |= RTK_TDESC_CMD_TCPCSUM; + if (m->m_pkthdr.csum_flags & M_CSUM_UDPv4) + rtk_flags |= RTK_TDESC_CMD_UDPCSUM; + } map = sc->rtk_ldata.rtk_tx_dmamap[*idx]; - error = bus_dmamap_load_mbuf(sc->sc_dmat, map, - m_head, BUS_DMA_NOWAIT); + error = bus_dmamap_load_mbuf(sc->sc_dmat, map, m, BUS_DMA_NOWAIT); if (error) { + /* XXX try to defrag if EFBIG? */ + aprint_error("%s: can't map mbuf (error %d)\n", sc->sc_dev.dv_xname, error); + + if (error == EFBIG && + sc->rtk_ldata.rtk_tx_free == RTK_TX_DESC_CNT) { + return error; + } + return ENOBUFS; } - if (map->dm_nsegs > sc->rtk_ldata.rtk_tx_free - 4) - return ENOBUFS; + if (map->dm_nsegs > sc->rtk_ldata.rtk_tx_free - 4) { + error = ENOBUFS; + goto fail_unload; + } /* * Map the segment array into descriptors. Note that we set the * start-of-frame and end-of-frame markers for either TX or RX, but @@ -1539,8 +1561,16 @@ re_encap(struct rtk_softc *sc, struct mbuf *m_head, int *idx) curidx = *idx; while (1) { d = &sc->rtk_ldata.rtk_tx_list[curidx]; - if (le32toh(d->rtk_cmdstat) & RTK_RDESC_STAT_OWN) - return ENOBUFS; + if (le32toh(d->rtk_cmdstat) & RTK_RDESC_STAT_OWN) { + while (i > 0) { + sc->rtk_ldata.rtk_tx_list[ + (curidx + RTK_TX_DESC_CNT - i) % + RTK_TX_DESC_CNT].rtk_cmdstat = 0; + i--; + } + error = ENOBUFS; + goto fail_unload; + } cmdstat = map->dm_segs[i].ds_len; d->rtk_bufaddr_lo = @@ -1570,7 +1600,7 @@ re_encap(struct rtk_softc *sc, struct mbuf *m_head, int *idx) sc->rtk_ldata.rtk_tx_dmamap[*idx] = sc->rtk_ldata.rtk_tx_dmamap[curidx]; sc->rtk_ldata.rtk_tx_dmamap[curidx] = map; - sc->rtk_ldata.rtk_tx_mbuf[curidx] = m_head; + sc->rtk_ldata.rtk_tx_mbuf[curidx] = m; sc->rtk_ldata.rtk_tx_free -= map->dm_nsegs; /* @@ -1579,7 +1609,7 @@ re_encap(struct rtk_softc *sc, struct mbuf *m_head, int *idx) * transmission attempt. */ - if ((mtag = VLAN_OUTPUT_TAG(&sc->ethercom, m_head)) != NULL) { + if ((mtag = VLAN_OUTPUT_TAG(&sc->ethercom, m)) != NULL) { sc->rtk_ldata.rtk_tx_list[*idx].rtk_vlanctl = htole32(htons(VLAN_TAG_VALUE(mtag)) | RTK_TDESC_VLANCTL_TAG); @@ -1597,6 +1627,11 @@ re_encap(struct rtk_softc *sc, struct mbuf *m_head, int *idx) *idx = curidx; return 0; + +fail_unload: + bus_dmamap_unload(sc->sc_dmat, map); + + return error; } /* @@ -1614,11 +1649,19 @@ re_start(struct ifnet *ifp) idx = sc->rtk_ldata.rtk_tx_prodidx; while (sc->rtk_ldata.rtk_tx_mbuf[idx] == NULL) { + int error; + IF_DEQUEUE(&ifp->if_snd, m_head); if (m_head == NULL) break; - if (re_encap(sc, m_head, &idx)) { + error = re_encap(sc, m_head, &idx); + if (error == EFBIG) { + ifp->if_oerrors++; + m_freem(m_head); + continue; + } + if (error) { IF_PREPEND(&ifp->if_snd, m_head); ifp->if_flags |= IFF_OACTIVE; break; diff --git a/sys/dev/ic/rtl81x9reg.h b/sys/dev/ic/rtl81x9reg.h index f314f781c5d0..cbbb22d3b331 100644 --- a/sys/dev/ic/rtl81x9reg.h +++ b/sys/dev/ic/rtl81x9reg.h @@ -1,4 +1,4 @@ -/* $NetBSD: rtl81x9reg.h,v 1.10 2005/02/27 00:27:02 perry Exp $ */ +/* $NetBSD: rtl81x9reg.h,v 1.11 2005/03/12 08:01:51 yamt Exp $ */ /* * Copyright (c) 1997, 1998 @@ -465,6 +465,7 @@ struct rtk_desc { #define RTK_TDESC_CMD_UDPCSUM 0x00020000 /* UDP checksum enable */ #define RTK_TDESC_CMD_IPCSUM 0x00040000 /* IP header checksum enable */ #define RTK_TDESC_CMD_MSSVAL 0x07FF0000 /* Large send MSS value */ +#define RTK_TDESC_CMD_MSSVAL_SHIFT 16 /* Shift of the above */ #define RTK_TDESC_CMD_LGSEND 0x08000000 /* TCP large send enb */ #define RTK_TDESC_CMD_EOF 0x10000000 /* end of frame marker */ #define RTK_TDESC_CMD_SOF 0x20000000 /* start of frame marker */ @@ -567,5 +568,3 @@ struct rtk_stats { #define RTK_JUMBO_FRAMELEN 9018 #define RTK_JUMBO_MTU (RTK_JUMBO_FRAMELEN-ETHER_HDR_LEN-ETHER_CRC_LEN) - -#define RTK_NTXSEGS 32