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