Module Name:    src
Committed By:   jdolecek
Date:           Thu May 14 09:47:25 UTC 2020

Modified Files:
        src/sys/arch/xen/xen: if_xennet_xenbus.c

Log Message:
rearrange so that suspend & resume doesn't cause panics, and interface
is more likely to work - particularly, don't try to xengnt_revoke_access()
after resume, move xen_intr_disestablish() call to resume, also
unmask the event channel on resume

XXX right now xennet device detaches immediately after resume, which is not
desirable and needs to be fixed

part of PR port-xen/55207


To generate a diff of this commit:
cvs rdiff -u -r1.124 -r1.125 src/sys/arch/xen/xen/if_xennet_xenbus.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/xen/xen/if_xennet_xenbus.c
diff -u src/sys/arch/xen/xen/if_xennet_xenbus.c:1.124 src/sys/arch/xen/xen/if_xennet_xenbus.c:1.125
--- src/sys/arch/xen/xen/if_xennet_xenbus.c:1.124	Tue May  5 09:52:13 2020
+++ src/sys/arch/xen/xen/if_xennet_xenbus.c	Thu May 14 09:47:25 2020
@@ -1,4 +1,4 @@
-/*      $NetBSD: if_xennet_xenbus.c,v 1.124 2020/05/05 09:52:13 jdolecek Exp $      */
+/*      $NetBSD: if_xennet_xenbus.c,v 1.125 2020/05/14 09:47:25 jdolecek Exp $      */
 
 /*
  * Copyright (c) 2006 Manuel Bouyer.
@@ -81,7 +81,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_xennet_xenbus.c,v 1.124 2020/05/05 09:52:13 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_xennet_xenbus.c,v 1.125 2020/05/14 09:47:25 jdolecek Exp $");
 
 #include "opt_xen.h"
 #include "opt_nfs_boot.h"
@@ -218,7 +218,7 @@ static int  xennet_xenbus_detach(device_
 static void xennet_backend_changed(void *, XenbusState);
 
 static void xennet_alloc_rx_buffer(struct xennet_xenbus_softc *);
-static void xennet_free_rx_buffer(struct xennet_xenbus_softc *);
+static void xennet_free_rx_buffer(struct xennet_xenbus_softc *, bool);
 static void xennet_tx_complete(struct xennet_xenbus_softc *);
 static void xennet_rx_mbuf_free(struct mbuf *, void *, size_t, void *);
 static int  xennet_handler(void *);
@@ -233,7 +233,7 @@ static void xennet_start(struct ifnet *)
 static int  xennet_ioctl(struct ifnet *, u_long, void *);
 
 static bool xennet_xenbus_suspend(device_t dev, const pmf_qual_t *);
-static bool xennet_xenbus_resume (device_t dev, const pmf_qual_t *);
+static bool xennet_xenbus_resume(device_t dev, const pmf_qual_t *);
 
 CFATTACH_DECL3_NEW(xennet, sizeof(struct xennet_xenbus_softc),
    xennet_xenbus_match, xennet_xenbus_attach, xennet_xenbus_detach, NULL,
@@ -412,15 +412,6 @@ xennet_xenbus_attach(device_t parent, de
 	sc->sc_tx_ring.sring = tx_ring;
 	sc->sc_rx_ring.sring = rx_ring;
 
-	/* resume shared structures and tell backend that we are ready */
-	if (xennet_xenbus_resume(self, PMF_Q_NONE) == false) {
-		uvm_km_free(kernel_map, (vaddr_t)tx_ring, PAGE_SIZE,
-		    UVM_KMF_WIRED);
-		uvm_km_free(kernel_map, (vaddr_t)rx_ring, PAGE_SIZE,
-		    UVM_KMF_WIRED);
-		return;
-	}
-
 	rnd_attach_source(&sc->sc_rnd_source, device_xname(sc->sc_dev),
 	    RND_TYPE_NET, RND_FLAG_DEFAULT);
 
@@ -444,6 +435,15 @@ xennet_xenbus_attach(device_t parent, de
 		aprint_error_dev(self, "couldn't establish power handler\n");
 	else
 		pmf_class_network_register(self, ifp);
+
+	/* resume shared structures and tell backend that we are ready */
+	if (xennet_xenbus_resume(self, PMF_Q_NONE) == false) {
+		uvm_km_free(kernel_map, (vaddr_t)tx_ring, PAGE_SIZE,
+		    UVM_KMF_WIRED);
+		uvm_km_free(kernel_map, (vaddr_t)rx_ring, PAGE_SIZE,
+		    UVM_KMF_WIRED);
+		return;
+	}
 }
 
 static int
@@ -451,7 +451,6 @@ xennet_xenbus_detach(device_t self, int 
 {
 	struct xennet_xenbus_softc *sc = device_private(self);
 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
-	RING_IDX i;
 
 	if ((flags & (DETACH_SHUTDOWN | DETACH_FORCE)) == DETACH_SHUTDOWN) {
 		/* Trigger state transition with backend */
@@ -480,14 +479,7 @@ xennet_xenbus_detach(device_t self, int 
 	mutex_exit(&sc->sc_tx_lock);
 
 	mutex_enter(&sc->sc_rx_lock);
-	xennet_free_rx_buffer(sc);
-	for (i = 0; i < NET_RX_RING_SIZE; i++) {
-		struct xennet_rxreq *rxreq = &sc->sc_rxreqs[i];
-		if (rxreq->rxreq_m != NULL) {
-			m_freem(rxreq->rxreq_m);
-			rxreq->rxreq_m = NULL;
-		}
-	}
+	xennet_free_rx_buffer(sc, true);
 	mutex_exit(&sc->sc_rx_lock);
 
 	ether_ifdetach(ifp);
@@ -537,19 +529,16 @@ xennet_xenbus_resume(device_t dev, const
 	netif_rx_sring_t *rx_ring;
 	paddr_t ma;
 
-	/* invalidate the RX and TX rings */
-	if (sc->sc_backend_status == BEST_SUSPENDED) {
-		/*
-		 * Device was suspended, so ensure that access associated to
-		 * the previous RX and TX rings are revoked.
-		 */
-		xengnt_revoke_access(sc->sc_tx_ring_gntref);
-		xengnt_revoke_access(sc->sc_rx_ring_gntref);
-	}
-
+	/* All grants were removed during suspend */
 	sc->sc_tx_ring_gntref = GRANT_INVALID_REF;
 	sc->sc_rx_ring_gntref = GRANT_INVALID_REF;
 
+	mutex_enter(&sc->sc_rx_lock);
+	/* Free but don't revoke, the grant is gone */
+	xennet_free_rx_buffer(sc, false);
+	KASSERT(sc->sc_free_rxreql == NET_TX_RING_SIZE);
+	mutex_exit(&sc->sc_rx_lock);
+
 	tx_ring = sc->sc_tx_ring.sring;
 	rx_ring = sc->sc_rx_ring.sring;
 
@@ -570,6 +559,11 @@ xennet_xenbus_resume(device_t dev, const
 	error = xenbus_grant_ring(sc->sc_xbusd, ma, &sc->sc_rx_ring_gntref);
 	if (error)
 		goto abort_resume;
+
+	if (sc->sc_ih != NULL) {
+		xen_intr_disestablish(sc->sc_ih);
+		sc->sc_ih = NULL;
+	}
 	error = xenbus_alloc_evtchn(sc->sc_xbusd, &sc->sc_evtchn);
 	if (error)
 		goto abort_resume;
@@ -578,6 +572,24 @@ xennet_xenbus_resume(device_t dev, const
 	sc->sc_ih = xen_intr_establish_xname(-1, &xen_pic, sc->sc_evtchn,
 	    IST_LEVEL, IPL_NET, &xennet_handler, sc, true, device_xname(dev));
 	KASSERT(sc->sc_ih != NULL);
+
+	/* Re-fill Rx ring */
+	mutex_enter(&sc->sc_rx_lock);
+	xennet_alloc_rx_buffer(sc);
+	KASSERT(sc->sc_free_rxreql == 0);
+	mutex_exit(&sc->sc_rx_lock);
+
+	xenbus_switch_state(sc->sc_xbusd, NULL, XenbusStateInitialised);
+
+	if (sc->sc_backend_status == BEST_SUSPENDED) {
+		if (xennet_talk_to_backend(sc)) {
+			xenbus_device_resume(sc->sc_xbusd);
+			hypervisor_unmask_event(sc->sc_evtchn);
+			xenbus_switch_state(sc->sc_xbusd, NULL,
+			    XenbusStateConnected);
+		}
+	}
+
 	return true;
 
 abort_resume:
@@ -665,10 +677,6 @@ again:
 	xennet_alloc_rx_buffer(sc);
 	mutex_exit(&sc->sc_rx_lock);
 
-	if (sc->sc_backend_status == BEST_SUSPENDED) {
-		xenbus_device_resume(sc->sc_xbusd);
-	}
-
 	sc->sc_backend_status = BEST_CONNECTED;
 
 	return true;
@@ -689,13 +697,15 @@ xennet_xenbus_suspend(device_t dev, cons
 	 * so we do not mask event channel here
 	 */
 
-	/* collect any outstanding TX responses */
 	mutex_enter(&sc->sc_tx_lock);
+
+	/* collect any outstanding TX responses */
 	xennet_tx_complete(sc);
 	while (sc->sc_tx_ring.sring->rsp_prod != sc->sc_tx_ring.rsp_cons) {
 		kpause("xnsuspend", true, hz/2, &sc->sc_tx_lock);
 		xennet_tx_complete(sc);
 	}
+	KASSERT(sc->sc_free_txreql == NET_RX_RING_SIZE);
 	mutex_exit(&sc->sc_tx_lock);
 
 	/*
@@ -704,13 +714,7 @@ xennet_xenbus_suspend(device_t dev, cons
 	 * here, as dom0 does not expect the guest domain to suddenly revoke
 	 * access to these grants.
 	 */
-
 	sc->sc_backend_status = BEST_SUSPENDED;
-	if (sc->sc_ih != NULL) {
-		/* event already disabled */
-		xen_intr_disestablish(sc->sc_ih);
-		sc->sc_ih = NULL;
-	}
 
 	xenbus_device_suspend(sc->sc_xbusd);
 	aprint_verbose_dev(dev, "removed event channel %d\n", sc->sc_evtchn);
@@ -734,8 +738,10 @@ static void xennet_backend_changed(void 
 		xenbus_switch_state(sc->sc_xbusd, NULL, XenbusStateClosed);
 		break;
 	case XenbusStateInitWait:
-		if (sc->sc_backend_status == BEST_CONNECTED)
+		if (sc->sc_backend_status == BEST_CONNECTED
+		   || sc->sc_backend_status == BEST_SUSPENDED)
 			break;
+
 		if (xennet_talk_to_backend(sc))
 			xenbus_switch_state(sc->sc_xbusd, NULL,
 			    XenbusStateConnected);
@@ -839,7 +845,7 @@ xennet_alloc_rx_buffer(struct xennet_xen
  * Reclaim all RX buffers used by the I/O ring between frontend and backend
  */
 static void
-xennet_free_rx_buffer(struct xennet_xenbus_softc *sc)
+xennet_free_rx_buffer(struct xennet_xenbus_softc *sc, bool revoke)
 {
 	RING_IDX i;
 
@@ -859,7 +865,8 @@ xennet_free_rx_buffer(struct xennet_xenb
 			    rxreq_next);
 			sc->sc_free_rxreql++;
 
-			xengnt_revoke_access(rxreq->rxreq_gntref);
+			if (revoke)
+				xengnt_revoke_access(rxreq->rxreq_gntref);
 			rxreq->rxreq_gntref = GRANT_INVALID_REF;
 		}
 

Reply via email to