Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 18 Feb 2009 18:27:48 +0000 (UTC)
From:      Doug Rabson <dfr@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-user@freebsd.org
Subject:   svn commit: r188754 - user/dfr/xenhvm/7/sys/dev/xen/netfront
Message-ID:  <200902181827.n1IIRmJA071293@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: dfr
Date: Wed Feb 18 18:27:48 2009
New Revision: 188754
URL: http://svn.freebsd.org/changeset/base/188754

Log:
  Eliminate the data copy on transmit and start getting ready to support TSO.

Modified:
  user/dfr/xenhvm/7/sys/dev/xen/netfront/netfront.c

Modified: user/dfr/xenhvm/7/sys/dev/xen/netfront/netfront.c
==============================================================================
--- user/dfr/xenhvm/7/sys/dev/xen/netfront/netfront.c	Wed Feb 18 18:25:16 2009	(r188753)
+++ user/dfr/xenhvm/7/sys/dev/xen/netfront/netfront.c	Wed Feb 18 18:27:48 2009	(r188754)
@@ -95,6 +95,7 @@ static const int MODPARM_rx_copy = 1;
 static const int MODPARM_rx_flip = 0;
 #endif
 
+#define MAX_SKB_FRAGS	(65536/PAGE_SIZE + 2)
 #define RX_COPY_THRESHOLD 256
 
 #define net_ratelimit() 0
@@ -339,28 +340,6 @@ xennet_get_rx_ref(struct netfront_info *
 #define DPRINTK(fmt, args...)
 #endif
 
-static __inline struct mbuf* 
-makembuf (struct mbuf *buf)
-{
-	struct mbuf *m = NULL;
-	
-        MGETHDR (m, M_DONTWAIT, MT_DATA);
-	
-        if (! m)
-		return 0;
-		
-	M_MOVE_PKTHDR(m, buf);
-
-	m_cljget(m, M_DONTWAIT, MJUMPAGESIZE);
-        m->m_pkthdr.len = buf->m_pkthdr.len;
-        m->m_len = buf->m_len;
-	m_copydata(buf, 0, buf->m_pkthdr.len, mtod(m,caddr_t) );
-
-	m->m_ext.ext_args = (caddr_t *)(uintptr_t)(vtophys(mtod(m,caddr_t)) >> PAGE_SHIFT);
-
-       	return m;
-}
-
 /**
  * Read the 'mac' node at the given device's node in the store, and parse that
  * as colon-separated octets, placing result the given mac array.  mac must be
@@ -500,7 +479,7 @@ talk_to_backend(device_t dev, struct net
 		message = "writing feature-sg";
 		goto abort_transaction;
 	}
-#ifdef HAVE_TSO
+#if __FreeBSD_version >= 700000
 	err = xenbus_printf(xbt, node, "feature-gso-tcpv4", "%d", 1);
 	if (err) {
 		message = "writing feature-gso-tcpv4";
@@ -1007,7 +986,12 @@ xn_txeof(struct netfront_info *np)
 			id = RING_GET_RESPONSE(&np->tx, i)->id;
 			m = np->xn_cdata.xn_tx_chain[id]; 
 			
-			ifp->if_opackets++;
+			/*
+			 * Increment packet count if this is the last
+			 * mbuf of the chain.
+			 */
+			if (!m->m_next)
+				ifp->if_opackets++;
 			KASSERT(m != NULL, ("mbuf not found in xn_tx_chain"));
 			M_ASSERTVALID(m);
 			if (unlikely(gnttab_query_foreign_access(
@@ -1025,7 +1009,7 @@ xn_txeof(struct netfront_info *np)
 			
 			np->xn_cdata.xn_tx_chain[id] = NULL;
 			add_id_to_freelist(np->xn_cdata.xn_tx_chain, id);
-			m_freem(m);
+			m_free(m);
 		}
 		np->tx.rsp_cons = prod;
 		
@@ -1320,13 +1304,14 @@ xn_start_locked(struct ifnet *ifp) 
 {
 	int otherend_id;
 	unsigned short id;
-	struct mbuf *m_head, *new_m;
+	struct mbuf *m_head, *m;
 	struct netfront_info *sc;
 	netif_tx_request_t *tx;
+	netif_extra_info_t *extra;
 	RING_IDX i;
 	grant_ref_t ref;
 	u_long mfn, tx_bytes;
-	int notify;
+	int notify, nfrags;
 
 	sc = ifp->if_softc;
 	otherend_id = xenbus_get_otherend_id(sc->xbdev);
@@ -1346,36 +1331,95 @@ xn_start_locked(struct ifnet *ifp) 
 			break;
 		}
 		
-		id = get_id_from_freelist(sc->xn_cdata.xn_tx_chain);
+
+		/*
+		 * Defragment the mbuf if necessary.
+		 */
+		for (m = m_head, nfrags = 0; m; m = m->m_next)
+			nfrags++;
+		if (nfrags > MAX_SKB_FRAGS) {
+			m = m_defrag(m_head, M_DONTWAIT);
+			if (!m) {
+				m_freem(m_head);
+				break;
+			}
+			m_head = m;
+		}
 
 		/*
 		 * Start packing the mbufs in this chain into
 		 * the fragment pointers. Stop when we run out
 		 * of fragments or hit the end of the mbuf chain.
 		 */
-		new_m = makembuf(m_head);
-		tx = RING_GET_REQUEST(&sc->tx, i);
-		tx->id = id;
-		ref = gnttab_claim_grant_reference(&sc->gref_tx_head);
-		KASSERT((short)ref >= 0, ("Negative ref"));
-		mfn = virt_to_mfn(mtod(new_m, vm_offset_t));
-		gnttab_grant_foreign_access_ref(ref, otherend_id,
-		    mfn, GNTMAP_readonly);
-		tx->gref = sc->grant_tx_ref[id] = ref;
-		tx->size = new_m->m_pkthdr.len;
-		if (new_m->m_pkthdr.csum_flags & CSUM_DELAY_DATA)
-			tx->flags = NETTXF_csum_blank | NETTXF_data_validated;
-		else
+		m = m_head;
+		extra = NULL;
+		for (m = m_head; m; m = m->m_next) {
+			tx = RING_GET_REQUEST(&sc->tx, i);
+			id = get_id_from_freelist(sc->xn_cdata.xn_tx_chain);
+			sc->xn_cdata.xn_tx_chain[id] = m;
+			tx->id = id;
+			ref = gnttab_claim_grant_reference(&sc->gref_tx_head);
+			KASSERT((short)ref >= 0, ("Negative ref"));
+			mfn = virt_to_mfn(mtod(m, vm_offset_t));
+			gnttab_grant_foreign_access_ref(ref, otherend_id,
+			    mfn, GNTMAP_readonly);
+			tx->gref = sc->grant_tx_ref[id] = ref;
+			tx->offset = mtod(m, vm_offset_t) & (PAGE_SIZE - 1);
 			tx->flags = 0;
-		new_m->m_next = NULL;
-		new_m->m_nextpkt = NULL;
+			if (m == m_head) {
+				/*
+				 * The first fragment has the entire packet
+				 * size, subsequent fragments have just the
+				 * fragment size. The backend works out the
+				 * true size of the first fragment by
+				 * subtracting the sizes of the other
+				 * fragments.
+				 */
+				tx->size = m->m_pkthdr.len;
 
-		m_freem(m_head);
+				/*
+				 * The first fragment contains the
+				 * checksum flags and is optionally
+				 * followed by extra data for TSO etc.
+				 */
+				if (m->m_pkthdr.csum_flags
+				    & CSUM_DELAY_DATA) {
+					tx->flags |= (NETTXF_csum_blank
+					    | NETTXF_data_validated);
+				}
+#if __FreeBSD_version >= 700000
+				if (m->m_pkthdr.csum_flags & CSUM_TSO) {
+					struct netif_extra_info *gso =
+						(struct netif_extra_info *)
+						RING_GET_REQUEST(&sc->tx, ++i);
+
+					if (extra)
+						extra->flags |= XEN_NETIF_EXTRA_FLAG_MORE;
+					else
+						tx->flags |= NETTXF_extra_info;
+
+					gso->u.gso.size = m->m_pkthdr.len;
+					gso->u.gso.type = XEN_NETIF_GSO_TYPE_TCPV4;
+					gso->u.gso.pad = 0;
+					gso->u.gso.features = 0;
+
+					gso->type = XEN_NETIF_EXTRA_TYPE_GSO;
+					gso->flags = 0;
+					extra = gso;
+				}
+#endif
+			} else {
+				tx->size = m->m_len;
+			}
+			if (m->m_next) {
+				tx->flags |= NETTXF_more_data;
+				i++;
+			}
+		}
 
-		sc->xn_cdata.xn_tx_chain[id] = new_m;
-		BPF_MTAP(ifp, new_m);
+		BPF_MTAP(ifp, m_head);
 
-		sc->stats.tx_bytes += new_m->m_pkthdr.len;
+		sc->stats.tx_bytes += m_head->m_pkthdr.len;
 		sc->stats.tx_packets++;
 	}
 
@@ -1518,11 +1562,14 @@ xn_ioctl(struct ifnet *ifp, u_long cmd, 
 	case SIOCSIFCAP:
 		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
 		if (mask & IFCAP_HWCSUM) {
-			if (IFCAP_HWCSUM & ifp->if_capenable)
-				ifp->if_capenable &= ~IFCAP_HWCSUM;
-			else
-				ifp->if_capenable |= IFCAP_HWCSUM;
+			ifp->if_capenable ^= IFCAP_HWCSUM;
 		}
+#if __FreeBSD_version >= 700000
+		if (mask & IFCAP_TSO4) {
+			ifp->if_capenable ^= IFCAP_TSO4;
+			/* XXX inform backend? */
+		}
+#endif
 		error = 0;
 		break;
 	case SIOCADDMULTI:
@@ -1733,6 +1780,9 @@ create_netdev(device_t dev)
 	
     	ifp->if_hwassist = XN_CSUM_FEATURES;
     	ifp->if_capabilities = IFCAP_HWCSUM;
+#if __FreeBSD_version >= 700000
+	//ifp->if_capabilities |= IFCAP_TSO4;
+#endif
     	ifp->if_capenable = ifp->if_capabilities;
 	
     	ether_ifattach(ifp, np->mac);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200902181827.n1IIRmJA071293>