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#include "hw/remote-port-memory-slave.h"
  23
  24#ifndef REMOTE_PORT_ERR_DEBUG
  25#define REMOTE_PORT_DEBUG_LEVEL 0
  26#else
  27#define REMOTE_PORT_DEBUG_LEVEL 1
  28#endif
  29
  30#define DB_PRINT_L(level, ...) do { \
  31    if (REMOTE_PORT_DEBUG_LEVEL > level) { \
  32        fprintf(stderr,  ": %s: ", __func__); \
  33        fprintf(stderr, ## __VA_ARGS__); \
  34    } \
  35} while (0);
  36
  37/* Slow path dealing with odd stuff like byte-enables.  */
  38static void process_data_slow(RemotePortMemorySlave *s,
  39                              struct rp_pkt *pkt,
  40                              DMADirection dir,
  41                              uint8_t *data, uint8_t *byte_en)
  42{
  43    unsigned int i;
  44    unsigned int byte_en_len = pkt->busaccess_ext_base.byte_enable_len;
  45
  46    for (i = 0; i < pkt->busaccess.len; i++) {
  47        if (byte_en && !byte_en[i % byte_en_len]) {
  48            continue;
  49        }
  50        dma_memory_rw_attr(s->as, pkt->busaccess.addr + i, data + i,
  51                           1, dir, s->attr);
  52    }
  53}
  54
  55static void rp_cmd_rw(RemotePortMemorySlave *s, struct rp_pkt *pkt,
  56                      DMADirection dir)
  57{
  58    size_t pktlen = sizeof(struct rp_pkt_busaccess_ext_base);
  59    struct rp_encode_busaccess_in in = {0};
  60    size_t enclen;
  61    int64_t delay;
  62    uint8_t *data = NULL;
  63    uint8_t *byte_en;
  64
  65    byte_en = rp_busaccess_byte_en_ptr(s->peer, &pkt->busaccess_ext_base);
  66
  67    if (dir == DMA_DIRECTION_TO_DEVICE) {
  68        pktlen += pkt->busaccess.len;
  69    } else {
  70        data = rp_busaccess_rx_dataptr(s->peer, &pkt->busaccess_ext_base);
  71    }
  72
  73    assert(pkt->busaccess.width == 0);
  74    assert(pkt->busaccess.stream_width == pkt->busaccess.len);
  75    assert(!(pkt->hdr.flags & RP_PKT_FLAGS_response));
  76
  77    rp_dpkt_alloc(&s->rsp, pktlen);
  78    if (dir == DMA_DIRECTION_TO_DEVICE) {
  79        data = rp_busaccess_tx_dataptr(s->peer,
  80                                       &s->rsp.pkt->busaccess_ext_base);
  81    }
  82    if (dir == DMA_DIRECTION_FROM_DEVICE && REMOTE_PORT_DEBUG_LEVEL > 0) {
  83        DB_PRINT_L(0, "address: %" PRIx64 "\n", pkt->busaccess.addr);
  84        qemu_hexdump((const char *)data, stderr, ": write: ",
  85                     pkt->busaccess.len);
  86    }
  87    s->attr.secure = !!(pkt->busaccess.attributes & RP_BUS_ATTR_SECURE);
  88    s->attr.master_id = pkt->busaccess.master_id;
  89
  90    if (byte_en) {
  91        process_data_slow(s, pkt, dir, data, byte_en);
  92    } else {
  93        dma_memory_rw_attr(s->as, pkt->busaccess.addr, data,
  94                           pkt->busaccess.len, dir, s->attr);
  95    }
  96    if (dir == DMA_DIRECTION_TO_DEVICE && REMOTE_PORT_DEBUG_LEVEL > 0) {
  97        DB_PRINT_L(0, "address: %" PRIx64 "\n", pkt->busaccess.addr);
  98        qemu_hexdump((const char *)data, stderr, ": read: ",
  99                     pkt->busaccess.len);
 100    }
 101    /* delay here could be set to the annotated cost of doing issuing
 102       these accesses. QEMU doesn't support this kind of annotations
 103       at the moment. So we just clear the delay.  */
 104    delay = 0;
 105
 106    rp_encode_busaccess_in_rsp_init(&in, pkt);
 107    in.clk = pkt->busaccess.timestamp + delay;
 108    enclen = rp_encode_busaccess(s->peer, &s->rsp.pkt->busaccess_ext_base,
 109                                 &in);
 110    assert(enclen <= pktlen);
 111
 112    rp_write(s->rp, (void *)s->rsp.pkt, enclen);
 113}
 114
 115static void rp_memory_slave_realize(DeviceState *dev, Error **errp)
 116{
 117    RemotePortMemorySlave *s = REMOTE_PORT_MEMORY_SLAVE(dev);
 118
 119    s->peer = rp_get_peer(s->rp);
 120
 121    /* FIXME: do something with per paster address spaces */
 122    s->as = s->mr ? address_space_init_shareable(s->mr, NULL)
 123                  : &address_space_memory;
 124}
 125
 126static void rp_memory_slave_write(RemotePortDevice *s, struct rp_pkt *pkt)
 127{
 128    return rp_cmd_rw(REMOTE_PORT_MEMORY_SLAVE(s), pkt,
 129                     DMA_DIRECTION_FROM_DEVICE);
 130}
 131
 132static void rp_memory_slave_read(RemotePortDevice *s, struct rp_pkt *pkt)
 133{
 134    return rp_cmd_rw(REMOTE_PORT_MEMORY_SLAVE(s), pkt,
 135                     DMA_DIRECTION_TO_DEVICE);
 136}
 137
 138static void rp_memory_slave_init(Object *obj)
 139{
 140    RemotePortMemorySlave *rpms = REMOTE_PORT_MEMORY_SLAVE(obj);
 141
 142    object_property_add_link(obj, "rp-adaptor0", "remote-port",
 143                             (Object **)&rpms->rp,
 144                             qdev_prop_allow_set_link_before_realize,
 145                             OBJ_PROP_LINK_UNREF_ON_RELEASE,
 146                             &error_abort);
 147    object_property_add_link(obj, "mr", TYPE_MEMORY_REGION,
 148                             (Object **)&rpms->mr,
 149                             qdev_prop_allow_set_link_before_realize,
 150                             OBJ_PROP_LINK_UNREF_ON_RELEASE,
 151                             &error_abort);
 152}
 153
 154static void rp_memory_slave_class_init(ObjectClass *oc, void *data)
 155{
 156    RemotePortDeviceClass *rpdc = REMOTE_PORT_DEVICE_CLASS(oc);
 157    DeviceClass *dc = DEVICE_CLASS(oc);
 158
 159    rpdc->ops[RP_CMD_write] = rp_memory_slave_write;
 160    rpdc->ops[RP_CMD_read] = rp_memory_slave_read;
 161    dc->realize = rp_memory_slave_realize;
 162}
 163
 164static const TypeInfo rp_info = {
 165    .name          = TYPE_REMOTE_PORT_MEMORY_SLAVE,
 166    .parent        = TYPE_DEVICE,
 167    .instance_size = sizeof(RemotePortMemorySlave),
 168    .instance_init = rp_memory_slave_init,
 169    .class_init    = rp_memory_slave_class_init,
 170    .interfaces    = (InterfaceInfo[]) {
 171        { TYPE_REMOTE_PORT_DEVICE },
 172        { },
 173    },
 174};
 175
 176static void rp_register_types(void)
 177{
 178    type_register_static(&rp_info);
 179}
 180
 181type_init(rp_register_types)
 182