Index | Thread | Search

From:
Moritz Buhl <mbuhl@openbsd.org>
Subject:
igc(4) tso
To:
tech@openbsd.org
Date:
Tue, 9 Jan 2024 23:22:37 +0100

Download raw body.

Thread
  • Moritz Buhl:

    igc(4) tso

Here is a diff that implements tso for igc(4).
It looks very similar to the other intel cards but it was missing
VLAN_HWTAGGING.

I am not too happy how olinfo_status is initialized now so I am
open to suggestions.

I tested the diff on I225-V and I225-LM in various configurations.
More testing welcome.

mbuhl

Index: dev/pci//if_igc.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_igc.c,v
diff -u -p -r1.14 if_igc.c
--- dev/pci//if_igc.c	10 Nov 2023 15:51:20 -0000	1.14
+++ dev/pci//if_igc.c	9 Jan 2024 18:46:50 -0000
@@ -44,12 +44,16 @@
 
 #include <net/if.h>
 #include <net/if_media.h>
+#include <net/route.h>
 #include <net/toeplitz.h>
 
 #include <netinet/in.h>
 #include <netinet/if_ether.h>
 #include <netinet/ip.h>
 #include <netinet/ip6.h>
+#include <netinet/tcp.h>
+#include <netinet/tcp_timer.h>
+#include <netinet/tcp_var.h>
 
 #if NBPFILTER > 0
 #include <net/bpf.h>
@@ -117,7 +121,8 @@ int	igc_media_change(struct ifnet *);
 void	igc_iff(struct igc_softc *);
 void	igc_update_link_status(struct igc_softc *);
 int	igc_get_buf(struct rx_ring *, int);
-int	igc_tx_ctx_setup(struct tx_ring *, struct mbuf *, int, uint32_t *);
+int	igc_tx_ctx_setup(struct tx_ring *, struct mbuf *, int, uint32_t *,
+    uint32_t *);
 
 void	igc_configure_queues(struct igc_softc *);
 void	igc_set_queues(struct igc_softc *, uint32_t, uint32_t, int);
@@ -790,15 +795,14 @@ igc_setup_interface(struct igc_softc *sc
 
 	ifp->if_capabilities = IFCAP_VLAN_MTU;
 
-#ifdef notyet
 #if NVLAN > 0
 	ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING;
 #endif
-#endif
 
 	ifp->if_capabilities |= IFCAP_CSUM_IPv4;
 	ifp->if_capabilities |= IFCAP_CSUM_TCPv4 | IFCAP_CSUM_UDPv4;
 	ifp->if_capabilities |= IFCAP_CSUM_TCPv6 | IFCAP_CSUM_UDPv6;
+	ifp->if_capabilities |= IFCAP_TSOv4 | IFCAP_TSOv6;
 
 	/* Initialize ifmedia structures. */
 	ifmedia_init(&sc->media, IFM_IMASK, igc_media_change, igc_media_status);
@@ -954,7 +958,8 @@ igc_start(struct ifqueue *ifq)
 	struct mbuf *m;
 	unsigned int prod, free, last, i;
 	unsigned int mask;
-	uint32_t cmd_type_len;
+	uint32_t cmd_type_len = IGC_ADVTXD_DCMD_IFCS | IGC_ADVTXD_DTYP_DATA |
+	    IGC_ADVTXD_DCMD_DEXT;
 	uint32_t olinfo_status;
 	int post = 0;
 #if NBPFILTER > 0
@@ -996,29 +1001,31 @@ igc_start(struct ifqueue *ifq)
 			continue;
 		}
 
-		olinfo_status = m->m_pkthdr.len << IGC_ADVTXD_PAYLEN_SHIFT;
-
 		bus_dmamap_sync(txr->txdma.dma_tag, map, 0,
 		    map->dm_mapsize, BUS_DMASYNC_PREWRITE);
 
-		if (igc_tx_ctx_setup(txr, m, prod, &olinfo_status)) {
+		if (ISSET(m->m_flags, M_VLANTAG))
+			cmd_type_len |= IGC_ADVTXD_DCMD_VLE;
+
+		if (igc_tx_ctx_setup(txr, m, prod, &cmd_type_len,
+		    &olinfo_status)) {
 			/* Consume the first descriptor */
 			prod++;
 			prod &= mask;
 			free--;
+		} else {
+			olinfo_status =
+			    m->m_pkthdr.len << IGC_ADVTXD_PAYLEN_SHIFT;
 		}
 
 		for (i = 0; i < map->dm_nsegs; i++) {
 			txdesc = &txr->tx_base[prod];
 
-			cmd_type_len = IGC_ADVTXD_DCMD_IFCS | IGC_ADVTXD_DTYP_DATA |
-			    IGC_ADVTXD_DCMD_DEXT | map->dm_segs[i].ds_len;
-			if (i == map->dm_nsegs - 1)
-				cmd_type_len |= IGC_ADVTXD_DCMD_EOP |
-				    IGC_ADVTXD_DCMD_RS;
-
-			htolem64(&txdesc->read.buffer_addr, map->dm_segs[i].ds_addr);
-			htolem32(&txdesc->read.cmd_type_len, cmd_type_len);
+			htolem64(&txdesc->read.buffer_addr,
+			    map->dm_segs[i].ds_addr);
+			htolem32(&txdesc->read.cmd_type_len, cmd_type_len |
+			    map->dm_segs[i].ds_len | ((i == map->dm_nsegs - 1)?
+				IGC_ADVTXD_DCMD_EOP | IGC_ADVTXD_DCMD_RS : 0));
 			htolem32(&txdesc->read.olinfo_status, olinfo_status);
 
 			last = prod;
@@ -1999,23 +2006,26 @@ igc_free_transmit_buffers(struct tx_ring
 
 int
 igc_tx_ctx_setup(struct tx_ring *txr, struct mbuf *mp, int prod,
-    uint32_t *olinfo_status)
+    uint32_t *cmd_type_len, uint32_t *olinfo_status)
 {
 	struct ether_extracted ext;
 	struct igc_adv_tx_context_desc *txdesc;
+	uint32_t mss_l4len_idx = 0;
 	uint32_t type_tucmd_mlhl = 0;
 	uint32_t vlan_macip_lens = 0;
-	uint32_t iphlen;
+	uint32_t ethlen, iphlen;
 	int off = 0;
 
-	vlan_macip_lens |= (sizeof(*ext.eh) << IGC_ADVTXD_MACLEN_SHIFT);
+	if (mp->m_pkthdr.csum_flags & M_TCP_TSO)
+		*olinfo_status = 0;
+	else 
+		*olinfo_status = mp->m_pkthdr.len << IGC_ADVTXD_PAYLEN_SHIFT;
 
 	/*
 	 * In advanced descriptors the vlan tag must
 	 * be placed into the context descriptor. Hence
 	 * we need to make one even if not doing offloads.
 	 */
-#ifdef notyet
 #if NVLAN > 0
 	if (ISSET(mp->m_flags, M_VLANTAG)) {
 		uint32_t vtag = mp->m_pkthdr.ether_vtag;
@@ -2023,8 +2033,9 @@ igc_tx_ctx_setup(struct tx_ring *txr, st
 		off = 1;
 	}
 #endif
-#endif
 
+	ethlen = sizeof(*ext.eh);
+	vlan_macip_lens |= (ethlen << IGC_ADVTXD_MACLEN_SHIFT);
 	ether_extract_headers(mp, &ext);
 
 	if (ext.ip4) {
@@ -2042,6 +2053,8 @@ igc_tx_ctx_setup(struct tx_ring *txr, st
 		type_tucmd_mlhl |= IGC_ADVTXD_TUCMD_IPV6;
 #endif
 	} else {
+		if (mp->m_pkthdr.csum_flags & M_TCP_TSO)
+			tcpstat_inc(tcps_outbadtso);
 		return 0;
 	}
 
@@ -2065,6 +2078,29 @@ igc_tx_ctx_setup(struct tx_ring *txr, st
 	if (off == 0)
 		return 0;
 
+	if (mp->m_pkthdr.csum_flags & M_TCP_TSO) {
+		if (ext.tcp) {
+			uint32_t hdrlen, thlen, paylen, outlen;
+
+			thlen = ext.tcp->th_off << 2;
+
+			outlen = mp->m_pkthdr.ph_mss;
+			mss_l4len_idx |= outlen << IGC_ADVTXD_MSS_SHIFT;
+			mss_l4len_idx |= thlen << IGC_ADVTXD_L4LEN_SHIFT;
+
+			hdrlen = ethlen + iphlen + thlen;
+			paylen = mp->m_pkthdr.len - hdrlen;
+			*olinfo_status |= paylen << IGC_ADVTXD_PAYLEN_SHIFT;
+
+			*cmd_type_len |= IGC_ADVTXD_DCMD_TSE;
+			off = 1;
+
+			tcpstat_add(tcps_outpkttso,
+			    (paylen + outlen - 1) / outlen);
+		} else
+			tcpstat_inc(tcps_outbadtso);
+	}
+
 	/* Now ready a context descriptor */
 	txdesc = (struct igc_adv_tx_context_desc *)&txr->tx_base[prod];
 
@@ -2072,7 +2108,7 @@ igc_tx_ctx_setup(struct tx_ring *txr, st
 	htolem32(&txdesc->vlan_macip_lens, vlan_macip_lens);
 	htolem32(&txdesc->type_tucmd_mlhl, type_tucmd_mlhl);
 	htolem32(&txdesc->seqnum_seed, 0);
-	htolem32(&txdesc->mss_l4len_idx, 0);
+	htolem32(&txdesc->mss_l4len_idx, mss_l4len_idx);
 
 	return 1;
 }