qemu/hw/core/remote-port-memory-master.c
<<
>>
Prefs
   1/*
   2 * QEMU remote port memory master.
   3 *
   4 * Copyright (c) 2014 Xilinx Inc
   5 * Written by Edgar E. Iglesias <edgar.iglesias@xilinx.com>
   6 *
   7 * This code is licensed under the GNU GPL.
   8 */
   9
  10#include "qemu/osdep.h"
  11#include "sysemu/sysemu.h"
  12#include "qemu/log.h"
  13#include "qapi/qmp/qerror.h"
  14#include "qapi/error.h"
  15#include "hw/sysbus.h"
  16#include "migration/vmstate.h"
  17#include "hw/qdev-properties.h"
  18#include "trace.h"
  19
  20#include "hw/remote-port-proto.h"
  21#include "hw/remote-port.h"
  22#include "hw/remote-port-device.h"
  23#include "hw/remote-port-memory-master.h"
  24
  25#include "hw/fdt_generic_util.h"
  26
  27#ifndef REMOTE_PORT_ERR_DEBUG
  28#define REMOTE_PORT_DEBUG_LEVEL 0
  29#else
  30#define REMOTE_PORT_DEBUG_LEVEL 1
  31#endif
  32
  33#define DB_PRINT_L(level, ...) do { \
  34    if (REMOTE_PORT_DEBUG_LEVEL > level) { \
  35        fprintf(stderr,  ": %s: ", __func__); \
  36        fprintf(stderr, ## __VA_ARGS__); \
  37    } \
  38} while (0)
  39
  40#define REMOTE_PORT_MEMORY_MASTER_PARENT_CLASS \
  41    object_class_get_parent( \
  42            object_class_by_name(TYPE_REMOTE_PORT_MEMORY_MASTER))
  43
  44#define RP_MAX_ACCESS_SIZE 4096
  45
  46MemTxResult rp_mm_access_with_def_attr(RemotePort *rp, uint32_t rp_dev,
  47                                       struct rp_peer_state *peer,
  48                                       MemoryTransaction *tr,
  49                                       bool relative, uint64_t offset,
  50                                       uint32_t def_attr)
  51{
  52    uint64_t addr = tr->addr;
  53    RemotePortRespSlot *rsp_slot;
  54    RemotePortDynPkt *rsp;
  55    struct  {
  56        struct rp_pkt_busaccess_ext_base pkt;
  57        uint8_t reserved[RP_MAX_ACCESS_SIZE];
  58    } pay;
  59    uint8_t *data = rp_busaccess_tx_dataptr(peer, &pay.pkt);
  60    struct rp_encode_busaccess_in in = {0};
  61    int i;
  62    int len;
  63    MemTxResult ret;
  64
  65    DB_PRINT_L(0, "addr: %" HWADDR_PRIx " data: %" PRIx64 "\n",
  66               addr, tr->data.u64);
  67
  68    if (tr->rw) {
  69        /* Data up to 8 bytes is passed as values.  */
  70        if (tr->size <= 8) {
  71            for (i = 0; i < tr->size; i++) {
  72                data[i] = tr->data.u64 >> (i * 8);
  73            }
  74        } else {
  75            memcpy(data, tr->data.p8, tr->size);
  76        }
  77    }
  78
  79    addr += relative ? 0 : offset;
  80
  81    in.cmd = tr->rw ? RP_CMD_write : RP_CMD_read;
  82    in.id = rp_new_id(rp);
  83    in.dev = rp_dev;
  84    in.clk = rp_normalized_vmclk(rp);
  85    in.master_id = tr->attr.requester_id;
  86    in.addr = addr;
  87    in.attr = def_attr;
  88    in.attr |= tr->attr.secure ? RP_BUS_ATTR_SECURE : 0;
  89    in.size = tr->size;
  90    in.stream_width = tr->size;
  91    len = rp_encode_busaccess(peer, &pay.pkt, &in);
  92    len += tr->rw ? tr->size : 0;
  93
  94    trace_remote_port_memory_master_tx_busaccess(rp_cmd_to_string(in.cmd),
  95        in.id, in.flags, in.dev, in.addr, in.size, in.attr);
  96
  97    rp_rsp_mutex_lock(rp);
  98    rp_write(rp, (void *) &pay, len);
  99
 100    rsp_slot = rp_dev_wait_resp(rp, in.dev, in.id);
 101    rsp = &rsp_slot->rsp;
 102
 103    /* We dont support out of order answers yet.  */
 104    assert(rsp->pkt->hdr.id == in.id);
 105
 106    switch (rp_get_busaccess_response(rsp->pkt)) {
 107    case RP_RESP_OK:
 108        ret = MEMTX_OK;
 109        break;
 110    case RP_RESP_ADDR_ERROR:
 111        ret = MEMTX_DECODE_ERROR;
 112        break;
 113    default:
 114        ret = MEMTX_ERROR;
 115        break;
 116    }
 117
 118    if (!tr->rw) {
 119        data = rp_busaccess_rx_dataptr(peer, &rsp->pkt->busaccess_ext_base);
 120        /* Data up to 8 bytes is return as values.  */
 121        if (tr->size <= 8) {
 122            for (i = 0; i < tr->size; i++) {
 123                tr->data.u64 |= data[i] << (i * 8);
 124            }
 125        } else {
 126            memcpy(tr->data.p8, data, tr->size);
 127        }
 128    }
 129
 130    trace_remote_port_memory_master_rx_busaccess(
 131        rp_cmd_to_string(rsp->pkt->hdr.cmd), rsp->pkt->hdr.id,
 132        rsp->pkt->hdr.flags, rsp->pkt->hdr.dev, rsp->pkt->busaccess.addr,
 133        rsp->pkt->busaccess.len, rsp->pkt->busaccess.attributes);
 134
 135    rp_resp_slot_done(rp, rsp_slot);
 136    rp_rsp_mutex_unlock(rp);
 137
 138    /*
 139     * For strongly ordered or transactions that don't allow Early Acking,
 140     * we need to drain the pending RP processing queue here. This is
 141     * because RP handles responses in parallel with normal requests so
 142     * they may get reordered. This becomes visible for example with reads
 143     * to read-to-clear registers that clear interrupts. Even though the
 144     * lowering of the interrupt-wires arrives to us before the read-resp,
 145     * we may handle the response before the wire update, resulting in
 146     * spurious interrupts.
 147     *
 148     * This has some room for optimization but for now we use the big hammer
 149     * and drain the entire qeueue.
 150     */
 151    rp_process(rp);
 152
 153    /* Reads are sync-points, roll the sync timer.  */
 154    rp_restart_sync_timer(rp);
 155    DB_PRINT_L(1, "\n");
 156    return ret;
 157}
 158
 159MemTxResult rp_mm_access(RemotePort *rp, uint32_t rp_dev,
 160                         struct rp_peer_state *peer,
 161                         MemoryTransaction *tr,
 162                         bool relative, uint64_t offset)
 163{
 164    return rp_mm_access_with_def_attr(rp, rp_dev, peer, tr, relative, offset,
 165                                      0);
 166}
 167
 168static MemTxResult rp_access(MemoryTransaction *tr)
 169{
 170    RemotePortMap *map = tr->opaque;
 171    RemotePortMemoryMaster *s = map->parent;
 172
 173    return rp_mm_access(s->rp, s->rp_dev, s->peer, tr, s->relative,
 174                        map->offset);
 175}
 176
 177static const MemoryRegionOps rp_ops_template = {
 178    .access = rp_access,
 179    .valid.max_access_size = RP_MAX_ACCESS_SIZE,
 180    .impl.unaligned = false,
 181    .endianness = DEVICE_LITTLE_ENDIAN,
 182};
 183
 184static void rp_memory_master_realize(DeviceState *dev, Error **errp)
 185{
 186    RemotePortMemoryMaster *s = REMOTE_PORT_MEMORY_MASTER(dev);
 187    int i;
 188
 189    /* Sanity check max access size.  */
 190    if (s->max_access_size > RP_MAX_ACCESS_SIZE) {
 191        error_setg(errp, "%s: max-access-size %d too large! MAX is %d",
 192                   TYPE_REMOTE_PORT_MEMORY_MASTER, s->max_access_size,
 193                   RP_MAX_ACCESS_SIZE);
 194        return;
 195    }
 196
 197    if (s->max_access_size < 4) {
 198        error_setg(errp, "%s: max-access-size %d too small! MIN is 4",
 199                   TYPE_REMOTE_PORT_MEMORY_MASTER, s->max_access_size);
 200        return;
 201    }
 202
 203    assert(s->rp);
 204    s->peer = rp_get_peer(s->rp);
 205
 206    /* Create a single static region if configuration says so.  */
 207    if (s->map_num) {
 208        /* Initialize rp_ops from template.  */
 209        s->rp_ops = g_malloc(sizeof *s->rp_ops);
 210        memcpy(s->rp_ops, &rp_ops_template, sizeof *s->rp_ops);
 211        s->rp_ops->valid.max_access_size = s->max_access_size;
 212
 213        s->mmaps = g_new0(typeof(*s->mmaps), s->map_num);
 214        for (i = 0; i < s->map_num; ++i) {
 215            char *name = g_strdup_printf("rp-%d", i);
 216
 217            s->mmaps[i].offset = s->map_offset;
 218            memory_region_init_io(&s->mmaps[i].iomem, OBJECT(dev), s->rp_ops,
 219                                  &s->mmaps[i], name, s->map_size);
 220            sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmaps[i].iomem);
 221            s->mmaps[i].parent = s;
 222            g_free(name);
 223        }
 224    }
 225}
 226
 227static void rp_memory_master_init(Object *obj)
 228{
 229    RemotePortMemoryMaster *rpms = REMOTE_PORT_MEMORY_MASTER(obj);
 230    object_property_add_link(obj, "rp-adaptor0", "remote-port",
 231                             (Object **)&rpms->rp,
 232                             qdev_prop_allow_set_link,
 233                             OBJ_PROP_LINK_STRONG);
 234}
 235
 236static bool rp_parse_reg(FDTGenericMMap *obj, FDTGenericRegPropInfo reg,
 237                         Error **errp)
 238{
 239    RemotePortMemoryMaster *s = REMOTE_PORT_MEMORY_MASTER(obj);
 240    FDTGenericMMapClass *parent_fmc =
 241        FDT_GENERIC_MMAP_CLASS(REMOTE_PORT_MEMORY_MASTER_PARENT_CLASS);
 242    int i;
 243
 244    /* Initialize rp_ops from template.  */
 245    s->rp_ops = g_malloc(sizeof *s->rp_ops);
 246    memcpy(s->rp_ops, &rp_ops_template, sizeof *s->rp_ops);
 247    s->rp_ops->valid.max_access_size = s->max_access_size;
 248
 249    s->mmaps = g_new0(typeof(*s->mmaps), reg.n);
 250    for (i = 0; i < reg.n; ++i) {
 251        char *name = g_strdup_printf("rp-%d", i);
 252
 253        s->mmaps[i].offset = reg.a[i];
 254        memory_region_init_io(&s->mmaps[i].iomem, OBJECT(obj), s->rp_ops,
 255                              &s->mmaps[i], name, reg.s[i]);
 256        sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmaps[i].iomem);
 257        s->mmaps[i].parent = s;
 258        g_free(name);
 259    }
 260
 261    return parent_fmc ? parent_fmc->parse_reg(obj, reg, errp) : false;
 262}
 263
 264static Property rp_properties[] = {
 265    DEFINE_PROP_UINT32("map-num", RemotePortMemoryMaster, map_num, 0),
 266    DEFINE_PROP_UINT64("map-offset", RemotePortMemoryMaster, map_offset, 0),
 267    DEFINE_PROP_UINT64("map-size", RemotePortMemoryMaster, map_size, 0),
 268    DEFINE_PROP_UINT32("rp-chan0", RemotePortMemoryMaster, rp_dev, 0),
 269    DEFINE_PROP_BOOL("relative", RemotePortMemoryMaster, relative, false),
 270    DEFINE_PROP_UINT32("max-access-size", RemotePortMemoryMaster,
 271                       max_access_size, RP_MAX_ACCESS_SIZE),
 272    DEFINE_PROP_END_OF_LIST()
 273};
 274
 275static void rp_memory_master_class_init(ObjectClass *oc, void *data)
 276{
 277    FDTGenericMMapClass *fmc = FDT_GENERIC_MMAP_CLASS(oc);
 278    DeviceClass *dc = DEVICE_CLASS(oc);
 279    device_class_set_props(dc, rp_properties);
 280    dc->realize = rp_memory_master_realize;
 281    fmc->parse_reg = rp_parse_reg;
 282}
 283
 284static const TypeInfo rp_info = {
 285    .name          = TYPE_REMOTE_PORT_MEMORY_MASTER,
 286    .parent        = TYPE_SYS_BUS_DEVICE,
 287    .instance_size = sizeof(RemotePortMemoryMaster),
 288    .instance_init = rp_memory_master_init,
 289    .class_init    = rp_memory_master_class_init,
 290    .interfaces    = (InterfaceInfo[]) {
 291        { TYPE_FDT_GENERIC_MMAP },
 292        { TYPE_REMOTE_PORT_DEVICE },
 293        { },
 294    },
 295};
 296
 297static void rp_register_types(void)
 298{
 299    type_register_static(&rp_info);
 300}
 301
 302type_init(rp_register_types)
 303