With r206844, CSUM_TCP is also set for CSUM_TSO case. Modify

drivers to take into account for the change. Basically CSUM_TSO
should be checked before checking CSUM_TCP.
This commit is contained in:
Pyun YongHyeon 2010-04-19 22:10:40 +00:00
parent 696dd8f41c
commit 6da6d0a9e3
6 changed files with 125 additions and 133 deletions

View File

@ -1629,22 +1629,8 @@ age_encap(struct age_softc *sc, struct mbuf **m_head)
}
m = *m_head;
/* Configure Tx IP/TCP/UDP checksum offload. */
if ((m->m_pkthdr.csum_flags & AGE_CSUM_FEATURES) != 0) {
cflags |= AGE_TD_CSUM;
if ((m->m_pkthdr.csum_flags & CSUM_TCP) != 0)
cflags |= AGE_TD_TCPCSUM;
if ((m->m_pkthdr.csum_flags & CSUM_UDP) != 0)
cflags |= AGE_TD_UDPCSUM;
/* Set checksum start offset. */
cflags |= (poff << AGE_TD_CSUM_PLOADOFFSET_SHIFT);
/* Set checksum insertion position of TCP/UDP. */
cflags |= ((poff + m->m_pkthdr.csum_data) <<
AGE_TD_CSUM_XSUMOFFSET_SHIFT);
}
/* Configure TSO. */
if ((m->m_pkthdr.csum_flags & CSUM_TSO) != 0) {
/* Configure TSO. */
if (poff + (tcp->th_off << 2) == m->m_pkthdr.len) {
/* Not TSO but IP/TCP checksum offload. */
cflags |= AGE_TD_IPCSUM | AGE_TD_TCPCSUM;
@ -1660,6 +1646,18 @@ age_encap(struct age_softc *sc, struct mbuf **m_head)
/* Set IP/TCP header size. */
cflags |= ip->ip_hl << AGE_TD_IPHDR_LEN_SHIFT;
cflags |= tcp->th_off << AGE_TD_TSO_TCPHDR_LEN_SHIFT;
} else if ((m->m_pkthdr.csum_flags & AGE_CSUM_FEATURES) != 0) {
/* Configure Tx IP/TCP/UDP checksum offload. */
cflags |= AGE_TD_CSUM;
if ((m->m_pkthdr.csum_flags & CSUM_TCP) != 0)
cflags |= AGE_TD_TCPCSUM;
if ((m->m_pkthdr.csum_flags & CSUM_UDP) != 0)
cflags |= AGE_TD_UDPCSUM;
/* Set checksum start offset. */
cflags |= (poff << AGE_TD_CSUM_PLOADOFFSET_SHIFT);
/* Set checksum insertion position of TCP/UDP. */
cflags |= ((poff + m->m_pkthdr.csum_data) <<
AGE_TD_CSUM_XSUMOFFSET_SHIFT);
}
/* Configure VLAN hardware tag insertion. */

View File

@ -1908,28 +1908,7 @@ alc_encap(struct alc_softc *sc, struct mbuf **m_head)
vtag = (vtag << TD_VLAN_SHIFT) & TD_VLAN_MASK;
cflags |= TD_INS_VLAN_TAG;
}
/* Configure Tx checksum offload. */
if ((m->m_pkthdr.csum_flags & ALC_CSUM_FEATURES) != 0) {
#ifdef ALC_USE_CUSTOM_CSUM
cflags |= TD_CUSTOM_CSUM;
/* Set checksum start offset. */
cflags |= ((poff >> 1) << TD_PLOAD_OFFSET_SHIFT) &
TD_PLOAD_OFFSET_MASK;
/* Set checksum insertion position of TCP/UDP. */
cflags |= (((poff + m->m_pkthdr.csum_data) >> 1) <<
TD_CUSTOM_CSUM_OFFSET_SHIFT) & TD_CUSTOM_CSUM_OFFSET_MASK;
#else
if ((m->m_pkthdr.csum_flags & CSUM_IP) != 0)
cflags |= TD_IPCSUM;
if ((m->m_pkthdr.csum_flags & CSUM_TCP) != 0)
cflags |= TD_TCPCSUM;
if ((m->m_pkthdr.csum_flags & CSUM_UDP) != 0)
cflags |= TD_UDPCSUM;
/* Set TCP/UDP header offset. */
cflags |= (poff << TD_L4HDR_OFFSET_SHIFT) &
TD_L4HDR_OFFSET_MASK;
#endif
} else if ((m->m_pkthdr.csum_flags & CSUM_TSO) != 0) {
if ((m->m_pkthdr.csum_flags & CSUM_TSO) != 0) {
/* Request TSO and set MSS. */
cflags |= TD_TSO | TD_TSO_DESCV1;
cflags |= ((uint32_t)m->m_pkthdr.tso_segsz << TD_MSS_SHIFT) &
@ -1961,6 +1940,27 @@ alc_encap(struct alc_softc *sc, struct mbuf **m_head)
}
/* Handle remaining fragments. */
idx = 1;
} else if ((m->m_pkthdr.csum_flags & ALC_CSUM_FEATURES) != 0) {
/* Configure Tx checksum offload. */
#ifdef ALC_USE_CUSTOM_CSUM
cflags |= TD_CUSTOM_CSUM;
/* Set checksum start offset. */
cflags |= ((poff >> 1) << TD_PLOAD_OFFSET_SHIFT) &
TD_PLOAD_OFFSET_MASK;
/* Set checksum insertion position of TCP/UDP. */
cflags |= (((poff + m->m_pkthdr.csum_data) >> 1) <<
TD_CUSTOM_CSUM_OFFSET_SHIFT) & TD_CUSTOM_CSUM_OFFSET_MASK;
#else
if ((m->m_pkthdr.csum_flags & CSUM_IP) != 0)
cflags |= TD_IPCSUM;
if ((m->m_pkthdr.csum_flags & CSUM_TCP) != 0)
cflags |= TD_TCPCSUM;
if ((m->m_pkthdr.csum_flags & CSUM_UDP) != 0)
cflags |= TD_UDPCSUM;
/* Set TCP/UDP header offset. */
cflags |= (poff << TD_L4HDR_OFFSET_SHIFT) &
TD_L4HDR_OFFSET_MASK;
#endif
}
for (; idx < nsegs; idx++) {
desc = &sc->alc_rdata.alc_tx_ring[prod];

View File

@ -1737,8 +1737,14 @@ ale_encap(struct ale_softc *sc, struct mbuf **m_head)
bus_dmamap_sync(sc->ale_cdata.ale_tx_tag, map, BUS_DMASYNC_PREWRITE);
m = *m_head;
/* Configure Tx checksum offload. */
if ((m->m_pkthdr.csum_flags & ALE_CSUM_FEATURES) != 0) {
if ((m->m_pkthdr.csum_flags & CSUM_TSO) != 0) {
/* Request TSO and set MSS. */
cflags |= ALE_TD_TSO;
cflags |= ((uint32_t)m->m_pkthdr.tso_segsz << ALE_TD_MSS_SHIFT);
/* Set IP/TCP header size. */
cflags |= ip->ip_hl << ALE_TD_IPHDR_LEN_SHIFT;
cflags |= tcp->th_off << ALE_TD_TCPHDR_LEN_SHIFT;
} else if ((m->m_pkthdr.csum_flags & ALE_CSUM_FEATURES) != 0) {
/*
* AR81xx supports Tx custom checksum offload feature
* that offloads single 16bit checksum computation.
@ -1769,15 +1775,6 @@ ale_encap(struct ale_softc *sc, struct mbuf **m_head)
ALE_TD_CSUM_XSUMOFFSET_SHIFT);
}
if ((m->m_pkthdr.csum_flags & CSUM_TSO) != 0) {
/* Request TSO and set MSS. */
cflags |= ALE_TD_TSO;
cflags |= ((uint32_t)m->m_pkthdr.tso_segsz << ALE_TD_MSS_SHIFT);
/* Set IP/TCP header size. */
cflags |= ip->ip_hl << ALE_TD_IPHDR_LEN_SHIFT;
cflags |= tcp->th_off << ALE_TD_TCPHDR_LEN_SHIFT;
}
/* Configure VLAN hardware tag insertion. */
if ((m->m_flags & M_VLANTAG) != 0) {
vtag = ALE_TX_VLAN_TAG(m->m_pkthdr.ether_vtag);

View File

@ -1417,60 +1417,6 @@ fxp_encap(struct fxp_softc *sc, struct mbuf **m_head)
FXP_IPCB_HARDWAREPARSING_ENABLE;
m = *m_head;
/*
* Deal with TCP/IP checksum offload. Note that
* in order for TCP checksum offload to work,
* the pseudo header checksum must have already
* been computed and stored in the checksum field
* in the TCP header. The stack should have
* already done this for us.
*/
if (m->m_pkthdr.csum_flags & FXP_CSUM_FEATURES) {
txp->tx_cb->ipcb_ip_schedule = FXP_IPCB_TCPUDP_CHECKSUM_ENABLE;
if (m->m_pkthdr.csum_flags & CSUM_TCP)
txp->tx_cb->ipcb_ip_schedule |= FXP_IPCB_TCP_PACKET;
#ifdef FXP_IP_CSUM_WAR
/*
* XXX The 82550 chip appears to have trouble
* dealing with IP header checksums in very small
* datagrams, namely fragments from 1 to 3 bytes
* in size. For example, say you want to transmit
* a UDP packet of 1473 bytes. The packet will be
* fragmented over two IP datagrams, the latter
* containing only one byte of data. The 82550 will
* botch the header checksum on the 1-byte fragment.
* As long as the datagram contains 4 or more bytes
* of data, you're ok.
*
* The following code attempts to work around this
* problem: if the datagram is less than 38 bytes
* in size (14 bytes ether header, 20 bytes IP header,
* plus 4 bytes of data), we punt and compute the IP
* header checksum by hand. This workaround doesn't
* work very well, however, since it can be fooled
* by things like VLAN tags and IP options that make
* the header sizes/offsets vary.
*/
if (m->m_pkthdr.csum_flags & CSUM_IP) {
if (m->m_pkthdr.len < 38) {
struct ip *ip;
m->m_data += ETHER_HDR_LEN;
ip = mtod(m, struct ip *);
ip->ip_sum = in_cksum(m, ip->ip_hl << 2);
m->m_data -= ETHER_HDR_LEN;
m->m_pkthdr.csum_flags &= ~CSUM_IP;
} else {
txp->tx_cb->ipcb_ip_activation_high =
FXP_IPCB_HARDWAREPARSING_ENABLE;
txp->tx_cb->ipcb_ip_schedule |=
FXP_IPCB_IP_CHECKSUM_ENABLE;
}
}
#endif
}
if (m->m_pkthdr.csum_flags & CSUM_TSO) {
/*
* 82550/82551 requires ethernet/IP/TCP headers must be
@ -1539,6 +1485,58 @@ fxp_encap(struct fxp_softc *sc, struct mbuf **m_head)
tcp_payload = m->m_pkthdr.len - ip_off - (ip->ip_hl << 2);
tcp_payload -= tcp->th_off << 2;
*m_head = m;
} else if (m->m_pkthdr.csum_flags & FXP_CSUM_FEATURES) {
/*
* Deal with TCP/IP checksum offload. Note that
* in order for TCP checksum offload to work,
* the pseudo header checksum must have already
* been computed and stored in the checksum field
* in the TCP header. The stack should have
* already done this for us.
*/
txp->tx_cb->ipcb_ip_schedule = FXP_IPCB_TCPUDP_CHECKSUM_ENABLE;
if (m->m_pkthdr.csum_flags & CSUM_TCP)
txp->tx_cb->ipcb_ip_schedule |= FXP_IPCB_TCP_PACKET;
#ifdef FXP_IP_CSUM_WAR
/*
* XXX The 82550 chip appears to have trouble
* dealing with IP header checksums in very small
* datagrams, namely fragments from 1 to 3 bytes
* in size. For example, say you want to transmit
* a UDP packet of 1473 bytes. The packet will be
* fragmented over two IP datagrams, the latter
* containing only one byte of data. The 82550 will
* botch the header checksum on the 1-byte fragment.
* As long as the datagram contains 4 or more bytes
* of data, you're ok.
*
* The following code attempts to work around this
* problem: if the datagram is less than 38 bytes
* in size (14 bytes ether header, 20 bytes IP header,
* plus 4 bytes of data), we punt and compute the IP
* header checksum by hand. This workaround doesn't
* work very well, however, since it can be fooled
* by things like VLAN tags and IP options that make
* the header sizes/offsets vary.
*/
if (m->m_pkthdr.csum_flags & CSUM_IP) {
if (m->m_pkthdr.len < 38) {
struct ip *ip;
m->m_data += ETHER_HDR_LEN;
ip = mtod(m, struct ip *);
ip->ip_sum = in_cksum(m, ip->ip_hl << 2);
m->m_data -= ETHER_HDR_LEN;
m->m_pkthdr.csum_flags &= ~CSUM_IP;
} else {
txp->tx_cb->ipcb_ip_activation_high =
FXP_IPCB_HARDWAREPARSING_ENABLE;
txp->tx_cb->ipcb_ip_schedule |=
FXP_IPCB_IP_CHECKSUM_ENABLE;
}
}
#endif
}
error = bus_dmamap_load_mbuf_sg(sc->fxp_txmtag, txp->tx_map, *m_head,

View File

@ -2605,23 +2605,32 @@ msk_encap(struct msk_if_softc *sc_if, struct mbuf **m_head)
ip = (struct ip *)(mtod(m, char *) + offset);
offset += (ip->ip_hl << 2);
tcp_offset = offset;
/*
* It seems that Yukon II has Tx checksum offload bug for
* small TCP packets that's less than 60 bytes in size
* (e.g. TCP window probe packet, pure ACK packet).
* Common work around like padding with zeros to make the
* frame minimum ethernet frame size didn't work at all.
* Instead of disabling checksum offload completely we
* resort to S/W checksum routine when we encounter short
* TCP frames.
* Short UDP packets appear to be handled correctly by
* Yukon II. Also I assume this bug does not happen on
* controllers that use newer descriptor format or
* automatic Tx checksum calaulcation.
*/
if ((sc_if->msk_flags & MSK_FLAG_AUTOTX_CSUM) == 0 &&
if ((m->m_pkthdr.csum_flags & CSUM_TSO) != 0) {
m = m_pullup(m, offset + sizeof(struct tcphdr));
if (m == NULL) {
*m_head = NULL;
return (ENOBUFS);
}
tcp = (struct tcphdr *)(mtod(m, char *) + offset);
offset += (tcp->th_off << 2);
} else if ((sc_if->msk_flags & MSK_FLAG_AUTOTX_CSUM) == 0 &&
(m->m_pkthdr.len < MSK_MIN_FRAMELEN) &&
(m->m_pkthdr.csum_flags & CSUM_TCP) != 0) {
/*
* It seems that Yukon II has Tx checksum offload bug
* for small TCP packets that's less than 60 bytes in
* size (e.g. TCP window probe packet, pure ACK packet).
* Common work around like padding with zeros to make
* the frame minimum ethernet frame size didn't work at
* all.
* Instead of disabling checksum offload completely we
* resort to S/W checksum routine when we encounter
* short TCP frames.
* Short UDP packets appear to be handled correctly by
* Yukon II. Also I assume this bug does not happen on
* controllers that use newer descriptor format or
* automatic Tx checksum calaulcation.
*/
m = m_pullup(m, offset + sizeof(struct tcphdr));
if (m == NULL) {
*m_head = NULL;
@ -2632,15 +2641,6 @@ msk_encap(struct msk_if_softc *sc_if, struct mbuf **m_head)
m->m_pkthdr.len, offset);
m->m_pkthdr.csum_flags &= ~CSUM_TCP;
}
if ((m->m_pkthdr.csum_flags & CSUM_TSO) != 0) {
m = m_pullup(m, offset + sizeof(struct tcphdr));
if (m == NULL) {
*m_head = NULL;
return (ENOBUFS);
}
tcp = (struct tcphdr *)(mtod(m, char *) + offset);
offset += (tcp->th_off << 2);
}
*m_head = m;
}

View File

@ -2366,7 +2366,12 @@ nfe_encap(struct nfe_softc *sc, struct mbuf **m_head)
m = *m_head;
cflags = flags = 0;
tso_segsz = 0;
if ((m->m_pkthdr.csum_flags & NFE_CSUM_FEATURES) != 0) {
if ((m->m_pkthdr.csum_flags & CSUM_TSO) != 0) {
tso_segsz = (uint32_t)m->m_pkthdr.tso_segsz <<
NFE_TX_TSO_SHIFT;
cflags &= ~(NFE_TX_IP_CSUM | NFE_TX_TCP_UDP_CSUM);
cflags |= NFE_TX_TSO;
} else if ((m->m_pkthdr.csum_flags & NFE_CSUM_FEATURES) != 0) {
if ((m->m_pkthdr.csum_flags & CSUM_IP) != 0)
cflags |= NFE_TX_IP_CSUM;
if ((m->m_pkthdr.csum_flags & CSUM_TCP) != 0)
@ -2374,12 +2379,6 @@ nfe_encap(struct nfe_softc *sc, struct mbuf **m_head)
if ((m->m_pkthdr.csum_flags & CSUM_UDP) != 0)
cflags |= NFE_TX_TCP_UDP_CSUM;
}
if ((m->m_pkthdr.csum_flags & CSUM_TSO) != 0) {
tso_segsz = (uint32_t)m->m_pkthdr.tso_segsz <<
NFE_TX_TSO_SHIFT;
cflags &= ~(NFE_TX_IP_CSUM | NFE_TX_TCP_UDP_CSUM);
cflags |= NFE_TX_TSO;
}
for (i = 0; i < nsegs; i++) {
if (sc->nfe_flags & NFE_40BIT_ADDR) {