summaryrefslogtreecommitdiffstats
path: root/sys/dev/msk
diff options
context:
space:
mode:
authoryongari <yongari@FreeBSD.org>2007-04-11 00:47:29 +0000
committeryongari <yongari@FreeBSD.org>2007-04-11 00:47:29 +0000
commit8a4ba838b29d91b8163878b538490e08e87765cc (patch)
tree3b8e5dfaeb583c0d387f67433bc443612930452c /sys/dev/msk
parent1e6e7c9b8c8234c23911142b6ecdf6cecacc8534 (diff)
downloadFreeBSD-src-8a4ba838b29d91b8163878b538490e08e87765cc.zip
FreeBSD-src-8a4ba838b29d91b8163878b538490e08e87765cc.tar.gz
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
Diffstat (limited to 'sys/dev/msk')
-rw-r--r--sys/dev/msk/if_msk.c30
1 files changed, 25 insertions, 5 deletions
diff --git a/sys/dev/msk/if_msk.c b/sys/dev/msk/if_msk.c
index a2bb2c7..57038e1 100644
--- a/sys/dev/msk/if_msk.c
+++ b/sys/dev/msk/if_msk.c
@@ -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) {
OpenPOWER on IntegriCloud