Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 9 Feb 2009 03:46:15 +0000 (UTC)
From:      Pyun YongHyeon <yongari@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-7@freebsd.org
Subject:   svn commit: r188373 - in stable/7/sys: . contrib/pf dev/ath/ath_hal dev/cxgb dev/fxp
Message-ID:  <200902090346.n193kFN1044227@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: yongari
Date: Mon Feb  9 03:46:15 2009
New Revision: 188373
URL: http://svn.freebsd.org/changeset/base/188373

Log:
  MFC r185329:
    Implement Rx checksum offload for 82559 or later controllers.
    82559 or later controllers added simple checksum calculation logic
    in RU. For backward compatibility the computed checksum is appended
    at the end of the data posted to Rx buffer. This type of simple
    checksum calculation support had been used on several vendors such
    as Sun HME/GEM, SysKonnect GENESIS and Marvell Yukon controllers.
    Because this type of checksum offload support requires parsing of
    received frame and pseudo checksum calculation with software
    routine it still consumes more CPU cycles than that of full-fledged
    checksum offload controller. But it's still better than software
    checksum calculation.

Modified:
  stable/7/sys/   (props changed)
  stable/7/sys/contrib/pf/   (props changed)
  stable/7/sys/dev/ath/ath_hal/   (props changed)
  stable/7/sys/dev/cxgb/   (props changed)
  stable/7/sys/dev/fxp/if_fxp.c
  stable/7/sys/dev/fxp/if_fxpvar.h

Modified: stable/7/sys/dev/fxp/if_fxp.c
==============================================================================
--- stable/7/sys/dev/fxp/if_fxp.c	Mon Feb  9 03:43:46 2009	(r188372)
+++ stable/7/sys/dev/fxp/if_fxp.c	Mon Feb  9 03:46:15 2009	(r188373)
@@ -59,15 +59,15 @@ __FBSDID("$FreeBSD$");
 #include <net/if_types.h>
 #include <net/if_vlan_var.h>
 
-#include <machine/bus.h>
-#include <machine/resource.h>
-
-#ifdef FXP_IP_CSUM_WAR
 #include <netinet/in.h>
 #include <netinet/in_systm.h>
 #include <netinet/ip.h>
+#include <netinet/tcp.h>
+#include <netinet/udp.h>
+
+#include <machine/bus.h>
 #include <machine/in_cksum.h>
-#endif
+#include <machine/resource.h>
 
 #include <dev/pci/pcivar.h>
 #include <dev/pci/pcireg.h>		/* for PCIM_CMD_xxx */
@@ -213,6 +213,8 @@ static int		fxp_suspend(device_t dev);
 static int		fxp_resume(device_t dev);
 
 static void		fxp_intr(void *xsc);
+static void		fxp_rxcsum(struct fxp_softc *sc, struct ifnet *ifp,
+			    struct mbuf *m, uint16_t status, int pos);
 static void		fxp_intr_body(struct fxp_softc *sc, struct ifnet *ifp,
 			    uint8_t statack, int count);
 static void 		fxp_init(void *xsc);
@@ -591,6 +593,9 @@ fxp_attach(device_t dev)
 		sc->flags |= FXP_FLAG_SAVE_BAD;
 	}
 
+	/* For 82559 or later chips, Rx checksum offload is supported. */
+	if (sc->revision >= FXP_REV_82559_A0)
+		sc->flags |= FXP_FLAG_82559_RXCSUM;
 	/*
 	 * Enable use of extended RFDs and TCBs for 82550
 	 * and later chips. Note: we need extended TXCB support
@@ -603,6 +608,8 @@ fxp_attach(device_t dev)
 		sc->rfa_size = sizeof (struct fxp_rfa);
 		sc->tx_cmd = FXP_CB_COMMAND_IPCBXMIT;
 		sc->flags |= FXP_FLAG_EXT_RFA;
+		/* Use extended RFA instead of 82559 checksum mode. */
+		sc->flags &= ~FXP_FLAG_82559_RXCSUM;
 	} else {
 		sc->rfa_size = sizeof (struct fxp_rfa) - FXP_RFAX_LEN;
 		sc->tx_cmd = FXP_CB_COMMAND_XMIT;
@@ -780,6 +787,11 @@ fxp_attach(device_t dev)
 		ifp->if_capenable |= IFCAP_HWCSUM;
 	}
 
+	if (sc->flags & FXP_FLAG_82559_RXCSUM) {
+		ifp->if_capabilities |= IFCAP_RXCSUM;
+		ifp->if_capenable |= IFCAP_RXCSUM;
+	}
+
 #ifdef DEVICE_POLLING
 	/* Inform the world we support polling. */
 	ifp->if_capabilities |= IFCAP_POLLING;
@@ -1558,6 +1570,84 @@ fxp_txeof(struct fxp_softc *sc)
 }
 
 static void
+fxp_rxcsum(struct fxp_softc *sc, struct ifnet *ifp, struct mbuf *m,
+    uint16_t status, int pos)
+{
+	struct ether_header *eh;
+	struct ip *ip;
+	struct udphdr *uh;
+	int32_t hlen, len, pktlen, temp32;
+	uint16_t csum, *opts;
+
+	if ((sc->flags & FXP_FLAG_82559_RXCSUM) == 0) {
+		if ((status & FXP_RFA_STATUS_PARSE) != 0) {
+			if (status & FXP_RFDX_CS_IP_CSUM_BIT_VALID)
+				m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED;
+			if (status & FXP_RFDX_CS_IP_CSUM_VALID)
+				m->m_pkthdr.csum_flags |= CSUM_IP_VALID;
+			if ((status & FXP_RFDX_CS_TCPUDP_CSUM_BIT_VALID) &&
+			    (status & FXP_RFDX_CS_TCPUDP_CSUM_VALID)) {
+				m->m_pkthdr.csum_flags |= CSUM_DATA_VALID |
+				    CSUM_PSEUDO_HDR;
+				m->m_pkthdr.csum_data = 0xffff;
+			}
+		}
+		return;
+	}
+
+	pktlen = m->m_pkthdr.len;
+	if (pktlen < sizeof(struct ether_header) + sizeof(struct ip))
+		return;
+	eh = mtod(m, struct ether_header *);
+	if (eh->ether_type != htons(ETHERTYPE_IP))
+		return;
+	ip = (struct ip *)(eh + 1);
+	if (ip->ip_v != IPVERSION)
+		return;
+
+	hlen = ip->ip_hl << 2;
+	pktlen -= sizeof(struct ether_header);
+	if (hlen < sizeof(struct ip))
+		return;
+	if (ntohs(ip->ip_len) < hlen)
+		return;
+	if (ntohs(ip->ip_len) != pktlen)
+		return;
+	if (ip->ip_off & htons(IP_MF | IP_OFFMASK))
+		return;	/* can't handle fragmented packet */
+
+	switch (ip->ip_p) {
+	case IPPROTO_TCP:
+		if (pktlen < (hlen + sizeof(struct tcphdr)))
+			return;
+		break;
+	case IPPROTO_UDP:
+		if (pktlen < (hlen + sizeof(struct udphdr)))
+			return;
+		uh = (struct udphdr *)((caddr_t)ip + hlen);
+		if (uh->uh_sum == 0)
+			return; /* no checksum */
+		break;
+	default:
+		return;
+	}
+	/* Extract computed checksum. */
+	csum = be16dec(mtod(m, char *) + pos);
+	/* checksum fixup for IP options */
+	len = hlen - sizeof(struct ip);
+	if (len > 0) {
+		opts = (uint16_t *)(ip + 1);
+		for (; len > 0; len -= sizeof(uint16_t), opts++) {
+			temp32 = csum - *opts;
+			temp32 = (temp32 >> 16) + (temp32 & 65535);
+			csum = temp32 & 65535;
+		}
+	}
+	m->m_pkthdr.csum_flags |= CSUM_DATA_VALID;
+	m->m_pkthdr.csum_data = csum;
+}
+
+static void
 fxp_intr_body(struct fxp_softc *sc, struct ifnet *ifp, uint8_t statack,
     int count)
 {
@@ -1661,6 +1751,11 @@ fxp_intr_body(struct fxp_softc *sc, stru
 			 * of bogus length or CRC errors.
 			 */
 			total_len = le16toh(rfa->actual_size) & 0x3fff;
+			if ((sc->flags & FXP_FLAG_82559_RXCSUM) != 0 &&
+			    (ifp->if_capenable & IFCAP_RXCSUM) != 0) {
+				/* Adjust for appended checksum bytes. */
+				total_len -= 2;
+			}
 			if (total_len < sizeof(struct ether_header) ||
 			    total_len > MCLBYTES - RFA_ALIGNMENT_FUDGE -
 				sc->rfa_size || status & FXP_RFA_STATUS_CRC) {
@@ -1668,30 +1763,12 @@ fxp_intr_body(struct fxp_softc *sc, stru
 				continue;
 			}
 
-                        /* Do IP checksum checking. */
-			if ((ifp->if_capenable & IFCAP_RXCSUM) != 0 &&
-			    (status & FXP_RFA_STATUS_PARSE)) {
-				if (rfa->rfax_csum_sts &
-				    FXP_RFDX_CS_IP_CSUM_BIT_VALID)
-					m->m_pkthdr.csum_flags |=
-					    CSUM_IP_CHECKED;
-				if (rfa->rfax_csum_sts &
-				    FXP_RFDX_CS_IP_CSUM_VALID)
-					m->m_pkthdr.csum_flags |=
-					    CSUM_IP_VALID;
-				if ((rfa->rfax_csum_sts &
-				    FXP_RFDX_CS_TCPUDP_CSUM_BIT_VALID) &&
-				    (rfa->rfax_csum_sts &
-				    FXP_RFDX_CS_TCPUDP_CSUM_VALID)) {
-					m->m_pkthdr.csum_flags |=
-					    CSUM_DATA_VALID|CSUM_PSEUDO_HDR;
-					m->m_pkthdr.csum_data = 0xffff;
-				}
-			}
-
 			m->m_pkthdr.len = m->m_len = total_len;
 			m->m_pkthdr.rcvif = ifp;
 
+                        /* Do IP checksum checking. */
+			if ((ifp->if_capenable & IFCAP_RXCSUM) != 0)
+				fxp_rxcsum(sc, ifp, m, status, total_len);
 			/*
 			 * Drop locks before calling if_input() since it
 			 * may re-enter fxp_start() in the netisr case.
@@ -2024,7 +2101,8 @@ fxp_init_body(struct fxp_softc *sc)
 	cbp->ext_rfa =		sc->flags & FXP_FLAG_EXT_RFA ? 1 : 0;
 	cbp->mediatype =	sc->flags & FXP_FLAG_SERIAL_MEDIA ? 0 : 1;
 	cbp->csma_dis =		0;	/* (don't) disable link */
-	cbp->tcp_udp_cksum =	0;	/* (don't) enable checksum */
+	cbp->tcp_udp_cksum =	((sc->flags & FXP_FLAG_82559_RXCSUM) != 0 &&
+	    (ifp->if_capenable & IFCAP_RXCSUM) != 0) ? 1 : 0;
 	cbp->vlan_tco =		0;	/* (don't) enable vlan wakeup */
 	cbp->link_wake_en =	0;	/* (don't) assert PME# on link change */
 	cbp->arp_wake_en =	0;	/* (don't) assert PME# on arp */
@@ -2506,8 +2584,11 @@ fxp_ioctl(struct ifnet *ifp, u_long comm
 				ifp->if_hwassist &= ~FXP_CSUM_FEATURES;
 		}
 		if ((mask & IFCAP_RXCSUM) != 0 &&
-		    (ifp->if_capabilities & IFCAP_RXCSUM) != 0)
+		    (ifp->if_capabilities & IFCAP_RXCSUM) != 0) {
 			ifp->if_capenable ^= IFCAP_RXCSUM;
+			if ((sc->flags & FXP_FLAG_82559_RXCSUM) != 0)
+				reinit++;
+		}
 		if ((mask & IFCAP_VLAN_MTU) != 0 &&
 		    (ifp->if_capabilities & IFCAP_VLAN_MTU) != 0) {
 			ifp->if_capenable ^= IFCAP_VLAN_MTU;

Modified: stable/7/sys/dev/fxp/if_fxpvar.h
==============================================================================
--- stable/7/sys/dev/fxp/if_fxpvar.h	Mon Feb  9 03:43:46 2009	(r188372)
+++ stable/7/sys/dev/fxp/if_fxpvar.h	Mon Feb  9 03:46:15 2009	(r188373)
@@ -194,6 +194,7 @@ struct fxp_softc {
 #define FXP_FLAG_DEFERRED_RNR	0x0200	/* DEVICE_POLLING deferred RNR */
 #define FXP_FLAG_EXT_RFA	0x0400	/* extended RFDs for csum offload */
 #define FXP_FLAG_SAVE_BAD	0x0800	/* save bad pkts: bad size, CRC, etc */
+#define FXP_FLAG_82559_RXCSUM	0x1000	/* 82559 compatible RX checksum */
 
 /* Macros to ease CSR access. */
 #define	CSR_READ_1(sc, reg)		bus_read_1(sc->fxp_res[0], reg)



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200902090346.n193kFN1044227>