diff options
author | yongari <yongari@FreeBSD.org> | 2008-03-28 01:21:21 +0000 |
---|---|---|
committer | yongari <yongari@FreeBSD.org> | 2008-03-28 01:21:21 +0000 |
commit | e8dec714c152599d2c50ced87a4f8feac69f47be (patch) | |
tree | 5c0f9b16502a0566dcc1156adef8feb1da3df8bf | |
parent | cee246254050beb0770a8ab9cdff03f44c2db3c9 (diff) | |
download | FreeBSD-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.c | 26 |
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; + } } /* |