xref: /openbmc/qemu/hw/net/rocker/rocker_desc.c (revision 4a09d0bb)
1 /*
2  * QEMU rocker switch emulation - Descriptor ring support
3  *
4  * Copyright (c) 2014 Scott Feldman <sfeldma@gmail.com>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
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 
26 struct 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 
40 struct desc_info {
41     DescRing *ring;
42     RockerDesc desc;
43     char *buf;
44     size_t buf_size;
45 };
46 
47 uint16_t desc_buf_size(DescInfo *info)
48 {
49     return le16_to_cpu(info->desc.buf_size);
50 }
51 
52 uint16_t desc_tlv_size(DescInfo *info)
53 {
54     return le16_to_cpu(info->desc.tlv_size);
55 }
56 
57 char *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 
79 int 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 
96 DescRing *desc_get_ring(DescInfo *info)
97 {
98     return info->ring;
99 }
100 
101 int desc_ring_index(DescRing *ring)
102 {
103     return ring->index;
104 }
105 
106 static bool desc_ring_empty(DescRing *ring)
107 {
108     return ring->head == ring->tail;
109 }
110 
111 bool 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 
124 uint64_t desc_ring_get_base_addr(DescRing *ring)
125 {
126     return ring->base_addr;
127 }
128 
129 bool 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 
160 uint32_t desc_ring_get_size(DescRing *ring)
161 {
162     return ring->size;
163 }
164 
165 static 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 
176 static 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 
185 static 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 
195 static DescInfo *__desc_ring_fetch_desc(DescRing *ring)
196 {
197     return desc_read(ring, ring->tail);
198 }
199 
200 DescInfo *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 
209 static 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     /* return true if starting credit count */
219 
220     return ring->credits++ == 0;
221 }
222 
223 bool 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 
238 static bool ring_pump(DescRing *ring)
239 {
240     DescInfo *info;
241     bool primed = false;
242     int err;
243 
244     /* If the ring has a consumer, call consumer for each
245      * desc starting at tail and stopping when tail reaches
246      * head (the empty ring condition).
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 
262 bool 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 
294 uint32_t desc_ring_get_head(DescRing *ring)
295 {
296     return ring->head;
297 }
298 
299 uint32_t desc_ring_get_tail(DescRing *ring)
300 {
301     return ring->tail;
302 }
303 
304 void 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 
312 bool 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     /* return true if credits are still outstanding */
324 
325     return ring->credits > 0;
326 }
327 
328 uint32_t desc_ring_get_credits(DescRing *ring)
329 {
330     return ring->credits;
331 }
332 
333 void 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 
340 unsigned desc_ring_get_msix_vector(DescRing *ring)
341 {
342     return ring->msix_vector;
343 }
344 
345 DescRing *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 
360 void desc_ring_free(DescRing *ring)
361 {
362     g_free(ring->info);
363     g_free(ring);
364 }
365 
366 void 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