Module Name:    src
Committed By:   mlelstv
Date:           Mon Jun  9 14:18:28 UTC 2014

Modified Files:
        src/sys/dev/usb: if_smsc.c if_smscreg.h if_smscvar.h

Log Message:
Fix receive loop, enable turbo mode, checksum offloading still needs
correct handling of pseudo headers.

The Raspberry PI now copies at 2MByte/s with scp and 4MByte/s with NFS.

Based on work from nick@.


To generate a diff of this commit:
cvs rdiff -u -r1.12 -r1.13 src/sys/dev/usb/if_smsc.c
cvs rdiff -u -r1.3 -r1.4 src/sys/dev/usb/if_smscreg.h
cvs rdiff -u -r1.2 -r1.3 src/sys/dev/usb/if_smscvar.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/usb/if_smsc.c
diff -u src/sys/dev/usb/if_smsc.c:1.12 src/sys/dev/usb/if_smsc.c:1.13
--- src/sys/dev/usb/if_smsc.c:1.12	Fri Nov  1 14:24:03 2013
+++ src/sys/dev/usb/if_smsc.c	Mon Jun  9 14:18:28 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_smsc.c,v 1.12 2013/11/01 14:24:03 skrll Exp $	*/
+/*	$NetBSD: if_smsc.c,v 1.13 2014/06/09 14:18:28 mlelstv Exp $	*/
 
 /*	$OpenBSD: if_smsc.c,v 1.4 2012/09/27 12:38:11 jsg Exp $	*/
 /* $FreeBSD: src/sys/dev/usb/net/if_smsc.c,v 1.1 2012/08/15 04:03:55 gonzo Exp $ */
@@ -108,6 +108,7 @@
 int smsc_debug = 0;
 #endif
 
+#define ETHER_ALIGN 2
 /*
  * Various supported device vendors/products.
  */
@@ -481,17 +482,19 @@ smsc_sethwcsum(struct smsc_softc *sc)
 	}
 
 	/* Enable/disable the Rx checksum */
-	if (ifp->if_capabilities & IFCAP_CSUM_IPv4_Rx)
-		val |= SMSC_COE_CTRL_RX_EN;
+	if (ifp->if_capenable & (IFCAP_CSUM_TCPv4_Rx|IFCAP_CSUM_UDPv4_Rx))
+		val |= (SMSC_COE_CTRL_RX_EN | SMSC_COE_CTRL_RX_MODE);
 	else
-		val &= ~SMSC_COE_CTRL_RX_EN;
+		val &= ~(SMSC_COE_CTRL_RX_EN | SMSC_COE_CTRL_RX_MODE);
 
 	/* Enable/disable the Tx checksum (currently not supported) */
-	if (ifp->if_capabilities & IFCAP_CSUM_IPv4_Tx)
+	if (ifp->if_capenable & (IFCAP_CSUM_TCPv4_Tx|IFCAP_CSUM_UDPv4_Tx))
 		val |= SMSC_COE_CTRL_TX_EN;
 	else
 		val &= ~SMSC_COE_CTRL_TX_EN;
 
+	sc->sc_coe_ctrl = val;
+
 	err = smsc_write_reg(sc, SMSC_COE_CTRL, val);
 	if (err != 0) {
 		smsc_warn_printf(sc, "failed to write SMSC_COE_CTRL (err=%d)\n",
@@ -573,6 +576,9 @@ smsc_init(struct ifnet *ifp)
 	/* Load the multicast filter. */
 	smsc_setmulti(sc);
 
+	/* TCP/UDP checksum offload engines. */
+	smsc_sethwcsum(sc);
+
 	/* Open RX and TX pipes. */
 	err = usbd_open_pipe(sc->sc_iface, sc->sc_ed[SMSC_ENDPT_RX],
 	    USBD_EXCLUSIVE_USE, &sc->sc_ep[SMSC_ENDPT_RX]);
@@ -602,9 +608,6 @@ smsc_init(struct ifnet *ifp)
 		usbd_transfer(c->sc_xfer);
 	}
 
-	/* TCP/UDP checksum offload engines. */
-	smsc_sethwcsum(sc);
-
 	/* Indicate we are up and running. */
 	ifp->if_flags |= IFF_RUNNING;
 	ifp->if_flags &= ~IFF_OACTIVE;
@@ -808,14 +811,11 @@ smsc_chip_init(struct smsc_softc *sc)
 	 * Burst capability is the number of URBs that can be in a burst of
 	 * data/ethernet frames.
 	 */
-#ifdef SMSC_TURBO
+
 	if (sc->sc_udev->speed == USB_SPEED_HIGH)
 		burst_cap = 37;
 	else
 		burst_cap = 128;
-#else
-	burst_cap = 0;
-#endif
 
 	smsc_write_reg(sc, SMSC_BURST_CAP, burst_cap);
 
@@ -835,9 +835,14 @@ smsc_chip_init(struct smsc_softc *sc)
 	 * The following settings are used for 'turbo mode', a.k.a multiple
 	 * frames per Rx transaction (again info taken form Linux driver).
 	 */
-#ifdef SMSC_TURBO
-	reg_val |= (SMSC_HW_CFG_MEF | SMSC_HW_CFG_BCE);
-#endif
+	if (burst_cap)
+		reg_val |= (SMSC_HW_CFG_MEF | SMSC_HW_CFG_BCE);
+
+	/*               
+	 * set Rx data offset to ETHER_ALIGN which will make the IP header
+	 * align on a word boundary.
+	*/              
+	reg_val |= ETHER_ALIGN << SMSC_HW_CFG_RXDOFF_SHIFT;
 
 	smsc_write_reg(sc, SMSC_HW_CFG, reg_val);
 
@@ -868,6 +873,9 @@ smsc_chip_init(struct smsc_softc *sc)
 		goto init_failed;
 	}
 
+	/* disable pad stripping, collides with checksum offload */
+	sc->sc_mac_csr &= ~SMSC_MAC_CSR_PADSTR;
+
 	/* Vlan */
 	smsc_write_reg(sc, SMSC_VLAN1, (uint32_t)ETHERTYPE_VLAN);
 
@@ -1043,6 +1051,15 @@ smsc_attach(device_t parent, device_t se
 	ifp->if_start = smsc_start;
 	ifp->if_stop = smsc_stop;
 
+#ifdef notyet
+	/*
+	 * We can do TCPv4, and UDPv4 checksums in hardware.
+	 */
+	ifp->if_capabilities |=
+	    /*IFCAP_CSUM_TCPv4_Tx |*/ IFCAP_CSUM_TCPv4_Rx |
+	    /*IFCAP_CSUM_UDPv4_Tx |*/ IFCAP_CSUM_UDPv4_Rx;
+#endif
+
         sc->sc_ec.ec_capabilities = ETHERCAP_VLAN_MTU;
 
 	/* Setup some of the basics */
@@ -1238,10 +1255,10 @@ smsc_rxeof(usbd_xfer_handle xfer, usbd_p
 	struct ifnet		*ifp = &sc->sc_ec.ec_if;
 	u_char			*buf = c->sc_buf;
 	uint32_t		total_len;
-	uint16_t		pktlen = 0;
+	uint32_t		rxhdr;
+	uint16_t		pktlen;
 	struct mbuf		*m;
 	int			s;
-	uint32_t		rxhdr;
 
 	if (sc->sc_dying)
 		return;
@@ -1264,7 +1281,7 @@ smsc_rxeof(usbd_xfer_handle xfer, usbd_p
 	usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
 	smsc_dbg_printf(sc, "xfer status total_len %d\n", total_len);
 
-	do {
+	while (total_len != 0) {
 		if (total_len < sizeof(rxhdr)) {
 			smsc_dbg_printf(sc, "total_len %d < sizeof(rxhdr) %zu\n",
 			    total_len, sizeof(rxhdr));
@@ -1272,10 +1289,9 @@ smsc_rxeof(usbd_xfer_handle xfer, usbd_p
 			goto done;
 		}
 
-		buf += pktlen;
-
 		memcpy(&rxhdr, buf, sizeof(rxhdr));
 		rxhdr = le32toh(rxhdr);
+		buf += sizeof(rxhdr);
 		total_len -= sizeof(rxhdr);
 
 		if (rxhdr & SMSC_RX_STAT_ERROR) {
@@ -1287,6 +1303,9 @@ smsc_rxeof(usbd_xfer_handle xfer, usbd_p
 		pktlen = (uint16_t)SMSC_RX_STAT_FRM_LENGTH(rxhdr);
 		smsc_dbg_printf(sc, "rxeof total_len %d pktlen %d rxhdr "
 		    "0x%08x\n", total_len, pktlen, rxhdr);
+
+		pktlen += ETHER_ALIGN;
+
 		if (pktlen > total_len) {
 			smsc_dbg_printf(sc, "pktlen %d > total_len %d\n",
 			    pktlen, total_len);
@@ -1294,9 +1313,6 @@ smsc_rxeof(usbd_xfer_handle xfer, usbd_p
 			goto done;
 		}
 
-		buf += sizeof(rxhdr);
-		total_len -= pktlen;
-
 		m = smsc_newbuf();
 		if (m == NULL) {
 			smsc_dbg_printf(sc, "smc_newbuf returned NULL\n");
@@ -1306,25 +1322,71 @@ smsc_rxeof(usbd_xfer_handle xfer, usbd_p
 
 		ifp->if_ipackets++;
 		m->m_pkthdr.rcvif = ifp;
-
-		pktlen -= 2;	// JDM
-
 		m->m_pkthdr.len = m->m_len = pktlen;
-#define ETHER_ALIGN 2
+		m->m_flags |= M_HASFCS;
 		m_adj(m, ETHER_ALIGN);
+		memcpy(mtod(m, char *), buf + ETHER_ALIGN, m->m_len);
 
-		memcpy(mtod(m, char *), buf, pktlen);
+		/* Check if RX TCP/UDP checksumming is being offloaded */
+		if (sc->sc_coe_ctrl & SMSC_COE_CTRL_RX_EN) {
+			smsc_dbg_printf(sc,"RX checksum offload checking\n");
+			struct ether_header *eh;
+
+			eh = mtod(m, struct ether_header *);
+
+			/* Remove the extra 2 bytes of the csum */
+			m_adj(m, -2);
+
+			/*
+			 * The checksum appears to be simplistically calculated
+			 * over the udp/tcp header and data up to the end of the
+			 * eth frame.  Which means if the eth frame is padded
+			 * the csum calculation is incorrectly performed over
+			 * the padding bytes as well. Therefore to be safe we
+			 * ignore the H/W csum on frames less than or equal to
+			 * 64 bytes.
+			 *
+			 * Ignore H/W csum for non-IPv4 packets.
+			 */
+			smsc_dbg_printf(sc,"Ethertype %02x pktlen %02x\n",
+			   be16toh(eh->ether_type), pktlen);
+			if (be16toh(eh->ether_type) == ETHERTYPE_IP &&
+			   pktlen > ETHER_MIN_LEN) {
+
+				m->m_pkthdr.csum_flags |=
+				   (M_CSUM_TCPv4 | M_CSUM_UDPv4 | M_CSUM_DATA);
+
+				/*
+				 * Copy the TCP/UDP checksum from the last 2
+				 * bytes of the transfer and put in the
+				 * csum_data field.
+				 */
+				memcpy(&m->m_pkthdr.csum_data,
+				   buf + pktlen - 2, 2);
+				/*
+				 * The data is copied in network order, but the
+				 * csum algorithm in the kernel expects it to be
+				 * in host network order.
+				 */
+				m->m_pkthdr.csum_data =
+				   ntohs(m->m_pkthdr.csum_data);
+				smsc_dbg_printf(sc,
+				   "RX checksum offloaded (0x%04x)\n",
+				   m->m_pkthdr.csum_data);
+			}
+		}
+
+		buf += pktlen;
+		total_len -= pktlen;
 
 		/* push the packet up */
 		s = splnet();
 		bpf_mtap(ifp, m);
 		ifp->if_input(ifp, m);
 		splx(s);
-	} while (total_len > 0);
+	}
 
 done:
-	memset(c->sc_buf, 0, sc->sc_bufsz);
-
 	/* Setup new transfer. */
 	usbd_setup_xfer(xfer, sc->sc_ep[SMSC_ENDPT_RX],
 	    c, c->sc_buf, sc->sc_bufsz,

Index: src/sys/dev/usb/if_smscreg.h
diff -u src/sys/dev/usb/if_smscreg.h:1.3 src/sys/dev/usb/if_smscreg.h:1.4
--- src/sys/dev/usb/if_smscreg.h:1.3	Wed Apr  3 15:57:44 2013
+++ src/sys/dev/usb/if_smscreg.h	Mon Jun  9 14:18:28 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_smscreg.h,v 1.3 2013/04/03 15:57:44 skrll Exp $	*/
+/*	$NetBSD: if_smscreg.h,v 1.4 2014/06/09 14:18:28 mlelstv Exp $	*/
 
 /*	$OpenBSD: if_smscreg.h,v 1.2 2012/09/27 12:38:11 jsg Exp $	*/
 /*-
@@ -161,6 +161,7 @@
 
 #define SMSC_HW_CFG_BIR			(0x1UL << 12)
 #define SMSC_HW_CFG_LEDB		(0x1UL << 11)
+#define SMSC_HW_CFG_RXDOFF_SHIFT	(9)
 #define SMSC_HW_CFG_RXDOFF		(0x3UL << 9)    /* RX pkt alignment */
 #define SMSC_HW_CFG_DRP			(0x1UL << 6)
 #define SMSC_HW_CFG_MEF			(0x1UL << 5)
@@ -200,6 +201,8 @@
 #define SMSC_MAC_CSR_PASSBAD		(0x1UL << 16)  /* Pass on bad frames */
 #define SMSC_MAC_CSR_HPFILT		(0x1UL << 13)  /* Hash filtering */
 #define SMSC_MAC_CSR_BCAST		(0x1UL << 11)  /* Broadcast */
+#define SMSC_MAC_CSR_DISRTY		(0x1UL << 10)  /* Disable Retry */
+#define SMSC_MAC_CSR_PADSTR		(0x1UL << 8)   /* PAD stripping */
 #define SMSC_MAC_CSR_TXEN		(0x1UL << 3)   /* TX enable */
 #define SMSC_MAC_CSR_RXEN		(0x1UL << 2)   /* RX enable */
 

Index: src/sys/dev/usb/if_smscvar.h
diff -u src/sys/dev/usb/if_smscvar.h:1.2 src/sys/dev/usb/if_smscvar.h:1.3
--- src/sys/dev/usb/if_smscvar.h:1.2	Sat Feb  9 16:42:45 2013
+++ src/sys/dev/usb/if_smscvar.h	Mon Jun  9 14:18:28 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_smscvar.h,v 1.2 2013/02/09 16:42:45 skrll Exp $	*/
+/*	$NetBSD: if_smscvar.h,v 1.3 2014/06/09 14:18:28 mlelstv Exp $	*/
 
 /*	$OpenBSD: if_smscreg.h,v 1.2 2012/09/27 12:38:11 jsg Exp $	*/
 /*-
@@ -69,6 +69,8 @@ struct smsc_softc {
 	uint32_t		sc_mac_csr;
 	uint32_t		sc_rev_id;
 
+	uint32_t		sc_coe_ctrl;
+
 	int			sc_if_flags;
 	int			sc_refcnt;
 

Reply via email to