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
  17#include "hw/remote-port-proto.h"
  18#include "hw/remote-port-device.h"
  19
  20#include "hw/fdt_generic_util.h"
  21
  22#ifndef REMOTE_PORT_ERR_DEBUG
  23#define REMOTE_PORT_DEBUG_LEVEL 0
  24#else
  25#define REMOTE_PORT_DEBUG_LEVEL 1
  26#endif
  27
  28#define DB_PRINT_L(level, ...) do { \
  29    if (REMOTE_PORT_DEBUG_LEVEL > level) { \
  30        fprintf(stderr,  ": %s: ", __func__); \
  31        fprintf(stderr, ## __VA_ARGS__); \
  32    } \
  33} while (0);
  34
  35#define TYPE_REMOTE_PORT_MEMORY_MASTER "remote-port-memory-master"
  36#define REMOTE_PORT_MEMORY_MASTER(obj) \
  37        OBJECT_CHECK(RemotePortMemoryMaster, (obj), \
  38                     TYPE_REMOTE_PORT_MEMORY_MASTER)
  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
  44typedef struct RemotePortMemoryMaster RemotePortMemoryMaster;
  45
  46typedef struct RemotePortMap {
  47    RemotePortMemoryMaster *parent;
  48    MemoryRegion iomem;
  49    uint64_t offset;
  50} RemotePortMap;
  51
  52struct RemotePortMemoryMaster {
  53    /* private */
  54    SysBusDevice parent;
  55
  56    RemotePortMap *mmaps;
  57
  58    /* public */
  59    uint32_t rp_dev;
  60    struct RemotePort *rp;
  61};
  62
  63static uint64_t rp_io_read(void *opaque, hwaddr addr, unsigned size,
  64                           MemTxAttrs attr)
  65{
  66    RemotePortMap *map = opaque;
  67    RemotePortMemoryMaster *s = map->parent;
  68    struct rp_pkt_busaccess pkt;
  69    uint64_t value = 0;
  70    int64_t clk;
  71    int64_t rclk;
  72    uint8_t *data;
  73    uint32_t id;
  74    uint64_t rp_attr = 0;
  75    int len;
  76    int i;
  77    RemotePortDynPkt rsp;
  78
  79    DB_PRINT_L(1, "\n");
  80    clk = rp_normalized_vmclk(s->rp);
  81    id = rp_new_id(s->rp);
  82    rp_attr |= attr.secure ? RP_BUS_ATTR_SECURE : 0;
  83    len = rp_encode_read(id, s->rp_dev, &pkt, clk,
  84                         attr.master_id, addr + map->offset,
  85                         rp_attr, size, 0, size);
  86
  87    rp_rsp_mutex_lock(s->rp);
  88    rp_write(s->rp, (void *) &pkt, len);
  89
  90    rsp = rp_wait_resp(s->rp);
  91    /* We dont support out of order answers yet.  */
  92    assert(rsp.pkt->hdr.id == be32_to_cpu(pkt.hdr.id));
  93
  94    data = rp_busaccess_dataptr(&rsp.pkt->busaccess);
  95    for (i = 0; i < size; i++) {
  96        value |= data[i] << (i *8);
  97    }
  98    rclk = rsp.pkt->busaccess.timestamp;
  99    rp_dpkt_invalidate(&rsp);
 100    rp_rsp_mutex_unlock(s->rp);
 101    rp_sync_vmclock(s->rp, clk, rclk);
 102
 103    /* Reads are sync-points, roll the sync timer.  */
 104    rp_restart_sync_timer(s->rp);
 105    rp_leave_iothread(s->rp);
 106    DB_PRINT_L(0, "addr: %" HWADDR_PRIx " data: %" PRIx64 "\n", addr, value);
 107    return value;
 108}
 109
 110static void rp_io_write(void *opaque, hwaddr addr, uint64_t value,
 111                        unsigned size, MemTxAttrs attr)
 112{
 113    RemotePortMap *map = opaque;
 114    RemotePortMemoryMaster *s = map->parent;
 115    int64_t clk;
 116    int64_t rclk;
 117    uint64_t rp_attr = 0;
 118    uint32_t id;
 119    RemotePortDynPkt rsp;
 120
 121    struct  {
 122        struct rp_pkt_busaccess pkt;
 123        uint8_t data[8];
 124    } pay;
 125    int i;
 126    int len;
 127
 128    DB_PRINT_L(0, "addr: %" HWADDR_PRIx " data: %" PRIx64 "\n", addr, value);
 129
 130    for (i = 0; i < 8; i++) {
 131        pay.data[i] = value >> (i * 8);
 132    }
 133
 134    assert(size <= 8);
 135    clk = rp_normalized_vmclk(s->rp);
 136    id = rp_new_id(s->rp);
 137    rp_attr |= attr.secure ? RP_BUS_ATTR_SECURE : 0;
 138    len = rp_encode_write(id, s->rp_dev, &pay.pkt, clk,
 139                          attr.master_id, addr + map->offset,
 140                          rp_attr, size, 0, size);
 141
 142    rp_rsp_mutex_lock(s->rp);
 143
 144    rp_write(s->rp, (void *) &pay, len + size);
 145
 146    rsp = rp_wait_resp(s->rp);
 147
 148    /* We dont support out of order answers yet.  */
 149    assert(rsp.pkt->hdr.id == be32_to_cpu(pay.pkt.hdr.id));
 150    rclk = rsp.pkt->busaccess.timestamp;
 151    rp_dpkt_invalidate(&rsp);
 152    rp_rsp_mutex_unlock(s->rp);
 153    rp_sync_vmclock(s->rp, clk, rclk);
 154    /* Reads are sync-points, roll the sync timer.  */
 155    rp_restart_sync_timer(s->rp);
 156    rp_leave_iothread(s->rp);
 157    DB_PRINT_L(1, "\n");
 158}
 159
 160static void rp_io_access(MemoryTransaction *tr)
 161{
 162    MemTxAttrs attr = tr->attr;
 163    void *opaque = tr->opaque;
 164    hwaddr addr = tr->addr;
 165    unsigned size = tr->size;
 166    uint64_t value = tr->data.u64;;
 167    bool is_write = tr->rw;
 168
 169    if (is_write) {
 170        rp_io_write(opaque, addr, value, size, attr);
 171    } else {
 172        tr->data.u64 = rp_io_read(opaque, addr, size, attr);
 173    }
 174}
 175
 176static const MemoryRegionOps rp_ops = {
 177    .access = rp_io_access,
 178    .endianness = DEVICE_LITTLE_ENDIAN,
 179};
 180
 181static void rp_memory_master_init(Object *obj)
 182{
 183    RemotePortMemoryMaster *rpms = REMOTE_PORT_MEMORY_MASTER(obj);
 184    object_property_add_link(obj, "rp-adaptor0", "remote-port",
 185                             (Object **)&rpms->rp,
 186                             qdev_prop_allow_set_link_before_realize,
 187                             OBJ_PROP_LINK_UNREF_ON_RELEASE,
 188                             &error_abort);
 189}
 190
 191static bool rp_parse_reg(FDTGenericMMap *obj, FDTGenericRegPropInfo reg,
 192                         Error **errp)
 193{
 194    RemotePortMemoryMaster *s = REMOTE_PORT_MEMORY_MASTER(obj);
 195    FDTGenericMMapClass *parent_fmc = 
 196        FDT_GENERIC_MMAP_CLASS(REMOTE_PORT_MEMORY_MASTER_PARENT_CLASS);
 197    int i;
 198
 199    s->mmaps = g_new0(typeof(*s->mmaps), reg.n);
 200    for (i = 0; i < reg.n; ++i) {
 201        char *name = g_strdup_printf("rp-%d", i);
 202
 203        s->mmaps[i].offset = reg.a[i];
 204        memory_region_init_io(&s->mmaps[i].iomem, OBJECT(obj), &rp_ops,
 205                              &s->mmaps[i], name, reg.s[i]);
 206        sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmaps[i].iomem);
 207        s->mmaps[i].parent = s;
 208        g_free(name);
 209    }
 210
 211    return parent_fmc ? parent_fmc->parse_reg(obj, reg, errp) : false;
 212}
 213
 214static Property rp_properties[] = {
 215    DEFINE_PROP_UINT32("rp-chan0", RemotePortMemoryMaster, rp_dev, 0),
 216    DEFINE_PROP_END_OF_LIST()
 217};
 218
 219static void rp_memory_master_class_init(ObjectClass *oc, void *data)
 220{
 221    FDTGenericMMapClass *fmc = FDT_GENERIC_MMAP_CLASS(oc);
 222    DeviceClass *dc = DEVICE_CLASS(oc);
 223    dc->props = rp_properties;
 224    fmc->parse_reg = rp_parse_reg;
 225}
 226
 227static const TypeInfo rp_info = {
 228    .name          = TYPE_REMOTE_PORT_MEMORY_MASTER,
 229    .parent        = TYPE_SYS_BUS_DEVICE,
 230    .instance_size = sizeof(RemotePortMemoryMaster),
 231    .instance_init = rp_memory_master_init,
 232    .class_init    = rp_memory_master_class_init,
 233    .interfaces    = (InterfaceInfo[]) {
 234        { TYPE_FDT_GENERIC_MMAP },
 235        { TYPE_REMOTE_PORT_DEVICE },
 236        { },
 237    },
 238};
 239
 240static void rp_register_types(void)
 241{
 242    type_register_static(&rp_info);
 243}
 244
 245type_init(rp_register_types)
 246