]>
Commit | Line | Data |
---|---|---|
98d176f8 YS |
1 | /* |
2 | * QEMU paravirtual RDMA - Device rings | |
3 | * | |
4 | * Copyright (C) 2018 Oracle | |
5 | * Copyright (C) 2018 Red Hat Inc | |
6 | * | |
7 | * Authors: | |
8 | * Yuval Shaia <yuval.shaia@oracle.com> | |
9 | * Marcel Apfelbaum <marcel@redhat.com> | |
10 | * | |
11 | * This work is licensed under the terms of the GNU GPL, version 2 or later. | |
12 | * See the COPYING file in the top-level directory. | |
13 | * | |
14 | */ | |
15 | ||
0efc9511 MT |
16 | #include "qemu/osdep.h" |
17 | #include "hw/pci/pci.h" | |
18 | #include "cpu.h" | |
1d2695ef | 19 | #include "qemu/cutils.h" |
98d176f8 | 20 | |
4d71b38a YS |
21 | #include "trace.h" |
22 | ||
98d176f8 | 23 | #include "../rdma_utils.h" |
98d176f8 YS |
24 | #include "pvrdma_dev_ring.h" |
25 | ||
26 | int pvrdma_ring_init(PvrdmaRing *ring, const char *name, PCIDevice *dev, | |
3aa1b7af | 27 | PvrdmaRingState *ring_state, uint32_t max_elems, |
6f559013 | 28 | size_t elem_sz, dma_addr_t *tbl, uint32_t npages) |
98d176f8 YS |
29 | { |
30 | int i; | |
31 | int rc = 0; | |
32 | ||
1d2695ef | 33 | pstrcpy(ring->name, MAX_RING_NAME_SZ, name); |
98d176f8 YS |
34 | ring->dev = dev; |
35 | ring->ring_state = ring_state; | |
36 | ring->max_elems = max_elems; | |
37 | ring->elem_sz = elem_sz; | |
98d176f8 | 38 | /* TODO: Give a moment to think if we want to redo driver settings |
d73415a3 SH |
39 | qatomic_set(&ring->ring_state->prod_tail, 0); |
40 | qatomic_set(&ring->ring_state->cons_head, 0); | |
98d176f8 YS |
41 | */ |
42 | ring->npages = npages; | |
b21e2380 | 43 | ring->pages = g_new0(void *, npages); |
98d176f8 YS |
44 | |
45 | for (i = 0; i < npages; i++) { | |
46 | if (!tbl[i]) { | |
4d71b38a | 47 | rdma_error_report("npages=%d but tbl[%d] is NULL", npages, i); |
98d176f8 YS |
48 | continue; |
49 | } | |
50 | ||
51 | ring->pages[i] = rdma_pci_dma_map(dev, tbl[i], TARGET_PAGE_SIZE); | |
52 | if (!ring->pages[i]) { | |
53 | rc = -ENOMEM; | |
4d71b38a | 54 | rdma_error_report("Failed to map to page %d in ring %s", i, name); |
98d176f8 YS |
55 | goto out_free; |
56 | } | |
57 | memset(ring->pages[i], 0, TARGET_PAGE_SIZE); | |
58 | } | |
59 | ||
60 | goto out; | |
61 | ||
62 | out_free: | |
63 | while (i--) { | |
64 | rdma_pci_dma_unmap(dev, ring->pages[i], TARGET_PAGE_SIZE); | |
65 | } | |
66 | g_free(ring->pages); | |
67 | ||
68 | out: | |
69 | return rc; | |
70 | } | |
71 | ||
72 | void *pvrdma_ring_next_elem_read(PvrdmaRing *ring) | |
73 | { | |
3aa1b7af CH |
74 | unsigned int idx, offset; |
75 | const uint32_t tail = qatomic_read(&ring->ring_state->prod_tail); | |
76 | const uint32_t head = qatomic_read(&ring->ring_state->cons_head); | |
98d176f8 | 77 | |
3aa1b7af CH |
78 | if (tail & ~((ring->max_elems << 1) - 1) || |
79 | head & ~((ring->max_elems << 1) - 1) || | |
80 | tail == head) { | |
4d71b38a | 81 | trace_pvrdma_ring_next_elem_read_no_data(ring->name); |
98d176f8 YS |
82 | return NULL; |
83 | } | |
84 | ||
3aa1b7af | 85 | idx = head & (ring->max_elems - 1); |
98d176f8 | 86 | offset = idx * ring->elem_sz; |
98d176f8 YS |
87 | return ring->pages[offset / TARGET_PAGE_SIZE] + (offset % TARGET_PAGE_SIZE); |
88 | } | |
89 | ||
90 | void pvrdma_ring_read_inc(PvrdmaRing *ring) | |
91 | { | |
3aa1b7af CH |
92 | uint32_t idx = qatomic_read(&ring->ring_state->cons_head); |
93 | ||
94 | idx = (idx + 1) & ((ring->max_elems << 1) - 1); | |
95 | qatomic_set(&ring->ring_state->cons_head, idx); | |
98d176f8 YS |
96 | } |
97 | ||
98 | void *pvrdma_ring_next_elem_write(PvrdmaRing *ring) | |
99 | { | |
3aa1b7af CH |
100 | unsigned int idx, offset; |
101 | const uint32_t tail = qatomic_read(&ring->ring_state->prod_tail); | |
102 | const uint32_t head = qatomic_read(&ring->ring_state->cons_head); | |
98d176f8 | 103 | |
3aa1b7af CH |
104 | if (tail & ~((ring->max_elems << 1) - 1) || |
105 | head & ~((ring->max_elems << 1) - 1) || | |
106 | tail == (head ^ ring->max_elems)) { | |
4d71b38a | 107 | rdma_error_report("CQ is full"); |
98d176f8 YS |
108 | return NULL; |
109 | } | |
110 | ||
3aa1b7af | 111 | idx = tail & (ring->max_elems - 1); |
98d176f8 YS |
112 | offset = idx * ring->elem_sz; |
113 | return ring->pages[offset / TARGET_PAGE_SIZE] + (offset % TARGET_PAGE_SIZE); | |
114 | } | |
115 | ||
116 | void pvrdma_ring_write_inc(PvrdmaRing *ring) | |
117 | { | |
3aa1b7af CH |
118 | uint32_t idx = qatomic_read(&ring->ring_state->prod_tail); |
119 | ||
120 | idx = (idx + 1) & ((ring->max_elems << 1) - 1); | |
121 | qatomic_set(&ring->ring_state->prod_tail, idx); | |
98d176f8 YS |
122 | } |
123 | ||
124 | void pvrdma_ring_free(PvrdmaRing *ring) | |
125 | { | |
126 | if (!ring) { | |
127 | return; | |
128 | } | |
129 | ||
130 | if (!ring->pages) { | |
131 | return; | |
132 | } | |
133 | ||
98d176f8 YS |
134 | while (ring->npages--) { |
135 | rdma_pci_dma_unmap(ring->dev, ring->pages[ring->npages], | |
136 | TARGET_PAGE_SIZE); | |
137 | } | |
138 | ||
139 | g_free(ring->pages); | |
140 | ring->pages = NULL; | |
141 | } |