diff options
author | Daniel Baumann <mail@daniel-baumann.ch> | 2025-06-06 10:05:23 +0000 |
---|---|---|
committer | Daniel Baumann <mail@daniel-baumann.ch> | 2025-06-06 10:05:23 +0000 |
commit | 755cc582a2473d06f3a2131d506d0311cc70e9f9 (patch) | |
tree | 3efb1ddb8d57bbb4539ac0d229b384871c57820f /hw/rdma/vmw/pvrdma_dev_ring.c | |
parent | Initial commit. (diff) | |
download | qemu-upstream.tar.xz qemu-upstream.zip |
Adding upstream version 1:7.2+dfsg.upstream/1%7.2+dfsgupstream
Signed-off-by: Daniel Baumann <mail@daniel-baumann.ch>
Diffstat (limited to 'hw/rdma/vmw/pvrdma_dev_ring.c')
-rw-r--r-- | hw/rdma/vmw/pvrdma_dev_ring.c | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/hw/rdma/vmw/pvrdma_dev_ring.c b/hw/rdma/vmw/pvrdma_dev_ring.c new file mode 100644 index 00000000..598e6adc --- /dev/null +++ b/hw/rdma/vmw/pvrdma_dev_ring.c @@ -0,0 +1,142 @@ +/* + * QEMU paravirtual RDMA - Device rings + * + * Copyright (C) 2018 Oracle + * Copyright (C) 2018 Red Hat Inc + * + * Authors: + * Yuval Shaia <yuval.shaia@oracle.com> + * Marcel Apfelbaum <marcel@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "qemu/cutils.h" +#include "hw/pci/pci.h" +#include "cpu.h" +#include "qemu/cutils.h" + +#include "trace.h" + +#include "../rdma_utils.h" +#include "pvrdma_dev_ring.h" + +int pvrdma_ring_init(PvrdmaRing *ring, const char *name, PCIDevice *dev, + PvrdmaRingState *ring_state, uint32_t max_elems, + size_t elem_sz, dma_addr_t *tbl, uint32_t npages) +{ + int i; + int rc = 0; + + pstrcpy(ring->name, MAX_RING_NAME_SZ, name); + ring->dev = dev; + ring->ring_state = ring_state; + ring->max_elems = max_elems; + ring->elem_sz = elem_sz; + /* TODO: Give a moment to think if we want to redo driver settings + qatomic_set(&ring->ring_state->prod_tail, 0); + qatomic_set(&ring->ring_state->cons_head, 0); + */ + ring->npages = npages; + ring->pages = g_new0(void *, npages); + + for (i = 0; i < npages; i++) { + if (!tbl[i]) { + rdma_error_report("npages=%d but tbl[%d] is NULL", npages, i); + continue; + } + + ring->pages[i] = rdma_pci_dma_map(dev, tbl[i], TARGET_PAGE_SIZE); + if (!ring->pages[i]) { + rc = -ENOMEM; + rdma_error_report("Failed to map to page %d in ring %s", i, name); + goto out_free; + } + memset(ring->pages[i], 0, TARGET_PAGE_SIZE); + } + + goto out; + +out_free: + while (i--) { + rdma_pci_dma_unmap(dev, ring->pages[i], TARGET_PAGE_SIZE); + } + g_free(ring->pages); + +out: + return rc; +} + +void *pvrdma_ring_next_elem_read(PvrdmaRing *ring) +{ + unsigned int idx, offset; + const uint32_t tail = qatomic_read(&ring->ring_state->prod_tail); + const uint32_t head = qatomic_read(&ring->ring_state->cons_head); + + if (tail & ~((ring->max_elems << 1) - 1) || + head & ~((ring->max_elems << 1) - 1) || + tail == head) { + trace_pvrdma_ring_next_elem_read_no_data(ring->name); + return NULL; + } + + idx = head & (ring->max_elems - 1); + offset = idx * ring->elem_sz; + return ring->pages[offset / TARGET_PAGE_SIZE] + (offset % TARGET_PAGE_SIZE); +} + +void pvrdma_ring_read_inc(PvrdmaRing *ring) +{ + uint32_t idx = qatomic_read(&ring->ring_state->cons_head); + + idx = (idx + 1) & ((ring->max_elems << 1) - 1); + qatomic_set(&ring->ring_state->cons_head, idx); +} + +void *pvrdma_ring_next_elem_write(PvrdmaRing *ring) +{ + unsigned int idx, offset; + const uint32_t tail = qatomic_read(&ring->ring_state->prod_tail); + const uint32_t head = qatomic_read(&ring->ring_state->cons_head); + + if (tail & ~((ring->max_elems << 1) - 1) || + head & ~((ring->max_elems << 1) - 1) || + tail == (head ^ ring->max_elems)) { + rdma_error_report("CQ is full"); + return NULL; + } + + idx = tail & (ring->max_elems - 1); + offset = idx * ring->elem_sz; + return ring->pages[offset / TARGET_PAGE_SIZE] + (offset % TARGET_PAGE_SIZE); +} + +void pvrdma_ring_write_inc(PvrdmaRing *ring) +{ + uint32_t idx = qatomic_read(&ring->ring_state->prod_tail); + + idx = (idx + 1) & ((ring->max_elems << 1) - 1); + qatomic_set(&ring->ring_state->prod_tail, idx); +} + +void pvrdma_ring_free(PvrdmaRing *ring) +{ + if (!ring) { + return; + } + + if (!ring->pages) { + return; + } + + while (ring->npages--) { + rdma_pci_dma_unmap(ring->dev, ring->pages[ring->npages], + TARGET_PAGE_SIZE); + } + + g_free(ring->pages); + ring->pages = NULL; +} |