qemu/hw/core/remote-port-memory-slave.c
<<
>>
Prefs
   1/*
   2 * QEMU remote port memory slave. Read and write transactions
   3 * recieved from the remote port are translated into an address space.
   4 *
   5 * Copyright (c) 2013 Xilinx Inc
   6 * Written by Edgar E. Iglesias <edgar.iglesias@xilinx.com>
   7 * Written by Peter Crosthwaite <peter.crosthwaite@xilinx.com>
   8 *
   9 * This code is licensed under the GNU GPL.
  10 */
  11
  12#include "qemu/osdep.h"
  13#include "sysemu/sysemu.h"
  14#include "sysemu/dma.h"
  15#include "qemu/log.h"
  16#include "qapi/qmp/qerror.h"
  17#include "qapi/error.h"
  18#include "hw/qdev.h"
  19
  20#include "hw/remote-port-proto.h"
  21#include "hw/remote-port-device.h"
  22
  23#ifndef REMOTE_PORT_ERR_DEBUG
  24#define REMOTE_PORT_DEBUG_LEVEL 0
  25#else
  26#define REMOTE_PORT_DEBUG_LEVEL 1
  27#endif
  28
  29#define DB_PRINT_L(level, ...) do { \
  30    if (REMOTE_PORT_DEBUG_LEVEL > level) { \
  31        fprintf(stderr,  ": %s: ", __func__); \
  32        fprintf(stderr, ## __VA_ARGS__); \
  33    } \
  34} while (0);
  35
  36
  37#define TYPE_REMOTE_PORT_MEMORY_SLAVE "remote-port-memory-slave"
  38#define REMOTE_PORT_MEMORY_SLAVE(obj) \
  39        OBJECT_CHECK(RemotePortMemorySlave, (obj), \
  40                     TYPE_REMOTE_PORT_MEMORY_SLAVE)
  41
  42typedef struct RemotePortMemorySlave {
  43    /* private */
  44    DeviceState parent;
  45    /* public */
  46    struct RemotePort *rp;
  47    MemoryRegion *mr;
  48    AddressSpace *as;
  49    MemTxAttrs attr;
  50    RemotePortDynPkt rsp;
  51} RemotePortMemorySlave;
  52
  53static void rp_cmd_rw(RemotePortMemorySlave *s, struct rp_pkt *pkt,
  54                      DMADirection dir)
  55{
  56    size_t pktlen = sizeof(struct rp_pkt_busaccess);
  57    size_t enclen;
  58    int64_t delay;
  59    uint8_t *data = NULL;
  60
  61    if (dir == DMA_DIRECTION_TO_DEVICE) {
  62        pktlen += pkt->busaccess.len;
  63    } else {
  64        data = (uint8_t *)(pkt + 1);
  65    }
  66
  67    assert(pkt->busaccess.width == 0);
  68    assert(pkt->busaccess.stream_width == pkt->busaccess.len);
  69    assert(!(pkt->hdr.flags & RP_PKT_FLAGS_response));
  70
  71    rp_dpkt_alloc(&s->rsp, pktlen);
  72    if (dir == DMA_DIRECTION_TO_DEVICE) {
  73        data = (uint8_t *)(s->rsp.pkt + 1);
  74    }
  75    if (dir == DMA_DIRECTION_FROM_DEVICE && REMOTE_PORT_DEBUG_LEVEL > 0) {
  76        DB_PRINT_L(0, "address: %" PRIx64 "\n", pkt->busaccess.addr);
  77        qemu_hexdump((const char *)data, stderr, ": write: ",
  78                     pkt->busaccess.len);
  79    }
  80    s->attr.secure = !!(pkt->busaccess.attributes & RP_BUS_ATTR_SECURE);
  81    s->attr.master_id = pkt->busaccess.master_id;
  82    dma_memory_rw_attr(s->as, pkt->busaccess.addr, data, pkt->busaccess.len,
  83                       dir, s->attr);
  84    if (dir == DMA_DIRECTION_TO_DEVICE && REMOTE_PORT_DEBUG_LEVEL > 0) {
  85        DB_PRINT_L(0, "address: %" PRIx64 "\n", pkt->busaccess.addr);
  86        qemu_hexdump((const char *)data, stderr, ": read: ",
  87                     pkt->busaccess.len);
  88    }
  89    /* delay here could be set to the annotated cost of doing issuing
  90       these accesses. QEMU doesn't support this kind of annotations
  91       at the moment. So we just clear the delay.  */
  92    delay = 0;
  93
  94    enclen = (dir == DMA_DIRECTION_FROM_DEVICE ? rp_encode_write_resp :
  95                                                 rp_encode_read_resp)(
  96                    pkt->hdr.id, pkt->hdr.dev, &s->rsp.pkt->busaccess,
  97                    pkt->busaccess.timestamp + delay,
  98                    pkt->busaccess.master_id,
  99                    pkt->busaccess.addr,
 100                    pkt->busaccess.attributes,
 101                    pkt->busaccess.len,
 102                    pkt->busaccess.width,
 103                    pkt->busaccess.stream_width);
 104    assert(enclen == pktlen);
 105
 106    rp_write(s->rp, (void *)s->rsp.pkt, pktlen);
 107}
 108
 109static void rp_memory_master_realize(DeviceState *dev, Error **errp)
 110{
 111    RemotePortMemorySlave *s = REMOTE_PORT_MEMORY_SLAVE(dev);
 112
 113    /* FIXME: do something with per paster address spaces */
 114    s->as = s->mr ? address_space_init_shareable(s->mr, NULL)
 115                  : &address_space_memory;
 116}
 117
 118static void rp_memory_master_write(RemotePortDevice *s, struct rp_pkt *pkt)
 119{
 120    return rp_cmd_rw(REMOTE_PORT_MEMORY_SLAVE(s), pkt,
 121                     DMA_DIRECTION_FROM_DEVICE);
 122}
 123
 124static void rp_memory_master_read(RemotePortDevice *s, struct rp_pkt *pkt)
 125{
 126    return rp_cmd_rw(REMOTE_PORT_MEMORY_SLAVE(s), pkt,
 127                     DMA_DIRECTION_TO_DEVICE);
 128}
 129
 130static void rp_memory_master_init(Object *obj)
 131{
 132    RemotePortMemorySlave *rpms = REMOTE_PORT_MEMORY_SLAVE(obj);
 133
 134    object_property_add_link(obj, "rp-adaptor0", "remote-port",
 135                             (Object **)&rpms->rp,
 136                             qdev_prop_allow_set_link_before_realize,
 137                             OBJ_PROP_LINK_UNREF_ON_RELEASE,
 138                             &error_abort);
 139    object_property_add_link(obj, "mr", TYPE_MEMORY_REGION,
 140                             (Object **)&rpms->mr,
 141                             qdev_prop_allow_set_link_before_realize,
 142                             OBJ_PROP_LINK_UNREF_ON_RELEASE,
 143                             &error_abort);
 144}
 145
 146static void rp_memory_master_class_init(ObjectClass *oc, void *data)
 147{
 148    RemotePortDeviceClass *rpdc = REMOTE_PORT_DEVICE_CLASS(oc);
 149    DeviceClass *dc = DEVICE_CLASS(oc);
 150
 151    rpdc->ops[RP_CMD_write] = rp_memory_master_write;
 152    rpdc->ops[RP_CMD_read] = rp_memory_master_read;
 153    dc->realize = rp_memory_master_realize;
 154}
 155
 156static const TypeInfo rp_info = {
 157    .name          = TYPE_REMOTE_PORT_MEMORY_SLAVE,
 158    .parent        = TYPE_DEVICE,
 159    .instance_size = sizeof(RemotePortMemorySlave),
 160    .instance_init = rp_memory_master_init,
 161    .class_init    = rp_memory_master_class_init,
 162    .interfaces    = (InterfaceInfo[]) {
 163        { TYPE_REMOTE_PORT_DEVICE },
 164        { },
 165    },
 166};
 167
 168static void rp_register_types(void)
 169{
 170    type_register_static(&rp_info);
 171}
 172
 173type_init(rp_register_types)
 174