1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24#include "qemu/osdep.h"
25#include "hw/sysbus.h"
26#include "qemu/log.h"
27
28#include "qemu/bitops.h"
29#include "qapi/qmp/qerror.h"
30#include "hw/register.h"
31#include "hw/stream.h"
32#include "qemu/fifo.h"
33
34#ifndef STREAM_FIFO_ERR_DEBUG
35#define STREAM_FIFO_ERR_DEBUG 0
36#endif
37
38#define TYPE_STREAM_FIFO "stream-fifo"
39
40#define STREAM_FIFO(obj) \
41 OBJECT_CHECK(StreamFifo, (obj), TYPE_STREAM_FIFO)
42
43REG32(DP, 0x00)
44REG32(CTL, 0x04)
45 #define R_CTL_CORK (1 << 0)
46 #define R_CTL_RSVD ~1ull
47
48#define R_MAX ((R_CTL) + 1)
49
50typedef struct StreamFifo StreamFifo;
51
52struct StreamFifo {
53 SysBusDevice busdev;
54 MemoryRegion iomem;
55
56 Fifo fifo;
57
58 uint32_t regs[R_MAX];
59 RegisterInfo regs_info[R_MAX];
60
61 StreamSlave *tx_dev;
62
63 StreamCanPushNotifyFn notify;
64 void *notify_opaque;
65};
66
67static void stream_fifo_notify(void *opaque)
68{
69 StreamFifo *s = STREAM_FIFO(opaque);
70
71 while (!fifo_is_empty(&s->fifo) && !(s->regs[R_CTL] & R_CTL_CORK) &&
72 stream_can_push(s->tx_dev, stream_fifo_notify, s)) {
73 size_t ret;
74 uint8_t buf[4];
75
76 *((uint32_t *)buf) = cpu_to_le32(fifo_pop32(&s->fifo));
77 ret = stream_push(s->tx_dev, buf, 4, 0);
78 assert(ret == 4);
79 }
80
81 if (s->notify) {
82 StreamCanPushNotifyFn notify = s->notify;
83 s->notify = NULL;
84 notify(s->notify_opaque);
85 }
86}
87
88static bool stream_fifo_stream_can_push(StreamSlave *obj,
89 StreamCanPushNotifyFn notify,
90 void *notify_opaque)
91{
92 StreamFifo *s = STREAM_FIFO(obj);
93 bool ret = !(s->regs[R_CTL] & R_CTL_CORK) && !fifo_is_full(&s->fifo);
94
95 if (!ret) {
96 s->notify = notify;
97 s->notify_opaque = notify_opaque;
98 }
99 return ret;
100}
101
102static size_t stream_fifo_stream_push(StreamSlave *obj, uint8_t *buf,
103 size_t len, uint32_t attr)
104{
105 StreamFifo *s = STREAM_FIFO(obj);
106 size_t ret = 0;
107
108 assert(!(len % 4));
109 while (len && !(s->regs[R_CTL] & R_CTL_CORK) && !fifo_is_full(&s->fifo)) {
110 fifo_push32(&s->fifo, le32_to_cpu(*(uint32_t *)buf));
111 buf += (sizeof(uint32_t));
112 len -= 4;
113 ret += 4;
114 }
115 return ret;
116}
117
118
119static void stream_fifo_update(RegisterInfo *reg, uint64_t val)
120{
121 StreamFifo *s = STREAM_FIFO(reg->opaque);
122
123 stream_fifo_notify(s);
124}
125
126static void stream_fifo_dp_post_write(RegisterInfo *reg, uint64_t val)
127{
128 StreamFifo *s = STREAM_FIFO(reg->opaque);
129
130 if (fifo_is_full(&s->fifo)) {
131 qemu_log_mask(LOG_GUEST_ERROR, "Write to full fifo\n");
132 } else {
133 fifo_push32(&s->fifo, val);
134 }
135 stream_fifo_update(reg, val);
136}
137
138static uint64_t stream_fifo_dp_post_read(RegisterInfo *reg, uint64_t val)
139{
140 StreamFifo *s = STREAM_FIFO(reg->opaque);
141
142 if (fifo_is_empty(&s->fifo)) {
143 qemu_log_mask(LOG_GUEST_ERROR, "Write to full fifo\n");
144 } else {
145 return fifo_pop32(&s->fifo);
146 }
147 return 0;
148}
149
150
151
152static const RegisterAccessInfo stream_fifo_regs_info[] = {
153 { .name = "data port", .decode.addr = A_DP,
154 .post_write = stream_fifo_dp_post_write,
155 .post_read = stream_fifo_dp_post_read,
156 },{ .name = "control", .decode.addr = A_CTL,
157 .rsvd = R_CTL_RSVD,
158 .reset = R_CTL_CORK,
159 }
160};
161
162static void stream_fifo_reset(DeviceState *dev)
163{
164 StreamFifo *s = STREAM_FIFO(dev);
165 int i;
166
167 for (i = 0; i < R_MAX; ++i) {
168 register_reset(&s->regs_info[i]);
169 }
170
171 fifo_reset(&s->fifo);
172}
173
174static const MemoryRegionOps stream_fifo_ops = {
175 .read = register_read_memory_le,
176 .write = register_write_memory_le,
177 .endianness = DEVICE_LITTLE_ENDIAN,
178 .valid = {
179 .min_access_size = 4,
180 .max_access_size = 4,
181 }
182};
183
184static void stream_fifo_realize(DeviceState *dev, Error **errp)
185{
186 StreamFifo *s = STREAM_FIFO(dev);
187 const char *prefix = object_get_canonical_path(OBJECT(dev));
188 int i;
189
190 for (i = 0; i < ARRAY_SIZE(stream_fifo_regs_info); ++i) {
191 RegisterInfo *r = &s->regs_info[i];
192
193 *r = (RegisterInfo) {
194 .data = (uint8_t *)&s->regs[
195 stream_fifo_regs_info[i].decode.addr/4],
196 .data_size = sizeof(uint32_t),
197 .access = &stream_fifo_regs_info[i],
198 .debug = STREAM_FIFO_ERR_DEBUG,
199 .prefix = prefix,
200 .opaque = s,
201 };
202 memory_region_init_io(&r->mem, OBJECT(dev), &stream_fifo_ops, r,
203 r->access->name, 4);
204 memory_region_add_subregion(&s->iomem, r->access->decode.addr, &r->mem);
205#define STREAM_FIFO_DEPTH 64
206 fifo_create32(&s->fifo, STREAM_FIFO_DEPTH);
207 }
208}
209
210static void stream_fifo_init(Object *obj)
211{
212 StreamFifo *s = STREAM_FIFO(obj);
213
214 memory_region_init(&s->iomem, obj, "MMIO", R_MAX * 4);
215 sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem);
216
217 object_property_add_link(obj, "stream-connected",
218 TYPE_STREAM_SLAVE, (Object **) &s->tx_dev,
219 qdev_prop_allow_set_link_before_realize,
220 OBJ_PROP_LINK_UNREF_ON_RELEASE,
221 NULL);
222
223}
224
225static const VMStateDescription vmstate_stream_fifo = {
226 .name = "stream_fifo",
227 .version_id = 1,
228 .minimum_version_id = 1,
229 .minimum_version_id_old = 1,
230 .fields = (VMStateField[]) {
231 VMSTATE_UINT32_ARRAY(regs, StreamFifo, R_MAX),
232 VMSTATE_END_OF_LIST(),
233 }
234};
235
236static void stream_fifo_class_init(ObjectClass *klass, void *data)
237{
238 DeviceClass *dc = DEVICE_CLASS(klass);
239 StreamSlaveClass *ssc = STREAM_SLAVE_CLASS(klass);
240
241 dc->reset = stream_fifo_reset;
242 dc->realize = stream_fifo_realize;
243 dc->vmsd = &vmstate_stream_fifo;
244
245 ssc->push = stream_fifo_stream_push;
246 ssc->can_push = stream_fifo_stream_can_push;
247}
248
249static const TypeInfo stream_fifo_info = {
250 .name = TYPE_STREAM_FIFO,
251 .parent = TYPE_SYS_BUS_DEVICE,
252 .instance_size = sizeof(StreamFifo),
253 .class_init = stream_fifo_class_init,
254 .instance_init = stream_fifo_init,
255 .interfaces = (InterfaceInfo[]) {
256 { TYPE_STREAM_SLAVE },
257 { },
258 }
259};
260
261static void stream_fifo_register_types(void)
262{
263 type_register_static(&stream_fifo_info);
264}
265
266type_init(stream_fifo_register_types)
267