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#include "qemu/osdep.h"
26#include "hw/sysbus.h"
27#include "qemu/log.h"
28
29#include "qemu/bitops.h"
30#include "qapi/qmp/qerror.h"
31#include "hw/register-dep.h"
32#include "hw/stream.h"
33#include "qapi/error.h"
34#include "hw/remote-port-device.h"
35
36#ifndef REMOTE_PORT_STREAM_ERR_DEBUG
37#define REMOTE_PORT_STREAM_ERR_DEBUG 0
38#endif
39
40#define TYPE_REMOTE_PORT_STREAM "remote-port-stream"
41
42#define REMOTE_PORT_STREAM(obj) \
43 OBJECT_CHECK(RemotePortStream, (obj), TYPE_REMOTE_PORT_STREAM)
44
45typedef struct RemotePortStream RemotePortStream;
46
47struct RemotePortStream {
48 DeviceState parent_obj;
49
50 RemotePort *rp;
51 uint32_t rp_dev;
52 uint16_t stream_width;
53
54 StreamSlave *tx_dev;
55
56 StreamCanPushNotifyFn notify;
57 void *notify_opaque;
58
59 uint8_t *buf;
60 struct rp_pkt pkt;
61
62 bool rsp_pending;
63 uint32_t current_id;
64};
65
66static void rp_stream_notify(void *opaque)
67{
68 RemotePortStream *s = REMOTE_PORT_STREAM(opaque);
69
70
71 if (s->buf && stream_can_push(s->tx_dev, rp_stream_notify, s)) {
72 RemotePortDynPkt rsp;
73 struct rp_encode_busaccess_in in = {0};
74 size_t pktlen = sizeof(struct rp_pkt_busaccess_ext_base);
75 size_t enclen;
76 int64_t delay = 0;
77
78 size_t ret = stream_push(s->tx_dev, s->buf, 4, 0);
79 assert(ret == 4);
80 s->buf = NULL;
81
82 memset(&rsp, 0, sizeof(rsp));
83 rp_dpkt_alloc(&rsp, pktlen);
84 rp_encode_busaccess_in_rsp_init(&in, &s->pkt);
85 in.clk = s->pkt.busaccess.timestamp + delay;
86 enclen = rp_encode_busaccess(rp_get_peer(s->rp),
87 &rsp.pkt->busaccess_ext_base,
88 &in);
89 assert(enclen <= pktlen);
90
91 rp_write(s->rp, (void *)rsp.pkt, pktlen);
92 }
93}
94
95static void rp_stream_write(RemotePortDevice *obj, struct rp_pkt *pkt)
96{
97 RemotePortStream *s = REMOTE_PORT_STREAM(obj);
98
99 assert(pkt->busaccess.width == 0);
100 assert(pkt->busaccess.stream_width == pkt->busaccess.len);
101 assert(pkt->busaccess.addr == 0);
102
103 if (pkt->hdr.flags & RP_PKT_FLAGS_response) {
104
105 assert(s->rsp_pending);
106 s->rsp_pending = false;
107 if (s->notify) {
108 StreamCanPushNotifyFn notify = s->notify;
109 s->notify = NULL;
110 notify(s->notify_opaque);
111 }
112 } else {
113 assert(!s->buf);
114 s->buf = g_memdup(pkt + 1, 4);
115 s->pkt = *pkt;
116 rp_stream_notify(s);
117 }
118}
119
120static bool rp_stream_stream_can_push(StreamSlave *obj,
121 StreamCanPushNotifyFn notify,
122 void *notify_opaque)
123{
124 RemotePortStream *s = REMOTE_PORT_STREAM(obj);
125
126 if (s->rsp_pending) {
127 s->notify = notify;
128 s->notify = notify_opaque;
129 return false;
130 }
131 return true;
132}
133
134static size_t rp_stream_stream_push(StreamSlave *obj, uint8_t *buf,
135 size_t len, uint32_t attr)
136{
137 RemotePortStream *s = REMOTE_PORT_STREAM(obj);
138 RemotePortDynPkt rsp;
139 struct rp_pkt_busaccess_ext_base pkt;
140 struct rp_encode_busaccess_in in = {0};
141 uint64_t rp_attr = stream_attr_has_eop(attr) ? RP_BUS_ATTR_EOP : 0;
142 int64_t clk;
143 int enclen;
144
145 clk = rp_normalized_vmclk(s->rp);
146
147 in.cmd = RP_CMD_write;
148 in.id = rp_new_id(s->rp);
149 in.dev = s->rp_dev;
150 in.clk = clk;
151 in.attr = rp_attr;
152 in.size = len;
153 in.stream_width = s->stream_width;
154 enclen = rp_encode_busaccess(rp_get_peer(s->rp), &pkt, &in);
155
156 rp_rsp_mutex_lock(s->rp);
157 rp_write(s->rp, (void *) &pkt, enclen);
158 rp_write(s->rp, buf, len);
159 rsp = rp_wait_resp(s->rp);
160 assert(rsp.pkt->hdr.id == be32_to_cpu(pkt.hdr.id));
161 rp_dpkt_invalidate(&rsp);
162 rp_rsp_mutex_unlock(s->rp);
163 rp_restart_sync_timer(s->rp);
164 rp_leave_iothread(s->rp);
165 return len;
166}
167
168static void rp_stream_init(Object *obj)
169{
170 RemotePortStream *s = REMOTE_PORT_STREAM(obj);
171
172 object_property_add_link(obj, "axistream-connected",
173 TYPE_STREAM_SLAVE, (Object **) &s->tx_dev,
174 qdev_prop_allow_set_link_before_realize,
175 OBJ_PROP_LINK_UNREF_ON_RELEASE,
176 &error_abort);
177 object_property_add_link(obj, "rp-adaptor0", "remote-port",
178 (Object **)&s->rp,
179 qdev_prop_allow_set_link_before_realize,
180 OBJ_PROP_LINK_UNREF_ON_RELEASE,
181 &error_abort);
182}
183
184static Property rp_properties[] = {
185 DEFINE_PROP_UINT32("rp-chan0", RemotePortStream, rp_dev, 0),
186 DEFINE_PROP_UINT16("stream-width", RemotePortStream, stream_width, 4),
187 DEFINE_PROP_END_OF_LIST(),
188};
189
190static void rp_stream_class_init(ObjectClass *oc, void *data)
191{
192 DeviceClass *dc = DEVICE_CLASS(oc);
193 StreamSlaveClass *ssc = STREAM_SLAVE_CLASS(oc);
194 RemotePortDeviceClass *rpdc = REMOTE_PORT_DEVICE_CLASS(oc);
195
196 ssc->push = rp_stream_stream_push;
197 ssc->can_push = rp_stream_stream_can_push;
198 dc->props = rp_properties;
199 rpdc->ops[RP_CMD_write] = rp_stream_write;
200}
201
202static const TypeInfo rp_stream_info = {
203 .name = TYPE_REMOTE_PORT_STREAM,
204 .parent = TYPE_DEVICE,
205 .instance_size = sizeof(RemotePortStream),
206 .class_init = rp_stream_class_init,
207 .instance_init = rp_stream_init,
208 .interfaces = (InterfaceInfo[]) {
209 { TYPE_STREAM_SLAVE },
210 { TYPE_REMOTE_PORT_DEVICE },
211 { },
212 }
213};
214
215static void rp_stream_register_types(void)
216{
217 type_register_static(&rp_stream_info);
218}
219
220type_init(rp_stream_register_types)
221