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