qemu/hw/misc/stream-fifo.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2013 Xilinx Inc
   3 * Copyright (c) 2013 Peter Crosthwaite <peter.crosthwaite@xilinx.com>
   4 *
   5 * Permission is hereby granted, free of charge, to any person obtaining a copy
   6 * of this software and associated documentation files (the "Software"), to deal
   7 * in the Software without restriction, including without limitation the rights
   8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   9 * copies of the Software, and to permit persons to whom the Software is
  10 * furnished to do so, subject to the following conditions:
  11 *
  12 * The above copyright notice and this permission notice shall be included in
  13 * all copies or substantial portions of the Software.
  14 *
  15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21 * THE SOFTWARE.
  22 */
  23
  24#include "qemu/osdep.h"
  25#include "hw/sysbus.h"
  26#include "qemu/log.h"
  27
  28#include "qemu/bitops.h"
  29#include "qapi/qmp/qerror.h"
  30#include "migration/vmstate.h"
  31#include "hw/qdev-properties.h"
  32#include "hw/register.h"
  33#include "hw/stream.h"
  34#include "qemu/fifo.h"
  35
  36#ifndef STREAM_FIFO_ERR_DEBUG
  37#define STREAM_FIFO_ERR_DEBUG 0
  38#endif
  39
  40#define TYPE_STREAM_FIFO "stream-fifo"
  41
  42#define STREAM_FIFO(obj) \
  43     OBJECT_CHECK(StreamFifo, (obj), TYPE_STREAM_FIFO)
  44
  45REG32(DP, 0x00)
  46REG32(CTL, 0x04)
  47    #define R_CTL_CORK      (1 << 0)
  48    #define R_CTL_RSVD ~1ull
  49
  50#define R_MAX ((R_CTL) + 1)
  51
  52typedef struct StreamFifo StreamFifo;
  53
  54struct StreamFifo {
  55    SysBusDevice busdev;
  56    MemoryRegion iomem;
  57
  58    Fifo fifo;
  59
  60    uint32_t regs[R_MAX];
  61    RegisterInfo regs_info[R_MAX];
  62
  63    StreamSlave *tx_dev;
  64
  65    StreamCanPushNotifyFn notify;
  66    void *notify_opaque;
  67};
  68
  69static void stream_fifo_notify(void *opaque)
  70{
  71    StreamFifo *s = STREAM_FIFO(opaque);
  72
  73    while (!fifo_is_empty(&s->fifo) && !(s->regs[R_CTL] & R_CTL_CORK) &&
  74           stream_can_push(s->tx_dev, stream_fifo_notify, s)) {
  75        size_t ret;
  76        uint8_t buf[4];
  77
  78        *((uint32_t *)buf) = cpu_to_le32(fifo_pop32(&s->fifo));
  79        ret = stream_push(s->tx_dev, buf, 4, false);
  80        assert(ret == 4);
  81    }
  82
  83    if (s->notify) {
  84        StreamCanPushNotifyFn notify = s->notify;
  85        s->notify = NULL;
  86        notify(s->notify_opaque);
  87    }
  88}
  89
  90static bool stream_fifo_stream_can_push(StreamSlave *obj,
  91                                        StreamCanPushNotifyFn notify,
  92                                        void *notify_opaque)
  93{
  94    StreamFifo *s = STREAM_FIFO(obj);
  95    bool ret = !(s->regs[R_CTL] & R_CTL_CORK) && !fifo_is_full(&s->fifo);
  96
  97    if (!ret) {
  98        s->notify = notify;
  99        s->notify_opaque = notify_opaque;
 100    }
 101    return ret;
 102}
 103
 104static size_t stream_fifo_stream_push(StreamSlave *obj, uint8_t *buf,
 105                                      size_t len, bool eop)
 106{
 107    StreamFifo *s = STREAM_FIFO(obj);
 108    size_t ret = 0;
 109
 110    assert(!(len % 4));
 111    while (len && !(s->regs[R_CTL] & R_CTL_CORK) && !fifo_is_full(&s->fifo)) {
 112        fifo_push32(&s->fifo, le32_to_cpu(*(uint32_t *)buf));
 113        buf += (sizeof(uint32_t));
 114        len -= 4;
 115        ret += 4;
 116    }
 117    return ret;
 118}
 119
 120
 121static void stream_fifo_update(RegisterInfo *reg, uint64_t val)
 122{
 123    StreamFifo *s = STREAM_FIFO(reg->opaque);
 124
 125    stream_fifo_notify(s);
 126}
 127
 128static void stream_fifo_dp_post_write(RegisterInfo *reg, uint64_t val)
 129{
 130    StreamFifo *s = STREAM_FIFO(reg->opaque);
 131
 132    if (fifo_is_full(&s->fifo)) {
 133        qemu_log_mask(LOG_GUEST_ERROR, "Write to full fifo\n");
 134    } else {
 135        fifo_push32(&s->fifo, val);
 136    }
 137    stream_fifo_update(reg, val);
 138}
 139
 140static uint64_t stream_fifo_dp_post_read(RegisterInfo *reg, uint64_t val)
 141{
 142    StreamFifo *s = STREAM_FIFO(reg->opaque);
 143
 144    if (fifo_is_empty(&s->fifo)) {
 145        qemu_log_mask(LOG_GUEST_ERROR, "Write to full fifo\n");
 146    } else {
 147        return fifo_pop32(&s->fifo);
 148    }
 149    return 0;
 150}
 151
 152/* TODO: Define register definitions. One entry for each register */
 153
 154static const RegisterAccessInfo stream_fifo_regs_info[] = {
 155    {   .name = "data port",                .addr = A_DP,
 156            .post_write = stream_fifo_dp_post_write,
 157            .post_read = stream_fifo_dp_post_read,
 158    },{ .name = "control",                  .addr = A_CTL,
 159            .rsvd = R_CTL_RSVD,
 160            .reset = R_CTL_CORK,
 161    }
 162};
 163
 164static void stream_fifo_reset(DeviceState *dev)
 165{
 166    StreamFifo *s = STREAM_FIFO(dev);
 167    int i;
 168
 169    for (i = 0; i < R_MAX; ++i) {
 170        register_reset(&s->regs_info[i]);
 171    }
 172
 173    fifo_reset(&s->fifo);
 174}
 175
 176static const MemoryRegionOps stream_fifo_ops = {
 177    .read = register_read_memory,
 178    .write = register_write_memory,
 179    .endianness = DEVICE_LITTLE_ENDIAN,
 180    .valid = {
 181        .min_access_size = 4,
 182        .max_access_size = 4,
 183    }
 184};
 185
 186static void stream_fifo_realize(DeviceState *dev, Error **errp)
 187{
 188    StreamFifo *s = STREAM_FIFO(dev);
 189
 190#define STREAM_FIFO_DEPTH 64
 191    fifo_create32(&s->fifo, STREAM_FIFO_DEPTH);
 192}
 193
 194static void stream_fifo_init(Object *obj)
 195{
 196    StreamFifo *s = STREAM_FIFO(obj);
 197    RegisterInfoArray *reg_array;
 198
 199    memory_region_init(&s->iomem, obj, "MMIO", R_MAX * 4);
 200    reg_array =
 201        register_init_block32(DEVICE(obj), stream_fifo_regs_info,
 202                              ARRAY_SIZE(stream_fifo_regs_info),
 203                              s->regs_info, s->regs,
 204                              &stream_fifo_ops,
 205                              STREAM_FIFO_ERR_DEBUG,
 206                              R_MAX * 4);
 207    memory_region_add_subregion(&s->iomem,
 208                                0x0,
 209                                &reg_array->mem);
 210    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem);
 211
 212    object_property_add_link(obj, "stream-connected", TYPE_STREAM_SLAVE,
 213                             (Object **)&s->tx_dev,
 214                             qdev_prop_allow_set_link_before_realize,
 215                             OBJ_PROP_LINK_STRONG);
 216
 217}
 218
 219static const VMStateDescription vmstate_stream_fifo = {
 220    .name = "stream_fifo",
 221    .version_id = 1,
 222    .minimum_version_id = 1,
 223    .minimum_version_id_old = 1,
 224    .fields = (VMStateField[]) {
 225        VMSTATE_UINT32_ARRAY(regs, StreamFifo, R_MAX),
 226        VMSTATE_END_OF_LIST(),
 227    }
 228};
 229
 230static void stream_fifo_class_init(ObjectClass *klass, void *data)
 231{
 232    DeviceClass *dc = DEVICE_CLASS(klass);
 233    StreamSlaveClass *ssc = STREAM_SLAVE_CLASS(klass);
 234
 235    dc->reset = stream_fifo_reset;
 236    dc->realize = stream_fifo_realize;
 237    dc->vmsd = &vmstate_stream_fifo;
 238
 239    ssc->push = stream_fifo_stream_push;
 240    ssc->can_push = stream_fifo_stream_can_push;
 241}
 242
 243static const TypeInfo stream_fifo_info = {
 244    .name          = TYPE_STREAM_FIFO,
 245    .parent        = TYPE_SYS_BUS_DEVICE,
 246    .instance_size = sizeof(StreamFifo),
 247    .class_init    = stream_fifo_class_init,
 248    .instance_init = stream_fifo_init,
 249    .interfaces = (InterfaceInfo[]) {
 250        { TYPE_STREAM_SLAVE },
 251        { },
 252    }
 253};
 254
 255static void stream_fifo_register_types(void)
 256{
 257    type_register_static(&stream_fifo_info);
 258}
 259
 260type_init(stream_fifo_register_types)
 261