1
2
3
4
5
6
7
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#include "migration/vmstate.h"
17#include "hw/qdev-properties.h"
18#include "trace.h"
19
20#include "hw/remote-port-proto.h"
21#include "hw/remote-port.h"
22#include "hw/remote-port-device.h"
23#include "hw/remote-port-memory-master.h"
24
25#include "hw/fdt_generic_util.h"
26
27#ifndef REMOTE_PORT_ERR_DEBUG
28#define REMOTE_PORT_DEBUG_LEVEL 0
29#else
30#define REMOTE_PORT_DEBUG_LEVEL 1
31#endif
32
33#define DB_PRINT_L(level, ...) do { \
34 if (REMOTE_PORT_DEBUG_LEVEL > level) { \
35 fprintf(stderr, ": %s: ", __func__); \
36 fprintf(stderr, ## __VA_ARGS__); \
37 } \
38} while (0)
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
44#define RP_MAX_ACCESS_SIZE 4096
45
46MemTxResult rp_mm_access(RemotePort *rp, uint32_t rp_dev,
47 struct rp_peer_state *peer,
48 MemoryTransaction *tr,
49 bool relative, uint64_t offset)
50{
51 uint64_t addr = tr->addr;
52 RemotePortRespSlot *rsp_slot;
53 RemotePortDynPkt *rsp;
54 struct {
55 struct rp_pkt_busaccess_ext_base pkt;
56 uint8_t reserved[RP_MAX_ACCESS_SIZE];
57 } pay;
58 uint8_t *data = rp_busaccess_tx_dataptr(peer, &pay.pkt);
59 struct rp_encode_busaccess_in in = {0};
60 int i;
61 int len;
62 MemTxResult ret;
63
64 DB_PRINT_L(0, "addr: %" HWADDR_PRIx " data: %" PRIx64 "\n",
65 addr, tr->data.u64);
66
67 if (tr->rw) {
68
69 if (tr->size <= 8) {
70 for (i = 0; i < tr->size; i++) {
71 data[i] = tr->data.u64 >> (i * 8);
72 }
73 } else {
74 memcpy(data, tr->data.p8, tr->size);
75 }
76 }
77
78 addr += relative ? 0 : offset;
79
80 in.cmd = tr->rw ? RP_CMD_write : RP_CMD_read;
81 in.id = rp_new_id(rp);
82 in.dev = rp_dev;
83 in.clk = rp_normalized_vmclk(rp);
84 in.master_id = tr->attr.requester_id;
85 in.addr = addr;
86 in.attr |= tr->attr.secure ? RP_BUS_ATTR_SECURE : 0;
87 in.size = tr->size;
88 in.stream_width = tr->size;
89 len = rp_encode_busaccess(peer, &pay.pkt, &in);
90 len += tr->rw ? tr->size : 0;
91
92 trace_remote_port_memory_master_tx_busaccess(rp_cmd_to_string(in.cmd),
93 in.id, in.flags, in.dev, in.addr, in.size, in.attr);
94
95 rp_rsp_mutex_lock(rp);
96 rp_write(rp, (void *) &pay, len);
97
98 rsp_slot = rp_dev_wait_resp(rp, in.dev, in.id);
99 rsp = &rsp_slot->rsp;
100
101
102 assert(rsp->pkt->hdr.id == in.id);
103
104 switch (rp_get_busaccess_response(rsp->pkt)) {
105 case RP_RESP_OK:
106 ret = MEMTX_OK;
107 break;
108 case RP_RESP_ADDR_ERROR:
109 ret = MEMTX_DECODE_ERROR;
110 break;
111 default:
112 ret = MEMTX_ERROR;
113 break;
114 }
115
116 if (!tr->rw) {
117 data = rp_busaccess_rx_dataptr(peer, &rsp->pkt->busaccess_ext_base);
118
119 if (tr->size <= 8) {
120 for (i = 0; i < tr->size; i++) {
121 tr->data.u64 |= data[i] << (i * 8);
122 }
123 } else {
124 memcpy(tr->data.p8, data, tr->size);
125 }
126 }
127
128 trace_remote_port_memory_master_rx_busaccess(
129 rp_cmd_to_string(rsp->pkt->hdr.cmd), rsp->pkt->hdr.id,
130 rsp->pkt->hdr.flags, rsp->pkt->hdr.dev, rsp->pkt->busaccess.addr,
131 rsp->pkt->busaccess.len, rsp->pkt->busaccess.attributes);
132
133 rp_resp_slot_done(rp, rsp_slot);
134 rp_rsp_mutex_unlock(rp);
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149 rp_process(rp);
150
151
152 rp_restart_sync_timer(rp);
153 DB_PRINT_L(1, "\n");
154 return ret;
155}
156
157static MemTxResult rp_access(MemoryTransaction *tr)
158{
159 RemotePortMap *map = tr->opaque;
160 RemotePortMemoryMaster *s = map->parent;
161
162 return rp_mm_access(s->rp, s->rp_dev, s->peer, tr, s->relative,
163 map->offset);
164}
165
166static const MemoryRegionOps rp_ops_template = {
167 .access = rp_access,
168 .valid.max_access_size = RP_MAX_ACCESS_SIZE,
169 .impl.unaligned = false,
170 .endianness = DEVICE_LITTLE_ENDIAN,
171};
172
173static void rp_memory_master_realize(DeviceState *dev, Error **errp)
174{
175 RemotePortMemoryMaster *s = REMOTE_PORT_MEMORY_MASTER(dev);
176 int i;
177
178
179 if (s->max_access_size > RP_MAX_ACCESS_SIZE) {
180 error_setg(errp, "%s: max-access-size %d too large! MAX is %d",
181 TYPE_REMOTE_PORT_MEMORY_MASTER, s->max_access_size,
182 RP_MAX_ACCESS_SIZE);
183 return;
184 }
185
186 if (s->max_access_size < 4) {
187 error_setg(errp, "%s: max-access-size %d too small! MIN is 4",
188 TYPE_REMOTE_PORT_MEMORY_MASTER, s->max_access_size);
189 return;
190 }
191
192 assert(s->rp);
193 s->peer = rp_get_peer(s->rp);
194
195
196 if (s->map_num) {
197
198 s->rp_ops = g_malloc(sizeof *s->rp_ops);
199 memcpy(s->rp_ops, &rp_ops_template, sizeof *s->rp_ops);
200 s->rp_ops->valid.max_access_size = s->max_access_size;
201
202 s->mmaps = g_new0(typeof(*s->mmaps), s->map_num);
203 for (i = 0; i < s->map_num; ++i) {
204 char *name = g_strdup_printf("rp-%d", i);
205
206 s->mmaps[i].offset = s->map_offset;
207 memory_region_init_io(&s->mmaps[i].iomem, OBJECT(dev), s->rp_ops,
208 &s->mmaps[i], name, s->map_size);
209 sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmaps[i].iomem);
210 s->mmaps[i].parent = s;
211 g_free(name);
212 }
213 }
214}
215
216static void rp_memory_master_init(Object *obj)
217{
218 RemotePortMemoryMaster *rpms = REMOTE_PORT_MEMORY_MASTER(obj);
219 object_property_add_link(obj, "rp-adaptor0", "remote-port",
220 (Object **)&rpms->rp,
221 qdev_prop_allow_set_link,
222 OBJ_PROP_LINK_STRONG);
223}
224
225static bool rp_parse_reg(FDTGenericMMap *obj, FDTGenericRegPropInfo reg,
226 Error **errp)
227{
228 RemotePortMemoryMaster *s = REMOTE_PORT_MEMORY_MASTER(obj);
229 FDTGenericMMapClass *parent_fmc =
230 FDT_GENERIC_MMAP_CLASS(REMOTE_PORT_MEMORY_MASTER_PARENT_CLASS);
231 int i;
232
233
234 s->rp_ops = g_malloc(sizeof *s->rp_ops);
235 memcpy(s->rp_ops, &rp_ops_template, sizeof *s->rp_ops);
236 s->rp_ops->valid.max_access_size = s->max_access_size;
237
238 s->mmaps = g_new0(typeof(*s->mmaps), reg.n);
239 for (i = 0; i < reg.n; ++i) {
240 char *name = g_strdup_printf("rp-%d", i);
241
242 s->mmaps[i].offset = reg.a[i];
243 memory_region_init_io(&s->mmaps[i].iomem, OBJECT(obj), s->rp_ops,
244 &s->mmaps[i], name, reg.s[i]);
245 sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmaps[i].iomem);
246 s->mmaps[i].parent = s;
247 g_free(name);
248 }
249
250 return parent_fmc ? parent_fmc->parse_reg(obj, reg, errp) : false;
251}
252
253static Property rp_properties[] = {
254 DEFINE_PROP_UINT32("map-num", RemotePortMemoryMaster, map_num, 0),
255 DEFINE_PROP_UINT64("map-offset", RemotePortMemoryMaster, map_offset, 0),
256 DEFINE_PROP_UINT64("map-size", RemotePortMemoryMaster, map_size, 0),
257 DEFINE_PROP_UINT32("rp-chan0", RemotePortMemoryMaster, rp_dev, 0),
258 DEFINE_PROP_BOOL("relative", RemotePortMemoryMaster, relative, false),
259 DEFINE_PROP_UINT32("max-access-size", RemotePortMemoryMaster,
260 max_access_size, RP_MAX_ACCESS_SIZE),
261 DEFINE_PROP_END_OF_LIST()
262};
263
264static void rp_memory_master_class_init(ObjectClass *oc, void *data)
265{
266 FDTGenericMMapClass *fmc = FDT_GENERIC_MMAP_CLASS(oc);
267 DeviceClass *dc = DEVICE_CLASS(oc);
268 device_class_set_props(dc, rp_properties);
269 dc->realize = rp_memory_master_realize;
270 fmc->parse_reg = rp_parse_reg;
271}
272
273static const TypeInfo rp_info = {
274 .name = TYPE_REMOTE_PORT_MEMORY_MASTER,
275 .parent = TYPE_SYS_BUS_DEVICE,
276 .instance_size = sizeof(RemotePortMemoryMaster),
277 .instance_init = rp_memory_master_init,
278 .class_init = rp_memory_master_class_init,
279 .interfaces = (InterfaceInfo[]) {
280 { TYPE_FDT_GENERIC_MMAP },
281 { TYPE_REMOTE_PORT_DEVICE },
282 { },
283 },
284};
285
286static void rp_register_types(void)
287{
288 type_register_static(&rp_info);
289}
290
291type_init(rp_register_types)
292