rocker: Use g_new() & friends where that makes obvious sense
[qemu/ar7.git] / hw / net / rocker / rocker_desc.c
blob5e697b19e35e9278b708337be07d748cae7a54fe
1 /*
2 * QEMU rocker switch emulation - Descriptor ring support
4 * Copyright (c) 2014 Scott Feldman <sfeldma@gmail.com>
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.
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.
17 #include "net/net.h"
18 #include "hw/hw.h"
19 #include "hw/pci/pci.h"
21 #include "rocker.h"
22 #include "rocker_hw.h"
23 #include "rocker_desc.h"
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;
39 struct desc_info {
40 DescRing *ring;
41 RockerDesc desc;
42 char *buf;
43 size_t buf_size;
46 uint16_t desc_buf_size(DescInfo *info)
48 return le16_to_cpu(info->desc.buf_size);
51 uint16_t desc_tlv_size(DescInfo *info)
53 return le16_to_cpu(info->desc.tlv_size);
56 char *desc_get_buf(DescInfo *info, bool read_only)
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);
62 if (size > info->buf_size) {
63 info->buf = g_realloc(info->buf, size);
64 info->buf_size = size;
67 if (!info->buf) {
68 return NULL;
71 if (pci_dma_read(dev, le64_to_cpu(info->desc.buf_addr), info->buf, size)) {
72 return NULL;
75 return info->buf;
78 int desc_set_buf(DescInfo *info, size_t tlv_size)
80 PCIDevice *dev = PCI_DEVICE(info->ring->r);
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;
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);
92 return ROCKER_OK;
95 DescRing *desc_get_ring(DescInfo *info)
97 return info->ring;
100 int desc_ring_index(DescRing *ring)
102 return ring->index;
105 static bool desc_ring_empty(DescRing *ring)
107 return ring->head == ring->tail;
110 bool desc_ring_set_base_addr(DescRing *ring, uint64_t base_addr)
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;
118 ring->base_addr = base_addr;
120 return true;
123 uint64_t desc_ring_get_base_addr(DescRing *ring)
125 return ring->base_addr;
128 bool desc_ring_set_size(DescRing *ring, uint32_t size)
130 int i;
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;
138 for (i = 0; i < ring->size; i++) {
139 g_free(ring->info[i].buf);
142 ring->size = size;
143 ring->head = ring->tail = 0;
145 ring->info = g_renew(DescInfo, ring->info, size);
146 if (!ring->info) {
147 return false;
150 memset(ring->info, 0, size * sizeof(DescInfo));
152 for (i = 0; i < size; i++) {
153 ring->info[i].ring = ring;
156 return true;
159 uint32_t desc_ring_get_size(DescRing *ring)
161 return ring->size;
164 static DescInfo *desc_read(DescRing *ring, uint32_t index)
166 PCIDevice *dev = PCI_DEVICE(ring->r);
167 DescInfo *info = &ring->info[index];
168 hwaddr addr = ring->base_addr + (sizeof(RockerDesc) * index);
170 pci_dma_read(dev, addr, &info->desc, sizeof(info->desc));
172 return info;
175 static void desc_write(DescRing *ring, uint32_t index)
177 PCIDevice *dev = PCI_DEVICE(ring->r);
178 DescInfo *info = &ring->info[index];
179 hwaddr addr = ring->base_addr + (sizeof(RockerDesc) * index);
181 pci_dma_write(dev, addr, &info->desc, sizeof(info->desc));
184 static bool desc_ring_base_addr_check(DescRing *ring)
186 if (!ring->base_addr) {
187 DPRINTF("ERROR: ring[%d] not-initialized desc base address!\n",
188 ring->index);
189 return false;
191 return true;
194 static DescInfo *__desc_ring_fetch_desc(DescRing *ring)
196 return desc_read(ring, ring->tail);
199 DescInfo *desc_ring_fetch_desc(DescRing *ring)
201 if (desc_ring_empty(ring) || !desc_ring_base_addr_check(ring)) {
202 return NULL;
205 return desc_read(ring, ring->tail);
208 static bool __desc_ring_post_desc(DescRing *ring, int err)
210 uint16_t comp_err = 0x8000 | (uint16_t)-err;
211 DescInfo *info = &ring->info[ring->tail];
213 info->desc.comp_err = cpu_to_le16(comp_err);
214 desc_write(ring, ring->tail);
215 ring->tail = (ring->tail + 1) % ring->size;
217 /* return true if starting credit count */
219 return ring->credits++ == 0;
222 bool desc_ring_post_desc(DescRing *ring, int err)
224 if (desc_ring_empty(ring)) {
225 DPRINTF("ERROR: ring[%d] trying to post desc to empty ring\n",
226 ring->index);
227 return false;
230 if (!desc_ring_base_addr_check(ring)) {
231 return false;
234 return __desc_ring_post_desc(ring, err);
237 static bool ring_pump(DescRing *ring)
239 DescInfo *info;
240 bool primed = false;
241 int err;
243 /* If the ring has a consumer, call consumer for each
244 * desc starting at tail and stopping when tail reaches
245 * head (the empty ring condition).
248 if (ring->consume) {
249 while (ring->head != ring->tail) {
250 info = __desc_ring_fetch_desc(ring);
251 err = ring->consume(ring->r, info);
252 if (__desc_ring_post_desc(ring, err)) {
253 primed = true;
258 return primed;
261 bool desc_ring_set_head(DescRing *ring, uint32_t new)
263 uint32_t tail = ring->tail;
264 uint32_t head = ring->head;
266 if (!desc_ring_base_addr_check(ring)) {
267 return false;
270 if (new >= ring->size) {
271 DPRINTF("ERROR: trying to set head (%d) past ring[%d] size (%d)\n",
272 new, ring->index, ring->size);
273 return false;
276 if (((head < tail) && ((new >= tail) || (new < head))) ||
277 ((head > tail) && ((new >= tail) && (new < head)))) {
278 DPRINTF("ERROR: trying to wrap ring[%d] "
279 "(head %d, tail %d, new head %d)\n",
280 ring->index, head, tail, new);
281 return false;
284 if (new == ring->head) {
285 DPRINTF("WARNING: setting head (%d) to current head position\n", new);
288 ring->head = new;
290 return ring_pump(ring);
293 uint32_t desc_ring_get_head(DescRing *ring)
295 return ring->head;
298 uint32_t desc_ring_get_tail(DescRing *ring)
300 return ring->tail;
303 void desc_ring_set_ctrl(DescRing *ring, uint32_t val)
305 if (val & ROCKER_DMA_DESC_CTRL_RESET) {
306 DPRINTF("ring[%d] resetting\n", ring->index);
307 desc_ring_reset(ring);
311 bool desc_ring_ret_credits(DescRing *ring, uint32_t credits)
313 if (credits > ring->credits) {
314 DPRINTF("ERROR: trying to return more credits (%d) "
315 "than are outstanding (%d)\n", credits, ring->credits);
316 ring->credits = 0;
317 return false;
320 ring->credits -= credits;
322 /* return true if credits are still outstanding */
324 return ring->credits > 0;
327 uint32_t desc_ring_get_credits(DescRing *ring)
329 return ring->credits;
332 void desc_ring_set_consume(DescRing *ring, desc_ring_consume *consume,
333 unsigned vector)
335 ring->consume = consume;
336 ring->msix_vector = vector;
339 unsigned desc_ring_get_msix_vector(DescRing *ring)
341 return ring->msix_vector;
344 DescRing *desc_ring_alloc(Rocker *r, int index)
346 DescRing *ring;
348 ring = g_new0(DescRing, 1);
349 if (!ring) {
350 return NULL;
353 ring->r = r;
354 ring->index = index;
356 return ring;
359 void desc_ring_free(DescRing *ring)
361 g_free(ring->info);
362 g_free(ring);
365 void desc_ring_reset(DescRing *ring)
367 ring->base_addr = 0;
368 ring->size = 0;
369 ring->head = 0;
370 ring->tail = 0;
371 ring->ctrl = 0;
372 ring->credits = 0;