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