From: Ruslan Ruslichenko <Ruslan_Ruslichenko@epam.com>
Introduce 'remote-port-memory-master' device skeleton.
This device exposes a MemoryRegion within QEMU that represents
resources located in the external simulator. When implemented
fully, read/write accesses to the region will be encapsulated
into Remote Port packets and transmitted to the peer.
This enables QEMU to map remote peripherals or memory into
its own address space.
Signed-off-by: Edgar E. Iglesias <edgar.iglesias@amd.com>
Signed-off-by: Takahiro Nakata <takahiro.nakata.wr@renesas.com>
Signed-off-by: Ruslan Ruslichenko <Ruslan_Ruslichenko@epam.com>
---
hw/core/remote-port-memory-master.c | 151 ++++++++++++++++++++
hw/core/remote-port.c | 5 +
include/hw/core/remote-port-memory-master.h | 59 ++++++++
include/hw/core/remote-port.h | 2 +
4 files changed, 217 insertions(+)
create mode 100644 hw/core/remote-port-memory-master.c
create mode 100644 include/hw/core/remote-port-memory-master.h
diff --git a/hw/core/remote-port-memory-master.c b/hw/core/remote-port-memory-master.c
new file mode 100644
index 0000000000..d714f66ddf
--- /dev/null
+++ b/hw/core/remote-port-memory-master.c
@@ -0,0 +1,151 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * QEMU remote port memory master.
+ *
+ * Copyright (c) 2014 Xilinx Inc
+ * Written by Edgar E. Iglesias <edgar.iglesias@xilinx.com>
+ *
+ * This code is licensed under the GNU GPL.
+ */
+
+#include "qemu/osdep.h"
+#include "system/system.h"
+#include "qemu/log.h"
+#include "qapi/qmp/qerror.h"
+#include "qapi/error.h"
+#include "hw/core/sysbus.h"
+#include "migration/vmstate.h"
+#include "hw/core/qdev-properties.h"
+#include "trace.h"
+
+#include "hw/core/remote-port-proto.h"
+#include "hw/core/remote-port.h"
+#include "hw/core/remote-port-memory-master.h"
+
+#ifndef REMOTE_PORT_ERR_DEBUG
+#define REMOTE_PORT_DEBUG_LEVEL 0
+#else
+#define REMOTE_PORT_DEBUG_LEVEL 1
+#endif
+
+#define DB_PRINT_L(level, ...) do { \
+ if (REMOTE_PORT_DEBUG_LEVEL > level) { \
+ fprintf(stderr, ": %s: ", __func__); \
+ fprintf(stderr, ## __VA_ARGS__); \
+ } \
+} while (0)
+
+#define REMOTE_PORT_MEMORY_MASTER_PARENT_CLASS \
+ object_class_get_parent( \
+ object_class_by_name(TYPE_REMOTE_PORT_MEMORY_MASTER))
+
+#define RP_MAX_ACCESS_SIZE 4096
+
+static MemTxResult rp_access(MemoryTransaction *tr)
+{
+ /* TBD */
+ return MEMTX_OK;
+}
+
+static const MemoryRegionOps rp_ops_template = {
+ .access = rp_access,
+ .valid.max_access_size = RP_MAX_ACCESS_SIZE,
+ .valid.unaligned = true,
+ .impl.max_access_size = RP_MAX_ACCESS_SIZE,
+ .impl.unaligned = false,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void rp_memory_master_realize(DeviceState *dev, Error **errp)
+{
+ RemotePortMemoryMaster *s = REMOTE_PORT_MEMORY_MASTER(dev);
+ int i;
+
+ /* Sanity check max access size. */
+ if (s->max_access_size > RP_MAX_ACCESS_SIZE) {
+ error_setg(errp, "%s: max-access-size %d too large! MAX is %d",
+ TYPE_REMOTE_PORT_MEMORY_MASTER, s->max_access_size,
+ RP_MAX_ACCESS_SIZE);
+ return;
+ }
+
+ if (s->max_access_size < 4) {
+ error_setg(errp, "%s: max-access-size %d too small! MIN is 4",
+ TYPE_REMOTE_PORT_MEMORY_MASTER, s->max_access_size);
+ return;
+ }
+
+ assert(s->rp);
+ s->peer = rp_get_peer(s->rp);
+
+ /* Create a single static region if configuration says so. */
+ if (s->map_num) {
+ /* Initialize rp_ops from template. */
+ s->rp_ops = g_malloc(sizeof *s->rp_ops);
+ memcpy(s->rp_ops, &rp_ops_template, sizeof *s->rp_ops);
+ s->rp_ops->valid.max_access_size = s->max_access_size;
+ s->rp_ops->impl.max_access_size = s->max_access_size;
+
+ s->mmaps = g_new0(typeof(*s->mmaps), s->map_num);
+ for (i = 0; i < s->map_num; ++i) {
+ char *name = g_strdup_printf("rp-%d", i);
+
+ s->mmaps[i].offset = s->map_offset;
+ memory_region_init_io(&s->mmaps[i].iomem, OBJECT(dev), s->rp_ops,
+ &s->mmaps[i], name, s->map_size);
+ sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmaps[i].iomem);
+ s->mmaps[i].parent = s;
+ g_free(name);
+ }
+ }
+}
+
+static void rp_prop_allow_set_link(const Object *obj, const char *name,
+ Object *val, Error **errp)
+{
+}
+
+static void rp_memory_master_init(Object *obj)
+{
+ RemotePortMemoryMaster *rpms = REMOTE_PORT_MEMORY_MASTER(obj);
+ object_property_add_link(obj, "rp-adaptor0", "remote-port",
+ (Object **)&rpms->rp,
+ rp_prop_allow_set_link,
+ OBJ_PROP_LINK_STRONG);
+}
+
+static Property rp_properties[] = {
+ DEFINE_PROP_UINT32("map-num", RemotePortMemoryMaster, map_num, 0),
+ DEFINE_PROP_UINT64("map-offset", RemotePortMemoryMaster, map_offset, 0),
+ DEFINE_PROP_UINT64("map-size", RemotePortMemoryMaster, map_size, 0),
+ DEFINE_PROP_UINT32("rp-chan0", RemotePortMemoryMaster, rp_dev, 0),
+ DEFINE_PROP_BOOL("relative", RemotePortMemoryMaster, relative, false),
+ DEFINE_PROP_UINT32("max-access-size", RemotePortMemoryMaster,
+ max_access_size, RP_MAX_ACCESS_SIZE),
+};
+
+static void rp_memory_master_class_init(ObjectClass *oc, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+ device_class_set_props_n(dc, rp_properties, ARRAY_SIZE(rp_properties));
+ dc->realize = rp_memory_master_realize;
+}
+
+static const TypeInfo rp_info = {
+ .name = TYPE_REMOTE_PORT_MEMORY_MASTER,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(RemotePortMemoryMaster),
+ .instance_init = rp_memory_master_init,
+ .class_init = rp_memory_master_class_init,
+ .interfaces = (InterfaceInfo[]) {
+ { TYPE_REMOTE_PORT_DEVICE },
+ { },
+ },
+};
+
+static void rp_register_types(void)
+{
+ type_register_static(&rp_info);
+}
+
+type_init(rp_register_types)
diff --git a/hw/core/remote-port.c b/hw/core/remote-port.c
index 6a1933a5a6..c783a12153 100644
--- a/hw/core/remote-port.c
+++ b/hw/core/remote-port.c
@@ -938,6 +938,11 @@ static void rp_init(Object *obj)
}
}
+struct rp_peer_state *rp_get_peer(RemotePort *s)
+{
+ return &s->peer;
+}
+
static void rp_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/include/hw/core/remote-port-memory-master.h b/include/hw/core/remote-port-memory-master.h
new file mode 100644
index 0000000000..70f7c38c35
--- /dev/null
+++ b/include/hw/core/remote-port-memory-master.h
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * QEMU remote port memory master. Read and write transactions
+ * recieved from QEMU are transmitted over remote-port.
+ *
+ * Copyright (c) 2020 Xilinx Inc
+ * Written by Edgar E. Iglesias <edgar.iglesias@xilinx.com>
+ *
+ * This code is licensed under the GNU GPL.
+ */
+#ifndef REMOTE_PORT_MEMORY_MASTER_H
+#define REMOTE_PORT_MEMORY_MASTER_H
+
+#include "hw/core/remote-port.h"
+
+#define TYPE_REMOTE_PORT_MEMORY_MASTER "remote-port-memory-master"
+#define REMOTE_PORT_MEMORY_MASTER(obj) \
+ OBJECT_CHECK(RemotePortMemoryMaster, (obj), \
+ TYPE_REMOTE_PORT_MEMORY_MASTER)
+
+typedef struct RemotePortMemoryMaster RemotePortMemoryMaster;
+
+typedef struct RemotePortMap {
+ void *parent;
+ MemoryRegion iomem;
+ uint32_t rp_dev;
+ uint64_t offset;
+} RemotePortMap;
+
+struct RemotePortMemoryMaster {
+ /* private */
+ SysBusDevice parent;
+
+ MemoryRegionOps *rp_ops;
+ RemotePortMap *mmaps;
+
+ /* public */
+ uint32_t map_num;
+ uint64_t map_offset;
+ uint64_t map_size;
+ uint32_t rp_dev;
+ bool relative;
+ uint32_t max_access_size;
+ struct RemotePort *rp;
+ struct rp_peer_state *peer;
+ int rp_timeout;
+};
+
+MemTxResult rp_mm_access(RemotePort *rp, uint32_t rp_dev,
+ struct rp_peer_state *peer,
+ MemoryTransaction *tr,
+ bool relative, uint64_t offset);
+
+MemTxResult rp_mm_access_with_def_attr(RemotePort *rp, uint32_t rp_dev,
+ struct rp_peer_state *peer,
+ MemoryTransaction *tr,
+ bool relative, uint64_t offset,
+ uint32_t def_attr);
+#endif
diff --git a/include/hw/core/remote-port.h b/include/hw/core/remote-port.h
index 1d8b64925a..e5dfaf7c3b 100644
--- a/include/hw/core/remote-port.h
+++ b/include/hw/core/remote-port.h
@@ -151,4 +151,6 @@ void rp_process(RemotePort *s);
ssize_t rp_write(RemotePort *s, const void *buf, size_t count);
+struct rp_peer_state *rp_get_peer(RemotePort *s);
+
#endif
--
2.43.0