1
2
3
4
5
6
7
8
9
10#include "qemu/osdep.h"
11#include "sysemu/sysemu.h"
12#include "sysemu/dma.h"
13#include "sysemu/char.h"
14#include "sysemu/cpus.h"
15#include "hw/sysbus.h"
16#include "hw/ptimer.h"
17#include "qemu/sockets.h"
18#include "qemu/thread.h"
19#include "qemu/log.h"
20#include "qapi/error.h"
21#include "qemu/error-report.h"
22#include "qom/cpu.h"
23
24#include <semaphore.h>
25#ifndef _WIN32
26#include <sys/mman.h>
27#endif
28
29#include "hw/fdt_generic_util.h"
30#include "hw/remote-port-proto.h"
31#include "hw/remote-port-device.h"
32#include "hw/remote-port.h"
33
34#define D(x)
35#define SYNCD(x)
36
37#ifndef REMOTE_PORT_ERR_DEBUG
38#define REMOTE_PORT_DEBUG_LEVEL 0
39#else
40#define REMOTE_PORT_DEBUG_LEVEL 1
41#endif
42
43#define DB_PRINT_L(level, ...) do { \
44 if (REMOTE_PORT_DEBUG_LEVEL > level) { \
45 fprintf(stderr, ": %s: ", __func__); \
46 fprintf(stderr, ## __VA_ARGS__); \
47 } \
48} while (0);
49
50#define REMOTE_PORT_CLASS(klass) \
51 OBJECT_CLASS_CHECK(RemotePortClass, (klass), TYPE_REMOTE_PORT)
52
53static bool time_warp_enable = true;
54
55bool rp_time_warp_enable(bool en)
56{
57 bool ret = time_warp_enable;
58
59 time_warp_enable = en;
60 return ret;
61}
62
63static void rp_process(RemotePort *s);
64static void rp_event_read(void *opaque);
65static void sync_timer_hit(void *opaque);
66static void syncresp_timer_hit(void *opaque);
67
68static void rp_pkt_dump(const char *prefix, const char *buf, size_t len)
69{
70 qemu_hexdump(buf, stdout, prefix, len);
71}
72
73uint32_t rp_new_id(RemotePort *s)
74{
75 return s->current_id++;
76}
77
78void rp_rsp_mutex_lock(RemotePort *s)
79{
80 qemu_mutex_lock(&s->rsp_mutex);
81}
82
83void rp_rsp_mutex_unlock(RemotePort *s)
84{
85 qemu_mutex_unlock(&s->rsp_mutex);
86}
87
88int64_t rp_normalized_vmclk(RemotePort *s)
89{
90 int64_t clk;
91
92 clk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
93 clk -= s->peer.clk_base;
94 return clk;
95}
96
97static inline int64_t rp_denormalize_clk(RemotePort *s, int64_t rclk)
98{
99 int64_t clk;
100 clk = rclk + s->peer.clk_base;
101 return clk;
102}
103
104void rp_restart_sync_timer(RemotePort *s)
105{
106 if (!use_icount || !s->do_sync) {
107 return;
108 }
109
110 if (s->sync.quantum) {
111 ptimer_stop(s->sync.ptimer);
112 ptimer_set_limit(s->sync.ptimer, s->sync.quantum, 1);
113 ptimer_run(s->sync.ptimer, 1);
114 } else {
115 ptimer_stop(s->sync.ptimer);
116 ptimer_set_limit(s->sync.ptimer, 10 * 1000, 1);
117 ptimer_run(s->sync.ptimer, 1);
118 }
119}
120
121static void rp_fatal_error(RemotePort *s, const char *reason)
122{
123 int64_t clk = rp_normalized_vmclk(s);
124 error_report("%s: %s clk=%" PRIu64 " ns\n", s->prefix, reason, clk);
125 exit(EXIT_FAILURE);
126}
127
128static ssize_t rp_recv(RemotePort *s, void *buf, size_t count)
129{
130 ssize_t r;
131
132 r = qemu_chr_fe_read_all(s->chr, buf, count);
133 if (r <= 0) {
134 rp_fatal_error(s, "Disconnected");
135 }
136 if (r != count) {
137 error_report("%s: Bad read, expected %zd but got %zd\n",
138 s->prefix, count, r);
139 rp_fatal_error(s, "Bad read");
140 }
141
142 return r;
143}
144
145ssize_t rp_write(RemotePort *s, const void *buf, size_t count)
146{
147 ssize_t r;
148
149 qemu_mutex_lock(&s->write_mutex);
150 r = qemu_chr_fe_write(s->chr, buf, count);
151 qemu_mutex_unlock(&s->write_mutex);
152 if (r <= 0) {
153 error_report("%s: Disconnected r=%zd buf=%p count=%zd\n",
154 s->prefix, r, buf, count);
155 rp_fatal_error(s, "Bad write");
156 }
157 return r;
158}
159
160
161static int64_t rp_time_warp(RemotePort *s, int64_t diff)
162{
163 int64_t future = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + diff;
164 int64_t clk;
165
166 if (!time_warp_enable) {
167 return 0;
168 }
169
170
171 do {
172 bool cpus_idle;
173
174 cpus_idle = tcg_idle_clock_warp(future);
175 clk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
176 if (!cpus_idle) {
177 break;
178 }
179 } while (clk < future);
180
181 return future - clk;
182}
183
184static void rp_idle(void *opaque)
185{
186 int64_t deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL);
187 if (deadline == INT32_MAX) {
188 return;
189 }
190 rp_time_warp(opaque, deadline);
191}
192
193void rp_leave_iothread(RemotePort *s)
194{
195 if (use_icount && all_cpu_threads_idle() && time_warp_enable) {
196 async_run_on_cpu(first_cpu, rp_idle, s);
197 }
198}
199
200RemotePortDynPkt rp_wait_resp(RemotePort *s)
201{
202 while (!rp_dpkt_is_valid(&s->rspqueue)) {
203 rp_event_read(s);
204 qemu_cond_wait(&s->progress_cond, &s->rsp_mutex);
205 }
206 return s->rspqueue;
207}
208
209void rp_sync_vmclock(RemotePort *s, int64_t lclk, int64_t rclk)
210{
211 int64_t diff;
212
213
214 return;
215
216 if (!time_warp_enable) {
217 return;
218 }
219
220
221
222 while (lclk < rclk) {
223 diff = rclk - lclk;
224 tcg_clock_warp(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + diff);
225 lclk = rp_normalized_vmclk(s);
226 }
227
228 if (lclk < rclk) {
229 printf("Wrong sync! local=%" PRIu64 " remote=%" PRIu64 "\n", lclk, rclk);
230 }
231}
232
233static void rp_cmd_hello(RemotePort *s, struct rp_pkt *pkt)
234{
235 s->peer.version = pkt->hello.version;
236 if (pkt->hello.version.major != RP_VERSION_MAJOR) {
237 error_report("remote-port version missmatch remote=%d.%d local=%d.%d\n",
238 pkt->hello.version.major, pkt->hello.version.minor,
239 RP_VERSION_MAJOR, RP_VERSION_MINOR);
240 rp_fatal_error(s, "Bad version");
241 }
242
243 if (pkt->hello.caps.len) {
244 void *caps = (char *) pkt + pkt->hello.caps.offset;
245
246 rp_process_caps(&s->peer, caps, pkt->hello.caps.len);
247 }
248}
249
250static void rp_cmd_sync(RemotePort *s, struct rp_pkt *pkt)
251{
252 size_t enclen;
253 int64_t clk;
254 int64_t diff;
255
256 assert(!(pkt->hdr.flags & RP_PKT_FLAGS_response));
257
258
259 clk = rp_normalized_vmclk(s);
260 diff = pkt->sync.timestamp - clk;
261 if (diff > 0LL && use_icount && time_warp_enable) {
262 diff = rp_time_warp(s, diff);
263 }
264
265 enclen = rp_encode_sync_resp(pkt->hdr.id, pkt->hdr.dev, &s->sync.rsp.sync,
266 pkt->sync.timestamp);
267 assert(enclen == sizeof s->sync.rsp.sync);
268
269
270 if (all_cpu_threads_idle() || 0) {
271 if (pkt->sync.timestamp > clk && use_icount)
272 rp_sync_vmclock(s, clk, pkt->sync.timestamp);
273 }
274
275
276 if (diff <= 0LL || true) {
277
278 SYNCD(printf("%s: sync resp %lu\n", s->prefix, pkt->sync.timestamp));
279 rp_write(s, (void *) &s->sync.rsp, enclen);
280 return;
281 }
282
283 SYNCD(printf("%s: delayed sync resp - start diff=%ld (ts=%lu clk=%lu)\n",
284 s->prefix, pkt->sync.timestamp - clk, pkt->sync.timestamp, clk));
285 ptimer_set_limit(s->sync.ptimer_resp, diff, 1);
286 ptimer_run(s->sync.ptimer_resp, 1);
287 s->sync.resp_timer_enabled = true;
288}
289
290static void rp_say_hello(RemotePort *s)
291{
292 struct rp_pkt_hello pkt;
293 uint32_t caps[] = {
294 CAP_BUSACCESS_EXT_BASE,
295 CAP_BUSACCESS_EXT_BYTE_EN,
296 };
297 size_t len;
298
299 len = rp_encode_hello_caps(s->current_id++, 0, &pkt, RP_VERSION_MAJOR,
300 RP_VERSION_MINOR,
301 caps, caps, sizeof caps / sizeof caps[0]);
302 rp_write(s, (void *) &pkt, len);
303
304 if (sizeof caps) {
305 rp_write(s, caps, sizeof caps);
306 }
307}
308
309static void rp_say_sync(RemotePort *s, int64_t clk)
310{
311 struct rp_pkt_sync pkt;
312 size_t len;
313
314 len = rp_encode_sync(s->current_id++, 0, &pkt, clk);
315 rp_write(s, (void *) &pkt, len);
316}
317
318static void syncresp_timer_hit(void *opaque)
319{
320 RemotePort *s = REMOTE_PORT(opaque);
321
322 s->sync.resp_timer_enabled = false;
323 SYNCD(printf("%s: delayed sync response - send\n", s->prefix));
324 rp_write(s, (void *) &s->sync.rsp, sizeof s->sync.rsp.sync);
325 memset(&s->sync.rsp, 0, sizeof s->sync.rsp);
326
327 rp_leave_iothread(s);
328}
329
330static void sync_timer_hit(void *opaque)
331{
332 RemotePort *s = REMOTE_PORT(opaque);
333 int64_t clk;
334 int64_t rclk;
335 RemotePortDynPkt rsp;
336
337 if (!use_icount) {
338 hw_error("Sync timer without icount??\n");
339 }
340
341 clk = rp_normalized_vmclk(s);
342 if (s->sync.resp_timer_enabled) {
343 SYNCD(printf("%s: sync while delaying a resp! clk=%lu\n",
344 s->prefix, clk));
345 s->sync.need_sync = true;
346 rp_restart_sync_timer(s);
347 rp_leave_iothread(s);
348 return;
349 }
350
351
352 s->sync.need_sync = false;
353 qemu_mutex_lock(&s->rsp_mutex);
354
355 rp_say_sync(s, clk);
356
357 SYNCD(printf("%s: syncing wait for resp %lu\n", s->prefix, clk));
358 rsp = rp_wait_resp(s);
359 rclk = rsp.pkt->sync.timestamp;
360 rp_dpkt_invalidate(&rsp);
361 qemu_mutex_unlock(&s->rsp_mutex);
362
363 rp_sync_vmclock(s, clk, rclk);
364 rp_restart_sync_timer(s);
365}
366
367static char *rp_sanitize_prefix(RemotePort *s)
368{
369 char *sanitized_name;
370 char *c;
371
372 sanitized_name = g_strdup(s->prefix);
373 for (c = sanitized_name; *c != '\0'; c++) {
374 if (*c == '/')
375 *c = '_';
376 }
377 return sanitized_name;
378}
379
380static char *rp_autocreate_chardesc(RemotePort *s, bool server)
381{
382 char *prefix;
383 char *chardesc;
384 int r;
385
386 prefix = rp_sanitize_prefix(s);
387 r = asprintf(&chardesc, "unix:%s/qemu-rport-%s,wait%s",
388 machine_path, prefix, server ? ",server" : "");
389 assert(r > 0);
390 free(prefix);
391 return chardesc;
392}
393
394static CharDriverState *rp_autocreate_chardev(RemotePort *s, char *name)
395{
396 CharDriverState *chr;
397 char *chardesc;
398
399 chardesc = rp_autocreate_chardesc(s, false);
400 chr = qemu_chr_new(name, chardesc, NULL);
401 free(chardesc);
402
403 if (!chr) {
404 chardesc = rp_autocreate_chardesc(s, true);
405 chr = qemu_chr_new(name, chardesc, NULL);
406 free(chardesc);
407 }
408 return chr;
409}
410
411static unsigned int rp_has_work(RemotePort *s)
412{
413 unsigned int work = s->rx_queue.wpos - s->rx_queue.rpos;
414 return work;
415}
416
417static void rp_process(RemotePort *s)
418{
419 while (rp_has_work(s)) {
420 struct rp_pkt *pkt;
421 unsigned int rpos = s->rx_queue.rpos;
422 bool actioned = false;
423 RemotePortDevice *dev;
424 RemotePortDeviceClass *rpdc;
425
426 rpos &= ARRAY_SIZE(s->rx_queue.pkt) - 1;
427
428 pkt = s->rx_queue.pkt[rpos].pkt;
429 D(printf("%s: io-thread rpos=%d wpos=%d cmd=%d\n", s->prefix,
430 s->rx_queue.rpos, s->rx_queue.wpos, pkt->hdr.cmd));
431
432 dev = s->devs[pkt->hdr.dev];
433 if (dev) {
434 rpdc = REMOTE_PORT_DEVICE_GET_CLASS(dev);
435 if (rpdc->ops[pkt->hdr.cmd]) {
436 rpdc->ops[pkt->hdr.cmd](dev, pkt);
437 actioned = true;
438 }
439 }
440
441 switch (pkt->hdr.cmd) {
442 case RP_CMD_sync:
443 rp_cmd_sync(s, pkt);
444 break;
445 default:
446 assert(actioned);
447 }
448
449 s->rx_queue.rpos++;
450 qemu_sem_post(&s->rx_queue.sem);
451 }
452}
453
454static void rp_event_read(void *opaque)
455{
456 RemotePort *s = REMOTE_PORT(opaque);
457 unsigned char buf[32];
458 ssize_t r;
459
460
461 do {
462 r = read(s->event.pipe.read, buf, sizeof buf);
463 if (r == 0) {
464 hw_error("%s: pipe closed?\n", s->prefix);
465 }
466 } while (r == sizeof buf || (r < 0 && errno == EINTR));
467
468 rp_process(s);
469 rp_leave_iothread(s);
470}
471
472static void rp_event_notify(RemotePort *s)
473{
474 unsigned char d = 0;
475 ssize_t r;
476
477#ifdef _WIN32
478
479 r = qemu_send_wrap(s->event.pipe.write, &d, sizeof d, 0);
480#else
481 r = qemu_write_full(s->event.pipe.write, &d, sizeof d);
482#endif
483 if (r == 0) {
484 hw_error("%s: pipe closed\n", s->prefix);
485 }
486}
487
488
489static void rp_pt_handover_pkt(RemotePort *s, RemotePortDynPkt *dpkt)
490{
491
492
493 qemu_mutex_lock(&s->rsp_mutex);
494 s->rx_queue.wpos++;
495 smp_mb();
496 rp_event_notify(s);
497 qemu_cond_signal(&s->progress_cond);
498 qemu_mutex_unlock(&s->rsp_mutex);
499 while (1) {
500 if (qemu_sem_timedwait(&s->rx_queue.sem, 2 * 1000) == 0) {
501 break;
502 }
503#ifndef _WIN32
504 {
505 int sval;
506 sem_getvalue(&s->rx_queue.sem.sem, &sval);
507 printf("semwait: %d rpos=%u wpos=%u\n", sval,
508 s->rx_queue.rpos, s->rx_queue.wpos);
509 }
510#endif
511 }
512}
513
514static bool rp_pt_cmd_sync(RemotePort *s, struct rp_pkt *pkt)
515{
516 size_t enclen;
517 int64_t clk;
518 int64_t diff = 0;
519 struct rp_pkt rsp;
520
521 assert(!(pkt->hdr.flags & RP_PKT_FLAGS_response));
522
523 if (use_icount) {
524 clk = rp_normalized_vmclk(s);
525 diff = pkt->sync.timestamp - clk;
526 }
527 enclen = rp_encode_sync_resp(pkt->hdr.id, pkt->hdr.dev, &rsp.sync,
528 pkt->sync.timestamp);
529 assert(enclen == sizeof rsp.sync);
530
531 if (!use_icount || diff < s->sync.quantum) {
532
533 rp_write(s, (void *) &rsp, enclen);
534 return true;
535 }
536
537
538 return false;
539}
540
541static void rp_pt_process_pkt(RemotePort *s, RemotePortDynPkt *dpkt)
542{
543 struct rp_pkt *pkt = dpkt->pkt;
544
545 D(printf("%s: cmd=%x rsp=%d\n", __func__, pkt->hdr.cmd,
546 pkt->hdr.flags & RP_PKT_FLAGS_response));
547
548 if (pkt->hdr.dev >= ARRAY_SIZE(s->devs)) {
549
550 return;
551 }
552
553 if (pkt->hdr.flags & RP_PKT_FLAGS_response) {
554 qemu_mutex_lock(&s->rsp_mutex);
555 rp_dpkt_swap(&s->rspqueue, dpkt);
556 qemu_cond_signal(&s->progress_cond);
557 qemu_mutex_unlock(&s->rsp_mutex);
558 return;
559 }
560
561 switch (pkt->hdr.cmd) {
562 case RP_CMD_hello:
563 rp_cmd_hello(s, pkt);
564 break;
565 case RP_CMD_sync:
566 if (rp_pt_cmd_sync(s, pkt)) {
567 return;
568 }
569
570 case RP_CMD_read:
571 case RP_CMD_write:
572 case RP_CMD_interrupt:
573 rp_pt_handover_pkt(s, dpkt);
574 break;
575 default:
576 assert(0);
577 break;
578 }
579}
580
581static void rp_read_pkt(RemotePort *s, RemotePortDynPkt *dpkt)
582{
583 struct rp_pkt *pkt = dpkt->pkt;
584 int used;
585
586 rp_recv(s, pkt, sizeof pkt->hdr);
587 used = rp_decode_hdr((void *) &pkt->hdr);
588 assert(used == sizeof pkt->hdr);
589
590 if (pkt->hdr.len) {
591 rp_dpkt_alloc(dpkt, sizeof pkt->hdr + pkt->hdr.len);
592
593 pkt = dpkt->pkt;
594 rp_recv(s, &pkt->hdr + 1, pkt->hdr.len);
595 rp_decode_payload(pkt);
596 }
597}
598
599static void *rp_protocol_thread(void *arg)
600{
601 RemotePort *s = REMOTE_PORT(arg);
602 unsigned int i;
603
604
605 rp_dpkt_alloc(&s->rsp, sizeof s->rsp.pkt->busaccess + 1024);
606 rp_dpkt_alloc(&s->rspqueue, sizeof s->rspqueue.pkt->busaccess + 1024);
607 for (i = 0; i < ARRAY_SIZE(s->rx_queue.pkt); i++) {
608 rp_dpkt_alloc(&s->rx_queue.pkt[i],
609 sizeof s->rx_queue.pkt[i].pkt->busaccess + 1024);
610 }
611
612 rp_say_hello(s);
613
614 while (1) {
615 RemotePortDynPkt *dpkt;
616 unsigned int wpos = s->rx_queue.wpos;
617
618 wpos &= ARRAY_SIZE(s->rx_queue.pkt) - 1;
619 dpkt = &s->rx_queue.pkt[wpos];
620
621 rp_read_pkt(s, dpkt);
622 if (0) {
623 rp_pkt_dump("rport-pkt", (void *) dpkt->pkt,
624 sizeof dpkt->pkt->hdr + dpkt->pkt->hdr.len);
625 }
626 rp_pt_process_pkt(s, dpkt);
627 }
628 return NULL;
629}
630
631static void rp_realize(DeviceState *dev, Error **errp)
632{
633 RemotePort *s = REMOTE_PORT(dev);
634 int r;
635
636 s->prefix = object_get_canonical_path(OBJECT(dev));
637
638 s->peer.clk_base = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
639
640 qemu_mutex_init(&s->write_mutex);
641 qemu_mutex_init(&s->rsp_mutex);
642 qemu_cond_init(&s->progress_cond);
643
644 if (!s->chr) {
645 char *name;
646 static int nr = 0;
647 int r;
648
649 r = asprintf(&name, "rport%d", nr);
650 nr++;
651 assert(r > 0);
652
653 if (s->chrdev_id) {
654 s->chr = qemu_chr_find(s->chrdev_id);
655 }
656
657 if (s->chr) {
658
659 } else if (s->chardesc) {
660 s->chr = qemu_chr_new(name, s->chardesc, NULL);
661 } else {
662 if (!machine_path) {
663 error_report("%s: Missing chardesc prop."
664 " Forgot -machine-path?\n",
665 s->prefix);
666 exit(EXIT_FAILURE);
667 }
668 s->chr = rp_autocreate_chardev(s, name);
669 }
670 free(name);
671 if (!s->chr) {
672 error_report("%s: Unable to create remort-port channel %s\n",
673 s->prefix, s->chardesc);
674 exit(EXIT_FAILURE);
675 }
676 }
677
678
679#ifdef _WIN32
680
681
682
683 {
684 char *name;
685 int port;
686
687 s->event.pipe.read = inet_listen("127.0.0.1:0", NULL,
688 256, SOCK_STREAM, 0, &error_abort);
689 if (s->event.pipe.read < 0) {
690 perror("socket read");
691 exit(EXIT_FAILURE);
692 }
693
694 {
695 struct sockaddr_in saddr;
696 socklen_t slen = sizeof saddr;
697 int r;
698
699 r = getsockname(s->event.pipe.read, &saddr, &slen);
700 if (r < 0) {
701 perror("getsockname");
702 exit(EXIT_FAILURE);
703 }
704 port = htons(saddr.sin_port);
705 }
706
707 qemu_set_fd_handler(s->event.pipe.read, rp_event_read, NULL, s);
708 name = g_strdup_printf("127.0.0.1:%d", port);
709 s->event.pipe.write = inet_connect(name, &error_abort);
710 g_free(name);
711 if (s->event.pipe.write < 0) {
712 perror("socket write");
713 exit(EXIT_FAILURE);
714 }
715 }
716#else
717 r = qemu_pipe(s->event.pipes);
718 if (r < 0) {
719 error_report("%s: Unable to create remort-port internal pipes\n",
720 s->prefix);
721 exit(EXIT_FAILURE);
722 }
723 qemu_set_nonblock(s->event.pipe.read);
724 qemu_set_fd_handler(s->event.pipe.read, rp_event_read, NULL, s);
725#endif
726
727
728
729
730
731 s->sync.quantum = s->peer.local_cfg.quantum;
732
733 s->sync.bh = qemu_bh_new(sync_timer_hit, s);
734 s->sync.bh_resp = qemu_bh_new(syncresp_timer_hit, s);
735 s->sync.ptimer = ptimer_init(s->sync.bh);
736 s->sync.ptimer_resp = ptimer_init(s->sync.bh_resp);
737
738
739 ptimer_set_freq(s->sync.ptimer, 1000 * 1000 * 1000);
740 ptimer_set_freq(s->sync.ptimer_resp, 1000 * 1000 * 1000);
741
742 qemu_sem_init(&s->rx_queue.sem, ARRAY_SIZE(s->rx_queue.pkt) - 1);
743 qemu_thread_create(&s->thread, "remote-port", rp_protocol_thread, s,
744 QEMU_THREAD_JOINABLE);
745 rp_restart_sync_timer(s);
746}
747
748static const VMStateDescription vmstate_rp = {
749 .name = TYPE_REMOTE_PORT,
750 .version_id = 1,
751 .minimum_version_id = 1,
752 .minimum_version_id_old = 1,
753 .fields = (VMStateField[]) {
754 VMSTATE_END_OF_LIST(),
755 }
756};
757
758static Property rp_properties[] = {
759 DEFINE_PROP_CHR("chardev", RemotePort, chr),
760 DEFINE_PROP_STRING("chardesc", RemotePort, chardesc),
761 DEFINE_PROP_STRING("chrdev-id", RemotePort, chrdev_id),
762 DEFINE_PROP_BOOL("sync", RemotePort, do_sync, false),
763 DEFINE_PROP_UINT64("sync-quantum", RemotePort, peer.local_cfg.quantum, 0),
764 DEFINE_PROP_END_OF_LIST(),
765};
766
767static void rp_init(Object *obj)
768{
769 RemotePort *s = REMOTE_PORT(obj);
770 int i;
771
772
773 qemu_icount_enable_idle_timewarps(false);
774
775 for (i = 0; i < REMOTE_PORT_MAX_DEVS; ++i) {
776 char *name = g_strdup_printf("remote-port-dev%d", i);
777 object_property_add_link(obj, name, TYPE_REMOTE_PORT_DEVICE,
778 (Object **)&s->devs[i],
779 qdev_prop_allow_set_link,
780 OBJ_PROP_LINK_UNREF_ON_RELEASE,
781 &error_abort);
782 g_free(name);
783 }
784}
785
786
787void rp_device_attach(Object *adaptor, Object *dev,
788 int rp_nr, int dev_nr,
789 Error **errp)
790{
791 Error *err = NULL;
792 uint32_t nr_devs;
793 char *name;
794 int i;
795
796 assert(adaptor);
797 assert(dev);
798
799 D(printf("%s: rp_nr-%d dev_nr=%d\n", __func__, rp_nr, dev_nr));
800
801
802 if (!object_dynamic_cast(adaptor, TYPE_REMOTE_PORT)) {
803 error_setg(errp, "%s is not a Remote-Port adaptor!\n",
804 object_get_canonical_path(adaptor));
805 return;
806 }
807
808 name = g_strdup_printf("rp-adaptor%d", rp_nr);
809 object_property_set_link(dev, adaptor, name, &err);
810 g_free(name);
811 if (err != NULL) {
812 error_propagate(errp, err);
813 return;
814 }
815
816 name = g_strdup_printf("rp-chan%d", rp_nr);
817 object_property_set_int(dev, dev_nr, name, &err);
818 g_free(name);
819 if (err != NULL
820 && !object_dynamic_cast(dev, TYPE_REMOTE_PORT_DEVICE)) {
821
822
823
824
825
826 error_propagate(errp, err);
827 return;
828 }
829 err = NULL;
830
831 nr_devs = object_property_get_int(dev, "nr-devs", &err);
832 if (err) {
833 nr_devs = 1;
834 err = NULL;
835 }
836
837
838 for (i = 0; i < nr_devs; i++) {
839 name = g_strdup_printf("remote-port-dev%d", dev_nr + i);
840 object_property_set_link(adaptor, dev, name, &err);
841 g_free(name);
842 if (err != NULL) {
843 error_propagate(errp, err);
844 return;
845 }
846 }
847}
848
849struct rp_peer_state *rp_get_peer(RemotePort *s)
850{
851 return &s->peer;
852}
853
854static void rp_class_init(ObjectClass *klass, void *data)
855{
856 DeviceClass *dc = DEVICE_CLASS(klass);
857
858 dc->realize = rp_realize;
859 dc->vmsd = &vmstate_rp;
860 dc->props = rp_properties;
861}
862
863static const TypeInfo rp_info = {
864 .name = TYPE_REMOTE_PORT,
865 .parent = TYPE_DEVICE,
866 .instance_size = sizeof(RemotePort),
867 .instance_init = rp_init,
868 .class_init = rp_class_init,
869 .interfaces = (InterfaceInfo[]) {
870 { },
871 },
872};
873
874static const TypeInfo rp_device_info = {
875 .name = TYPE_REMOTE_PORT_DEVICE,
876 .parent = TYPE_INTERFACE,
877 .class_size = sizeof(RemotePortDeviceClass),
878};
879
880static void rp_register_types(void)
881{
882 type_register_static(&rp_info);
883 type_register_static(&rp_device_info);
884}
885
886type_init(rp_register_types)
887