mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-19 10:53:58 +00:00
Add work around for hardware Tx checksum offload bug in Yukon II.
Yukon II generated corrupted TCP checksum for short TCP packets that's less than 60 bytes in size(e.g. window probe packet, pure ACK packet etc). Padding the frame with zeros to make the frame minimum ethernet frame size didn't work at all. Instead of dropping Tx checksum offload support we calculate TCP checksum with S/W method when we encounter short TCP frames. Fortunately it seems that short UDP datagrams appear to be handled correctly by Yukon II. While I'm here simplify ethernet/VLAN header size calculation logic. PR: 111384
This commit is contained in:
parent
6f7c3bdd63
commit
b5898b804f
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=168608
@ -131,6 +131,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <netinet/udp.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
#include <machine/in_cksum.h>
|
||||
#include <machine/resource.h>
|
||||
#include <sys/rman.h>
|
||||
|
||||
@ -2647,7 +2648,6 @@ msk_encap(struct msk_if_softc *sc_if, struct mbuf **m_head)
|
||||
* hardware. However, TSO performance of Yukon II is very
|
||||
* good such that it's worth to implement it.
|
||||
*/
|
||||
struct ether_vlan_header *evh;
|
||||
struct ether_header *eh;
|
||||
struct ip *ip;
|
||||
struct tcphdr *tcp;
|
||||
@ -2669,17 +2669,37 @@ msk_encap(struct msk_if_softc *sc_if, struct mbuf **m_head)
|
||||
*m_head = NULL;
|
||||
return (ENOBUFS);
|
||||
}
|
||||
evh = mtod(m, struct ether_vlan_header *);
|
||||
ip = (struct ip *)(evh + 1);
|
||||
} else
|
||||
ip = (struct ip *)(eh + 1);
|
||||
}
|
||||
m = m_pullup(m, offset + sizeof(struct ip));
|
||||
if (m == NULL) {
|
||||
*m_head = NULL;
|
||||
return (ENOBUFS);
|
||||
}
|
||||
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.
|
||||
*/
|
||||
if (m->m_pkthdr.len < MSK_MIN_FRAMELEN &&
|
||||
(m->m_pkthdr.csum_flags & CSUM_TCP) != 0) {
|
||||
uint16_t csum;
|
||||
|
||||
csum = in_cksum_skip(m, ntohs(ip->ip_len) + offset -
|
||||
(ip->ip_hl << 2), offset);
|
||||
*(uint16_t *)(m->m_data + offset +
|
||||
m->m_pkthdr.csum_data) = csum;
|
||||
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) {
|
||||
|
Loading…
Reference in New Issue
Block a user