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