qemu/hw/net/rocker/rocker_desc.c
<<
>>
Prefs
   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
  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    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
  79int 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
  96DescRing *desc_get_ring(DescInfo *info)
  97{
  98    return info->ring;
  99}
 100
 101int desc_ring_index(DescRing *ring)
 102{
 103    return ring->index;
 104}
 105
 106static bool desc_ring_empty(DescRing *ring)
 107{
 108    return ring->head == ring->tail;
 109}
 110
 111bool 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
 124uint64_t desc_ring_get_base_addr(DescRing *ring)
 125{
 126    return ring->base_addr;
 127}
 128
 129bool 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
 160uint32_t desc_ring_get_size(DescRing *ring)
 161{
 162    return ring->size;
 163}
 164
 165static 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
 176static 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
 185static 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
 195static DescInfo *__desc_ring_fetch_desc(DescRing *ring)
 196{
 197    return desc_read(ring, ring->tail);
 198}
 199
 200DescInfo *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
 209static 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
 223bool 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
 238static 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
 262bool 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
 294uint32_t desc_ring_get_head(DescRing *ring)
 295{
 296    return ring->head;
 297}
 298
 299uint32_t desc_ring_get_tail(DescRing *ring)
 300{
 301    return ring->tail;
 302}
 303
 304void 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
 312bool 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
 328uint32_t desc_ring_get_credits(DescRing *ring)
 329{
 330    return ring->credits;
 331}
 332
 333void 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
 340unsigned desc_ring_get_msix_vector(DescRing *ring)
 341{
 342    return ring->msix_vector;
 343}
 344
 345DescRing *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
 360void desc_ring_free(DescRing *ring)
 361{
 362    g_free(ring->info);
 363    g_free(ring);
 364}
 365
 366void 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