qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

rocker_desc.c (8276B)


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