Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/pci vioif(4): use device reset to stop interrupt com...



details:   https://anonhg.NetBSD.org/src/rev/dcad35793544
branches:  trunk
changeset: 373954:dcad35793544
user:      yamaguchi <yamaguchi%NetBSD.org@localhost>
date:      Thu Mar 23 01:30:26 2023 +0000

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

diffstat:

 sys/dev/pci/if_vioif.c |  112 ++++++++++++++++++++++++++++++++++--------------
 1 files changed, 78 insertions(+), 34 deletions(-)

diffs (227 lines):

diff -r e3b870ac1db1 -r dcad35793544 sys/dev/pci/if_vioif.c
--- a/sys/dev/pci/if_vioif.c    Thu Mar 23 01:26:29 2023 +0000
+++ b/sys/dev/pci/if_vioif.c    Thu Mar 23 01:30:26 2023 +0000
@@ -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 @@
 #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 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 @@
                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 @@
                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 @@
        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 @@
        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 @@
        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 @@
                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);
+       }
+
+       /* 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);
        }
 
-       /* only way to stop I/O and DMA is resetting... */
-       virtio_reset(vsc);
-
        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 @@
 
        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 @@
        struct vioif_softc *sc = device_private(virtio_child(vsc));
        u_int limit;
 
+       mutex_enter(rxq->rxq_lock);
+
+       KASSERT(rxq->rxq_active);
+
+       if (rxq->rxq_stopping) {
+               rxq->rxq_active = false;
+               goto done;
+       }
+
        limit = sc->sc_rx_process_limit;
-
-       mutex_enter(rxq->rxq_lock);
-
-       if (!rxq->rxq_stopping)
-               vioif_rx_handle_locked(rxq, limit);
-
+       vioif_rx_handle_locked(rxq, limit);
+
+done:
        mutex_exit(rxq->rxq_lock);
 }
 
@@ -1845,11 +1875,19 @@
        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;
-
-       mutex_enter(txq->txq_lock);
-       if (!txq->txq_stopping)
-               vioif_tx_handle_locked(txq, limit);
+       vioif_tx_handle_locked(txq, limit);
+
+done:
        mutex_exit(txq->txq_lock);
 }
 
@@ -1934,8 +1972,6 @@
        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 @@
            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



Home | Main Index | Thread Index | Old Index