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