The branch main has been updated by andrew:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=ea130fa32099ea7e0c03702efdec28e745ea6ef1

commit ea130fa32099ea7e0c03702efdec28e745ea6ef1
Author:     Sarah Walker <[email protected]>
AuthorDate: 2026-02-27 14:17:15 +0000
Commit:     Andrew Turner <[email protected]>
CommitDate: 2026-06-18 16:04:24 +0000

    virtio_net: Use bus_dma for command/ack buffers
    
    While the majority of virtio platforms will be fully coherent, some may
    require cache maintenance or other specific device memory handling (eg for
    secure partitioning). Using bus_dma allows for these usecases.
    
    The virtio buffers are marked as coherent; this should ensure that sync
    calls are no-ops in the common cases.
    
    Reviewed by:    andrew
    Sponsored by:   Arm Ltd
    Differential Revision:  https://reviews.freebsd.org/D55564
---
 sys/dev/virtio/network/if_vtnet.c    | 350 ++++++++++++++++++++++++++++-------
 sys/dev/virtio/network/if_vtnetvar.h |   6 +
 2 files changed, 291 insertions(+), 65 deletions(-)

diff --git a/sys/dev/virtio/network/if_vtnet.c 
b/sys/dev/virtio/network/if_vtnet.c
index 57cbdca0dbeb..ad642052d06d 100644
--- a/sys/dev/virtio/network/if_vtnet.c
+++ b/sys/dev/virtio/network/if_vtnet.c
@@ -219,7 +219,7 @@ static void vtnet_init_locked(struct vtnet_softc *, int);
 static void    vtnet_init(void *);
 
 static void    vtnet_free_ctrl_vq(struct vtnet_softc *);
-static void    vtnet_exec_ctrl_cmd(struct vtnet_softc *, void *,
+static int     vtnet_exec_ctrl_cmd(struct vtnet_softc *, uint8_t *,
                    struct sglist *, int, int);
 static int     vtnet_ctrl_mac_cmd(struct vtnet_softc *, uint8_t *);
 static int     vtnet_ctrl_guest_offloads(struct vtnet_softc *, uint64_t);
@@ -523,14 +523,60 @@ vtnet_attach(device_t dev)
                goto fail;
        }
 
+       mtx_init(&sc->vtnet_hdr_mtx, device_get_nameunit(dev),
+           "VirtIO Net header lock", MTX_DEF);
+
+       error = bus_dma_tag_create(
+           bus_get_dma_tag(dev),               /* parent */
+           sizeof(uint16_t),                   /* alignment */
+           0,                                  /* boundary */
+           BUS_SPACE_MAXADDR,                  /* lowaddr */
+           BUS_SPACE_MAXADDR,                  /* highaddr */
+           NULL, NULL,                         /* filter, filterarg */
+           PAGE_SIZE,                          /* max request size */
+           1,                                  /* max # segments */
+           PAGE_SIZE,                          /* maxsegsize */
+           BUS_DMA_COHERENT,                   /* flags */
+           busdma_lock_mutex,                  /* lockfunc */
+           &sc->vtnet_hdr_mtx,                 /* lockarg */
+           &sc->vtnet_hdr_dmat);
+       if (error) {
+               device_printf(dev, "cannot create bus_dma_tag\n");
+               goto fail;
+       }
+
+       mtx_init(&sc->vtnet_ack_mtx, device_get_nameunit(dev),
+           "VirtIO Net ACK lock", MTX_DEF);
+
+       error = bus_dma_tag_create(
+           bus_get_dma_tag(dev),               /* parent */
+           sizeof(uint8_t),                    /* alignment */
+           0,                                  /* boundary */
+           BUS_SPACE_MAXADDR,                  /* lowaddr */
+           BUS_SPACE_MAXADDR,                  /* highaddr */
+           NULL, NULL,                         /* filter, filterarg */
+           sizeof(uint8_t),                    /* max request size */
+           1,                                  /* max # segments */
+           sizeof(uint8_t),                    /* maxsegsize */
+           BUS_DMA_COHERENT,                   /* flags */
+           busdma_lock_mutex,                  /* lockfunc */
+           &sc->vtnet_ack_mtx,                 /* lockarg */
+           &sc->vtnet_ack_dmat);
+       if (error) {
+               device_printf(dev, "cannot create bus_dma_tag\n");
+               goto fail;
+       }
+
 #ifdef __powerpc__
-       /*
-        * Virtio uses physical addresses rather than bus addresses, so we
-        * need to ask busdma to skip the iommu physical->bus mapping.  At
-        * present, this is only a thing on the powerpc architectures.
-        */
-       bus_dma_tag_set_iommu(sc->vtnet_rx_dmat, NULL, NULL);
-       bus_dma_tag_set_iommu(sc->vtnet_tx_dmat, NULL, NULL);
+        /*
+         * Virtio uses physical addresses rather than bus addresses, so we
+         * need to ask busdma to skip the iommu physical->bus mapping.  At
+         * present, this is only a thing on the powerpc architectures.
+         */
+        bus_dma_tag_set_iommu(sc->vtnet_rx_dmat, NULL, NULL);
+        bus_dma_tag_set_iommu(sc->vtnet_tx_dmat, NULL, NULL);
+        bus_dma_tag_set_iommu(sc->vtnet_hdr_dmat, NULL, NULL);
+        bus_dma_tag_set_iommu(sc->vtnet_ack_dmat, NULL, NULL);
 #endif
 
        error = vtnet_alloc_rx_filters(sc);
@@ -3774,10 +3820,43 @@ vtnet_free_ctrl_vq(struct vtnet_softc *sc)
 }
 
 static void
-vtnet_exec_ctrl_cmd(struct vtnet_softc *sc, void *cookie,
-    struct sglist *sg, int readable, int writable)
+vtnet_load_callback(void *arg, bus_dma_segment_t *segs, int nsegs,
+    int error)
 {
+       bus_addr_t *paddr;
+
+       if (error != 0)
+               return;
+
+       KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs));
+
+       paddr = (bus_addr_t *)arg;
+       *paddr = segs[0].ds_addr;
+}
+
+static int
+vtnet_exec_ctrl_cmd(struct vtnet_softc *sc, uint8_t *ack, struct sglist *sg,
+    int readable, int writable)
+{
+       bus_dmamap_t ack_dmap;
+       bus_addr_t ack_paddr;
        struct virtqueue *vq;
+       int error;
+
+       error = bus_dmamap_create(sc->vtnet_ack_dmat, 0, &ack_dmap);
+       if (error)
+               goto error_out;
+
+       error = bus_dmamap_load(sc->vtnet_ack_dmat, ack_dmap, ack,
+           sizeof(uint8_t), vtnet_load_callback, &ack_paddr, BUS_DMA_NOWAIT);
+       if (error)
+               goto error_destroy;
+
+       bus_dmamap_sync(sc->vtnet_ack_dmat, ack_dmap, BUS_DMASYNC_PREWRITE);
+
+       error = sglist_append_phys(sg, ack_paddr, sizeof(uint8_t));
+       if (error)
+               goto error_unload;
 
        vq = sc->vtnet_ctrl_vq;
 
@@ -3785,152 +3864,237 @@ vtnet_exec_ctrl_cmd(struct vtnet_softc *sc, void 
*cookie,
        VTNET_CORE_LOCK_ASSERT(sc);
 
        if (!virtqueue_empty(vq))
-               return;
+               goto error_unload;
 
        /*
         * Poll for the response, but the command is likely completed before
         * returning from the notify.
         */
-       if (virtqueue_enqueue(vq, cookie, sg, readable, writable) == 0)  {
+       if (virtqueue_enqueue(vq, (void *)ack, sg, readable, writable) == 0)  {
                virtqueue_notify(vq);
                virtqueue_poll(vq, NULL);
        }
+
+       bus_dmamap_sync(sc->vtnet_ack_dmat, ack_dmap, BUS_DMASYNC_POSTREAD);
+
+error_unload:
+       bus_dmamap_unload(sc->vtnet_ack_dmat, ack_dmap);
+error_destroy:
+       bus_dmamap_destroy(sc->vtnet_ack_dmat, ack_dmap);
+error_out:
+       return (error);
 }
 
 static int
 vtnet_ctrl_mac_cmd(struct vtnet_softc *sc, uint8_t *hwaddr)
 {
        struct sglist_seg segs[3];
+       bus_dmamap_t hdr_dmap;
+       bus_addr_t hdr_paddr;
        struct sglist sg;
        struct {
                struct virtio_net_ctrl_hdr hdr __aligned(2);
                uint8_t pad1;
                uint8_t addr[ETHER_ADDR_LEN] __aligned(8);
                uint8_t pad2;
-               uint8_t ack;
        } s;
+       uint8_t ack;
        int error;
 
-       error = 0;
+       error = bus_dmamap_create(sc->vtnet_hdr_dmat, 0, &hdr_dmap);
+       if (error)
+               goto error_out;
+
+       error = bus_dmamap_load(sc->vtnet_hdr_dmat, hdr_dmap, &s,
+           sizeof(s), vtnet_load_callback, &hdr_paddr, BUS_DMA_NOWAIT);
+       if (error)
+               goto error_destroy_hdr;
+
        MPASS(sc->vtnet_flags & VTNET_FLAG_CTRL_MAC);
 
        s.hdr.class = VIRTIO_NET_CTRL_MAC;
        s.hdr.cmd = VIRTIO_NET_CTRL_MAC_ADDR_SET;
        bcopy(hwaddr, &s.addr[0], ETHER_ADDR_LEN);
-       s.ack = VIRTIO_NET_ERR;
+       ack = VIRTIO_NET_ERR;
+       bus_dmamap_sync(sc->vtnet_hdr_dmat, hdr_dmap, BUS_DMASYNC_PREWRITE);
 
        sglist_init(&sg, nitems(segs), segs);
-       error |= sglist_append(&sg, &s.hdr, sizeof(struct virtio_net_ctrl_hdr));
-       error |= sglist_append(&sg, &s.addr[0], ETHER_ADDR_LEN);
-       error |= sglist_append(&sg, &s.ack, sizeof(uint8_t));
-       MPASS(error == 0 && sg.sg_nseg == nitems(segs));
+       error |= sglist_append_phys(&sg, hdr_paddr,
+           sizeof(struct virtio_net_ctrl_hdr));
+       error |= sglist_append_phys(&sg,
+           hdr_paddr + ((uintptr_t)&s.addr - (uintptr_t)&s),
+           ETHER_ADDR_LEN);
+       MPASS(error == 0 && sg.sg_nseg == nitems(segs) - 1);
 
        if (error == 0)
-               vtnet_exec_ctrl_cmd(sc, &s.ack, &sg, sg.sg_nseg - 1, 1);
+               error = vtnet_exec_ctrl_cmd(sc, &ack, &sg, sg.sg_nseg, 1);
+       if (error == 0)
+               error = (ack == VIRTIO_NET_OK ? 0 : EIO);
 
-       return (s.ack == VIRTIO_NET_OK ? 0 : EIO);
+       bus_dmamap_unload(sc->vtnet_hdr_dmat, hdr_dmap);
+error_destroy_hdr:
+       bus_dmamap_destroy(sc->vtnet_hdr_dmat, hdr_dmap);
+error_out:
+       return (error);
 }
 
 static int
 vtnet_ctrl_guest_offloads(struct vtnet_softc *sc, uint64_t offloads)
 {
        struct sglist_seg segs[3];
+       bus_dmamap_t hdr_dmap;
+       bus_addr_t hdr_paddr;
        struct sglist sg;
        struct {
                struct virtio_net_ctrl_hdr hdr __aligned(2);
                uint8_t pad1;
                uint64_t offloads __aligned(8);
                uint8_t pad2;
-               uint8_t ack;
        } s;
+       uint8_t ack;
        int error;
 
-       error = 0;
+       error = bus_dmamap_create(sc->vtnet_hdr_dmat, 0, &hdr_dmap);
+       if (error)
+               goto error_out;
+
+       error = bus_dmamap_load(sc->vtnet_hdr_dmat, hdr_dmap, &s,
+           sizeof(s), vtnet_load_callback, &hdr_paddr, BUS_DMA_NOWAIT);
+       if (error)
+               goto error_destroy_hdr;
+
        MPASS(sc->vtnet_features & VIRTIO_NET_F_CTRL_GUEST_OFFLOADS);
 
        s.hdr.class = VIRTIO_NET_CTRL_GUEST_OFFLOADS;
        s.hdr.cmd = VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET;
        s.offloads = vtnet_gtoh64(sc, offloads);
-       s.ack = VIRTIO_NET_ERR;
+       ack = VIRTIO_NET_ERR;
+       bus_dmamap_sync(sc->vtnet_hdr_dmat, hdr_dmap, BUS_DMASYNC_PREWRITE);
 
        sglist_init(&sg, nitems(segs), segs);
-       error |= sglist_append(&sg, &s.hdr, sizeof(struct virtio_net_ctrl_hdr));
-       error |= sglist_append(&sg, &s.offloads, sizeof(uint64_t));
-       error |= sglist_append(&sg, &s.ack, sizeof(uint8_t));
-       MPASS(error == 0 && sg.sg_nseg == nitems(segs));
+       error |= sglist_append_phys(&sg, hdr_paddr,
+           sizeof(struct virtio_net_ctrl_hdr));
+       error |= sglist_append_phys(&sg,
+           hdr_paddr + ((uintptr_t)&s.offloads - (uintptr_t)&s),
+           sizeof(uint64_t));
+       MPASS(error == 0 && sg.sg_nseg == nitems(segs) - 1);
 
        if (error == 0)
-               vtnet_exec_ctrl_cmd(sc, &s.ack, &sg, sg.sg_nseg - 1, 1);
+               error = vtnet_exec_ctrl_cmd(sc, &ack, &sg, sg.sg_nseg, 1);
+       if (error == 0)
+               error = (ack == VIRTIO_NET_OK ? 0 : EIO);
 
-       return (s.ack == VIRTIO_NET_OK ? 0 : EIO);
+       bus_dmamap_unload(sc->vtnet_hdr_dmat, hdr_dmap);
+error_destroy_hdr:
+       bus_dmamap_destroy(sc->vtnet_hdr_dmat, hdr_dmap);
+error_out:
+       return (error);
 }
 
 static int
 vtnet_ctrl_mq_cmd(struct vtnet_softc *sc, uint16_t npairs)
 {
        struct sglist_seg segs[3];
+       bus_dmamap_t hdr_dmap;
+       bus_addr_t hdr_paddr;
        struct sglist sg;
        struct {
                struct virtio_net_ctrl_hdr hdr __aligned(2);
                uint8_t pad1;
                struct virtio_net_ctrl_mq mq __aligned(2);
                uint8_t pad2;
-               uint8_t ack;
        } s;
+       uint8_t ack;
        int error;
 
-       error = 0;
+       error = bus_dmamap_create(sc->vtnet_hdr_dmat, 0, &hdr_dmap);
+       if (error)
+               goto error_out;
+
+       error = bus_dmamap_load(sc->vtnet_hdr_dmat, hdr_dmap, &s,
+           sizeof(s), vtnet_load_callback, &hdr_paddr, BUS_DMA_NOWAIT);
+       if (error)
+               goto error_destroy_hdr;
+
        MPASS(sc->vtnet_flags & VTNET_FLAG_MQ);
 
        s.hdr.class = VIRTIO_NET_CTRL_MQ;
        s.hdr.cmd = VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET;
        s.mq.virtqueue_pairs = vtnet_gtoh16(sc, npairs);
-       s.ack = VIRTIO_NET_ERR;
+       ack = VIRTIO_NET_ERR;
+       bus_dmamap_sync(sc->vtnet_hdr_dmat, hdr_dmap, BUS_DMASYNC_PREWRITE);
 
        sglist_init(&sg, nitems(segs), segs);
-       error |= sglist_append(&sg, &s.hdr, sizeof(struct virtio_net_ctrl_hdr));
-       error |= sglist_append(&sg, &s.mq, sizeof(struct virtio_net_ctrl_mq));
-       error |= sglist_append(&sg, &s.ack, sizeof(uint8_t));
-       MPASS(error == 0 && sg.sg_nseg == nitems(segs));
+       error |= sglist_append_phys(&sg, hdr_paddr,
+           sizeof(struct virtio_net_ctrl_hdr));
+       error |= sglist_append_phys(&sg,
+           hdr_paddr + ((uintptr_t)&s.mq - (uintptr_t)&s),
+           sizeof(struct virtio_net_ctrl_mq));
+       MPASS(error == 0 && sg.sg_nseg == nitems(segs) - 1);
 
        if (error == 0)
-               vtnet_exec_ctrl_cmd(sc, &s.ack, &sg, sg.sg_nseg - 1, 1);
+               error = vtnet_exec_ctrl_cmd(sc, &ack, &sg, sg.sg_nseg, 1);
+       if (error == 0)
+               error = (ack == VIRTIO_NET_OK ? 0 : EIO);
 
-       return (s.ack == VIRTIO_NET_OK ? 0 : EIO);
+       bus_dmamap_unload(sc->vtnet_hdr_dmat, hdr_dmap);
+error_destroy_hdr:
+       bus_dmamap_destroy(sc->vtnet_hdr_dmat, hdr_dmap);
+error_out:
+       return (error);
 }
 
 static int
 vtnet_ctrl_rx_cmd(struct vtnet_softc *sc, uint8_t cmd, bool on)
 {
        struct sglist_seg segs[3];
+       bus_dmamap_t hdr_dmap;
+       bus_addr_t hdr_paddr;
        struct sglist sg;
        struct {
                struct virtio_net_ctrl_hdr hdr __aligned(2);
                uint8_t pad1;
                uint8_t onoff;
                uint8_t pad2;
-               uint8_t ack;
        } s;
+       uint8_t ack;
        int error;
 
-       error = 0;
+       error = bus_dmamap_create(sc->vtnet_hdr_dmat, 0, &hdr_dmap);
+       if (error)
+               goto error_out;
+
+       error = bus_dmamap_load(sc->vtnet_hdr_dmat, hdr_dmap, &s,
+           sizeof(s), vtnet_load_callback, &hdr_paddr, BUS_DMA_NOWAIT);
+       if (error)
+               goto error_destroy_hdr;
+
        MPASS(sc->vtnet_flags & VTNET_FLAG_CTRL_RX);
 
        s.hdr.class = VIRTIO_NET_CTRL_RX;
        s.hdr.cmd = cmd;
        s.onoff = on;
-       s.ack = VIRTIO_NET_ERR;
+       ack = VIRTIO_NET_ERR;
+       bus_dmamap_sync(sc->vtnet_hdr_dmat, hdr_dmap, BUS_DMASYNC_PREWRITE);
 
        sglist_init(&sg, nitems(segs), segs);
-       error |= sglist_append(&sg, &s.hdr, sizeof(struct virtio_net_ctrl_hdr));
-       error |= sglist_append(&sg, &s.onoff, sizeof(uint8_t));
-       error |= sglist_append(&sg, &s.ack, sizeof(uint8_t));
-       MPASS(error == 0 && sg.sg_nseg == nitems(segs));
+       error |= sglist_append_phys(&sg, hdr_paddr,
+           sizeof(struct virtio_net_ctrl_hdr));
+       error |= sglist_append_phys(&sg,
+           hdr_paddr + ((uintptr_t)&s.onoff - (uintptr_t)&s),
+           sizeof(uint8_t));
+       MPASS(error == 0 && sg.sg_nseg == nitems(segs) - 1);
 
        if (error == 0)
-               vtnet_exec_ctrl_cmd(sc, &s.ack, &sg, sg.sg_nseg - 1, 1);
+               error = vtnet_exec_ctrl_cmd(sc, &ack, &sg, sg.sg_nseg, 1);
+       if (error == 0)
+               error = (ack == VIRTIO_NET_OK ? 0 : EIO);
 
-       return (s.ack == VIRTIO_NET_OK ? 0 : EIO);
+       bus_dmamap_unload(sc->vtnet_hdr_dmat, hdr_dmap);
+error_destroy_hdr:
+       bus_dmamap_destroy(sc->vtnet_hdr_dmat, hdr_dmap);
+error_out:
+       return (error);
 }
 
 static int
@@ -4001,6 +4165,10 @@ vtnet_rx_filter_mac(struct vtnet_softc *sc)
        struct virtio_net_ctrl_hdr hdr __aligned(2);
        struct vtnet_mac_filter *filter;
        struct sglist_seg segs[4];
+       bus_dmamap_t filter_dmap;
+       bus_addr_t filter_paddr;
+       bus_dmamap_t hdr_dmap;
+       bus_addr_t hdr_paddr;
        struct sglist sg;
        if_t ifp;
        bool promisc, allmulti;
@@ -4040,6 +4208,25 @@ vtnet_rx_filter_mac(struct vtnet_softc *sc)
        if (promisc && allmulti)
                goto out;
 
+       error = bus_dmamap_create(sc->vtnet_hdr_dmat, 0, &hdr_dmap);
+       if (error)
+               goto out_error;
+
+       error = bus_dmamap_load(sc->vtnet_hdr_dmat, hdr_dmap, &hdr,
+           sizeof(hdr), vtnet_load_callback, &hdr_paddr, BUS_DMA_NOWAIT);
+       if (error)
+               goto out_destroy_hdr;
+
+       error = bus_dmamap_create(sc->vtnet_hdr_dmat, 0, &filter_dmap);
+       if (error)
+               goto out_unload_hdr;
+
+       error = bus_dmamap_load(sc->vtnet_hdr_dmat, hdr_dmap, filter,
+           sizeof(*filter), vtnet_load_callback, &filter_paddr,
+           BUS_DMA_NOWAIT);
+       if (error)
+               goto out_destroy_filter;
+
        filter->vmf_unicast.nentries = vtnet_gtoh32(sc, ucnt);
        filter->vmf_multicast.nentries = vtnet_gtoh32(sc, mcnt);
 
@@ -4048,19 +4235,33 @@ vtnet_rx_filter_mac(struct vtnet_softc *sc)
        ack = VIRTIO_NET_ERR;
 
        sglist_init(&sg, nitems(segs), segs);
-       error |= sglist_append(&sg, &hdr, sizeof(struct virtio_net_ctrl_hdr));
-       error |= sglist_append(&sg, &filter->vmf_unicast,
+       error |= sglist_append_phys(&sg, hdr_paddr,
+           sizeof(struct virtio_net_ctrl_hdr));
+       error |= sglist_append_phys(&sg,
+           filter_paddr + ((uintptr_t)&filter->vmf_unicast -
+           (uintptr_t)filter),
            sizeof(uint32_t) + ucnt * ETHER_ADDR_LEN);
-       error |= sglist_append(&sg, &filter->vmf_multicast,
+       error |= sglist_append_phys(&sg,
+           filter_paddr + ((uintptr_t)&filter->vmf_multicast -
+           (uintptr_t)filter),
            sizeof(uint32_t) + mcnt * ETHER_ADDR_LEN);
-       error |= sglist_append(&sg, &ack, sizeof(uint8_t));
-       MPASS(error == 0 && sg.sg_nseg == nitems(segs));
+       MPASS(error == 0 && sg.sg_nseg == nitems(segs) - 1);
 
        if (error == 0)
-               vtnet_exec_ctrl_cmd(sc, &ack, &sg, sg.sg_nseg - 1, 1);
-       if (ack != VIRTIO_NET_OK)
+               error = vtnet_exec_ctrl_cmd(sc, &ack, &sg, sg.sg_nseg, 1);
+       if (error == 0)
+               error = (ack == VIRTIO_NET_OK ? 0 : EIO);
+
+       bus_dmamap_unload(sc->vtnet_hdr_dmat, filter_dmap);
+out_destroy_filter:
+       bus_dmamap_destroy(sc->vtnet_hdr_dmat, filter_dmap);
+out_unload_hdr:
+       bus_dmamap_unload(sc->vtnet_hdr_dmat, hdr_dmap);
+out_destroy_hdr:
+       bus_dmamap_destroy(sc->vtnet_hdr_dmat, hdr_dmap);
+out_error:
+       if (error != 0)
                if_printf(ifp, "error setting host MAC filter table\n");
-
 out:
        if (promisc && vtnet_set_promisc(sc, true) != 0)
                if_printf(ifp, "cannot enable promiscuous mode\n");
@@ -4072,34 +4273,53 @@ static int
 vtnet_exec_vlan_filter(struct vtnet_softc *sc, int add, uint16_t tag)
 {
        struct sglist_seg segs[3];
+       bus_dmamap_t hdr_dmap;
+       bus_addr_t hdr_paddr;
        struct sglist sg;
        struct {
                struct virtio_net_ctrl_hdr hdr __aligned(2);
                uint8_t pad1;
                uint16_t tag __aligned(2);
                uint8_t pad2;
-               uint8_t ack;
        } s;
+       uint8_t ack;
        int error;
 
-       error = 0;
+       error = bus_dmamap_create(sc->vtnet_hdr_dmat, 0, &hdr_dmap);
+       if (error)
+               goto error_out;
+
+       error = bus_dmamap_load(sc->vtnet_hdr_dmat, hdr_dmap, &s,
+           sizeof(s), vtnet_load_callback, &hdr_paddr, BUS_DMA_NOWAIT);
+       if (error)
+               goto error_destroy_hdr;
+
        MPASS(sc->vtnet_flags & VTNET_FLAG_VLAN_FILTER);
 
        s.hdr.class = VIRTIO_NET_CTRL_VLAN;
        s.hdr.cmd = add ? VIRTIO_NET_CTRL_VLAN_ADD : VIRTIO_NET_CTRL_VLAN_DEL;
        s.tag = vtnet_gtoh16(sc, tag);
-       s.ack = VIRTIO_NET_ERR;
+       ack = VIRTIO_NET_ERR;
+       bus_dmamap_sync(sc->vtnet_hdr_dmat, hdr_dmap, BUS_DMASYNC_PREWRITE);
 
        sglist_init(&sg, nitems(segs), segs);
-       error |= sglist_append(&sg, &s.hdr, sizeof(struct virtio_net_ctrl_hdr));
-       error |= sglist_append(&sg, &s.tag, sizeof(uint16_t));
-       error |= sglist_append(&sg, &s.ack, sizeof(uint8_t));
-       MPASS(error == 0 && sg.sg_nseg == nitems(segs));
+       error |= sglist_append_phys(&sg, hdr_paddr,
+           sizeof(struct virtio_net_ctrl_hdr));
+       error |= sglist_append_phys(&sg,
+           hdr_paddr + ((uintptr_t)&s.tag - (uintptr_t)&s),
+           sizeof(uint16_t));
+       MPASS(error == 0 && sg.sg_nseg == nitems(segs) - 1);
 
        if (error == 0)
-               vtnet_exec_ctrl_cmd(sc, &s.ack, &sg, sg.sg_nseg - 1, 1);
+               error = vtnet_exec_ctrl_cmd(sc, &ack, &sg, sg.sg_nseg, 1);
+       if (error == 0)
+               error = (ack == VIRTIO_NET_OK ? 0 : EIO);
 
-       return (s.ack == VIRTIO_NET_OK ? 0 : EIO);
+       bus_dmamap_unload(sc->vtnet_hdr_dmat, hdr_dmap);
+error_destroy_hdr:
+       bus_dmamap_destroy(sc->vtnet_hdr_dmat, hdr_dmap);
+error_out:
+       return (error);
 }
 
 static void
diff --git a/sys/dev/virtio/network/if_vtnetvar.h 
b/sys/dev/virtio/network/if_vtnetvar.h
index 6cafe827d733..e445bdf6d6cb 100644
--- a/sys/dev/virtio/network/if_vtnetvar.h
+++ b/sys/dev/virtio/network/if_vtnetvar.h
@@ -196,6 +196,12 @@ struct vtnet_softc {
 
        bus_dma_tag_t            vtnet_tx_dmat;
        struct mtx               vtnet_tx_mtx;
+
+       bus_dma_tag_t            vtnet_hdr_dmat;
+       struct mtx               vtnet_hdr_mtx;
+
+       bus_dma_tag_t            vtnet_ack_dmat;
+       struct mtx               vtnet_ack_mtx;
 };
 /* vtnet flag descriptions for use with printf(9) %b identifier. */
 #define VTNET_FLAGS_BITS \

Reply via email to