From 6b176ce6683dce004b4c68b3dadd11b813e9f70a Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Mon, 30 Mar 2015 14:30:04 +0200 Subject: if_dwc: Checksum offload --- freebsd/sys/dev/dwc/if_dwc.c | 67 ++++++++++++++++++++++++++++++++++++++++---- freebsd/sys/dev/dwc/if_dwc.h | 2 ++ 2 files changed, 63 insertions(+), 6 deletions(-) diff --git a/freebsd/sys/dev/dwc/if_dwc.c b/freebsd/sys/dev/dwc/if_dwc.c index 4df9c186..27f6fcf3 100644 --- a/freebsd/sys/dev/dwc/if_dwc.c +++ b/freebsd/sys/dev/dwc/if_dwc.c @@ -107,13 +107,22 @@ __FBSDID("$FreeBSD$"); #define DDESC_TDES0_TXLAST (1 << 29) #define DDESC_TDES0_TXFIRST (1 << 28) #define DDESC_TDES0_TXCRCDIS (1 << 27) +#define DDESC_TDES0_CIC_IP_HDR (0x1 << 22) +#define DDESC_TDES0_CIC_IP_HDR_PYL (0x2 << 22) +#define DDESC_TDES0_CIC_IP_HDR_PYL_PHDR (0x3 << 22) #define DDESC_TDES0_TXRINGEND (1 << 21) #define DDESC_TDES0_TXCHAIN (1 << 20) #define DDESC_RDES0_OWN (1 << 31) #define DDESC_RDES0_FL_MASK 0x3fff #define DDESC_RDES0_FL_SHIFT 16 /* Frame Length */ +#define DDESC_RDES0_ESA (1 << 0) #define DDESC_RDES1_CHAINED (1 << 14) +#define DDESC_RDES4_IP_PYL_ERR (1 << 4) +#define DDESC_RDES4_IP_HDR_ERR (1 << 3) +#define DDESC_RDES4_IP_PYL_TYPE_MSK 0x7 +#define DDESC_RDES4_IP_PYL_UDP 1 +#define DDESC_RDES4_IP_PYL_TCP 2 struct dwc_bufmap { #ifndef __rtems__ @@ -132,6 +141,10 @@ struct dwc_hwdesc uint32_t tdes1; uint32_t addr; /* pointer to buffer data */ uint32_t addr_next; /* link to next descriptor */ + uint32_t tdes4; + uint32_t tdes5; + uint32_t timestamp_low; + uint32_t timestamp_high; }; /* @@ -157,6 +170,9 @@ struct dwc_hwdesc */ #define DWC_DESC_RING_ALIGN 2048 +#define DWC_CKSUM_ASSIST (CSUM_IP | CSUM_TCP | CSUM_UDP | \ + CSUM_TCP_IPV6 | CSUM_UDP_IPV6) + struct dwc_softc { struct resource *res[2]; bus_space_tag_t bst; @@ -240,8 +256,8 @@ dwc_get1paddr(void *arg, bus_dma_segment_t *segs, int nsegs, int error) #endif /* __rtems__ */ static void -dwc_setup_txdesc(struct dwc_softc *sc, int idx, bus_dma_segment_t segs[TX_MAX_DMA_SEGS], - int nsegs) +dwc_setup_txdesc(struct dwc_softc *sc, int csum_flags, int idx, + bus_dma_segment_t segs[TX_MAX_DMA_SEGS], int nsegs) { int i; @@ -266,9 +282,16 @@ dwc_setup_txdesc(struct dwc_softc *sc, int idx, bus_dma_segment_t segs[TX_MAX_DM tdes0 = DDESC_TDES0_TXCHAIN | DDESC_TDES0_TXINT | DDESC_TDES0_OWN; - if (i == 0) + if (i == 0) { tdes0 |= DDESC_TDES0_TXFIRST; + if ((csum_flags & (CSUM_TCP | CSUM_UDP | + CSUM_TCP_IPV6 | CSUM_UDP_IPV6)) != 0) + tdes0 |= DDESC_TDES0_CIC_IP_HDR_PYL_PHDR; + else if ((csum_flags & CSUM_IP) != 0) + tdes0 |= DDESC_TDES0_CIC_IP_HDR; + } + if (i == nsegs - 1) tdes0 |= DDESC_TDES0_TXLAST; @@ -350,7 +373,7 @@ dwc_setup_txbuf(struct dwc_softc *sc, struct mbuf *m, int *start_tx) BUS_DMASYNC_PREWRITE); #endif /* __rtems__ */ - dwc_setup_txdesc(sc, idx, segs, nsegs); + dwc_setup_txdesc(sc, m->m_pkthdr.csum_flags, idx, segs, nsegs); ETHER_BPF_MTAP(sc->ifp, m); *start_tx = 1; @@ -569,6 +592,7 @@ dwc_init_locked(struct dwc_softc *sc) /* Enable transmitters */ reg = READ4(sc, MAC_CONFIGURATION); + reg |= (CONF_IPC); reg |= (CONF_JD | CONF_ACS | CONF_BE); reg |= (CONF_TE | CONF_RE); WRITE4(sc, MAC_CONFIGURATION, reg); @@ -881,7 +905,8 @@ dwc_rxfinish_locked(struct dwc_softc *sc) struct mbuf *m0; struct mbuf *m; int error; - int rdes0; + uint32_t rdes0; + uint32_t rdes4; int idx; int len; @@ -906,6 +931,32 @@ dwc_rxfinish_locked(struct dwc_softc *sc) m->m_pkthdr.rcvif = ifp; m->m_pkthdr.len = len; m->m_len = len; + + /* Check checksum offload flags. */ + if ((rdes0 & DDESC_RDES0_ESA) != 0) { + rdes4 = sc->rxdesc_ring[idx].tdes4; + + /* TCP or UDP checks out, IP checks out too. */ + if ((rdes4 & DDESC_RDES4_IP_PYL_TYPE_MSK) == + DDESC_RDES4_IP_PYL_UDP || + (rdes4 & DDESC_RDES4_IP_PYL_TYPE_MSK) == + DDESC_RDES4_IP_PYL_TCP) { + m->m_pkthdr.csum_flags |= + CSUM_IP_CHECKED | + CSUM_IP_VALID | + CSUM_DATA_VALID | + CSUM_PSEUDO_HDR; + m->m_pkthdr.csum_data = 0xffff; + } else if ((rdes4 & (DDESC_RDES4_IP_PYL_ERR | + DDESC_RDES4_IP_HDR_ERR)) == 0) { + /* Only IP checks out. */ + m->m_pkthdr.csum_flags |= + CSUM_IP_CHECKED | + CSUM_IP_VALID; + m->m_pkthdr.csum_data = 0xffff; + } + } + #ifndef __rtems__ if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); #else /* __rtems__ */ @@ -1146,6 +1197,7 @@ setup_dma(struct dwc_softc *sc) "could not create new RX buffer.\n"); goto out; } + sc->rxdesc_ring[idx].tdes4 = 0; } out: @@ -1263,6 +1315,7 @@ dwc_attach(device_t dev) } reg = READ4(sc, BUS_MODE); + reg |= (BUS_MODE_ATDS); reg |= (BUS_MODE_EIGHTXPBL); reg |= (BUS_MODE_PBL_BEATS_8 << BUS_MODE_PBL_SHIFT); WRITE4(sc, BUS_MODE, reg); @@ -1297,8 +1350,10 @@ dwc_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 | IFCAP_VLAN_HWCSUM; ifp->if_capenable = ifp->if_capabilities; + ifp->if_hwassist = DWC_CKSUM_ASSIST; ifp->if_start = dwc_txstart; ifp->if_ioctl = dwc_ioctl; ifp->if_init = dwc_init; diff --git a/freebsd/sys/dev/dwc/if_dwc.h b/freebsd/sys/dev/dwc/if_dwc.h index 918ef008..aa5c9734 100644 --- a/freebsd/sys/dev/dwc/if_dwc.h +++ b/freebsd/sys/dev/dwc/if_dwc.h @@ -40,6 +40,7 @@ #define CONF_PS (1 << 15) /* GMII/MII */ #define CONF_FES (1 << 14) /* MII speed select */ #define CONF_DM (1 << 11) /* Full Duplex Enable */ +#define CONF_IPC (1 << 10) /* Checksum Enable */ #define CONF_ACS (1 << 7) #define CONF_TE (1 << 3) #define CONF_RE (1 << 2) @@ -209,6 +210,7 @@ #define BUS_MODE_EIGHTXPBL (1 << 24) /* Multiplies PBL by 8 */ #define BUS_MODE_PBL_SHIFT 8 /* Single block transfer size */ #define BUS_MODE_PBL_BEATS_8 8 +#define BUS_MODE_ATDS (1 << 7) /* Alternate Descriptor Size */ #define BUS_MODE_SWR (1 << 0) /* Reset */ #define TRANSMIT_POLL_DEMAND 0x1004 #define RECEIVE_POLL_DEMAND 0x1008 -- cgit v1.2.3