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#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
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
102
103
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
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