Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/dev/usb Fix receive loop, enable turbo mode, checksum of...
details: https://anonhg.NetBSD.org/src/rev/535534659f24
branches: trunk
changeset: 329789:535534659f24
user: mlelstv <mlelstv%NetBSD.org@localhost>
date: Mon Jun 09 14:18:28 2014 +0000
description:
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@.
diffstat:
sys/dev/usb/if_smsc.c | 124 +++++++++++++++++++++++++++++++++++-----------
sys/dev/usb/if_smscreg.h | 5 +-
sys/dev/usb/if_smscvar.h | 4 +-
3 files changed, 100 insertions(+), 33 deletions(-)
diffs (299 lines):
diff -r e48b57041c76 -r 535534659f24 sys/dev/usb/if_smsc.c
--- a/sys/dev/usb/if_smsc.c Mon Jun 09 13:03:16 2014 +0000
+++ b/sys/dev/usb/if_smsc.c Mon Jun 09 14:18:28 2014 +0000
@@ -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 @@
}
/* 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 @@
/* 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 @@
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 @@
* 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 @@
* 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
ifp->if_ipackets++;
m->m_pkthdr.rcvif = ifp;
+ m->m_pkthdr.len = m->m_len = pktlen;
+ m->m_flags |= M_HASFCS;
+ m_adj(m, ETHER_ALIGN);
+ memcpy(mtod(m, char *), buf + ETHER_ALIGN, m->m_len);
- pktlen -= 2; // JDM
+ /* 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);
- m->m_pkthdr.len = m->m_len = pktlen;
-#define ETHER_ALIGN 2
- m_adj(m, ETHER_ALIGN);
+ /*
+ * 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);
- memcpy(mtod(m, char *), buf, pktlen);
+ /*
+ * 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,
diff -r e48b57041c76 -r 535534659f24 sys/dev/usb/if_smscreg.h
--- a/sys/dev/usb/if_smscreg.h Mon Jun 09 13:03:16 2014 +0000
+++ b/sys/dev/usb/if_smscreg.h Mon Jun 09 14:18:28 2014 +0000
@@ -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 */
diff -r e48b57041c76 -r 535534659f24 sys/dev/usb/if_smscvar.h
--- a/sys/dev/usb/if_smscvar.h Mon Jun 09 13:03:16 2014 +0000
+++ b/sys/dev/usb/if_smscvar.h Mon Jun 09 14:18:28 2014 +0000
@@ -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 @@
uint32_t sc_mac_csr;
uint32_t sc_rev_id;
+ uint32_t sc_coe_ctrl;
+
int sc_if_flags;
int sc_refcnt;
Home |
Main Index |
Thread Index |
Old Index