From eebfc9ef1e2cc67d4e298d957bd4d2383c7da9f8 Mon Sep 17 00:00:00 2001 From: rjs Date: Mon, 24 Aug 2015 18:51:37 +0000 Subject: [PATCH] Add hardware checksumming support. --- sys/dev/cadence/cemacreg.h | 33 ++++++++++-------- sys/dev/cadence/if_cemac.c | 68 ++++++++++++++++++++++++++++++++++---- 2 files changed, 81 insertions(+), 20 deletions(-) diff --git a/sys/dev/cadence/cemacreg.h b/sys/dev/cadence/cemacreg.h index 0963ad849b49..1872a863807a 100644 --- a/sys/dev/cadence/cemacreg.h +++ b/sys/dev/cadence/cemacreg.h @@ -1,4 +1,4 @@ -/* $NetBSD: cemacreg.h,v 1.2 2015/08/13 14:51:35 rjs Exp $ */ +/* $NetBSD: cemacreg.h,v 1.3 2015/08/24 18:51:37 rjs Exp $ */ /*- * Copyright (c) 2015 Genetec Corporation. All rights reserved. @@ -164,6 +164,7 @@ #define GEM_CFG_CLK_64 __SHIFTIN(4, GEM_CFG_CLK) #define GEM_CFG_CLK_96 __SHIFTIN(5, GEM_CFG_CLK) #define GEM_CFG_DBW __BITS(22, 21) +#define GEM_CFG_RX_CHKSUM_OFFLD_EN __BIT(24) /* Status Register bits: */ #define ETH_SR_IDLE 0x0004U /* 1 = PHY logic is running */ @@ -244,30 +245,36 @@ typedef struct eth_dsc { #define ETH_RDSC_F_USED 0x00000001U /* frame info bits: */ -#define ETH_RDSC_I_BCAST 0x80000000U -#define ETH_RDSC_I_MULTICAST 0x40000000U -#define ETH_RDSC_I_UNICAST 0x20000000U +#define ETH_RDSC_I_BCAST __BIT(31) +#define ETH_RDSC_I_MULTICAST __BIT(30) +#define ETH_RDSC_I_UNICAST __BIT(29) #define ETH_RDSC_I_VLAN 0x10000000U #define ETH_RDSC_I_UNKNOWN_SRC 0x08000000U #define ETH_RDSC_I_MATCH1 0x04000000U #define ETH_RDSC_I_MATCH2 0x02000000U #define ETH_RDSC_I_MATCH3 0x01000000U #define ETH_RDSC_I_MATCH4 0x00800000U -#define ETH_RDSC_I_LEN 0x000007FFU +#define ETH_RDSC_I_CHKSUM __BITS(23, 22) +#define ETH_RDSC_I_CHKSUM_NONE __SHIFTIN(0, ETH_RDSC_I_CHKSUM) +#define ETH_RDSC_I_CHKSUM_IP __SHIFTIN(1, ETH_RDSC_I_CHKSUM) +#define ETH_RDSC_I_CHKSUM_TCP __SHIFTIN(2, ETH_RDSC_I_CHKSUM) +#define ETH_RDSC_I_CHKSUM_UDP __SHIFTIN(3, ETH_RDSC_I_CHKSUM) +#define ETH_RDSC_I_LEN __BITS(13, 0) #define ETH_TDSC_I_USED __BIT(31) /* done transmitting */ #define ETH_TDSC_I_WRAP __BIT(30) /* end of descr ring */ #define ETH_TDSC_I_RETRY_ERR __BIT(29) #define ETH_TDSC_I_AHB_ERR __BIT(27) #define ETH_TDSC_I_LATE_COLL __BIT(26) -#define ETH_TDSC_I_CKSUM_GEN_STAT_MASK __BIT(20) -#define ETH_TDSC_I_CKSUM_GEN_STAT_VLAN_HDR_ERR __BIT(20) -#define ETH_TDSC_I_CKSUM_GEN_STAT_SNAP_HDR_ERR __BIT(20) -#define ETH_TDSC_I_CKSUM_GEN_STAT_IP_HDR_ERR __BIT(20) -#define ETH_TDSC_I_CKSUM_GEN_STAT_UNKNOWN_TYPE __BIT(20) -#define ETH_TDSC_I_CKSUM_GEN_STAT_UNSUPP_FRAG __BIT(20) -#define ETH_TDSC_I_CKSUM_GEN_STAT_NOT_TCPUDP __BIT(20) -#define ETH_TDSC_I_CKSUM_GEN_STAT_SHORT_PKT __BIT(20) +#define ETH_TDSC_I_CHKSUM __BITS(22, 20) +#define ETH_TDSC_I_CHKSUM_GEN_STAT_NO_ERR __SHIFTIN(0, ETH_TDSC_I_CHKSUM) +#define ETH_TDSC_I_CHKSUM_GEN_STAT_VLAN_HDR_ERR __SHIFTIN(1, ETH_TDSC_I_CHKSUM) +#define ETH_TDSC_I_CHKSUM_GEN_STAT_SNAP_HDR_ERR __SHIFTIN(2, ETH_TDSC_I_CHKSUM) +#define ETH_TDSC_I_CHKSUM_GEN_STAT_IP_HDR_ERR __SHIFTIN(3, ETH_TDSC_I_CHKSUM) +#define ETH_TDSC_I_CHKSUM_GEN_STAT_UNKNOWN_TYPE __SHIFTIN(4, ETH_TDSC_I_CHKSUM) +#define ETH_TDSC_I_CHKSUM_GEN_STAT_UNSUPP_FRAG __SHIFTIN(5, ETH_TDSC_I_CHKSUM) +#define ETH_TDSC_I_CHKSUM_GEN_STAT_NOT_TCPUDP __SHIFTIN(6, ETH_TDSC_I_CHKSUM) +#define ETH_TDSC_I_CHKSUM_GEN_STAT_SHORT_PKT __SHIFTIN(7, ETH_TDSC_I_CHKSUM) #define ETH_TDSC_I_NO_CRC_APPENDED __BIT(16) #define ETH_TDSC_I_LAST_BUF __BIT(15) /* last buf in frame */ #define ETH_TDSC_I_LEN __BITS(13, 0) diff --git a/sys/dev/cadence/if_cemac.c b/sys/dev/cadence/if_cemac.c index 3ddf4905196a..a3988f848a9f 100644 --- a/sys/dev/cadence/if_cemac.c +++ b/sys/dev/cadence/if_cemac.c @@ -1,4 +1,4 @@ -/* $NetBSD: if_cemac.c,v 1.6 2015/08/24 18:40:57 rjs Exp $ */ +/* $NetBSD: if_cemac.c,v 1.7 2015/08/24 18:51:37 rjs Exp $ */ /* * Copyright (c) 2015 Genetec Corporation. All rights reserved. @@ -40,7 +40,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: if_cemac.c,v 1.6 2015/08/24 18:40:57 rjs Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_cemac.c,v 1.7 2015/08/24 18:51:37 rjs Exp $"); #include #include @@ -322,7 +322,7 @@ cemac_intr(void *arg) uint32_t nfo; DPRINTFN(2,("#2 RDSC[%i].INFO=0x%08X\n", sc->rxqi % RX_QLEN, sc->RDSC[sc->rxqi % RX_QLEN].Info)); while (sc->RDSC[(bi = sc->rxqi % RX_QLEN)].Addr & ETH_RDSC_F_USED) { - int fl; + int fl, csum; struct mbuf *m; nfo = sc->RDSC[bi].Info; @@ -339,6 +339,23 @@ cemac_intr(void *arg) sc->rxq[bi].m->m_pkthdr.rcvif = ifp; sc->rxq[bi].m->m_pkthdr.len = sc->rxq[bi].m->m_len = fl; + switch (nfo & ETH_RDSC_I_CHKSUM) { + case ETH_RDSC_I_CHKSUM_IP: + csum = M_CSUM_IPv4; + break; + case ETH_RDSC_I_CHKSUM_UDP: + csum = M_CSUM_IPv4 | M_CSUM_UDPv4 | + M_CSUM_UDPv6; + break; + case ETH_RDSC_I_CHKSUM_TCP: + csum = M_CSUM_IPv4 | M_CSUM_TCPv4 | + M_CSUM_TCPv6; + break; + default: + csum = 0; + break; + } + sc->rxq[bi].m->m_pkthdr.csum_flags = csum; bpf_mtap(ifp, sc->rxq[bi].m); DPRINTFN(2,("received %u bytes packet\n", fl)); (*ifp->if_input)(ifp, sc->rxq[bi].m); @@ -578,6 +595,16 @@ cemac_init(struct cemac_softc *sc) CEMAC_WRITE(ETH_CTL, ETH_CTL_TE | ETH_CTL_RE | ETH_CTL_ISR | ETH_CTL_CSR | ETH_CTL_MPE); #endif + /* + * We can support hardware checksumming. + */ + ifp->if_capabilities |= + IFCAP_CSUM_IPv4_Tx | IFCAP_CSUM_IPv4_Rx | + IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_TCPv4_Rx | + IFCAP_CSUM_UDPv4_Tx | IFCAP_CSUM_UDPv4_Rx | + IFCAP_CSUM_TCPv6_Tx | IFCAP_CSUM_TCPv6_Rx | + IFCAP_CSUM_UDPv6_Tx | IFCAP_CSUM_UDPv6_Rx; + /* * We can support 802.1Q VLAN-sized frames. */ @@ -726,10 +753,16 @@ cemac_ifioctl(struct ifnet *ifp, u_long cmd, void *data) break; default: error = ether_ioctl(ifp, cmd, data); - if (error == ENETRESET) { - if (ifp->if_flags & IFF_RUNNING) - cemac_setaddr(ifp); - error = 0; + if (error != ENETRESET) + break; + error = 0; + + if (cmd == SIOCSIFCAP) { + error = (*ifp->if_init)(ifp); + } else if (cmd != SIOCADDMULTI && cmd != SIOCDELMULTI) + ; + else if (ifp->if_flags & IFF_RUNNING) { + cemac_setaddr(ifp); } } splx(s); @@ -856,10 +889,31 @@ static int cemac_ifinit(struct ifnet *ifp) { struct cemac_softc *sc = ifp->if_softc; + uint32_t dma, cfg; int s = splnet(); callout_stop(&sc->cemac_tick_ch); + if (ISSET(sc->cemac_flags, CEMAC_FLAG_GEM)) { + + if (ifp->if_capenable & + (IFCAP_CSUM_IPv4_Tx | + IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_UDPv4_Tx | + IFCAP_CSUM_TCPv6_Tx | IFCAP_CSUM_UDPv6_Tx)) { + dma = CEMAC_READ(GEM_DMA_CFG); + dma |= GEM_DMA_CFG_CHKSUM_GEN_OFFLOAD_EN; + CEMAC_WRITE(GEM_DMA_CFG, dma); + } + if (ifp->if_capenable & + (IFCAP_CSUM_IPv4_Rx | + IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_UDPv4_Rx | + IFCAP_CSUM_TCPv6_Rx | IFCAP_CSUM_UDPv6_Rx)) { + cfg = CEMAC_READ(ETH_CFG); + cfg |= GEM_CFG_RX_CHKSUM_OFFLD_EN; + CEMAC_WRITE(ETH_CFG, cfg); + } + } + // enable interrupts CEMAC_WRITE(ETH_IDR, -1); CEMAC_WRITE(ETH_IER, ETH_ISR_RCOM | ETH_ISR_TBRE | ETH_ISR_TIDLE