Module Name:    src
Committed By:   yamaguchi
Date:           Thu Mar 23 02:48:30 UTC 2023

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

Log Message:
vioif(4): added functions to manipulate network queues


To generate a diff of this commit:
cvs rdiff -u -r1.98 -r1.99 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.98 src/sys/dev/pci/if_vioif.c:1.99
--- src/sys/dev/pci/if_vioif.c:1.98	Thu Mar 23 02:42:49 2023
+++ src/sys/dev/pci/if_vioif.c	Thu Mar 23 02:48:29 2023
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_vioif.c,v 1.98 2023/03/23 02:42:49 yamaguchi Exp $	*/
+/*	$NetBSD: if_vioif.c,v 1.99 2023/03/23 02:48:29 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.98 2023/03/23 02:42:49 yamaguchi Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_vioif.c,v 1.99 2023/03/23 02:48:29 yamaguchi Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_net_mpsafe.h"
@@ -259,7 +259,7 @@ struct vioif_netqueue {
 
 	char			 netq_evgroup[32];
 	struct evcnt		 netq_mbuf_load_failed;
-	struct evcnt		 netq_enqueue_reserve_failed;
+	struct evcnt		 netq_enqueue_failed;
 
 	void			*netq_ctx;
 };
@@ -370,6 +370,21 @@ static int	vioif_ifflags_cb(struct ether
 /* tx & rx */
 static void	vioif_net_sched_handle(struct vioif_softc *,
 		    struct vioif_netqueue *);
+static int	vioif_net_load_mbuf(struct virtio_softc *,
+		    struct vioif_net_map *, struct mbuf *, int);
+static void	vioif_net_unload_mbuf(struct virtio_softc *,
+		    struct vioif_net_map *);
+static int	vioif_net_enqueue_tx(struct virtio_softc *, struct virtqueue *,
+		    int, struct vioif_net_map *);
+static int	vioif_net_enqueue_rx(struct virtio_softc *, struct virtqueue *,
+		    int, struct vioif_net_map *);
+static struct mbuf *
+		vioif_net_dequeue_commit(struct virtio_softc *,
+		    struct virtqueue *, int, struct vioif_net_map *, int);
+static void	vioif_net_intr_enable(struct vioif_softc *,
+		    struct virtio_softc *);
+static void	vioif_net_intr_disable(struct vioif_softc *,
+		    struct virtio_softc *);
 
 /* rx */
 static void	vioif_populate_rx_mbufs_locked(struct vioif_softc *,
@@ -412,12 +427,11 @@ static int	vioif_ctrl_intr(void *);
 static int	vioif_config_change(struct virtio_softc *);
 static void	vioif_ctl_softint(void *);
 static int	vioif_ctrl_mq_vq_pairs_set(struct vioif_softc *, int);
-static void	vioif_enable_interrupt_vqpairs(struct vioif_softc *);
-static void	vioif_disable_interrupt_vqpairs(struct vioif_softc *);
 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);
+static void	vioif_notify(struct virtio_softc *, struct virtqueue *);
 
 CFATTACH_DECL_NEW(vioif, sizeof(struct vioif_softc),
 		  vioif_match, vioif_attach, NULL, NULL);
@@ -1180,34 +1194,6 @@ vioif_finalize_teardown(device_t self)
 	return 0;
 }
 
-static void
-vioif_enable_interrupt_vqpairs(struct vioif_softc *sc)
-{
-	struct virtio_softc *vsc = sc->sc_virtio;
-	struct vioif_netqueue *netq;
-	size_t i, netq_act_num;
-
-	netq_act_num = sc->sc_act_nvq_pairs * 2;
-	for (i = 0; i < netq_act_num; i++) {
-		netq = &sc->sc_netqs[i];
-		virtio_start_vq_intr(vsc, netq->netq_vq);
-	}
-}
-
-static void
-vioif_disable_interrupt_vqpairs(struct vioif_softc *sc)
-{
-	struct virtio_softc *vsc = sc->sc_virtio;
-	struct vioif_netqueue *netq;
-	size_t i, netq_act_num;
-
-	netq_act_num = sc->sc_act_nvq_pairs * 2;
-	for (i = 0; i < netq_act_num; i++) {
-		netq = &sc->sc_netqs[i];
-		virtio_stop_vq_intr(vsc, netq->netq_vq);
-	}
-}
-
 /*
  * Interface functions for ifnet
  */
@@ -1252,7 +1238,7 @@ vioif_init(struct ifnet *ifp)
 	SET(ifp->if_flags, IFF_RUNNING);
 	CLR(ifp->if_flags, IFF_OACTIVE);
 
-	vioif_enable_interrupt_vqpairs(sc);
+	vioif_net_intr_enable(sc, vsc);
 
 	vioif_update_link_status(sc);
 	r = vioif_rx_filter(sc);
@@ -1267,12 +1253,12 @@ vioif_stop(struct ifnet *ifp, int disabl
 	struct virtio_softc *vsc = sc->sc_virtio;
 	struct vioif_netqueue *netq;
 	struct vioif_ctrlqueue *ctrlq = &sc->sc_ctrlq;
-	size_t i, netq_act_num;
+	size_t i, act_qnum;
 
-	netq_act_num = sc->sc_act_nvq_pairs * 2;
+	act_qnum = sc->sc_act_nvq_pairs * 2;
 
 	CLR(ifp->if_flags, IFF_RUNNING);
-	for (i = 0; i < netq_act_num; i++) {
+	for (i = 0; i < act_qnum; i++) {
 		netq = &sc->sc_netqs[i];
 
 		mutex_enter(&netq->netq_lock);
@@ -1281,7 +1267,7 @@ vioif_stop(struct ifnet *ifp, int disabl
 	}
 
 	/* disable interrupts */
-	vioif_disable_interrupt_vqpairs(sc);
+	vioif_net_intr_disable(sc, vsc);
 	if (sc->sc_has_ctrl)
 		virtio_stop_vq_intr(vsc, ctrlq->ctrlq_vq);
 
@@ -1295,7 +1281,7 @@ vioif_stop(struct ifnet *ifp, int disabl
 
 	vioif_intr_barrier();
 
-	for (i = 0; i < netq_act_num; i++) {
+	for (i = 0; i < act_qnum; i++) {
 		netq = &sc->sc_netqs[i];
 		vioif_work_wait(sc->sc_txrx_workqueue, &netq->netq_work);
 	}
@@ -1309,7 +1295,7 @@ vioif_stop(struct ifnet *ifp, int disabl
 	}
 
 	/* all packet processing is stopped */
-	for (i = 0; i < netq_act_num; i++) {
+	for (i = 0; i < act_qnum; i++) {
 		netq = &sc->sc_netqs[i];
 
 		mutex_enter(&netq->netq_lock);
@@ -1327,7 +1313,6 @@ vioif_send_common_locked(struct ifnet *i
 	struct virtqueue *vq = netq->netq_vq;
 	struct vioif_tx_context *txc;
 	struct vioif_net_map *map;
-	struct virtio_net_hdr *hdr;
 	struct mbuf *m;
 	int queued = 0;
 
@@ -1367,25 +1352,23 @@ vioif_send_common_locked(struct ifnet *i
 		map = &netq->netq_maps[slot];
 		KASSERT(map->vnm_mbuf == NULL);
 
-		r = bus_dmamap_load_mbuf(virtio_dmat(vsc),
-		    map->vnm_mbuf_map, m, BUS_DMA_WRITE | BUS_DMA_NOWAIT);
+		r = vioif_net_load_mbuf(vsc, map, m, BUS_DMA_WRITE);
 		if (r != 0) {
 			/* maybe just too fragmented */
 			struct mbuf *newm;
 
 			newm = m_defrag(m, M_NOWAIT);
-			if (newm == NULL) {
+			if (newm != NULL) {
+				m = newm;
+				r = vioif_net_load_mbuf(vsc, map, m,
+				    BUS_DMA_WRITE);
+			} else {
 				txc->txc_defrag_failed.ev_count++;
-				goto skip;
+				r = -1;
 			}
 
-			m = newm;
-			r = bus_dmamap_load_mbuf(virtio_dmat(vsc),
-			    map->vnm_mbuf_map, m,
-			    BUS_DMA_WRITE | BUS_DMA_NOWAIT);
 			if (r != 0) {
 				netq->netq_mbuf_load_failed.ev_count++;
-skip:
 				m_freem(m);
 				if_statinc(ifp, if_oerrors);
 				virtio_enqueue_abort(vsc, vq, slot);
@@ -1393,36 +1376,25 @@ skip:
 			}
 		}
 
-		/* This should actually never fail */
-		r = virtio_enqueue_reserve(vsc, vq, slot,
-		    map->vnm_mbuf_map->dm_nsegs + 1);
+		memset(map->vnm_hdr, 0, sc->sc_hdr_size);
+
+		r = vioif_net_enqueue_tx(vsc, vq, slot, map);
 		if (r != 0) {
-			netq->netq_enqueue_reserve_failed.ev_count++;
-			bus_dmamap_unload(virtio_dmat(vsc),
-			     map->vnm_mbuf_map);
-			/* slot already freed by virtio_enqueue_reserve */
+			netq->netq_enqueue_failed.ev_count++;
+			vioif_net_unload_mbuf(vsc, map);
 			m_freem(m);
+			/* slot already freed by vioif_net_enqueue_tx */
+
 			if_statinc(ifp, if_oerrors);
 			continue;
 		}
 
-		map->vnm_mbuf = m;
-		hdr = map->vnm_hdr;
-		memset(hdr, 0, sc->sc_hdr_size);
-		bus_dmamap_sync(virtio_dmat(vsc), map->vnm_mbuf_map,
-		    0, map->vnm_mbuf_map->dm_mapsize, BUS_DMASYNC_PREWRITE);
-		bus_dmamap_sync(virtio_dmat(vsc), map->vnm_hdr_map,
-		    0, map->vnm_hdr_map->dm_mapsize, BUS_DMASYNC_PREWRITE);
-		virtio_enqueue(vsc, vq, slot, map->vnm_hdr_map, true);
-		virtio_enqueue(vsc, vq, slot, map->vnm_mbuf_map, true);
-		virtio_enqueue_commit(vsc, vq, slot, false);
-
 		queued++;
 		bpf_mtap(ifp, m, BPF_D_OUT);
 	}
 
 	if (queued > 0) {
-		virtio_enqueue_commit(vsc, vq, -1, true);
+		vioif_notify(vsc, vq);
 		ifp->if_timer = 5;
 	}
 }
@@ -1569,6 +1541,147 @@ vioif_net_sched_handle(struct vioif_soft
 	}
 }
 
+static int
+vioif_net_load_mbuf(struct virtio_softc *vsc, struct vioif_net_map *map,
+   struct mbuf *m, int dma_flags)
+{
+	int r;
+
+	KASSERT(map->vnm_mbuf == NULL);
+
+	r = bus_dmamap_load_mbuf(virtio_dmat(vsc),
+	    map->vnm_mbuf_map, m, dma_flags | BUS_DMA_NOWAIT);
+	if (r == 0) {
+		map->vnm_mbuf = m;
+	}
+
+	return r;
+}
+
+static void
+vioif_net_unload_mbuf(struct virtio_softc *vsc, struct vioif_net_map *map)
+{
+
+	KASSERT(map->vnm_mbuf != NULL);
+	bus_dmamap_unload(virtio_dmat(vsc), map->vnm_mbuf_map);
+	map->vnm_mbuf = NULL;
+}
+
+static int
+vioif_net_enqueue(struct virtio_softc *vsc, struct virtqueue *vq,
+    int slot, struct vioif_net_map *map, int dma_ops, bool is_write)
+{
+	int r;
+
+	KASSERT(map->vnm_mbuf != NULL);
+
+	/* This should actually never fail */
+	r = virtio_enqueue_reserve(vsc, vq, slot,
+	    map->vnm_mbuf_map->dm_nsegs + 1);
+	if (r != 0) {
+		/* slot already freed by virtio_enqueue_reserve */
+		return r;
+	}
+
+	bus_dmamap_sync(virtio_dmat(vsc), map->vnm_mbuf_map,
+	    0, map->vnm_mbuf_map->dm_mapsize, dma_ops);
+	bus_dmamap_sync(virtio_dmat(vsc), map->vnm_hdr_map,
+	    0, map->vnm_hdr_map->dm_mapsize, dma_ops);
+
+	virtio_enqueue(vsc, vq, slot, map->vnm_hdr_map, is_write);
+	virtio_enqueue(vsc, vq, slot, map->vnm_mbuf_map, is_write);
+	virtio_enqueue_commit(vsc, vq, slot, false);
+
+	return 0;
+}
+
+static int
+vioif_net_enqueue_tx(struct virtio_softc *vsc, struct virtqueue *vq,
+    int slot, struct vioif_net_map *map)
+{
+
+	return vioif_net_enqueue(vsc, vq, slot, map,
+	    BUS_DMASYNC_PREWRITE, true);
+}
+
+static int
+vioif_net_enqueue_rx(struct virtio_softc *vsc, struct virtqueue *vq,
+    int slot, struct vioif_net_map *map)
+{
+
+	return vioif_net_enqueue(vsc, vq, slot, map,
+	    BUS_DMASYNC_PREREAD, false);
+}
+
+static void
+vioif_notify(struct virtio_softc *vsc, struct virtqueue *vq)
+{
+
+	virtio_enqueue_commit(vsc, vq, -1, true);
+}
+
+static struct mbuf *
+vioif_net_dequeue_commit(struct virtio_softc *vsc, struct virtqueue *vq,
+   int slot, struct vioif_net_map *map, int dma_flags)
+{
+	struct mbuf *m;
+
+	m = map->vnm_mbuf;
+	KASSERT(m != NULL);
+	map->vnm_mbuf = NULL;
+
+	bus_dmamap_sync(virtio_dmat(vsc), map->vnm_hdr_map,
+	    0, map->vnm_hdr_map->dm_mapsize, dma_flags);
+	bus_dmamap_sync(virtio_dmat(vsc), map->vnm_mbuf_map,
+	    0, map->vnm_mbuf_map->dm_mapsize, dma_flags);
+
+	bus_dmamap_unload(virtio_dmat(vsc), map->vnm_mbuf_map);
+	virtio_dequeue_commit(vsc, vq, slot);
+
+	return m;
+}
+
+static void
+vioif_net_intr_enable(struct vioif_softc *sc, struct virtio_softc *vsc)
+{
+	struct vioif_netqueue *netq;
+	size_t i, act_qnum;
+	int enqueued;
+
+	act_qnum = sc->sc_act_nvq_pairs * 2;
+	for (i = 0; i < act_qnum; i++) {
+		netq = &sc->sc_netqs[i];
+
+		KASSERT(!netq->netq_stopping);
+		KASSERT(!netq->netq_running_handle);
+
+		enqueued = virtio_start_vq_intr(vsc, netq->netq_vq);
+		if (enqueued != 0) {
+			virtio_stop_vq_intr(vsc, netq->netq_vq);
+
+			mutex_enter(&netq->netq_lock);
+			netq->netq_running_handle = true;
+			vioif_net_sched_handle(sc, netq);
+			mutex_exit(&netq->netq_lock);
+		}
+	}
+}
+
+static void
+vioif_net_intr_disable(struct vioif_softc *sc, struct virtio_softc *vsc)
+{
+	struct vioif_netqueue *netq;
+	size_t i, act_qnum;
+
+	act_qnum = sc->sc_act_nvq_pairs * 2;
+	for (i = 0; i < act_qnum; i++) {
+		netq = &sc->sc_netqs[i];
+
+		virtio_stop_vq_intr(vsc, netq->netq_vq);
+	}
+
+}
+
 /*
  * Receive implementation
  */
@@ -1595,9 +1708,6 @@ vioif_populate_rx_mbufs_locked(struct vi
 		if (__predict_false(r != 0))
 			panic("enqueue_prep for rx buffers");
 
-		map = &netq->netq_maps[slot];
-		KASSERT(map->vnm_mbuf == NULL);
-
 		MGETHDR(m, M_DONTWAIT, MT_DATA);
 		if (m == NULL) {
 			virtio_enqueue_abort(vsc, vq, slot);
@@ -1615,9 +1725,8 @@ vioif_populate_rx_mbufs_locked(struct vi
 		m->m_len = m->m_pkthdr.len = MCLBYTES;
 		m_adj(m, ETHER_ALIGN);
 
-		r = bus_dmamap_load_mbuf(virtio_dmat(vsc),
-		    map->vnm_mbuf_map, m, BUS_DMA_READ | BUS_DMA_NOWAIT);
-
+		map = &netq->netq_maps[slot];
+		r = vioif_net_load_mbuf(vsc, map, m, BUS_DMA_READ);
 		if (r != 0) {
 			virtio_enqueue_abort(vsc, vq, slot);
 			m_freem(m);
@@ -1625,28 +1734,20 @@ vioif_populate_rx_mbufs_locked(struct vi
 			break;
 		}
 
-		r = virtio_enqueue_reserve(vsc, vq, slot,
-		    map->vnm_mbuf_map->dm_nsegs + 1);
+		r = vioif_net_enqueue_rx(vsc, vq, slot, map);
 		if (r != 0) {
-			netq->netq_enqueue_reserve_failed.ev_count++;
-			bus_dmamap_unload(virtio_dmat(vsc), map->vnm_mbuf_map);
+			vioif_net_unload_mbuf(vsc, map);
+			netq->netq_enqueue_failed.ev_count++;
 			m_freem(m);
-			/* slot already freed by virtio_enqueue_reserve */
+			/* slot already freed by vioif_net_enqueue_rx */
 			break;
 		}
 
-		map->vnm_mbuf = m;
-		bus_dmamap_sync(virtio_dmat(vsc), map->vnm_hdr_map,
-		    0, sc->sc_hdr_size, BUS_DMASYNC_PREREAD);
-		bus_dmamap_sync(virtio_dmat(vsc), map->vnm_mbuf_map,
-		    0, map->vnm_mbuf_map->dm_mapsize, BUS_DMASYNC_PREREAD);
-		virtio_enqueue(vsc, vq, slot, map->vnm_hdr_map, false);
-		virtio_enqueue(vsc, vq, slot, map->vnm_mbuf_map, false);
-		virtio_enqueue_commit(vsc, vq, slot, false);
 		ndone++;
 	}
+
 	if (ndone > 0)
-		virtio_enqueue_commit(vsc, vq, -1, true);
+		vioif_notify(vsc, vq);
 }
 
 static void
@@ -1654,6 +1755,7 @@ vioif_rx_queue_clear(struct vioif_softc 
     struct vioif_netqueue *netq)
 {
 	struct vioif_net_map *map;
+	struct mbuf *m;
 	unsigned int i, vq_num;
 	bool more;
 
@@ -1669,12 +1771,12 @@ vioif_rx_queue_clear(struct vioif_softc 
 	for (i = 0; i < vq_num; i++) {
 		map = &netq->netq_maps[i];
 
-		if (map->vnm_mbuf == NULL)
+		m = map->vnm_mbuf;
+		if (m == NULL)
 			continue;
 
-		bus_dmamap_unload(virtio_dmat(vsc), map->vnm_mbuf_map);
-		m_freem(map->vnm_mbuf);
-		map->vnm_mbuf = NULL;
+		vioif_net_unload_mbuf(vsc, map);
+		m_freem(m);
 	}
 	mutex_exit(&netq->netq_lock);
 }
@@ -1711,16 +1813,9 @@ vioif_rx_deq_locked(struct vioif_softc *
 
 		map = &netq->netq_maps[slot];
 		KASSERT(map->vnm_mbuf != NULL);
-
-		bus_dmamap_sync(virtio_dmat(vsc), map->vnm_hdr_map,
-		    0, sc->sc_hdr_size, BUS_DMASYNC_POSTREAD);
-		bus_dmamap_sync(virtio_dmat(vsc), map->vnm_mbuf_map,
-		    0, map->vnm_mbuf_map->dm_mapsize, BUS_DMASYNC_POSTREAD);
-
-		bus_dmamap_unload(virtio_dmat(vsc), map->vnm_mbuf_map);
-		m = map->vnm_mbuf;
-		map->vnm_mbuf = NULL;
-		virtio_dequeue_commit(vsc, vq, slot);
+		m = vioif_net_dequeue_commit(vsc, vq, slot,
+		    map, BUS_DMASYNC_POSTREAD);
+		KASSERT(m != NULL);
 
 		m->m_len = m->m_pkthdr.len = len - sc->sc_hdr_size;
 		m_set_rcvif(m, ifp);
@@ -1929,6 +2024,7 @@ vioif_tx_queue_clear(struct vioif_softc 
     struct vioif_netqueue *netq)
 {
 	struct vioif_net_map *map;
+	struct mbuf *m;
 	unsigned int i, vq_num;
 	bool more;
 
@@ -1943,12 +2039,13 @@ vioif_tx_queue_clear(struct vioif_softc 
 
 	for (i = 0; i < vq_num; i++) {
 		map = &netq->netq_maps[i];
-		if (map->vnm_mbuf == NULL)
+
+		m = map->vnm_mbuf;
+		if (m == NULL)
 			continue;
 
-		bus_dmamap_unload(virtio_dmat(vsc), map->vnm_mbuf_map);
-		m_freem(map->vnm_mbuf);
-		map->vnm_mbuf = NULL;
+		vioif_net_unload_mbuf(vsc, map);
+		m_freem(m);
 	}
 	mutex_exit(&netq->netq_lock);
 }
@@ -1980,16 +2077,9 @@ vioif_tx_deq_locked(struct vioif_softc *
 
 		map = &netq->netq_maps[slot];
 		KASSERT(map->vnm_mbuf != NULL);
-
-		bus_dmamap_sync(virtio_dmat(vsc), map->vnm_hdr_map,
-		    0, sc->sc_hdr_size, BUS_DMASYNC_POSTWRITE);
-		bus_dmamap_sync(virtio_dmat(vsc), map->vnm_mbuf_map,
-		    0, map->vnm_mbuf_map->dm_mapsize, BUS_DMASYNC_POSTWRITE);
-
-		bus_dmamap_unload(virtio_dmat(vsc), map->vnm_mbuf_map);
-		m = map->vnm_mbuf;
-		map->vnm_mbuf = NULL;
-		virtio_dequeue_commit(vsc, vq, slot);
+		m = vioif_net_dequeue_commit(vsc, vq, slot,
+		    map, BUS_DMASYNC_POSTWRITE);
+		KASSERT(m != NULL);
 
 		if_statinc(ifp, if_opackets);
 		m_freem(m);
@@ -2665,9 +2755,9 @@ vioif_setup_stats(struct vioif_softc *sc
 		netq = &sc->sc_netqs[i];
 		evcnt_attach_dynamic(&netq->netq_mbuf_load_failed, EVCNT_TYPE_MISC,
 		    NULL, netq->netq_evgroup, "failed to load mbuf to DMA");
-		evcnt_attach_dynamic(&netq->netq_enqueue_reserve_failed,
+		evcnt_attach_dynamic(&netq->netq_enqueue_failed,
 		    EVCNT_TYPE_MISC, NULL, netq->netq_evgroup,
-		    "virtio_enqueue_reserve failed");
+		    "virtqueue enqueue failed failed");
 
 		switch (VIOIF_NETQ_DIR(i)) {
 		case VIOIF_NETQ_RX:

Reply via email to