From f3300b2f0bf664bb8c43e09a12fc24f679fce0a1 Mon Sep 17 00:00:00 2001 From: Bill Paul Date: Wed, 13 Aug 2003 22:39:21 +0000 Subject: [PATCH] Set the TX hardware checksum offload bits on all the descriptors of a multi-fragment transmission. I'm not sure if this is a bug or a requirement that I overlooked with going through the documentation, but the sample 8169 NIC that I have seems to require it at least some of the time or else it botches TCP checksums on segments that span multiple descriptors. --- sys/pci/if_rl.c | 39 ++++++++++++++++++++++----------------- sys/pci/if_rlreg.h | 1 + 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/sys/pci/if_rl.c b/sys/pci/if_rl.c index 130aba0ed1a7..68cf0494ec5f 100644 --- a/sys/pci/if_rl.c +++ b/sys/pci/if_rl.c @@ -1140,7 +1140,7 @@ rl_dma_map_desc(arg, segs, nseg, mapsize, error) cmdstat |= RL_TDESC_CMD_OWN; if (idx == (RL_RX_DESC_CNT - 1)) cmdstat |= RL_TDESC_CMD_EOR; - d->rl_cmdstat = htole32(cmdstat); + d->rl_cmdstat = htole32(cmdstat | ctx->rl_flags); i++; if (i == nseg) break; @@ -1716,6 +1716,7 @@ rl_newbuf (sc, idx, m) arg.sc = sc; arg.rl_idx = idx; arg.rl_maxsegs = 1; + arg.rl_flags = 0; arg.rl_ring = sc->rl_ldata.rl_rx_list; error = bus_dmamap_load_mbuf(sc->rl_ldata.rl_mtag, @@ -2373,12 +2374,27 @@ rl_encapcplus(sc, m_head, idx) struct rl_dmaload_arg arg; bus_dmamap_t map; int error; - u_int32_t csumcmd = RL_TDESC_CMD_OWN; struct m_tag *mtag; if (sc->rl_ldata.rl_tx_free < 4) return(EFBIG); + /* + * Set up checksum offload. Note: checksum offload bits must + * appear in all descriptors of a multi-descriptor transmit + * attempt. (This is according to testing done with an 8169 + * chip. I'm not sure if this is a requirement or a bug.) + */ + + arg.rl_flags = 0; + + if (m_head->m_pkthdr.csum_flags & CSUM_IP) + arg.rl_flags |= RL_TDESC_CMD_IPCSUM; + if (m_head->m_pkthdr.csum_flags & CSUM_TCP) + arg.rl_flags |= RL_TDESC_CMD_TCPCSUM; + if (m_head->m_pkthdr.csum_flags & CSUM_UDP) + arg.rl_flags |= RL_TDESC_CMD_UDPCSUM; + arg.sc = sc; arg.rl_idx = *idx; arg.rl_maxsegs = sc->rl_ldata.rl_tx_free; @@ -2439,24 +2455,13 @@ rl_encapcplus(sc, m_head, idx) sc->rl_ldata.rl_tx_list[*idx].rl_vlanctl = htole32(htons(VLAN_TAG_VALUE(mtag)) | RL_TDESC_VLANCTL_TAG); - /* - * Set up checksum offload. Note: checksum offload bits must - * appear in the first descriptor of a multi-descriptor - * transmission attempt. - */ - - if (m_head->m_pkthdr.csum_flags & CSUM_IP) - csumcmd |= RL_TDESC_CMD_IPCSUM; - if (m_head->m_pkthdr.csum_flags & CSUM_TCP) - csumcmd |= RL_TDESC_CMD_TCPCSUM; - if (m_head->m_pkthdr.csum_flags & CSUM_UDP) - csumcmd |= RL_TDESC_CMD_UDPCSUM; - /* Transfer ownership of packet to the chip. */ - sc->rl_ldata.rl_tx_list[arg.rl_idx].rl_cmdstat |= htole32(csumcmd); + sc->rl_ldata.rl_tx_list[arg.rl_idx].rl_cmdstat |= + htole32(RL_TDESC_CMD_OWN); if (*idx != arg.rl_idx) - sc->rl_ldata.rl_tx_list[*idx].rl_cmdstat |= htole32(csumcmd); + sc->rl_ldata.rl_tx_list[*idx].rl_cmdstat |= + htole32(RL_TDESC_CMD_OWN); RL_DESC_INC(arg.rl_idx); *idx = arg.rl_idx; diff --git a/sys/pci/if_rlreg.h b/sys/pci/if_rlreg.h index 4a32aef18b04..5ca63688740f 100644 --- a/sys/pci/if_rlreg.h +++ b/sys/pci/if_rlreg.h @@ -602,6 +602,7 @@ struct rl_dmaload_arg { struct rl_softc *sc; int rl_idx; int rl_maxsegs; + u_int32_t rl_flags; struct rl_desc *rl_ring; };