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 @@ -3978,6 +4142,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; @@ -4017,6 +4185,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); @@ -4025,19 +4212,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"); @@ -4049,34 +4250,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 \