1
2
3
4
5
6
7
8
9
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
44 DeviceState parent;
45
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
90
91
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
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