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:
parent
696dd8f41c
commit
6da6d0a9e3
@ -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. */
|
||||
|
@ -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];
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user