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