20
#include "qemu/osdep.h"
21
#include "qemu/units.h"
22
#include "qapi/error.h"
23
#include "qemu/cutils.h"
24
#include "hw/pci/pci.h"
25
#include "hw/qdev-properties.h"
26
#include "hw/qdev-properties-system.h"
27
#include "hw/pci/msi.h"
28
#include "hw/pci/msix.h"
29
#include "sysemu/kvm.h"
30
#include "migration/blocker.h"
31
#include "migration/vmstate.h"
32
#include "qemu/error-report.h"
33
#include "qemu/event_notifier.h"
34
#include "qemu/module.h"
35
#include "qom/object_interfaces.h"
36
#include "chardev/char-fe.h"
37
#include "sysemu/hostmem.h"
38
#include "qapi/visitor.h"
40
#include "hw/misc/ivshmem.h"
41
#include "qom/object.h"
43
#define PCI_VENDOR_ID_IVSHMEM PCI_VENDOR_ID_REDHAT_QUMRANET
44
#define PCI_DEVICE_ID_IVSHMEM 0x1110
46
#define IVSHMEM_MAX_PEERS UINT16_MAX
47
#define IVSHMEM_IOEVENTFD 0
50
#define IVSHMEM_REG_BAR_SIZE 0x100
52
#define IVSHMEM_DEBUG 0
53
#define IVSHMEM_DPRINTF(fmt, ...) \
55
if (IVSHMEM_DEBUG) { \
56
printf("IVSHMEM: " fmt, ## __VA_ARGS__); \
60
#define TYPE_IVSHMEM_COMMON "ivshmem-common"
61
typedef struct IVShmemState IVShmemState;
62
DECLARE_INSTANCE_CHECKER(IVShmemState, IVSHMEM_COMMON,
65
#define TYPE_IVSHMEM_PLAIN "ivshmem-plain"
66
DECLARE_INSTANCE_CHECKER(IVShmemState, IVSHMEM_PLAIN,
69
#define TYPE_IVSHMEM_DOORBELL "ivshmem-doorbell"
70
DECLARE_INSTANCE_CHECKER(IVShmemState, IVSHMEM_DOORBELL,
71
TYPE_IVSHMEM_DOORBELL)
73
#define TYPE_IVSHMEM "ivshmem"
74
DECLARE_INSTANCE_CHECKER(IVShmemState, IVSHMEM,
79
EventNotifier *eventfds;
82
typedef struct MSIVector {
96
HostMemoryBackend *hostmem;
97
CharBackend server_chr;
105
MemoryRegion ivshmem_mmio;
106
MemoryRegion *ivshmem_bar2;
107
MemoryRegion server_bar2;
113
MSIVector *msi_vectors;
115
int msg_buffered_bytes;
119
Error *migration_blocker;
123
enum ivshmem_registers {
130
static inline uint32_t ivshmem_has_feature(IVShmemState *ivs,
131
unsigned int feature) {
132
return (ivs->features & (1 << feature));
135
static inline bool ivshmem_is_master(IVShmemState *s)
137
assert(s->master != ON_OFF_AUTO_AUTO);
138
return s->master == ON_OFF_AUTO_ON;
141
static void ivshmem_IntrMask_write(IVShmemState *s, uint32_t val)
143
IVSHMEM_DPRINTF("IntrMask write(w) val = 0x%04x\n", val);
148
static uint32_t ivshmem_IntrMask_read(IVShmemState *s)
150
uint32_t ret = s->intrmask;
152
IVSHMEM_DPRINTF("intrmask read(w) val = 0x%04x\n", ret);
156
static void ivshmem_IntrStatus_write(IVShmemState *s, uint32_t val)
158
IVSHMEM_DPRINTF("IntrStatus write(w) val = 0x%04x\n", val);
163
static uint32_t ivshmem_IntrStatus_read(IVShmemState *s)
165
uint32_t ret = s->intrstatus;
172
static void ivshmem_io_write(void *opaque, hwaddr addr,
173
uint64_t val, unsigned size)
175
IVShmemState *s = opaque;
177
uint16_t dest = val >> 16;
178
uint16_t vector = val & 0xff;
182
IVSHMEM_DPRINTF("writing to addr " HWADDR_FMT_plx "\n", addr);
186
ivshmem_IntrMask_write(s, val);
190
ivshmem_IntrStatus_write(s, val);
195
if (dest >= s->nb_peers) {
196
IVSHMEM_DPRINTF("Invalid destination VM ID (%d)\n", dest);
201
if (vector < s->peers[dest].nb_eventfds) {
202
IVSHMEM_DPRINTF("Notifying VM %d on vector %d\n", dest, vector);
203
event_notifier_set(&s->peers[dest].eventfds[vector]);
205
IVSHMEM_DPRINTF("Invalid destination vector %d on VM %d\n",
210
IVSHMEM_DPRINTF("Unhandled write " HWADDR_FMT_plx "\n", addr);
214
static uint64_t ivshmem_io_read(void *opaque, hwaddr addr,
218
IVShmemState *s = opaque;
224
ret = ivshmem_IntrMask_read(s);
228
ret = ivshmem_IntrStatus_read(s);
236
IVSHMEM_DPRINTF("why are we reading " HWADDR_FMT_plx "\n", addr);
243
static const MemoryRegionOps ivshmem_mmio_ops = {
244
.read = ivshmem_io_read,
245
.write = ivshmem_io_write,
246
.endianness = DEVICE_LITTLE_ENDIAN,
248
.min_access_size = 4,
249
.max_access_size = 4,
253
static void ivshmem_vector_notify(void *opaque)
255
MSIVector *entry = opaque;
256
PCIDevice *pdev = entry->pdev;
257
IVShmemState *s = IVSHMEM_COMMON(pdev);
258
int vector = entry - s->msi_vectors;
259
EventNotifier *n = &s->peers[s->vm_id].eventfds[vector];
261
if (!event_notifier_test_and_clear(n)) {
265
IVSHMEM_DPRINTF("interrupt on vector %p %d\n", pdev, vector);
266
if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
267
if (msix_enabled(pdev)) {
268
msix_notify(pdev, vector);
271
ivshmem_IntrStatus_write(s, 1);
275
static int ivshmem_vector_unmask(PCIDevice *dev, unsigned vector,
278
IVShmemState *s = IVSHMEM_COMMON(dev);
279
EventNotifier *n = &s->peers[s->vm_id].eventfds[vector];
280
MSIVector *v = &s->msi_vectors[vector];
283
IVSHMEM_DPRINTF("vector unmask %p %d\n", dev, vector);
285
error_report("ivshmem: vector %d route does not exist", vector);
288
assert(!v->unmasked);
290
ret = kvm_irqchip_update_msi_route(kvm_state, v->virq, msg, dev);
294
kvm_irqchip_commit_routes(kvm_state);
296
ret = kvm_irqchip_add_irqfd_notifier_gsi(kvm_state, n, NULL, v->virq);
305
static void ivshmem_vector_mask(PCIDevice *dev, unsigned vector)
307
IVShmemState *s = IVSHMEM_COMMON(dev);
308
EventNotifier *n = &s->peers[s->vm_id].eventfds[vector];
309
MSIVector *v = &s->msi_vectors[vector];
312
IVSHMEM_DPRINTF("vector mask %p %d\n", dev, vector);
314
error_report("ivshmem: vector %d route does not exist", vector);
319
ret = kvm_irqchip_remove_irqfd_notifier_gsi(kvm_state, n, v->virq);
321
error_report("remove_irqfd_notifier_gsi failed");
327
static void ivshmem_vector_poll(PCIDevice *dev,
328
unsigned int vector_start,
329
unsigned int vector_end)
331
IVShmemState *s = IVSHMEM_COMMON(dev);
334
IVSHMEM_DPRINTF("vector poll %p %d-%d\n", dev, vector_start, vector_end);
336
vector_end = MIN(vector_end, s->vectors);
338
for (vector = vector_start; vector < vector_end; vector++) {
339
EventNotifier *notifier = &s->peers[s->vm_id].eventfds[vector];
341
if (!msix_is_masked(dev, vector)) {
345
if (event_notifier_test_and_clear(notifier)) {
346
msix_set_pending(dev, vector);
351
static void watch_vector_notifier(IVShmemState *s, EventNotifier *n,
354
int eventfd = event_notifier_get_fd(n);
356
assert(!s->msi_vectors[vector].pdev);
357
s->msi_vectors[vector].pdev = PCI_DEVICE(s);
359
qemu_set_fd_handler(eventfd, ivshmem_vector_notify,
360
NULL, &s->msi_vectors[vector]);
363
static void ivshmem_add_eventfd(IVShmemState *s, int posn, int i)
365
memory_region_add_eventfd(&s->ivshmem_mmio,
370
&s->peers[posn].eventfds[i]);
373
static void ivshmem_del_eventfd(IVShmemState *s, int posn, int i)
375
memory_region_del_eventfd(&s->ivshmem_mmio,
380
&s->peers[posn].eventfds[i]);
383
static void close_peer_eventfds(IVShmemState *s, int posn)
387
assert(posn >= 0 && posn < s->nb_peers);
388
n = s->peers[posn].nb_eventfds;
390
if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) {
391
memory_region_transaction_begin();
392
for (i = 0; i < n; i++) {
393
ivshmem_del_eventfd(s, posn, i);
395
memory_region_transaction_commit();
398
for (i = 0; i < n; i++) {
399
event_notifier_cleanup(&s->peers[posn].eventfds[i]);
402
g_free(s->peers[posn].eventfds);
403
s->peers[posn].nb_eventfds = 0;
406
static void resize_peers(IVShmemState *s, int nb_peers)
408
int old_nb_peers = s->nb_peers;
411
assert(nb_peers > old_nb_peers);
412
IVSHMEM_DPRINTF("bumping storage to %d peers\n", nb_peers);
414
s->peers = g_renew(Peer, s->peers, nb_peers);
415
s->nb_peers = nb_peers;
417
for (i = old_nb_peers; i < nb_peers; i++) {
418
s->peers[i].eventfds = g_new0(EventNotifier, s->vectors);
419
s->peers[i].nb_eventfds = 0;
423
static void ivshmem_add_kvm_msi_virq(IVShmemState *s, int vector,
426
PCIDevice *pdev = PCI_DEVICE(s);
430
IVSHMEM_DPRINTF("ivshmem_add_kvm_msi_virq vector:%d\n", vector);
431
assert(!s->msi_vectors[vector].pdev);
433
c = kvm_irqchip_begin_route_changes(kvm_state);
434
ret = kvm_irqchip_add_msi_route(&c, vector, pdev);
436
error_setg(errp, "kvm_irqchip_add_msi_route failed");
439
kvm_irqchip_commit_route_changes(&c);
441
s->msi_vectors[vector].virq = ret;
442
s->msi_vectors[vector].pdev = pdev;
445
static void setup_interrupt(IVShmemState *s, int vector, Error **errp)
447
EventNotifier *n = &s->peers[s->vm_id].eventfds[vector];
448
bool with_irqfd = kvm_msi_via_irqfd_enabled() &&
449
ivshmem_has_feature(s, IVSHMEM_MSI);
450
PCIDevice *pdev = PCI_DEVICE(s);
453
IVSHMEM_DPRINTF("setting up interrupt for vector: %d\n", vector);
456
IVSHMEM_DPRINTF("with eventfd\n");
457
watch_vector_notifier(s, n, vector);
458
} else if (msix_enabled(pdev)) {
459
IVSHMEM_DPRINTF("with irqfd\n");
460
ivshmem_add_kvm_msi_virq(s, vector, &err);
462
error_propagate(errp, err);
466
if (!msix_is_masked(pdev, vector)) {
467
kvm_irqchip_add_irqfd_notifier_gsi(kvm_state, n, NULL,
468
s->msi_vectors[vector].virq);
473
IVSHMEM_DPRINTF("with irqfd, delayed until msix enabled\n");
477
static void process_msg_shmem(IVShmemState *s, int fd, Error **errp)
482
if (s->ivshmem_bar2) {
483
error_setg(errp, "server sent unexpected shared memory message");
488
if (fstat(fd, &buf) < 0) {
489
error_setg_errno(errp, errno,
490
"can't determine size of shared memory sent by server");
498
if (!memory_region_init_ram_from_fd(&s->server_bar2, OBJECT(s),
499
"ivshmem.bar2", size, RAM_SHARED,
504
s->ivshmem_bar2 = &s->server_bar2;
507
static void process_msg_disconnect(IVShmemState *s, uint16_t posn,
510
IVSHMEM_DPRINTF("posn %d has gone away\n", posn);
511
if (posn >= s->nb_peers || posn == s->vm_id) {
512
error_setg(errp, "invalid peer %d", posn);
515
close_peer_eventfds(s, posn);
518
static void process_msg_connect(IVShmemState *s, uint16_t posn, int fd,
521
Peer *peer = &s->peers[posn];
528
if (peer->nb_eventfds >= s->vectors) {
529
error_setg(errp, "Too many eventfd received, device has %d vectors",
534
vector = peer->nb_eventfds++;
536
IVSHMEM_DPRINTF("eventfds[%d][%d] = %d\n", posn, vector, fd);
537
event_notifier_init_fd(&peer->eventfds[vector], fd);
538
g_unix_set_fd_nonblocking(fd, true, NULL);
540
if (posn == s->vm_id) {
541
setup_interrupt(s, vector, errp);
545
if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) {
546
ivshmem_add_eventfd(s, posn, vector);
550
static void process_msg(IVShmemState *s, int64_t msg, int fd, Error **errp)
552
IVSHMEM_DPRINTF("posn is %" PRId64 ", fd is %d\n", msg, fd);
554
if (msg < -1 || msg > IVSHMEM_MAX_PEERS) {
555
error_setg(errp, "server sent invalid message %" PRId64, msg);
561
process_msg_shmem(s, fd, errp);
565
if (msg >= s->nb_peers) {
566
resize_peers(s, msg + 1);
570
process_msg_connect(s, msg, fd, errp);
572
process_msg_disconnect(s, msg, errp);
576
static int ivshmem_can_receive(void *opaque)
578
IVShmemState *s = opaque;
580
assert(s->msg_buffered_bytes < sizeof(s->msg_buf));
581
return sizeof(s->msg_buf) - s->msg_buffered_bytes;
584
static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
586
IVShmemState *s = opaque;
591
assert(size >= 0 && s->msg_buffered_bytes + size <= sizeof(s->msg_buf));
592
memcpy((unsigned char *)&s->msg_buf + s->msg_buffered_bytes, buf, size);
593
s->msg_buffered_bytes += size;
594
if (s->msg_buffered_bytes < sizeof(s->msg_buf)) {
597
msg = le64_to_cpu(s->msg_buf);
598
s->msg_buffered_bytes = 0;
600
fd = qemu_chr_fe_get_msgfd(&s->server_chr);
602
process_msg(s, msg, fd, &err);
604
error_report_err(err);
608
static int64_t ivshmem_recv_msg(IVShmemState *s, int *pfd, Error **errp)
615
ret = qemu_chr_fe_read_all(&s->server_chr, (uint8_t *)&msg + n,
621
error_setg_errno(errp, -ret, "read from server failed");
625
} while (n < sizeof(msg));
627
*pfd = qemu_chr_fe_get_msgfd(&s->server_chr);
628
return le64_to_cpu(msg);
631
static void ivshmem_recv_setup(IVShmemState *s, Error **errp)
637
msg = ivshmem_recv_msg(s, &fd, &err);
639
error_propagate(errp, err);
642
if (msg != IVSHMEM_PROTOCOL_VERSION) {
643
error_setg(errp, "server sent version %" PRId64 ", expecting %d",
644
msg, IVSHMEM_PROTOCOL_VERSION);
648
error_setg(errp, "server sent invalid version message");
665
msg = ivshmem_recv_msg(s, &fd, &err);
667
error_propagate(errp, err);
670
if (fd != -1 || msg < 0 || msg > IVSHMEM_MAX_PEERS) {
671
error_setg(errp, "server sent invalid ID message");
680
msg = ivshmem_recv_msg(s, &fd, &err);
682
error_propagate(errp, err);
685
process_msg(s, msg, fd, &err);
687
error_propagate(errp, err);
698
assert(s->ivshmem_bar2);
704
static void ivshmem_msix_vector_use(IVShmemState *s)
706
PCIDevice *d = PCI_DEVICE(s);
709
for (i = 0; i < s->vectors; i++) {
710
msix_vector_use(d, i);
714
static void ivshmem_disable_irqfd(IVShmemState *s);
716
static void ivshmem_reset(DeviceState *d)
718
IVShmemState *s = IVSHMEM_COMMON(d);
720
ivshmem_disable_irqfd(s);
724
if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
725
ivshmem_msix_vector_use(s);
729
static int ivshmem_setup_interrupts(IVShmemState *s, Error **errp)
732
s->msi_vectors = g_new0(MSIVector, s->vectors);
734
if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
735
if (msix_init_exclusive_bar(PCI_DEVICE(s), s->vectors, 1, errp)) {
739
IVSHMEM_DPRINTF("msix initialized (%d vectors)\n", s->vectors);
740
ivshmem_msix_vector_use(s);
746
static void ivshmem_remove_kvm_msi_virq(IVShmemState *s, int vector)
748
IVSHMEM_DPRINTF("ivshmem_remove_kvm_msi_virq vector:%d\n", vector);
750
if (s->msi_vectors[vector].pdev == NULL) {
755
kvm_irqchip_release_virq(kvm_state, s->msi_vectors[vector].virq);
757
s->msi_vectors[vector].pdev = NULL;
760
static void ivshmem_enable_irqfd(IVShmemState *s)
762
PCIDevice *pdev = PCI_DEVICE(s);
765
for (i = 0; i < s->peers[s->vm_id].nb_eventfds; i++) {
768
ivshmem_add_kvm_msi_virq(s, i, &err);
770
error_report_err(err);
775
if (msix_set_vector_notifiers(pdev,
776
ivshmem_vector_unmask,
778
ivshmem_vector_poll)) {
779
error_report("ivshmem: msix_set_vector_notifiers failed");
786
ivshmem_remove_kvm_msi_virq(s, i);
790
static void ivshmem_disable_irqfd(IVShmemState *s)
792
PCIDevice *pdev = PCI_DEVICE(s);
795
if (!pdev->msix_vector_use_notifier) {
799
msix_unset_vector_notifiers(pdev);
801
for (i = 0; i < s->peers[s->vm_id].nb_eventfds; i++) {
807
if (s->msi_vectors[i].unmasked) {
808
ivshmem_vector_mask(pdev, i);
810
ivshmem_remove_kvm_msi_virq(s, i);
815
static void ivshmem_write_config(PCIDevice *pdev, uint32_t address,
816
uint32_t val, int len)
818
IVShmemState *s = IVSHMEM_COMMON(pdev);
819
int is_enabled, was_enabled = msix_enabled(pdev);
821
pci_default_write_config(pdev, address, val, len);
822
is_enabled = msix_enabled(pdev);
824
if (kvm_msi_via_irqfd_enabled()) {
825
if (!was_enabled && is_enabled) {
826
ivshmem_enable_irqfd(s);
827
} else if (was_enabled && !is_enabled) {
828
ivshmem_disable_irqfd(s);
833
static void ivshmem_common_realize(PCIDevice *dev, Error **errp)
836
IVShmemState *s = IVSHMEM_COMMON(dev);
841
if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD) &&
842
!ivshmem_has_feature(s, IVSHMEM_MSI)) {
843
error_setg(errp, "ioeventfd/irqfd requires MSI");
847
pci_conf = dev->config;
848
pci_conf[PCI_COMMAND] = PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
850
memory_region_init_io(&s->ivshmem_mmio, OBJECT(s), &ivshmem_mmio_ops, s,
851
"ivshmem-mmio", IVSHMEM_REG_BAR_SIZE);
854
pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY,
857
if (s->hostmem != NULL) {
858
IVSHMEM_DPRINTF("using hostmem\n");
860
s->ivshmem_bar2 = host_memory_backend_get_memory(s->hostmem);
861
host_memory_backend_set_mapped(s->hostmem, true);
863
Chardev *chr = qemu_chr_fe_get_driver(&s->server_chr);
866
IVSHMEM_DPRINTF("using shared memory server (socket = %s)\n",
877
ivshmem_recv_setup(s, &err);
879
error_propagate(errp, err);
883
if (s->master == ON_OFF_AUTO_ON && s->vm_id != 0) {
885
"master must connect to the server before any peers");
889
qemu_chr_fe_set_handlers(&s->server_chr, ivshmem_can_receive,
890
ivshmem_read, NULL, NULL, s, NULL, true);
892
if (ivshmem_setup_interrupts(s, errp) < 0) {
893
error_prepend(errp, "Failed to initialize interrupts: ");
898
if (s->master == ON_OFF_AUTO_AUTO) {
899
s->master = s->vm_id == 0 ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF;
902
if (!ivshmem_is_master(s)) {
903
error_setg(&s->migration_blocker,
904
"Migration is disabled when using feature 'peer mode' in device 'ivshmem'");
905
if (migrate_add_blocker(&s->migration_blocker, errp) < 0) {
910
vmstate_register_ram(s->ivshmem_bar2, DEVICE(s));
911
pci_register_bar(PCI_DEVICE(s), 2,
912
PCI_BASE_ADDRESS_SPACE_MEMORY |
913
PCI_BASE_ADDRESS_MEM_PREFETCH |
914
PCI_BASE_ADDRESS_MEM_TYPE_64,
918
static void ivshmem_exit(PCIDevice *dev)
920
IVShmemState *s = IVSHMEM_COMMON(dev);
923
migrate_del_blocker(&s->migration_blocker);
925
if (memory_region_is_mapped(s->ivshmem_bar2)) {
927
void *addr = memory_region_get_ram_ptr(s->ivshmem_bar2);
930
if (munmap(addr, memory_region_size(s->ivshmem_bar2) == -1)) {
931
error_report("Failed to munmap shared memory %s",
935
fd = memory_region_get_fd(s->ivshmem_bar2);
939
vmstate_unregister_ram(s->ivshmem_bar2, DEVICE(dev));
943
host_memory_backend_set_mapped(s->hostmem, false);
947
for (i = 0; i < s->nb_peers; i++) {
948
close_peer_eventfds(s, i);
953
if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
954
msix_uninit_exclusive_bar(dev);
957
g_free(s->msi_vectors);
960
static int ivshmem_pre_load(void *opaque)
962
IVShmemState *s = opaque;
964
if (!ivshmem_is_master(s)) {
965
error_report("'peer' devices are not migratable");
972
static int ivshmem_post_load(void *opaque, int version_id)
974
IVShmemState *s = opaque;
976
if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
977
ivshmem_msix_vector_use(s);
982
static void ivshmem_common_class_init(ObjectClass *klass, void *data)
984
DeviceClass *dc = DEVICE_CLASS(klass);
985
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
987
k->realize = ivshmem_common_realize;
988
k->exit = ivshmem_exit;
989
k->config_write = ivshmem_write_config;
990
k->vendor_id = PCI_VENDOR_ID_IVSHMEM;
991
k->device_id = PCI_DEVICE_ID_IVSHMEM;
992
k->class_id = PCI_CLASS_MEMORY_RAM;
994
dc->reset = ivshmem_reset;
995
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
996
dc->desc = "Inter-VM shared memory";
999
static const TypeInfo ivshmem_common_info = {
1000
.name = TYPE_IVSHMEM_COMMON,
1001
.parent = TYPE_PCI_DEVICE,
1002
.instance_size = sizeof(IVShmemState),
1004
.class_init = ivshmem_common_class_init,
1005
.interfaces = (InterfaceInfo[]) {
1006
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
1011
static const VMStateDescription ivshmem_plain_vmsd = {
1012
.name = TYPE_IVSHMEM_PLAIN,
1014
.minimum_version_id = 0,
1015
.pre_load = ivshmem_pre_load,
1016
.post_load = ivshmem_post_load,
1017
.fields = (const VMStateField[]) {
1018
VMSTATE_PCI_DEVICE(parent_obj, IVShmemState),
1019
VMSTATE_UINT32(intrstatus, IVShmemState),
1020
VMSTATE_UINT32(intrmask, IVShmemState),
1021
VMSTATE_END_OF_LIST()
1025
static Property ivshmem_plain_properties[] = {
1026
DEFINE_PROP_ON_OFF_AUTO("master", IVShmemState, master, ON_OFF_AUTO_OFF),
1027
DEFINE_PROP_LINK("memdev", IVShmemState, hostmem, TYPE_MEMORY_BACKEND,
1028
HostMemoryBackend *),
1029
DEFINE_PROP_END_OF_LIST(),
1032
static void ivshmem_plain_realize(PCIDevice *dev, Error **errp)
1034
IVShmemState *s = IVSHMEM_COMMON(dev);
1037
error_setg(errp, "You must specify a 'memdev'");
1039
} else if (host_memory_backend_is_mapped(s->hostmem)) {
1040
error_setg(errp, "can't use already busy memdev: %s",
1041
object_get_canonical_path_component(OBJECT(s->hostmem)));
1045
ivshmem_common_realize(dev, errp);
1048
static void ivshmem_plain_class_init(ObjectClass *klass, void *data)
1050
DeviceClass *dc = DEVICE_CLASS(klass);
1051
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
1053
k->realize = ivshmem_plain_realize;
1054
device_class_set_props(dc, ivshmem_plain_properties);
1055
dc->vmsd = &ivshmem_plain_vmsd;
1058
static const TypeInfo ivshmem_plain_info = {
1059
.name = TYPE_IVSHMEM_PLAIN,
1060
.parent = TYPE_IVSHMEM_COMMON,
1061
.instance_size = sizeof(IVShmemState),
1062
.class_init = ivshmem_plain_class_init,
1065
static const VMStateDescription ivshmem_doorbell_vmsd = {
1066
.name = TYPE_IVSHMEM_DOORBELL,
1068
.minimum_version_id = 0,
1069
.pre_load = ivshmem_pre_load,
1070
.post_load = ivshmem_post_load,
1071
.fields = (const VMStateField[]) {
1072
VMSTATE_PCI_DEVICE(parent_obj, IVShmemState),
1073
VMSTATE_MSIX(parent_obj, IVShmemState),
1074
VMSTATE_UINT32(intrstatus, IVShmemState),
1075
VMSTATE_UINT32(intrmask, IVShmemState),
1076
VMSTATE_END_OF_LIST()
1080
static Property ivshmem_doorbell_properties[] = {
1081
DEFINE_PROP_CHR("chardev", IVShmemState, server_chr),
1082
DEFINE_PROP_UINT32("vectors", IVShmemState, vectors, 1),
1083
DEFINE_PROP_BIT("ioeventfd", IVShmemState, features, IVSHMEM_IOEVENTFD,
1085
DEFINE_PROP_ON_OFF_AUTO("master", IVShmemState, master, ON_OFF_AUTO_OFF),
1086
DEFINE_PROP_END_OF_LIST(),
1089
static void ivshmem_doorbell_init(Object *obj)
1091
IVShmemState *s = IVSHMEM_DOORBELL(obj);
1093
s->features |= (1 << IVSHMEM_MSI);
1096
static void ivshmem_doorbell_realize(PCIDevice *dev, Error **errp)
1098
IVShmemState *s = IVSHMEM_COMMON(dev);
1100
if (!qemu_chr_fe_backend_connected(&s->server_chr)) {
1101
error_setg(errp, "You must specify a 'chardev'");
1105
ivshmem_common_realize(dev, errp);
1108
static void ivshmem_doorbell_class_init(ObjectClass *klass, void *data)
1110
DeviceClass *dc = DEVICE_CLASS(klass);
1111
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
1113
k->realize = ivshmem_doorbell_realize;
1114
device_class_set_props(dc, ivshmem_doorbell_properties);
1115
dc->vmsd = &ivshmem_doorbell_vmsd;
1118
static const TypeInfo ivshmem_doorbell_info = {
1119
.name = TYPE_IVSHMEM_DOORBELL,
1120
.parent = TYPE_IVSHMEM_COMMON,
1121
.instance_size = sizeof(IVShmemState),
1122
.instance_init = ivshmem_doorbell_init,
1123
.class_init = ivshmem_doorbell_class_init,
1126
static void ivshmem_register_types(void)
1128
type_register_static(&ivshmem_common_info);
1129
type_register_static(&ivshmem_plain_info);
1130
type_register_static(&ivshmem_doorbell_info);
1133
type_init(ivshmem_register_types)