1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17#include "qemu/osdep.h"
18#include "net/net.h"
19#include "hw/pci/pci.h"
20
21#include "rocker.h"
22#include "rocker_hw.h"
23#include "rocker_desc.h"
24
25struct desc_ring {
26 hwaddr base_addr;
27 uint32_t size;
28 uint32_t head;
29 uint32_t tail;
30 uint32_t ctrl;
31 uint32_t credits;
32 Rocker *r;
33 DescInfo *info;
34 int index;
35 desc_ring_consume *consume;
36 unsigned msix_vector;
37};
38
39struct desc_info {
40 DescRing *ring;
41 RockerDesc desc;
42 char *buf;
43 size_t buf_size;
44};
45
46uint16_t desc_buf_size(DescInfo *info)
47{
48 return le16_to_cpu(info->desc.buf_size);
49}
50
51uint16_t desc_tlv_size(DescInfo *info)
52{
53 return le16_to_cpu(info->desc.tlv_size);
54}
55
56char *desc_get_buf(DescInfo *info, bool read_only)
57{
58 PCIDevice *dev = PCI_DEVICE(info->ring->r);
59 size_t size = read_only ? le16_to_cpu(info->desc.tlv_size) :
60 le16_to_cpu(info->desc.buf_size);
61
62 if (size > info->buf_size) {
63 info->buf = g_realloc(info->buf, size);
64 info->buf_size = size;
65 }
66
67 pci_dma_read(dev, le64_to_cpu(info->desc.buf_addr), info->buf, size);
68
69 return info->buf;
70}
71
72int desc_set_buf(DescInfo *info, size_t tlv_size)
73{
74 PCIDevice *dev = PCI_DEVICE(info->ring->r);
75
76 if (tlv_size > info->buf_size) {
77 DPRINTF("ERROR: trying to write more to desc buf than it "
78 "can hold buf_size %zu tlv_size %zu\n",
79 info->buf_size, tlv_size);
80 return -ROCKER_EMSGSIZE;
81 }
82
83 info->desc.tlv_size = cpu_to_le16(tlv_size);
84 pci_dma_write(dev, le64_to_cpu(info->desc.buf_addr), info->buf, tlv_size);
85
86 return ROCKER_OK;
87}
88
89DescRing *desc_get_ring(DescInfo *info)
90{
91 return info->ring;
92}
93
94int desc_ring_index(DescRing *ring)
95{
96 return ring->index;
97}
98
99static bool desc_ring_empty(DescRing *ring)
100{
101 return ring->head == ring->tail;
102}
103
104bool desc_ring_set_base_addr(DescRing *ring, uint64_t base_addr)
105{
106 if (base_addr & 0x7) {
107 DPRINTF("ERROR: ring[%d] desc base addr (0x" TARGET_FMT_plx
108 ") not 8-byte aligned\n", ring->index, base_addr);
109 return false;
110 }
111
112 ring->base_addr = base_addr;
113
114 return true;
115}
116
117uint64_t desc_ring_get_base_addr(DescRing *ring)
118{
119 return ring->base_addr;
120}
121
122bool desc_ring_set_size(DescRing *ring, uint32_t size)
123{
124 int i;
125
126 if (size < 2 || size > 0x10000 || (size & (size - 1))) {
127 DPRINTF("ERROR: ring[%d] size (%d) not a power of 2 "
128 "or in range [2, 64K]\n", ring->index, size);
129 return false;
130 }
131
132 for (i = 0; i < ring->size; i++) {
133 g_free(ring->info[i].buf);
134 }
135
136 ring->size = size;
137 ring->head = ring->tail = 0;
138
139 ring->info = g_renew(DescInfo, ring->info, size);
140
141 memset(ring->info, 0, size * sizeof(DescInfo));
142
143 for (i = 0; i < size; i++) {
144 ring->info[i].ring = ring;
145 }
146
147 return true;
148}
149
150uint32_t desc_ring_get_size(DescRing *ring)
151{
152 return ring->size;
153}
154
155static DescInfo *desc_read(DescRing *ring, uint32_t index)
156{
157 PCIDevice *dev = PCI_DEVICE(ring->r);
158 DescInfo *info = &ring->info[index];
159 hwaddr addr = ring->base_addr + (sizeof(RockerDesc) * index);
160
161 pci_dma_read(dev, addr, &info->desc, sizeof(info->desc));
162
163 return info;
164}
165
166static void desc_write(DescRing *ring, uint32_t index)
167{
168 PCIDevice *dev = PCI_DEVICE(ring->r);
169 DescInfo *info = &ring->info[index];
170 hwaddr addr = ring->base_addr + (sizeof(RockerDesc) * index);
171
172 pci_dma_write(dev, addr, &info->desc, sizeof(info->desc));
173}
174
175static bool desc_ring_base_addr_check(DescRing *ring)
176{
177 if (!ring->base_addr) {
178 DPRINTF("ERROR: ring[%d] not-initialized desc base address!\n",
179 ring->index);
180 return false;
181 }
182 return true;
183}
184
185static DescInfo *__desc_ring_fetch_desc(DescRing *ring)
186{
187 return desc_read(ring, ring->tail);
188}
189
190DescInfo *desc_ring_fetch_desc(DescRing *ring)
191{
192 if (desc_ring_empty(ring) || !desc_ring_base_addr_check(ring)) {
193 return NULL;
194 }
195
196 return desc_read(ring, ring->tail);
197}
198
199static bool __desc_ring_post_desc(DescRing *ring, int err)
200{
201 uint16_t comp_err = 0x8000 | (uint16_t)-err;
202 DescInfo *info = &ring->info[ring->tail];
203
204 info->desc.comp_err = cpu_to_le16(comp_err);
205 desc_write(ring, ring->tail);
206 ring->tail = (ring->tail + 1) % ring->size;
207
208
209
210 return ring->credits++ == 0;
211}
212
213bool desc_ring_post_desc(DescRing *ring, int err)
214{
215 if (desc_ring_empty(ring)) {
216 DPRINTF("ERROR: ring[%d] trying to post desc to empty ring\n",
217 ring->index);
218 return false;
219 }
220
221 if (!desc_ring_base_addr_check(ring)) {
222 return false;
223 }
224
225 return __desc_ring_post_desc(ring, err);
226}
227
228static bool ring_pump(DescRing *ring)
229{
230 DescInfo *info;
231 bool primed = false;
232 int err;
233
234
235
236
237
238
239 if (ring->consume) {
240 while (ring->head != ring->tail) {
241 info = __desc_ring_fetch_desc(ring);
242 err = ring->consume(ring->r, info);
243 if (__desc_ring_post_desc(ring, err)) {
244 primed = true;
245 }
246 }
247 }
248
249 return primed;
250}
251
252bool desc_ring_set_head(DescRing *ring, uint32_t new)
253{
254 uint32_t tail = ring->tail;
255 uint32_t head = ring->head;
256
257 if (!desc_ring_base_addr_check(ring)) {
258 return false;
259 }
260
261 if (new >= ring->size) {
262 DPRINTF("ERROR: trying to set head (%d) past ring[%d] size (%d)\n",
263 new, ring->index, ring->size);
264 return false;
265 }
266
267 if (((head < tail) && ((new >= tail) || (new < head))) ||
268 ((head > tail) && ((new >= tail) && (new < head)))) {
269 DPRINTF("ERROR: trying to wrap ring[%d] "
270 "(head %d, tail %d, new head %d)\n",
271 ring->index, head, tail, new);
272 return false;
273 }
274
275 if (new == ring->head) {
276 DPRINTF("WARNING: setting head (%d) to current head position\n", new);
277 }
278
279 ring->head = new;
280
281 return ring_pump(ring);
282}
283
284uint32_t desc_ring_get_head(DescRing *ring)
285{
286 return ring->head;
287}
288
289uint32_t desc_ring_get_tail(DescRing *ring)
290{
291 return ring->tail;
292}
293
294void desc_ring_set_ctrl(DescRing *ring, uint32_t val)
295{
296 if (val & ROCKER_DMA_DESC_CTRL_RESET) {
297 DPRINTF("ring[%d] resetting\n", ring->index);
298 desc_ring_reset(ring);
299 }
300}
301
302bool desc_ring_ret_credits(DescRing *ring, uint32_t credits)
303{
304 if (credits > ring->credits) {
305 DPRINTF("ERROR: trying to return more credits (%d) "
306 "than are outstanding (%d)\n", credits, ring->credits);
307 ring->credits = 0;
308 return false;
309 }
310
311 ring->credits -= credits;
312
313
314
315 return ring->credits > 0;
316}
317
318uint32_t desc_ring_get_credits(DescRing *ring)
319{
320 return ring->credits;
321}
322
323void desc_ring_set_consume(DescRing *ring, desc_ring_consume *consume,
324 unsigned vector)
325{
326 ring->consume = consume;
327 ring->msix_vector = vector;
328}
329
330unsigned desc_ring_get_msix_vector(DescRing *ring)
331{
332 return ring->msix_vector;
333}
334
335DescRing *desc_ring_alloc(Rocker *r, int index)
336{
337 DescRing *ring;
338
339 ring = g_new0(DescRing, 1);
340
341 ring->r = r;
342 ring->index = index;
343
344 return ring;
345}
346
347void desc_ring_free(DescRing *ring)
348{
349 g_free(ring->info);
350 g_free(ring);
351}
352
353void desc_ring_reset(DescRing *ring)
354{
355 ring->base_addr = 0;
356 ring->size = 0;
357 ring->head = 0;
358 ring->tail = 0;
359 ring->ctrl = 0;
360 ring->credits = 0;
361}
362