Module Name:    src
Committed By:   yamaguchi
Date:           Thu Mar 23 01:30:26 UTC 2023

Modified Files:
        src/sys/dev/pci: if_vioif.c

Log Message:
vioif(4): use device reset to stop interrupt completely


To generate a diff of this commit:
cvs rdiff -u -r1.84 -r1.85 src/sys/dev/pci/if_vioif.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/dev/pci/if_vioif.c
diff -u src/sys/dev/pci/if_vioif.c:1.84 src/sys/dev/pci/if_vioif.c:1.85
--- src/sys/dev/pci/if_vioif.c:1.84	Thu Mar 23 01:26:29 2023
+++ src/sys/dev/pci/if_vioif.c	Thu Mar 23 01:30:26 2023
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_vioif.c,v 1.84 2023/03/23 01:26:29 yamaguchi Exp $	*/
+/*	$NetBSD: if_vioif.c,v 1.85 2023/03/23 01:30:26 yamaguchi Exp $	*/
 
 /*
  * Copyright (c) 2020 The NetBSD Foundation, Inc.
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_vioif.c,v 1.84 2023/03/23 01:26:29 yamaguchi Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_vioif.c,v 1.85 2023/03/23 01:30:26 yamaguchi Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_net_mpsafe.h"
@@ -51,6 +51,7 @@ __KERNEL_RCSID(0, "$NetBSD: if_vioif.c,v
 #include <sys/module.h>
 #include <sys/pcq.h>
 #include <sys/workqueue.h>
+#include <sys/xcall.h>
 
 #include <dev/pci/virtioreg.h>
 #include <dev/pci/virtiovar.h>
@@ -420,6 +421,7 @@ static void	vioif_disable_interrupt_vqpa
 static int	vioif_setup_sysctl(struct vioif_softc *);
 static void	vioif_setup_stats(struct vioif_softc *);
 static int	vioif_ifflags(struct vioif_softc *);
+static void	vioif_intr_barrier(void);
 
 CFATTACH_DECL_NEW(vioif, sizeof(struct vioif_softc),
 		  vioif_match, vioif_attach, NULL, NULL);
@@ -958,7 +960,8 @@ vioif_attach(device_t parent, device_t s
 		nvqs++;
 		rxq->rxq_vq->vq_intrhand = vioif_rx_intr;
 		rxq->rxq_vq->vq_intrhand_arg = (void *)rxq;
-		rxq->rxq_stopping = true;
+		rxq->rxq_stopping = false;
+		rxq->rxq_active = false;
 		vioif_work_set(&rxq->rxq_work, vioif_rx_handle, rxq);
 
 		txq->txq_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NET);
@@ -987,6 +990,7 @@ vioif_attach(device_t parent, device_t s
 		txq->txq_vq->vq_intrhand_arg = (void *)txq;
 		txq->txq_link_active = VIOIF_IS_LINK_ACTIVE(sc);
 		txq->txq_stopping = false;
+		txq->txq_active = false;
 		txq->txq_intrq = pcq_create(txq->txq_vq->vq_num, KM_SLEEP);
 		vioif_work_set(&txq->txq_work, vioif_tx_handle, txq);
 	}
@@ -1183,9 +1187,7 @@ vioif_init(struct ifnet *ifp)
 	for (i = 0; i < sc->sc_req_nvq_pairs; i++) {
 		rxq = &sc->sc_rxq[i];
 
-		/* Have to set false before vioif_populate_rx_mbufs */
 		mutex_enter(rxq->rxq_lock);
-		rxq->rxq_stopping = false;
 		vioif_populate_rx_mbufs_locked(sc, rxq);
 		mutex_exit(rxq->rxq_lock);
 
@@ -1202,9 +1204,6 @@ vioif_init(struct ifnet *ifp)
 	else
 		sc->sc_act_nvq_pairs = 1;
 
-	for (i = 0; i < sc->sc_act_nvq_pairs; i++)
-		sc->sc_txq[i].txq_stopping = false;
-
 	vioif_enable_interrupt_vqpairs(sc);
 
 	vioif_update_link_status(sc);
@@ -1225,16 +1224,7 @@ vioif_stop(struct ifnet *ifp, int disabl
 	struct vioif_ctrlqueue *ctrlq = &sc->sc_ctrlq;
 	int i;
 
-	/* disable interrupts */
-	vioif_disable_interrupt_vqpairs(sc);
-	if (sc->sc_has_ctrl)
-		virtio_stop_vq_intr(vsc, ctrlq->ctrlq_vq);
 
-	/*
-	 * stop all packet processing:
-	 * 1. stop interrupt handlers by rxq_stopping and txq_stopping
-	 * 2. wait for stopping workqueue for packet processing
-	 */
 	for (i = 0; i < sc->sc_act_nvq_pairs; i++) {
 		txq = &sc->sc_txq[i];
 		rxq = &sc->sc_rxq[i];
@@ -1242,17 +1232,35 @@ vioif_stop(struct ifnet *ifp, int disabl
 		mutex_enter(rxq->rxq_lock);
 		rxq->rxq_stopping = true;
 		mutex_exit(rxq->rxq_lock);
-		vioif_work_wait(sc->sc_txrx_workqueue, &rxq->rxq_work);
 
 		mutex_enter(txq->txq_lock);
 		txq->txq_stopping = true;
 		mutex_exit(txq->txq_lock);
-		vioif_work_wait(sc->sc_txrx_workqueue, &txq->txq_work);
 	}
 
-	/* only way to stop I/O and DMA is resetting... */
+	/* disable interrupts */
+	vioif_disable_interrupt_vqpairs(sc);
+	if (sc->sc_has_ctrl)
+		virtio_stop_vq_intr(vsc, ctrlq->ctrlq_vq);
+
+	/*
+	 * only way to stop interrupt, I/O and DMA is resetting...
+	 *
+	 * NOTE: Devices based on VirtIO draft specification can not
+	 * stop interrupt completely even if virtio_stop_vq_intr() is called.
+	 */
 	virtio_reset(vsc);
 
+	vioif_intr_barrier();
+
+	for (i = 0; i < sc->sc_act_nvq_pairs; i++) {
+		txq = &sc->sc_txq[i];
+		rxq = &sc->sc_rxq[i];
+
+		vioif_work_wait(sc->sc_txrx_workqueue, &rxq->rxq_work);
+		vioif_work_wait(sc->sc_txrx_workqueue, &txq->txq_work);
+	}
+
 	for (i = 0; i < sc->sc_act_nvq_pairs; i++) {
 		vioif_rx_queue_clear(&sc->sc_rxq[i]);
 		vioif_tx_queue_clear(&sc->sc_txq[i]);
@@ -1260,6 +1268,22 @@ vioif_stop(struct ifnet *ifp, int disabl
 
 	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
 
+	/* all packet processing is stopped */
+	for (i = 0; i < sc->sc_act_nvq_pairs; i++) {
+		txq = &sc->sc_txq[i];
+		rxq = &sc->sc_rxq[i];
+
+		mutex_enter(rxq->rxq_lock);
+		rxq->rxq_stopping = false;
+		KASSERT(!rxq->rxq_active);
+		mutex_exit(rxq->rxq_lock);
+
+		mutex_enter(txq->txq_lock);
+		txq->txq_stopping = false;
+		KASSERT(!txq->txq_active);
+		mutex_exit(txq->txq_lock);
+	}
+
 	for (i = 0; i < sc->sc_act_nvq_pairs; i++) {
 		txq = &sc->sc_txq[i];
 		rxq = &sc->sc_rxq[i];
@@ -1718,13 +1742,19 @@ vioif_rx_handle(void *xrxq)
 	struct vioif_softc *sc = device_private(virtio_child(vsc));
 	u_int limit;
 
-	limit = sc->sc_rx_process_limit;
-
 	mutex_enter(rxq->rxq_lock);
 
-	if (!rxq->rxq_stopping)
-		vioif_rx_handle_locked(rxq, limit);
+	KASSERT(rxq->rxq_active);
+
+	if (rxq->rxq_stopping) {
+		rxq->rxq_active = false;
+		goto done;
+	}
+
+	limit = sc->sc_rx_process_limit;
+	vioif_rx_handle_locked(rxq, limit);
 
+done:
 	mutex_exit(rxq->rxq_lock);
 }
 
@@ -1845,11 +1875,19 @@ vioif_tx_handle(void *xtxq)
 	struct vioif_softc *sc = device_private(virtio_child(vsc));
 	u_int limit;
 
+	mutex_enter(txq->txq_lock);
+
+	KASSERT(txq->txq_active);
+
+	if (txq->txq_stopping) {
+		txq->txq_active = false;
+		goto done;
+	}
+
 	limit = sc->sc_tx_process_limit;
+	vioif_tx_handle_locked(txq, limit);
 
-	mutex_enter(txq->txq_lock);
-	if (!txq->txq_stopping)
-		vioif_tx_handle_locked(txq, limit);
+done:
 	mutex_exit(txq->txq_lock);
 }
 
@@ -1934,8 +1972,6 @@ vioif_tx_drain(struct vioif_txqueue *txq
 	struct virtio_softc *vsc = vq->vq_owner;
 	int i;
 
-	KASSERT(txq->txq_stopping);
-
 	for (i = 0; i < vq->vq_num; i++) {
 		if (txq->txq_mbufs[i] == NULL)
 			continue;
@@ -2629,6 +2665,14 @@ vioif_setup_stats(struct vioif_softc *sc
 	    NULL, device_xname(sc->sc_dev), "control command failed");
 }
 
+static void
+vioif_intr_barrier(void)
+{
+
+	/* wait for finish all interrupt handler */
+	xc_barrier(0);
+}
+
 MODULE(MODULE_CLASS_DRIVER, if_vioif, "virtio");
 
 #ifdef _MODULE

Reply via email to