summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoryongari <yongari@FreeBSD.org>2008-03-28 01:21:21 +0000
committeryongari <yongari@FreeBSD.org>2008-03-28 01:21:21 +0000
commite8dec714c152599d2c50ced87a4f8feac69f47be (patch)
tree5c0f9b16502a0566dcc1156adef8feb1da3df8bf
parentcee246254050beb0770a8ab9cdff03f44c2db3c9 (diff)
downloadFreeBSD-src-e8dec714c152599d2c50ced87a4f8feac69f47be.zip
FreeBSD-src-e8dec714c152599d2c50ced87a4f8feac69f47be.tar.gz
In revision 1.70, 1.71 and 1.84 re(4) tried to workaround checksum
offload bugs by manual padding for short IP/UDP frames. Unfortunately it seems that these workaround does not work reliably on newer PCIe variants of RealTek chips. To workaround the hardware bug, always pad short frames if Tx IP checksum offload is requested. It seems that the hardware has a bug in IP checksum offload handling. NetBSD manually pads short frames only when the length of IP frame is less than 28 bytes but I chose 60 bytes to safety. Also unconditionally set IP checksum offload bit in Tx descriptor if any TCP or UDP checksum offload is requested. This is the same way as Linux does but it's not mentioned in data sheet. Obtained from: NetBSD Tested by: remko, danger
-rw-r--r--sys/dev/re/if_re.c26
1 files changed, 14 insertions, 12 deletions
diff --git a/sys/dev/re/if_re.c b/sys/dev/re/if_re.c
index 85e6452..a4527a6 100644
--- a/sys/dev/re/if_re.c
+++ b/sys/dev/re/if_re.c
@@ -2167,16 +2167,12 @@ re_encap(sc, m_head)
* need to send a really small IP fragment that's less than 60
* bytes in size, and IP header checksumming is enabled, the
* resulting ethernet frame that appears on the wire will
- * have garbled payload. To work around this, if TX checksum
+ * have garbled payload. To work around this, if TX IP checksum
* offload is enabled, we always manually pad short frames out
* to the minimum ethernet frame size.
- *
- * Note: this appears unnecessary for TCP, and doing it for TCP
- * with PCIe adapters seems to result in bad checksums.
*/
- if ((*m_head)->m_pkthdr.csum_flags & (CSUM_IP | CSUM_UDP) &&
- ((*m_head)->m_pkthdr.csum_flags & CSUM_TCP) == 0 &&
- (*m_head)->m_pkthdr.len < RL_MIN_FRAMELEN) {
+ if ((*m_head)->m_pkthdr.len < RL_MIN_FRAMELEN &&
+ ((*m_head)->m_pkthdr.csum_flags & CSUM_IP) != 0) {
padlen = RL_MIN_FRAMELEN - (*m_head)->m_pkthdr.len;
if (M_WRITABLE(*m_head) == 0) {
/* Get a writable copy. */
@@ -2257,12 +2253,18 @@ re_encap(sc, m_head)
((uint32_t)(*m_head)->m_pkthdr.tso_segsz <<
RL_TDESC_CMD_MSSVAL_SHIFT);
else {
- if ((*m_head)->m_pkthdr.csum_flags & CSUM_IP)
+ /*
+ * Unconditionally enable IP checksum if TCP or UDP
+ * checksum is required. Otherwise, TCP/UDP checksum
+ * does't make effects.
+ */
+ if (((*m_head)->m_pkthdr.csum_flags & RE_CSUM_FEATURES) != 0) {
csum_flags |= RL_TDESC_CMD_IPCSUM;
- if ((*m_head)->m_pkthdr.csum_flags & CSUM_TCP)
- csum_flags |= RL_TDESC_CMD_TCPCSUM;
- if ((*m_head)->m_pkthdr.csum_flags & CSUM_UDP)
- csum_flags |= RL_TDESC_CMD_UDPCSUM;
+ if (((*m_head)->m_pkthdr.csum_flags & CSUM_TCP) != 0)
+ csum_flags |= RL_TDESC_CMD_TCPCSUM;
+ if (((*m_head)->m_pkthdr.csum_flags & CSUM_UDP) != 0)
+ csum_flags |= RL_TDESC_CMD_UDPCSUM;
+ }
}
/*
OpenPOWER on IntegriCloud