1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26#ifndef _DEFAULT_SOURCE
27# define _DEFAULT_SOURCE
28#endif
29#include <stdint.h>
30#include <stdlib.h>
31#include <stdio.h>
32#include <stddef.h>
33#include <assert.h>
34#include "hw/remote-port-proto.h"
35
36#undef MIN
37#define MIN(x, y) (x < y ? x : y)
38
39#if defined(__linux__)
40# include <endian.h>
41#elif defined(__FreeBSD__) || defined(__NetBSD__)
42# include <sys/endian.h>
43#elif defined(__OpenBSD__)
44# include <sys/types.h>
45# define be16toh(x) betoh16(x)
46# define be32toh(x) betoh32(x)
47# define be64toh(x) betoh64(x)
48#elif defined(__WIN32)
49
50# define htobe64(x) _byteswap_uint64(x)
51# define htobe32(x) _byteswap_ulong(x)
52# define htobe16(x) _byteswap_ushort(x)
53
54# define be64toh(x) _byteswap_uint64(x)
55# define be32toh(x) _byteswap_ulong(x)
56# define be16toh(x) _byteswap_ushort(x)
57#endif
58
59
60#ifndef htobe64
61# include <byteswap.h>
62
63# if __BYTE_ORDER == __LITTLE_ENDIAN
64# define htobe64(x) bswap_64(x)
65# define htobe32(x) bswap_32(x)
66# define htobe16(x) bswap_16(x)
67
68# define be64toh(x) bswap_64(x)
69# define be32toh(x) bswap_32(x)
70# define be16toh(x) bswap_16(x)
71# else
72# define htobe64(x) x
73# define htobe32(x) x
74# define htobe16(x) x
75
76# define be64toh(x) x
77# define be32toh(x) x
78# define be16toh(x) x
79# endif
80#endif
81
82static const char *rp_cmd_names[RP_CMD_max + 1] = {
83 [RP_CMD_nop] = "nop",
84 [RP_CMD_hello] = "hello",
85 [RP_CMD_cfg] = "cfg",
86 [RP_CMD_read] = "read",
87 [RP_CMD_write] = "write",
88 [RP_CMD_interrupt] = "interrupt",
89 [RP_CMD_sync] = "sync",
90};
91
92const char *rp_cmd_to_string(enum rp_cmd cmd)
93{
94 assert(cmd <= RP_CMD_max);
95 return rp_cmd_names[cmd];
96}
97
98int rp_decode_hdr(struct rp_pkt *pkt)
99{
100 int used = 0;
101
102 pkt->hdr.cmd = be32toh(pkt->hdr.cmd);
103 pkt->hdr.len = be32toh(pkt->hdr.len);
104 pkt->hdr.id = be32toh(pkt->hdr.id);
105 pkt->hdr.flags = be32toh(pkt->hdr.flags);
106 pkt->hdr.dev = be32toh(pkt->hdr.dev);
107 used += sizeof pkt->hdr;
108 return used;
109}
110
111int rp_decode_payload(struct rp_pkt *pkt)
112{
113 int used = 0;
114
115 uint64_t master_id;
116
117 switch (pkt->hdr.cmd) {
118 case RP_CMD_hello:
119 assert(pkt->hdr.len >= sizeof pkt->hello.version);
120 pkt->hello.version.major = be16toh(pkt->hello.version.major);
121 pkt->hello.version.minor = be16toh(pkt->hello.version.minor);
122 used += sizeof pkt->hello.version;
123
124 if ((pkt->hdr.len - used) >= sizeof pkt->hello.caps) {
125 void *offset;
126 int i;
127
128 pkt->hello.caps.offset = be32toh(pkt->hello.caps.offset);
129 pkt->hello.caps.len = be16toh(pkt->hello.caps.len);
130
131 offset = (char *)pkt + pkt->hello.caps.offset;
132 for (i = 0; i < pkt->hello.caps.len; i++) {
133 uint32_t cap;
134
135
136
137 memcpy(&cap, offset + i * sizeof cap, sizeof cap);
138 cap = be32toh(cap);
139 memcpy(offset + i * sizeof cap, &cap, sizeof cap);
140 }
141 used += sizeof pkt->hello.caps;
142 } else {
143 pkt->hello.caps.offset = 0;
144 pkt->hello.caps.len = 0;
145 }
146
147
148
149 used = pkt->hdr.len;
150 break;
151 case RP_CMD_write:
152 case RP_CMD_read:
153 assert(pkt->hdr.len >= sizeof pkt->busaccess - sizeof pkt->hdr);
154 pkt->busaccess.timestamp = be64toh(pkt->busaccess.timestamp);
155 pkt->busaccess.addr = be64toh(pkt->busaccess.addr);
156 pkt->busaccess.master_id = be16toh(pkt->busaccess.master_id);
157 pkt->busaccess.attributes = be64toh(pkt->busaccess.attributes);
158 pkt->busaccess.len = be32toh(pkt->busaccess.len);
159 pkt->busaccess.width = be32toh(pkt->busaccess.width);
160 pkt->busaccess.stream_width = be32toh(pkt->busaccess.stream_width);
161 master_id = be16toh(pkt->busaccess.master_id);
162
163 used += sizeof pkt->busaccess - sizeof pkt->hdr;
164
165 if (pkt->busaccess.attributes & RP_BUS_ATTR_EXT_BASE) {
166 struct rp_pkt_busaccess_ext_base *pext = &pkt->busaccess_ext_base;
167
168 assert(pkt->hdr.len >= sizeof *pext - sizeof pkt->hdr);
169 master_id |= (uint64_t)be16toh(pext->master_id_31_16) << 16;
170 master_id |= (uint64_t)be32toh(pext->master_id_63_32) << 32;
171 pext->data_offset = be32toh(pext->data_offset);
172 pext->next_offset = be32toh(pext->next_offset);
173 pext->byte_enable_offset = be32toh(pext->byte_enable_offset);
174 pext->byte_enable_len = be32toh(pext->byte_enable_len);
175
176 used += sizeof *pext - sizeof pkt->busaccess;
177 }
178 pkt->busaccess.master_id = master_id;
179 break;
180 case RP_CMD_interrupt:
181 pkt->interrupt.timestamp = be64toh(pkt->interrupt.timestamp);
182 pkt->interrupt.vector = be64toh(pkt->interrupt.vector);
183 pkt->interrupt.line = be32toh(pkt->interrupt.line);
184 pkt->interrupt.val = pkt->interrupt.val;
185 used += pkt->hdr.len;
186 break;
187 case RP_CMD_sync:
188 pkt->sync.timestamp = be64toh(pkt->interrupt.timestamp);
189 used += pkt->hdr.len;
190 break;
191 default:
192 break;
193 }
194 return used;
195}
196
197void rp_encode_hdr(struct rp_pkt_hdr *hdr, uint32_t cmd, uint32_t id,
198 uint32_t dev, uint32_t len, uint32_t flags)
199{
200 hdr->cmd = htobe32(cmd);
201 hdr->len = htobe32(len);
202 hdr->id = htobe32(id);
203 hdr->dev = htobe32(dev);
204 hdr->flags = htobe32(flags);
205}
206
207size_t rp_encode_hello_caps(uint32_t id, uint32_t dev, struct rp_pkt_hello *pkt,
208 uint16_t version_major, uint16_t version_minor,
209 uint32_t *caps, uint32_t *caps_out,
210 uint32_t caps_len)
211{
212 size_t psize = sizeof *pkt + sizeof caps[0] * caps_len;
213 unsigned int i;
214
215 rp_encode_hdr(&pkt->hdr, RP_CMD_hello, id, dev,
216 psize - sizeof pkt->hdr, 0);
217 pkt->version.major = htobe16(version_major);
218 pkt->version.minor = htobe16(version_minor);
219
220
221 pkt->caps.offset = htobe32(sizeof *pkt);
222 pkt->caps.len = htobe16(caps_len);
223
224 for (i = 0; i < caps_len; i++) {
225 uint32_t cap;
226
227 cap = caps[i];
228 caps_out[i] = htobe32(cap);
229 }
230 return sizeof *pkt;
231}
232
233static void rp_encode_busaccess_common(struct rp_pkt_busaccess *pkt,
234 int64_t clk, uint16_t master_id,
235 uint64_t addr, uint64_t attr, uint32_t size,
236 uint32_t width, uint32_t stream_width)
237{
238 pkt->timestamp = htobe64(clk);
239 pkt->master_id = htobe16(master_id);
240 pkt->addr = htobe64(addr);
241 pkt->attributes = htobe64(attr);
242 pkt->len = htobe32(size);
243 pkt->width = htobe32(width);
244 pkt->stream_width = htobe32(stream_width);
245}
246
247size_t rp_encode_read(uint32_t id, uint32_t dev,
248 struct rp_pkt_busaccess *pkt,
249 int64_t clk, uint16_t master_id,
250 uint64_t addr, uint64_t attr, uint32_t size,
251 uint32_t width, uint32_t stream_width)
252{
253 rp_encode_hdr(&pkt->hdr, RP_CMD_read, id, dev,
254 sizeof *pkt - sizeof pkt->hdr, 0);
255 rp_encode_busaccess_common(pkt, clk, master_id, addr, attr,
256 size, width, stream_width);
257 return sizeof *pkt;
258}
259
260size_t rp_encode_read_resp(uint32_t id, uint32_t dev,
261 struct rp_pkt_busaccess *pkt,
262 int64_t clk, uint16_t master_id,
263 uint64_t addr, uint64_t attr, uint32_t size,
264 uint32_t width, uint32_t stream_width)
265{
266 rp_encode_hdr(&pkt->hdr, RP_CMD_read, id, dev,
267 sizeof *pkt - sizeof pkt->hdr + size, RP_PKT_FLAGS_response);
268 rp_encode_busaccess_common(pkt, clk, master_id, addr, attr,
269 size, width, stream_width);
270 return sizeof *pkt + size;
271}
272
273size_t rp_encode_write(uint32_t id, uint32_t dev,
274 struct rp_pkt_busaccess *pkt,
275 int64_t clk, uint16_t master_id,
276 uint64_t addr, uint64_t attr, uint32_t size,
277 uint32_t width, uint32_t stream_width)
278{
279 rp_encode_hdr(&pkt->hdr, RP_CMD_write, id, dev,
280 sizeof *pkt - sizeof pkt->hdr + size, 0);
281 rp_encode_busaccess_common(pkt, clk, master_id, addr, attr,
282 size, width, stream_width);
283 return sizeof *pkt;
284}
285
286size_t rp_encode_write_resp(uint32_t id, uint32_t dev,
287 struct rp_pkt_busaccess *pkt,
288 int64_t clk, uint16_t master_id,
289 uint64_t addr, uint64_t attr, uint32_t size,
290 uint32_t width, uint32_t stream_width)
291{
292 rp_encode_hdr(&pkt->hdr, RP_CMD_write, id, dev,
293 sizeof *pkt - sizeof pkt->hdr, RP_PKT_FLAGS_response);
294 rp_encode_busaccess_common(pkt, clk, master_id, addr, attr,
295 size, width, stream_width);
296 return sizeof *pkt;
297}
298
299
300size_t rp_encode_busaccess(struct rp_peer_state *peer,
301 struct rp_pkt_busaccess_ext_base *pkt,
302 struct rp_encode_busaccess_in *in) {
303 struct rp_pkt_busaccess *pkt_v4_0 = (void *) pkt;
304 uint32_t hsize = 0;
305 uint32_t ret_size = 0;
306
307
308 if (in->cmd == RP_CMD_write && !(in->flags & RP_PKT_FLAGS_response)) {
309 hsize = in->size;
310 }
311 if (in->cmd == RP_CMD_read && (in->flags & RP_PKT_FLAGS_response)) {
312 hsize = in->size;
313 ret_size = in->size;
314 }
315
316
317
318
319
320 if (!peer->caps.busaccess_ext_base && !(in->attr & RP_BUS_ATTR_EXT_BASE)) {
321
322 assert(in->master_id < UINT16_MAX);
323
324 rp_encode_hdr(&pkt->hdr, in->cmd, in->id, in->dev,
325 sizeof *pkt_v4_0 - sizeof pkt->hdr + hsize, in->flags);
326 rp_encode_busaccess_common(pkt_v4_0, in->clk, in->master_id,
327 in->addr, in->attr,
328 in->size, in->width, in->stream_width);
329 return sizeof *pkt_v4_0 + ret_size;
330 }
331
332
333 pkt->master_id_31_16 = htobe16(in->master_id >> 16);
334 pkt->master_id_63_32 = htobe32(in->master_id >> 32);
335
336
337 pkt->data_offset = htobe32(sizeof *pkt);
338 pkt->next_offset = 0;
339
340 pkt->byte_enable_offset = htobe32(sizeof *pkt + hsize);
341 pkt->byte_enable_len = htobe32(in->byte_enable_len);
342 hsize += in->byte_enable_len;
343
344 rp_encode_hdr(&pkt->hdr, in->cmd, in->id, in->dev,
345 sizeof *pkt - sizeof pkt->hdr + hsize, in->flags);
346 rp_encode_busaccess_common(pkt_v4_0, in->clk, in->master_id, in->addr,
347 in->attr | RP_BUS_ATTR_EXT_BASE,
348 in->size, in->width, in->stream_width);
349
350 return sizeof *pkt + ret_size;
351}
352
353size_t rp_encode_interrupt_f(uint32_t id, uint32_t dev,
354 struct rp_pkt_interrupt *pkt,
355 int64_t clk,
356 uint32_t line, uint64_t vector, uint8_t val,
357 uint32_t flags)
358{
359 rp_encode_hdr(&pkt->hdr, RP_CMD_interrupt, id, dev,
360 sizeof *pkt - sizeof pkt->hdr, flags);
361 pkt->timestamp = htobe64(clk);
362 pkt->vector = htobe64(vector);
363 pkt->line = htobe32(line);
364 pkt->val = val;
365 return sizeof *pkt;
366}
367
368size_t rp_encode_interrupt(uint32_t id, uint32_t dev,
369 struct rp_pkt_interrupt *pkt,
370 int64_t clk,
371 uint32_t line, uint64_t vector, uint8_t val)
372{
373 return rp_encode_interrupt_f(id, dev, pkt, clk, line, vector, val, 0);
374}
375
376static size_t rp_encode_sync_common(uint32_t id, uint32_t dev,
377 struct rp_pkt_sync *pkt,
378 int64_t clk, uint32_t flags)
379{
380 rp_encode_hdr(&pkt->hdr, RP_CMD_sync, id, dev,
381 sizeof *pkt - sizeof pkt->hdr, flags);
382 pkt->timestamp = htobe64(clk);
383 return sizeof *pkt;
384}
385
386size_t rp_encode_sync(uint32_t id, uint32_t dev,
387 struct rp_pkt_sync *pkt,
388 int64_t clk)
389{
390 return rp_encode_sync_common(id, dev, pkt, clk, 0);
391}
392
393size_t rp_encode_sync_resp(uint32_t id, uint32_t dev,
394 struct rp_pkt_sync *pkt,
395 int64_t clk)
396{
397 return rp_encode_sync_common(id, dev, pkt, clk, RP_PKT_FLAGS_response);
398}
399
400void rp_process_caps(struct rp_peer_state *peer,
401 void *caps, size_t caps_len)
402{
403 int i;
404
405 assert(peer->caps.busaccess_ext_base == false);
406
407 for (i = 0; i < caps_len; i++) {
408 uint32_t cap;
409
410 memcpy(&cap, caps + i * sizeof cap, sizeof cap);
411
412 switch (cap) {
413 case CAP_BUSACCESS_EXT_BASE:
414 peer->caps.busaccess_ext_base = true;
415 break;
416 case CAP_BUSACCESS_EXT_BYTE_EN:
417 peer->caps.busaccess_ext_byte_en = true;
418 break;
419 case CAP_WIRE_POSTED_UPDATES:
420 peer->caps.wire_posted_updates = true;
421 break;
422 }
423 }
424}
425
426
427void rp_dpkt_alloc(RemotePortDynPkt *dpkt, size_t size)
428{
429 if (dpkt->size < size) {
430 char *u8;
431 dpkt->pkt = realloc(dpkt->pkt, size);
432 u8 = (void *) dpkt->pkt;
433 memset(u8 + dpkt->size, 0, size - dpkt->size);
434 dpkt->size = size;
435 }
436}
437
438void rp_dpkt_swap(RemotePortDynPkt *a, RemotePortDynPkt *b)
439{
440 struct rp_pkt *tmp_pkt;
441 size_t tmp_size;
442
443 tmp_pkt = a->pkt;
444 tmp_size = a->size;
445 a->pkt = b->pkt;
446 a->size = b->size;
447 b->pkt = tmp_pkt;
448 b->size = tmp_size;
449}
450
451bool rp_dpkt_is_valid(RemotePortDynPkt *dpkt)
452{
453 return dpkt->size > 0 && dpkt->pkt->hdr.len;
454}
455
456void rp_dpkt_invalidate(RemotePortDynPkt *dpkt)
457{
458 assert(rp_dpkt_is_valid(dpkt));
459 dpkt->pkt->hdr.len = 0;
460}
461
462inline void rp_dpkt_free(RemotePortDynPkt *dpkt)
463{
464 dpkt->size = 0;
465 free(dpkt->pkt);
466}
467