Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 26 Nov 2008 06:36:53 +0000 (UTC)
From:      Pyun YongHyeon <yongari@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r185329 - head/sys/dev/fxp
Message-ID:  <200811260636.mAQ6ardc046758@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: yongari
Date: Wed Nov 26 06:36:53 2008
New Revision: 185329
URL: http://svn.freebsd.org/changeset/base/185329

Log:
  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:
  head/sys/dev/fxp/if_fxp.c
  head/sys/dev/fxp/if_fxpvar.h

Modified: head/sys/dev/fxp/if_fxp.c
==============================================================================
--- head/sys/dev/fxp/if_fxp.c	Wed Nov 26 05:51:49 2008	(r185328)
+++ head/sys/dev/fxp/if_fxp.c	Wed Nov 26 06:36:53 2008	(r185329)
@@ -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: head/sys/dev/fxp/if_fxpvar.h
==============================================================================
--- head/sys/dev/fxp/if_fxpvar.h	Wed Nov 26 05:51:49 2008	(r185328)
+++ head/sys/dev/fxp/if_fxpvar.h	Wed Nov 26 06:36:53 2008	(r185329)
@@ -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?200811260636.mAQ6ardc046758>