diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2017-10-25 10:17:23 +0200 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2017-10-25 14:30:04 +0200 |
commit | a8a9cf1847f2832e9e5ce54e862063d7907fc42d (patch) | |
tree | 1a45986b09a72fe2bec334abbe33a8899270aecd | |
parent | 0323c286e32934979043d14d69660db4ba4c3181 (diff) |
ffec: Add checksum offload
Update #3090.
-rw-r--r-- | freebsd/sys/dev/ffec/if_ffec.c | 42 | ||||
-rw-r--r-- | freebsd/sys/dev/ffec/if_ffecreg.h | 14 |
2 files changed, 53 insertions, 3 deletions
diff --git a/freebsd/sys/dev/ffec/if_ffec.c b/freebsd/sys/dev/ffec/if_ffec.c index d44d6c5a..6f505acc 100644 --- a/freebsd/sys/dev/ffec/if_ffec.c +++ b/freebsd/sys/dev/ffec/if_ffec.c @@ -81,6 +81,8 @@ __FBSDID("$FreeBSD$"); #include <net/if_types.h> #include <net/if_var.h> #include <net/if_vlan_var.h> +#include <netinet/in.h> +#include <netinet/ip.h> #include <dev/ffec/if_ffecreg.h> #include <dev/ofw/ofw_bus.h> @@ -620,7 +622,9 @@ ffec_encap(struct ifnet *ifp, struct ffec_softc *sc, struct mbuf *m0, int error, i, nsegs; struct ffec_bufmap *bmap; uint32_t tx_idx; + int csum_flags; uint32_t flags; + uint32_t flags2; FFEC_ASSERT_LOCKED(sc); @@ -653,6 +657,27 @@ ffec_encap(struct ifnet *ifp, struct ffec_softc *sc, struct mbuf *m0, #endif /* __rtems__ */ bmap->mbuf = m0; + flags2 = FEC_TXDESC_INT; + csum_flags = m0->m_pkthdr.csum_flags; + + if ((csum_flags & CSUM_IP) != 0) { + struct mbuf *n; + int off; + int off2; + struct ip *ip; + + flags2 |= FEC_TXDESC_IINS; + n = m_getptr(m0, sizeof(struct ether_header), &off); + ip = (struct ip *)mtodo(n, off); + ip->ip_sum = 0; + + off2 = m0->m_pkthdr.csum_data; + if ((csum_flags & (CSUM_TCP | CSUM_UDP)) != 0 && off2 != 0) { + flags2 |= FEC_TXDESC_PINS; + *(uint16_t *)((caddr_t)(ip + 1) + off2) = 0; + } + } + /* * Fill in the TX descriptors back to front so that READY bit in first * descriptor is set last. @@ -666,6 +691,7 @@ ffec_encap(struct ifnet *ifp, struct ffec_softc *sc, struct mbuf *m0, tx_idx = prev_txidx(tx_idx);; tx_desc = &sc->txdesc_ring[tx_idx]; tx_desc->buf_paddr = segs[i].ds_addr; + tx_desc->flags2 = flags2; #ifdef __rtems__ rtems_cache_flush_multiple_data_lines((void *)segs[i].ds_addr, segs[i].ds_len); @@ -793,6 +819,7 @@ ffec_setup_rxdesc(struct ffec_softc *sc, int idx, bus_addr_t paddr) */ nidx = next_rxidx(idx); sc->rxdesc_ring[idx].buf_paddr = (uint32_t)paddr; + sc->rxdesc_ring[idx].flags2 = FEC_RXDESC_INT; wmb(); sc->rxdesc_ring[idx].flags_len = FEC_RXDESC_EMPTY | ((nidx == 0) ? FEC_RXDESC_WRAP : 0); @@ -851,7 +878,7 @@ ffec_alloc_mbufcl(struct ffec_softc *sc) } static void -ffec_rxfinish_onebuf(struct ffec_softc *sc, int len) +ffec_rxfinish_onebuf(struct ffec_softc *sc, int len, uint32_t flags2) { struct mbuf *m, *newmbuf; struct ffec_bufmap *bmap; @@ -898,6 +925,12 @@ ffec_rxfinish_onebuf(struct ffec_softc *sc, int len) m->m_pkthdr.len = len; m->m_pkthdr.rcvif = sc->ifp; + if ((flags2 & (FEC_RXDESC_ICE | FEC_RXDESC_PCR)) == 0) { + m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED | CSUM_IP_VALID | + CSUM_DATA_VALID | CSUM_PSEUDO_HDR; + m->m_pkthdr.csum_data = 0xffff; + } + if (sc->fectype & FECFLAG_RACC) { /* We use the RACC[SHIFT16] feature */ m->m_data = mtod(m, uint8_t *) + 2; @@ -973,7 +1006,7 @@ ffec_rxfinish_locked(struct ffec_softc *sc) /* * Normal case: a good frame all in one buffer. */ - ffec_rxfinish_onebuf(sc, len); + ffec_rxfinish_onebuf(sc, len, desc->flags2); } sc->rx_idx = next_rxidx(sc->rx_idx); } @@ -1305,6 +1338,7 @@ ffec_init_locked(struct ffec_softc *sc) regval |= FEC_ECR_DBSWP; #endif regval |= FEC_ECR_ETHEREN; + regval |= FEC_ECR_EN1588; WR4(sc, FEC_ECR_REG, regval); ifp->if_drv_flags |= IFF_DRV_RUNNING; @@ -1962,8 +1996,10 @@ ffec_attach(device_t dev) ifp->if_softc = sc; if_initname(ifp, device_get_name(dev), device_get_unit(dev)); ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; - ifp->if_capabilities = IFCAP_VLAN_MTU; + ifp->if_capabilities = IFCAP_HWCSUM | IFCAP_HWCSUM_IPV6 | + IFCAP_VLAN_MTU; ifp->if_capenable = ifp->if_capabilities; + ifp->if_hwassist = CSUM_IP | CSUM_TCP | CSUM_UDP; ifp->if_start = ffec_txstart; ifp->if_ioctl = ffec_ioctl; ifp->if_init = ffec_init; diff --git a/freebsd/sys/dev/ffec/if_ffecreg.h b/freebsd/sys/dev/ffec/if_ffecreg.h index 481bc303..9ec5b375 100644 --- a/freebsd/sys/dev/ffec/if_ffecreg.h +++ b/freebsd/sys/dev/ffec/if_ffecreg.h @@ -295,6 +295,11 @@ struct ffec_hwdesc { uint32_t flags_len; uint32_t buf_paddr; + uint32_t flags2; + uint32_t hlen_proto; + uint32_t bdu; + uint32_t ts; + uint32_t res[2]; }; #define FEC_TXDESC_READY (1U << 31) @@ -306,6 +311,11 @@ struct ffec_hwdesc #define FEC_TXDESC_ABC (1 << 25) #define FEC_TXDESC_LEN_MASK (0xffff) +#define FEC_TXDESC_INT (1 << 30) +#define FEC_TXDESC_TS (1 << 29) +#define FEC_TXDESC_PINS (1 << 28) +#define FEC_TXDESC_IINS (1 << 27) + #define FEC_RXDESC_EMPTY (1U << 31) #define FEC_RXDESC_R01 (1 << 30) #define FEC_RXDESC_WRAP (1 << 29) @@ -321,6 +331,10 @@ struct ffec_hwdesc #define FEC_RXDESC_TR (1 << 16) #define FEC_RXDESC_LEN_MASK (0xffff) +#define FEC_RXDESC_INT (1 << 23) +#define FEC_RXDESC_ICE (1 << 5) +#define FEC_RXDESC_PCR (1 << 4) + #define FEC_RXDESC_ERROR_BITS (FEC_RXDESC_LG | FEC_RXDESC_NO | \ FEC_RXDESC_OV | FEC_RXDESC_TR) |