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