svn commit: r225707 - head/sys/dev/xen/netfront

Justin T. Gibbs gibbs at FreeBSD.org
Wed Sep 21 00:08:25 UTC 2011


Author: gibbs
Date: Wed Sep 21 00:08:25 2011
New Revision: 225707
URL: http://svn.freebsd.org/changeset/base/225707

Log:
  Correct suspend/resume support in the Netfront driver.
  
  Sponsored by: BQ Internet
  
  sys/dev/xen/netfront/netfront.c:
  	o Implement netfront_suspend(), a specialized suspend
  	  handler for the netfront driver.  This routine simply
  	  disables the carrier so the driver is idle during
  	  system suspend processing.
  	o Fix a leak when re-initializing LRO during a link reset.
  	o In netif_release_tx_bufs(), when cleaning up the grant
  	  references for our TX ring, use gnttab_end_foreign_access_ref
  	  instead of attempting to grant the page again.
  	o In netif_release_tx_bufs(), we do not track mbufs associated
  	  with mbuf chains, but instead just free each mbuf directly.
  	  Use m_free(), not m_freem(), to avoid double frees of mbufs.
  	o Refactor some code to enhance clarity.
  
  Approved by:	re
  MFC after:	1 week

Modified:
  head/sys/dev/xen/netfront/netfront.c

Modified: head/sys/dev/xen/netfront/netfront.c
==============================================================================
--- head/sys/dev/xen/netfront/netfront.c	Wed Sep 21 00:06:02 2011	(r225706)
+++ head/sys/dev/xen/netfront/netfront.c	Wed Sep 21 00:08:25 2011	(r225707)
@@ -159,6 +159,7 @@ static int  xn_ioctl(struct ifnet *, u_l
 static void xn_ifinit_locked(struct netfront_info *);
 static void xn_ifinit(void *);
 static void xn_stop(struct netfront_info *);
+static int xn_configure_lro(struct netfront_info *np);
 #ifdef notyet
 static void xn_watchdog(struct ifnet *);
 #endif
@@ -174,7 +175,7 @@ static int talk_to_backend(device_t dev,
 static int create_netdev(device_t dev);
 static void netif_disconnect_backend(struct netfront_info *info);
 static int setup_device(device_t dev, struct netfront_info *info);
-static void end_access(int ref, void *page);
+static void free_ring(int *ref, void *ring_ptr_ref);
 
 static int  xn_ifmedia_upd(struct ifnet *ifp);
 static void xn_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr);
@@ -463,6 +464,18 @@ netfront_attach(device_t dev)
 	return 0;
 }
 
+static int
+netfront_suspend(device_t dev)
+{
+	struct netfront_info *info = device_get_softc(dev);
+
+	XN_RX_LOCK(info);
+	XN_TX_LOCK(info);
+	netfront_carrier_off(info);
+	XN_TX_UNLOCK(info);
+	XN_RX_UNLOCK(info);
+	return (0);
+}
 
 /**
  * We are reconnecting to the backend, due to a suspend/resume, or a backend
@@ -749,10 +762,7 @@ netif_release_tx_bufs(struct netfront_in
 		 */
 		if (((uintptr_t)m) <= NET_TX_RING_SIZE)
 			continue;
-		gnttab_grant_foreign_access_ref(np->grant_tx_ref[i],
-		    xenbus_get_otherend_id(np->xbdev),
-		    virt_to_mfn(mtod(m, vm_offset_t)),
-		    GNTMAP_readonly);
+		gnttab_end_foreign_access_ref(np->grant_tx_ref[i]);
 		gnttab_release_grant_reference(&np->gref_tx_head,
 		    np->grant_tx_ref[i]);
 		np->grant_tx_ref[i] = GRANT_REF_INVALID;
@@ -761,7 +771,7 @@ netif_release_tx_bufs(struct netfront_in
 		if (np->xn_cdata.xn_tx_chain_cnt < 0) {
 			panic("netif_release_tx_bufs: tx_chain_cnt must be >= 0");
 		}
-		m_freem(m);
+		m_free(m);
 	}
 }
 
@@ -1914,6 +1924,7 @@ network_connect(struct netfront_info *np
 	netif_release_tx_bufs(np);
 
 	/* Step 2: Rebuild the RX buffer freelist and the RX ring itself. */
+	xn_configure_lro(np);
 	for (requeue_idx = 0, i = 0; i < NET_RX_RING_SIZE; i++) {
 		struct mbuf *m;
 		u_long pfn;
@@ -1978,6 +1989,30 @@ show_device(struct netfront_info *sc)
 #endif
 }
 
+static int
+xn_configure_lro(struct netfront_info *np)
+{
+	int err;
+
+	err = 0;
+#if __FreeBSD_version >= 700000
+	if ((np->xn_ifp->if_capabilities & IFCAP_LRO) != 0)
+		tcp_lro_free(&np->xn_lro);
+	np->xn_ifp->if_capabilities &= ~IFCAP_LRO;
+	if (xn_enable_lro) {
+		err = tcp_lro_init(&np->xn_lro);
+		if (err) {
+			device_printf(np->xbdev, "LRO initialization failed\n");
+		} else {
+			np->xn_lro.ifp = np->xn_ifp;
+			np->xn_ifp->if_capabilities |= IFCAP_LRO;
+		}
+	}
+    	np->xn_ifp->if_capenable = np->xn_ifp->if_capabilities;
+#endif
+	return (err);
+}
+
 /** Create a network device.
  * @param handle device handle
  */
@@ -2057,17 +2092,9 @@ create_netdev(device_t dev)
     	ifp->if_capabilities = IFCAP_HWCSUM;
 #if __FreeBSD_version >= 700000
 	ifp->if_capabilities |= IFCAP_TSO4;
-	if (xn_enable_lro) {
-		int err = tcp_lro_init(&np->xn_lro);
-		if (err) {
-			device_printf(dev, "LRO initialization failed\n");
-			goto exit;
-		}
-		np->xn_lro.ifp = ifp;
-		ifp->if_capabilities |= IFCAP_LRO;
-	}
 #endif
     	ifp->if_capenable = ifp->if_capabilities;
+	xn_configure_lro(np);
 	
     	ether_ifattach(ifp, np->mac);
     	callout_init(&np->xn_stat_ch, CALLOUT_MPSAFE);
@@ -2133,12 +2160,8 @@ netif_disconnect_backend(struct netfront
 	XN_TX_UNLOCK(info);
 	XN_RX_UNLOCK(info);
 
-	end_access(info->tx_ring_ref, info->tx.sring);
-	end_access(info->rx_ring_ref, info->rx.sring);
-	info->tx_ring_ref = GRANT_REF_INVALID;
-	info->rx_ring_ref = GRANT_REF_INVALID;
-	info->tx.sring = NULL;
-	info->rx.sring = NULL;
+	free_ring(&info->tx_ring_ref, &info->tx.sring);
+	free_ring(&info->rx_ring_ref, &info->rx.sring);
 
 	if (info->irq)
 		unbind_from_irqhandler(info->irq);
@@ -2146,12 +2169,17 @@ netif_disconnect_backend(struct netfront
 	info->irq = 0;
 }
 
-
 static void
-end_access(int ref, void *page)
+free_ring(int *ref, void *ring_ptr_ref)
 {
-	if (ref != GRANT_REF_INVALID)
-		gnttab_end_foreign_access(ref, page);
+	void **ring_ptr_ptr = ring_ptr_ref;
+
+	if (*ref != GRANT_REF_INVALID) {
+		/* This API frees the associated storage. */
+		gnttab_end_foreign_access(*ref, *ring_ptr_ptr);
+		*ref = GRANT_REF_INVALID;
+	}
+	*ring_ptr_ptr = NULL;
 }
 
 static int
@@ -2174,7 +2202,7 @@ static device_method_t netfront_methods[
 	DEVMETHOD(device_attach,        netfront_attach), 
 	DEVMETHOD(device_detach,        netfront_detach), 
 	DEVMETHOD(device_shutdown,      bus_generic_shutdown), 
-	DEVMETHOD(device_suspend,       bus_generic_suspend), 
+	DEVMETHOD(device_suspend,       netfront_suspend), 
 	DEVMETHOD(device_resume,        netfront_resume), 
  
 	/* Xenbus interface */


More information about the svn-src-all mailing list