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 if (s->mr) {
123 s->as = g_malloc0(sizeof(AddressSpace));
124 address_space_init(s->as, s->mr, NULL);
125 } else {
126 s->as = &address_space_memory;
127 }
128}
129
130static void rp_memory_slave_write(RemotePortDevice *s, struct rp_pkt *pkt)
131{
132 return rp_cmd_rw(REMOTE_PORT_MEMORY_SLAVE(s), pkt,
133 DMA_DIRECTION_FROM_DEVICE);
134}
135
136static void rp_memory_slave_read(RemotePortDevice *s, struct rp_pkt *pkt)
137{
138 return rp_cmd_rw(REMOTE_PORT_MEMORY_SLAVE(s), pkt,
139 DMA_DIRECTION_TO_DEVICE);
140}
141
142static void rp_memory_slave_init(Object *obj)
143{
144 RemotePortMemorySlave *rpms = REMOTE_PORT_MEMORY_SLAVE(obj);
145
146 object_property_add_link(obj, "rp-adaptor0", "remote-port",
147 (Object **)&rpms->rp,
148 qdev_prop_allow_set_link_before_realize,
149 OBJ_PROP_LINK_UNREF_ON_RELEASE,
150 &error_abort);
151 object_property_add_link(obj, "mr", TYPE_MEMORY_REGION,
152 (Object **)&rpms->mr,
153 qdev_prop_allow_set_link_before_realize,
154 OBJ_PROP_LINK_UNREF_ON_RELEASE,
155 &error_abort);
156}
157
158static void rp_memory_slave_class_init(ObjectClass *oc, void *data)
159{
160 RemotePortDeviceClass *rpdc = REMOTE_PORT_DEVICE_CLASS(oc);
161 DeviceClass *dc = DEVICE_CLASS(oc);
162
163 rpdc->ops[RP_CMD_write] = rp_memory_slave_write;
164 rpdc->ops[RP_CMD_read] = rp_memory_slave_read;
165 dc->realize = rp_memory_slave_realize;
166}
167
168static const TypeInfo rp_info = {
169 .name = TYPE_REMOTE_PORT_MEMORY_SLAVE,
170 .parent = TYPE_DEVICE,
171 .instance_size = sizeof(RemotePortMemorySlave),
172 .instance_init = rp_memory_slave_init,
173 .class_init = rp_memory_slave_class_init,
174 .interfaces = (InterfaceInfo[]) {
175 { TYPE_REMOTE_PORT_DEVICE },
176 { },
177 },
178};
179
180static void rp_register_types(void)
181{
182 type_register_static(&rp_info);
183}
184
185type_init(rp_register_types)
186