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