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 */
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "[email protected]"

Reply via email to