summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkientzle <kientzle@FreeBSD.org>2012-10-25 04:37:47 +0000
committerkientzle <kientzle@FreeBSD.org>2012-10-25 04:37:47 +0000
commite8860ec0d6ccf06abf7e2ccaee03c4ba09cb27b3 (patch)
tree6f201bd2cf6c1ceb220b6588ace9025b677d6e94
parent0ecde454b513bcf3978bc30204c8ac058b871cef (diff)
downloadFreeBSD-src-e8860ec0d6ccf06abf7e2ccaee03c4ba09cb27b3.zip
FreeBSD-src-e8860ec0d6ccf06abf7e2ccaee03c4ba09cb27b3.tar.gz
Do proper padding of runt packets using code copied from bge(4).
Reviewed by: gnn
-rw-r--r--sys/arm/ti/cpsw/if_cpsw.c53
1 files changed, 51 insertions, 2 deletions
diff --git a/sys/arm/ti/cpsw/if_cpsw.c b/sys/arm/ti/cpsw/if_cpsw.c
index 12b519e..d671c72 100644
--- a/sys/arm/ti/cpsw/if_cpsw.c
+++ b/sys/arm/ti/cpsw/if_cpsw.c
@@ -581,8 +581,8 @@ cpsw_encap(struct cpsw_softc *sc, struct mbuf *m0)
bd.next = 0;
bd.bufptr = seg->ds_addr;
bd.bufoff = 0;
- bd.buflen = (seg->ds_len < 64 ? 64 : seg->ds_len);
- bd.pktlen = (seg->ds_len < 64 ? 64 : seg->ds_len);
+ bd.buflen = seg->ds_len;
+ bd.pktlen = seg->ds_len;
/* Set OWNERSHIP, SOP, EOP */
bd.flags = (7<<13);
@@ -599,6 +599,49 @@ cpsw_encap(struct cpsw_softc *sc, struct mbuf *m0)
return (0);
}
+/*
+ * Pad the packet to the minimum length for Ethernet.
+ * (CPSW hardware doesn't do this for us.)
+ */
+static int
+cpsw_pad(struct mbuf *m)
+{
+ int padlen = ETHER_MIN_LEN - m->m_pkthdr.len;
+ struct mbuf *last, *n;
+
+ if (padlen <= 0)
+ return (0);
+
+ /* If there's only the packet-header and we can pad there, use it. */
+ if (m->m_pkthdr.len == m->m_len && M_WRITABLE(m) &&
+ M_TRAILINGSPACE(m) >= padlen) {
+ last = m;
+ } else {
+ /*
+ * Walk packet chain to find last mbuf. We will either
+ * pad there, or append a new mbuf and pad it.
+ */
+ for (last = m; last->m_next != NULL; last = last->m_next)
+ ;
+ if (!(M_WRITABLE(last) && M_TRAILINGSPACE(last) >= padlen)) {
+ /* Allocate new empty mbuf, pad it. Compact later. */
+ MGET(n, M_DONTWAIT, MT_DATA);
+ if (n == NULL)
+ return (ENOBUFS);
+ n->m_len = 0;
+ last->m_next = n;
+ last = n;
+ }
+ }
+
+ /* Now zero the pad area. */
+ memset(mtod(last, caddr_t) + last->m_len, 0, padlen);
+ last->m_len += padlen;
+ m->m_pkthdr.len += padlen;
+
+ return (0);
+}
+
static void
cpsw_start(struct ifnet *ifp)
{
@@ -615,6 +658,7 @@ cpsw_start_locked(struct ifnet *ifp)
struct cpsw_softc *sc = ifp->if_softc;
struct mbuf *m0, *mtmp;
uint32_t queued = 0;
+ int error;
CPSW_TX_LOCK_ASSERT(sc);
@@ -628,6 +672,11 @@ cpsw_start_locked(struct ifnet *ifp)
if (m0 == NULL)
break;
+ if ((error = cpsw_pad(m0))) {
+ m_freem(m0);
+ continue;
+ }
+
mtmp = m_defrag(m0, M_NOWAIT);
if (mtmp)
m0 = mtmp;
OpenPOWER on IntegriCloud