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#define _BSD_SOURCE
27#include <stdint.h>
28#include <stdlib.h>
29#include <stdio.h>
30#include <stddef.h>
31#include <assert.h>
32#include "hw/remote-port-proto.h"
33
34#undef MIN
35#define MIN(x, y) (x < y ? x : y)
36
37#if defined(__linux__)
38# include <endian.h>
39#elif defined(__FreeBSD__) || defined(__NetBSD__)
40# include <sys/endian.h>
41#elif defined(__OpenBSD__)
42# include <sys/types.h>
43# define be16toh(x) betoh16(x)
44# define be32toh(x) betoh32(x)
45# define be64toh(x) betoh64(x)
46#elif defined(__WIN32)
47
48# define htobe64(x) _byteswap_uint64(x)
49# define htobe32(x) _byteswap_ulong(x)
50# define htobe16(x) _byteswap_ushort(x)
51
52# define be64toh(x) _byteswap_uint64(x)
53# define be32toh(x) _byteswap_ulong(x)
54# define be16toh(x) _byteswap_ushort(x)
55#endif
56
57
58#ifndef htobe64
59# include <byteswap.h>
60
61# if __BYTE_ORDER == __LITTLE_ENDIAN
62# define htobe64(x) bswap_64(x)
63# define htobe32(x) bswap_32(x)
64# define htobe16(x) bswap_16(x)
65
66# define be64toh(x) bswap_64(x)
67# define be32toh(x) bswap_32(x)
68# define be16toh(x) bswap_16(x)
69# else
70# define htobe64(x) x
71# define htobe32(x) x
72# define htobe16(x) x
73
74# define be64toh(x) x
75# define be32toh(x) x
76# define be16toh(x) x
77# endif
78#endif
79
80#define RP_OPT_ENT(name) [RP_OPT_ ## name] = offsetof(struct rp_cfg_state, name)
81static const size_t rp_opt_map[] = {
82 RP_OPT_ENT(quantum),
83};
84
85static const char *rp_cmd_names[RP_CMD_max + 1] = {
86 [RP_CMD_nop] = "nop",
87 [RP_CMD_hello] = "hello",
88 [RP_CMD_cfg] = "cfg",
89 [RP_CMD_read] = "read",
90 [RP_CMD_write] = "write",
91 [RP_CMD_interrupt] = "interrupt",
92 [RP_CMD_sync] = "sync",
93};
94
95const char *rp_cmd_to_string(enum rp_cmd cmd)
96{
97 assert(cmd <= RP_CMD_max);
98 return rp_cmd_names[cmd];
99}
100
101int rp_decode_hdr(struct rp_pkt *pkt)
102{
103 int used = 0;
104
105 pkt->hdr.cmd = be32toh(pkt->hdr.cmd);
106 pkt->hdr.len = be32toh(pkt->hdr.len);
107 pkt->hdr.id = be32toh(pkt->hdr.id);
108 pkt->hdr.flags = be32toh(pkt->hdr.flags);
109 pkt->hdr.dev = be32toh(pkt->hdr.dev);
110 used += sizeof pkt->hdr;
111 return used;
112}
113
114int rp_decode_payload(struct rp_pkt *pkt)
115{
116 int used = 0;
117
118 switch (pkt->hdr.cmd) {
119 case RP_CMD_hello:
120 assert(pkt->hdr.len >= sizeof pkt->hello.version);
121 pkt->hello.version.major = be16toh(pkt->hello.version.major);
122 pkt->hello.version.minor = be16toh(pkt->hello.version.minor);
123 used += pkt->hdr.len;
124 break;
125 case RP_CMD_write:
126 case RP_CMD_read:
127 assert(pkt->hdr.len >= sizeof pkt->busaccess - sizeof pkt->hdr);
128 pkt->busaccess.timestamp = be64toh(pkt->busaccess.timestamp);
129 pkt->busaccess.addr = be64toh(pkt->busaccess.addr);
130 pkt->busaccess.master_id = be16toh(pkt->busaccess.master_id);
131 pkt->busaccess.attributes = be64toh(pkt->busaccess.attributes);
132 pkt->busaccess.len = be32toh(pkt->busaccess.len);
133 pkt->busaccess.width = be32toh(pkt->busaccess.width);
134 pkt->busaccess.stream_width = be32toh(pkt->busaccess.stream_width);
135 used += sizeof pkt->busaccess - sizeof pkt->hdr;
136 break;
137 case RP_CMD_interrupt:
138 pkt->interrupt.timestamp = be64toh(pkt->interrupt.timestamp);
139 pkt->interrupt.vector = be64toh(pkt->interrupt.vector);
140 pkt->interrupt.line = be32toh(pkt->interrupt.line);
141 pkt->interrupt.val = pkt->interrupt.val;
142 used += pkt->hdr.len;
143 break;
144 case RP_CMD_sync:
145 pkt->sync.timestamp = be64toh(pkt->interrupt.timestamp);
146 used += pkt->hdr.len;
147 break;
148 default:
149 break;
150 }
151 return used;
152}
153
154void rp_encode_hdr(struct rp_pkt_hdr *hdr, uint32_t cmd, uint32_t id,
155 uint32_t dev, uint32_t len, uint32_t flags)
156{
157 hdr->cmd = htobe32(cmd);
158 hdr->len = htobe32(len);
159 hdr->id = htobe32(id);
160 hdr->dev = htobe32(dev);
161 hdr->flags = htobe32(flags);
162}
163
164size_t rp_encode_hello(uint32_t id, uint32_t dev, struct rp_pkt_hello *pkt,
165 uint16_t version_major, uint16_t version_minor)
166{
167 rp_encode_hdr(&pkt->hdr, RP_CMD_hello, id, dev,
168 sizeof *pkt - sizeof pkt->hdr, 0);
169 pkt->version.major = htobe16(version_major);
170 pkt->version.minor = htobe16(version_minor);
171 return sizeof *pkt;
172}
173
174static void rp_encode_busaccess_common(struct rp_pkt_busaccess *pkt,
175 int64_t clk, uint16_t master_id,
176 uint64_t addr, uint32_t attr, uint32_t size,
177 uint32_t width, uint32_t stream_width)
178{
179 pkt->timestamp = htobe64(clk);
180 pkt->master_id = htobe16(master_id);
181 pkt->addr = htobe64(addr);
182 pkt->attributes = htobe64(attr);
183 pkt->len = htobe32(size);
184 pkt->width = htobe32(width);
185 pkt->stream_width = htobe32(stream_width);
186}
187
188size_t rp_encode_read(uint32_t id, uint32_t dev,
189 struct rp_pkt_busaccess *pkt,
190 int64_t clk, uint16_t master_id,
191 uint64_t addr, uint32_t attr, uint32_t size,
192 uint32_t width, uint32_t stream_width)
193{
194 rp_encode_hdr(&pkt->hdr, RP_CMD_read, id, dev,
195 sizeof *pkt - sizeof pkt->hdr, 0);
196 rp_encode_busaccess_common(pkt, clk, master_id, addr, attr,
197 size, width, stream_width);
198 return sizeof *pkt;
199}
200
201size_t rp_encode_read_resp(uint32_t id, uint32_t dev,
202 struct rp_pkt_busaccess *pkt,
203 int64_t clk, uint16_t master_id,
204 uint64_t addr, uint32_t attr, uint32_t size,
205 uint32_t width, uint32_t stream_width)
206{
207 rp_encode_hdr(&pkt->hdr, RP_CMD_read, id, dev,
208 sizeof *pkt - sizeof pkt->hdr + size, RP_PKT_FLAGS_response);
209 rp_encode_busaccess_common(pkt, clk, master_id, addr, attr,
210 size, width, stream_width);
211 return sizeof *pkt + size;
212}
213
214size_t rp_encode_write(uint32_t id, uint32_t dev,
215 struct rp_pkt_busaccess *pkt,
216 int64_t clk, uint16_t master_id,
217 uint64_t addr, uint32_t attr, uint32_t size,
218 uint32_t width, uint32_t stream_width)
219{
220 rp_encode_hdr(&pkt->hdr, RP_CMD_write, id, dev,
221 sizeof *pkt - sizeof pkt->hdr + size, 0);
222 rp_encode_busaccess_common(pkt, clk, master_id, addr, attr,
223 size, width, stream_width);
224 return sizeof *pkt;
225}
226
227size_t rp_encode_write_resp(uint32_t id, uint32_t dev,
228 struct rp_pkt_busaccess *pkt,
229 int64_t clk, uint16_t master_id,
230 uint64_t addr, uint32_t attr, uint32_t size,
231 uint32_t width, uint32_t stream_width)
232{
233 rp_encode_hdr(&pkt->hdr, RP_CMD_write, id, dev,
234 sizeof *pkt - sizeof pkt->hdr, RP_PKT_FLAGS_response);
235 rp_encode_busaccess_common(pkt, clk, master_id, addr, attr,
236 size, width, stream_width);
237 return sizeof *pkt;
238}
239
240size_t rp_encode_interrupt(uint32_t id, uint32_t dev,
241 struct rp_pkt_interrupt *pkt,
242 int64_t clk,
243 uint32_t line, uint64_t vector, uint8_t val)
244{
245 rp_encode_hdr(&pkt->hdr, RP_CMD_interrupt, id, dev,
246 sizeof *pkt - sizeof pkt->hdr, 0);
247 pkt->timestamp = htobe64(clk);
248 pkt->vector = htobe64(vector);
249 pkt->line = htobe32(line);
250 pkt->val = val;
251 return sizeof *pkt;
252}
253
254static size_t rp_encode_sync_common(uint32_t id, uint32_t dev,
255 struct rp_pkt_sync *pkt,
256 int64_t clk, uint32_t flags)
257{
258 rp_encode_hdr(&pkt->hdr, RP_CMD_sync, id, dev,
259 sizeof *pkt - sizeof pkt->hdr, flags);
260 pkt->timestamp = htobe64(clk);
261 return sizeof *pkt;
262}
263
264size_t rp_encode_sync(uint32_t id, uint32_t dev,
265 struct rp_pkt_sync *pkt,
266 int64_t clk)
267{
268 return rp_encode_sync_common(id, dev, pkt, clk, 0);
269}
270
271size_t rp_encode_sync_resp(uint32_t id, uint32_t dev,
272 struct rp_pkt_sync *pkt,
273 int64_t clk)
274{
275 return rp_encode_sync_common(id, dev, pkt, clk, RP_PKT_FLAGS_response);
276}
277
278void rp_dpkt_alloc(RemotePortDynPkt *dpkt, size_t size)
279{
280 if (dpkt->size < size) {
281 char *u8;
282 dpkt->pkt = realloc(dpkt->pkt, size);
283 u8 = (void *) dpkt->pkt;
284 memset(u8 + dpkt->size, 0, size - dpkt->size);
285 dpkt->size = size;
286 }
287}
288
289void rp_dpkt_swap(RemotePortDynPkt *a, RemotePortDynPkt *b)
290{
291 struct rp_pkt *tmp_pkt;
292 size_t tmp_size;
293
294 tmp_pkt = a->pkt;
295 tmp_size = a->size;
296 a->pkt = b->pkt;
297 a->size = b->size;
298 b->pkt = tmp_pkt;
299 b->size = tmp_size;
300}
301
302bool rp_dpkt_is_valid(RemotePortDynPkt *dpkt)
303{
304 return dpkt->size > 0 && dpkt->pkt->hdr.len;
305}
306
307void rp_dpkt_invalidate(RemotePortDynPkt *dpkt)
308{
309 assert(rp_dpkt_is_valid(dpkt));
310 dpkt->pkt->hdr.len = 0;
311}
312
313inline void rp_dpkt_free(RemotePortDynPkt *dpkt)
314{
315 dpkt->size = 0;
316 free(dpkt->pkt);
317}
318