svn commit: r296039 - head/sys/dev/vnic

Zbigniew Bodek zbb at FreeBSD.org
Thu Feb 25 14:29:58 UTC 2016


Author: zbb
Date: Thu Feb 25 14:29:57 2016
New Revision: 296039
URL: https://svnweb.freebsd.org/changeset/base/296039

Log:
  Introduce HW TSO support for VNIC
  
  This feature was added in Pass2.0.
  Significantly improves VNIC's TCP performance on Tx.
  
  Reviewed by:   wma
  Obtained from: Semihalf
  Sponsored by:  Cavium
  Differential Revision: https://reviews.freebsd.org/D5424

Modified:
  head/sys/dev/vnic/nic.h
  head/sys/dev/vnic/nicvf_main.c
  head/sys/dev/vnic/nicvf_queues.c
  head/sys/dev/vnic/nicvf_queues.h
  head/sys/dev/vnic/q_struct.h

Modified: head/sys/dev/vnic/nic.h
==============================================================================
--- head/sys/dev/vnic/nic.h	Thu Feb 25 14:28:10 2016	(r296038)
+++ head/sys/dev/vnic/nic.h	Thu Feb 25 14:29:57 2016	(r296039)
@@ -292,6 +292,7 @@ struct nicvf {
 	uint8_t			max_queues;
 	struct resource		*reg_base;
 	boolean_t		link_up;
+	boolean_t		hw_tso;
 	uint8_t			duplex;
 	uint32_t		speed;
 	uint8_t			cpi_alg;

Modified: head/sys/dev/vnic/nicvf_main.c
==============================================================================
--- head/sys/dev/vnic/nicvf_main.c	Thu Feb 25 14:28:10 2016	(r296038)
+++ head/sys/dev/vnic/nicvf_main.c	Thu Feb 25 14:29:57 2016	(r296039)
@@ -66,6 +66,7 @@ __FBSDID("$FreeBSD$");
 #include <net/if_vlan_var.h>
 
 #include <netinet/in.h>
+#include <netinet/ip.h>
 #include <netinet/if_ether.h>
 #include <netinet/tcp_lro.h>
 
@@ -194,6 +195,9 @@ nicvf_attach(device_t dev)
 	nic->pnicvf = nic;
 
 	NICVF_CORE_LOCK_INIT(nic);
+	/* Enable HW TSO on Pass2 */
+	if (!pass1_silicon(dev))
+		nic->hw_tso = TRUE;
 
 	rid = VNIC_VF_REG_RID;
 	nic->reg_base = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
@@ -356,6 +360,14 @@ nicvf_setup_ifnet(struct nicvf *nic)
 	/* Set the default values */
 	if_setcapabilitiesbit(ifp, IFCAP_VLAN_MTU, 0);
 	if_setcapabilitiesbit(ifp, IFCAP_LRO, 0);
+	if (nic->hw_tso) {
+		/* TSO */
+		if_setcapabilitiesbit(ifp, IFCAP_TSO4, 0);
+		/* TSO parameters */
+		ifp->if_hw_tsomax = NICVF_TSO_MAXSIZE;
+		ifp->if_hw_tsomaxsegcount = NICVF_TSO_NSEGS;
+		ifp->if_hw_tsomaxsegsize = MCLBYTES;
+	}
 	/* IP/TCP/UDP HW checksums */
 	if_setcapabilitiesbit(ifp, IFCAP_HWCSUM, 0);
 	if_setcapabilitiesbit(ifp, IFCAP_HWSTATS, 0);
@@ -364,7 +376,8 @@ nicvf_setup_ifnet(struct nicvf *nic)
 	 */
 	if_clearhwassist(ifp);
 	if_sethwassistbits(ifp, (CSUM_IP | CSUM_TCP | CSUM_UDP | CSUM_SCTP), 0);
-
+	if (nic->hw_tso)
+		if_sethwassistbits(ifp, (CSUM_TSO), 0);
 	if_setcapenable(ifp, if_getcapabilities(ifp));
 
 	return (0);
@@ -513,6 +526,8 @@ nicvf_if_ioctl(struct ifnet *ifp, u_long
 			ifp->if_capenable ^= IFCAP_TXCSUM;
 		if (mask & IFCAP_RXCSUM)
 			ifp->if_capenable ^= IFCAP_RXCSUM;
+		if ((mask & IFCAP_TSO4) && nic->hw_tso)
+			ifp->if_capenable ^= IFCAP_TSO4;
 		if (mask & IFCAP_LRO) {
 			/*
 			 * Lock the driver for a moment to avoid

Modified: head/sys/dev/vnic/nicvf_queues.c
==============================================================================
--- head/sys/dev/vnic/nicvf_queues.c	Thu Feb 25 14:28:10 2016	(r296038)
+++ head/sys/dev/vnic/nicvf_queues.c	Thu Feb 25 14:29:57 2016	(r296039)
@@ -1070,8 +1070,8 @@ nicvf_init_snd_queue(struct nicvf *nic, 
 	    BUS_SPACE_MAXADDR,			/* lowaddr */
 	    BUS_SPACE_MAXADDR,			/* highaddr */
 	    NULL, NULL,				/* filtfunc, filtfuncarg */
-	    NICVF_TXBUF_MAXSIZE,		/* maxsize */
-	    NICVF_TXBUF_NSEGS,			/* nsegments */
+	    NICVF_TSO_MAXSIZE,			/* maxsize */
+	    NICVF_TSO_NSEGS,			/* nsegments */
 	    MCLBYTES,				/* maxsegsize */
 	    0,					/* flags */
 	    NULL, NULL,				/* lockfunc, lockfuncarg */
@@ -1727,14 +1727,18 @@ static __inline int
 nicvf_sq_add_hdr_subdesc(struct snd_queue *sq, int qentry,
 			 int subdesc_cnt, struct mbuf *mbuf, int len)
 {
+	struct nicvf *nic;
 	struct sq_hdr_subdesc *hdr;
 	struct ether_vlan_header *eh;
 #ifdef INET
 	struct ip *ip;
+	struct tcphdr *th;
 #endif
 	uint16_t etype;
 	int ehdrlen, iphlen, poff;
 
+	nic = sq->nic;
+
 	hdr = (struct sq_hdr_subdesc *)GET_SQ_DESC(sq, qentry);
 	sq->snd_buff[qentry].mbuf = mbuf;
 
@@ -1746,18 +1750,25 @@ nicvf_sq_add_hdr_subdesc(struct snd_queu
 	hdr->subdesc_cnt = subdesc_cnt;
 	hdr->tot_len = len;
 
-	if (mbuf->m_pkthdr.csum_flags != 0) {
-		hdr->csum_l3 = 1; /* Enable IP csum calculation */
-
-		eh = mtod(mbuf, struct ether_vlan_header *);
-		if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
-			ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
-			etype = ntohs(eh->evl_proto);
-		} else {
-			ehdrlen = ETHER_HDR_LEN;
-			etype = ntohs(eh->evl_encap_proto);
-		}
+	eh = mtod(mbuf, struct ether_vlan_header *);
+	if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
+		ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
+		etype = ntohs(eh->evl_proto);
+	} else {
+		ehdrlen = ETHER_HDR_LEN;
+		etype = ntohs(eh->evl_encap_proto);
+	}
 
+	switch (etype) {
+#ifdef INET6
+	case ETHERTYPE_IPV6:
+		/* ARM64TODO: Add support for IPv6 */
+		hdr->csum_l3 = 0;
+		sq->snd_buff[qentry].mbuf = NULL;
+		return (ENXIO);
+#endif
+#ifdef INET
+	case ETHERTYPE_IP:
 		if (mbuf->m_len < ehdrlen + sizeof(struct ip)) {
 			mbuf = m_pullup(mbuf, ehdrlen + sizeof(struct ip));
 			sq->snd_buff[qentry].mbuf = mbuf;
@@ -1765,21 +1776,13 @@ nicvf_sq_add_hdr_subdesc(struct snd_queu
 				return (ENOBUFS);
 		}
 
-		switch (etype) {
-#ifdef INET6
-		case ETHERTYPE_IPV6:
-			/* ARM64TODO: Add support for IPv6 */
-			hdr->csum_l3 = 0;
-			sq->snd_buff[qentry].mbuf = NULL;
-			return (ENXIO);
-#endif
-#ifdef INET
-		case ETHERTYPE_IP:
-			ip = (struct ip *)(mbuf->m_data + ehdrlen);
-			ip->ip_sum = 0;
-			iphlen = ip->ip_hl << 2;
-			poff = ehdrlen + iphlen;
+		ip = (struct ip *)(mbuf->m_data + ehdrlen);
+		ip->ip_sum = 0;
+		iphlen = ip->ip_hl << 2;
+		poff = ehdrlen + iphlen;
 
+		if (mbuf->m_pkthdr.csum_flags != 0) {
+			hdr->csum_l3 = 1; /* Enable IP csum calculation */
 			switch (ip->ip_p) {
 			case IPPROTO_TCP:
 				if ((mbuf->m_pkthdr.csum_flags & CSUM_TCP) == 0)
@@ -1820,17 +1823,28 @@ nicvf_sq_add_hdr_subdesc(struct snd_queu
 			default:
 				break;
 			}
-			break;
-#endif
-		default:
-			hdr->csum_l3 = 0;
-			return (0);
+			hdr->l3_offset = ehdrlen;
+			hdr->l4_offset = ehdrlen + iphlen;
 		}
 
-		hdr->l3_offset = ehdrlen;
-		hdr->l4_offset = ehdrlen + iphlen;
-	} else
+		if ((mbuf->m_pkthdr.tso_segsz != 0) && nic->hw_tso) {
+			/*
+			 * Extract ip again as m_data could have been modified.
+			 */
+			ip = (struct ip *)(mbuf->m_data + ehdrlen);
+			th = (struct tcphdr *)((caddr_t)ip + iphlen);
+
+			hdr->tso = 1;
+			hdr->tso_start = ehdrlen + iphlen + (th->th_off * 4);
+			hdr->tso_max_paysize = mbuf->m_pkthdr.tso_segsz;
+			hdr->inner_l3_offset = ehdrlen - 2;
+			nic->drv_stats.tx_tso++;
+		}
+		break;
+#endif
+	default:
 		hdr->csum_l3 = 0;
+	}
 
 	return (0);
 }
@@ -1859,10 +1873,11 @@ int
 nicvf_tx_mbuf_locked(struct snd_queue *sq, struct mbuf *mbuf)
 {
 	bus_dma_segment_t segs[256];
+	struct nicvf *nic;
 	struct snd_buff *snd_buff;
 	size_t seg;
 	int nsegs, qentry;
-	int subdesc_cnt = MIN_SQ_DESC_PER_PKT_XMIT - 1;
+	int subdesc_cnt;
 	int err;
 
 	NICVF_TX_LOCK_ASSERT(sq);
@@ -1880,7 +1895,11 @@ nicvf_tx_mbuf_locked(struct snd_queue *s
 	}
 
 	/* Set how many subdescriptors is required */
-	subdesc_cnt += nsegs;
+	nic = sq->nic;
+	if (mbuf->m_pkthdr.tso_segsz != 0 && nic->hw_tso)
+		subdesc_cnt = MIN_SQ_DESC_PER_PKT_XMIT;
+	else
+		subdesc_cnt = MIN_SQ_DESC_PER_PKT_XMIT + nsegs - 1;
 
 	if (subdesc_cnt > sq->free_cnt) {
 		/* ARM64TODO: Add mbuf defragmentation if we lack descriptors */

Modified: head/sys/dev/vnic/nicvf_queues.h
==============================================================================
--- head/sys/dev/vnic/nicvf_queues.h	Thu Feb 25 14:28:10 2016	(r296038)
+++ head/sys/dev/vnic/nicvf_queues.h	Thu Feb 25 14:29:57 2016	(r296039)
@@ -131,10 +131,13 @@
 #define	NICVF_RCV_BUF_ALIGN_LEN(addr)		\
     (NICVF_ALIGNED_ADDR((addr), NICVF_RCV_BUF_ALIGN_BYTES) - (addr))
 
-#define	NICVF_TXBUF_MAXSIZE	9212	/* Total max payload without TSO */
+#define	NICVF_TXBUF_MAXSIZE	NIC_HW_MAX_FRS	/* Total max payload without TSO */
 #define	NICVF_TXBUF_NSEGS	256	/* Single command is at most 256 buffers
 					   (hdr + 255 subcmds) */
-
+/* TSO-related definitions */
+#define	NICVF_TSO_MAXSIZE	IP_MAXPACKET
+#define	NICVF_TSO_NSEGS		NICVF_TXBUF_NSEGS
+#define	NICVF_TSO_HEADER_SIZE	128
 
 /* Queue enable/disable */
 #define	NICVF_SQ_EN		(1UL << 19)

Modified: head/sys/dev/vnic/q_struct.h
==============================================================================
--- head/sys/dev/vnic/q_struct.h	Thu Feb 25 14:28:10 2016	(r296038)
+++ head/sys/dev/vnic/q_struct.h	Thu Feb 25 14:29:57 2016	(r296039)
@@ -565,25 +565,28 @@ struct sq_hdr_subdesc {
 	uint64_t    subdesc_cnt:8;
 	uint64_t    csum_l4:2;
 	uint64_t    csum_l3:1;
-	uint64_t    rsvd0:5;
+	uint64_t    csum_inner_l4:2;
+	uint64_t    csum_inner_l3:1;
+	uint64_t    rsvd0:2;
 	uint64_t    l4_offset:8;
 	uint64_t    l3_offset:8;
 	uint64_t    rsvd1:4;
 	uint64_t    tot_len:20; /* W0 */
 
-	uint64_t    tso_sdc_cont:8;
-	uint64_t    tso_sdc_first:8;
-	uint64_t    tso_l4_offset:8;
-	uint64_t    tso_flags_last:12;
-	uint64_t    tso_flags_first:12;
-	uint64_t    rsvd2:2;
+	uint64_t    rsvd2:24;
+	uint64_t    inner_l4_offset:8;
+	uint64_t    inner_l3_offset:8;
+	uint64_t    tso_start:8;
+	uint64_t    rsvd3:2;
 	uint64_t    tso_max_paysize:14; /* W1 */
 #elif defined(__LITTLE_ENDIAN_BITFIELD)
 	uint64_t    tot_len:20;
 	uint64_t    rsvd1:4;
 	uint64_t    l3_offset:8;
 	uint64_t    l4_offset:8;
-	uint64_t    rsvd0:5;
+	uint64_t    rsvd0:2;
+	uint64_t    csum_inner_l3:1;
+	uint64_t    csum_inner_l4:2;
 	uint64_t    csum_l3:1;
 	uint64_t    csum_l4:2;
 	uint64_t    subdesc_cnt:8;
@@ -594,12 +597,11 @@ struct sq_hdr_subdesc {
 	uint64_t    subdesc_type:4; /* W0 */
 
 	uint64_t    tso_max_paysize:14;
-	uint64_t    rsvd2:2;
-	uint64_t    tso_flags_first:12;
-	uint64_t    tso_flags_last:12;
-	uint64_t    tso_l4_offset:8;
-	uint64_t    tso_sdc_first:8;
-	uint64_t    tso_sdc_cont:8; /* W1 */
+	uint64_t    rsvd3:2;
+	uint64_t    tso_start:8;
+	uint64_t    inner_l3_offset:8;
+	uint64_t    inner_l4_offset:8;
+	uint64_t    rsvd2:24;
 #endif
 };
 


More information about the svn-src-head mailing list