RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
/*
|
|
|
|
* Inter-VM Shared Memory PCI device.
|
|
|
|
*
|
|
|
|
* Author:
|
|
|
|
* Cam Macdonell <cam@cs.ualberta.ca>
|
|
|
|
*
|
|
|
|
* Based On: cirrus_vga.c
|
|
|
|
* Copyright (c) 2004 Fabrice Bellard
|
|
|
|
* Copyright (c) 2004 Makoto Suzuki (suzu)
|
|
|
|
*
|
|
|
|
* and rtl8139.c
|
|
|
|
* Copyright (c) 2006 Igor Kovalenko
|
|
|
|
*
|
|
|
|
* This code is licensed under the GNU GPL v2.
|
2012-01-13 16:44:23 +00:00
|
|
|
*
|
|
|
|
* Contributions after 2012-01-13 are licensed under the terms of the
|
|
|
|
* GNU GPL, version 2 or (at your option) any later version.
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
*/
|
2016-01-26 18:17:17 +00:00
|
|
|
#include "qemu/osdep.h"
|
include/qemu/osdep.h: Don't include qapi/error.h
Commit 57cb38b included qapi/error.h into qemu/osdep.h to get the
Error typedef. Since then, we've moved to include qemu/osdep.h
everywhere. Its file comment explains: "To avoid getting into
possible circular include dependencies, this file should not include
any other QEMU headers, with the exceptions of config-host.h,
compiler.h, os-posix.h and os-win32.h, all of which are doing a
similar job to this file and are under similar constraints."
qapi/error.h doesn't do a similar job, and it doesn't adhere to
similar constraints: it includes qapi-types.h. That's in excess of
100KiB of crap most .c files don't actually need.
Add the typedef to qemu/typedefs.h, and include that instead of
qapi/error.h. Include qapi/error.h in .c files that need it and don't
get it now. Include qapi-types.h in qom/object.h for uint16List.
Update scripts/clean-includes accordingly. Update it further to match
reality: replace config.h by config-target.h, add sysemu/os-posix.h,
sysemu/os-win32.h. Update the list of includes in the qemu/osdep.h
comment quoted above similarly.
This reduces the number of objects depending on qapi/error.h from "all
of them" to less than a third. Unfortunately, the number depending on
qapi-types.h shrinks only a little. More work is needed for that one.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
[Fix compilation without the spice devel packages. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2016-03-14 08:01:28 +00:00
|
|
|
#include "qapi/error.h"
|
2016-03-20 17:16:19 +00:00
|
|
|
#include "qemu/cutils.h"
|
2013-02-04 14:40:22 +00:00
|
|
|
#include "hw/hw.h"
|
2013-02-05 16:06:20 +00:00
|
|
|
#include "hw/i386/pc.h"
|
2013-02-04 14:40:22 +00:00
|
|
|
#include "hw/pci/pci.h"
|
2015-07-09 13:50:13 +00:00
|
|
|
#include "hw/pci/msi.h"
|
2013-02-04 14:40:22 +00:00
|
|
|
#include "hw/pci/msix.h"
|
2012-12-17 17:20:04 +00:00
|
|
|
#include "sysemu/kvm.h"
|
2012-12-17 17:19:50 +00:00
|
|
|
#include "migration/migration.h"
|
2015-03-17 17:29:20 +00:00
|
|
|
#include "qemu/error-report.h"
|
2012-12-17 17:20:00 +00:00
|
|
|
#include "qemu/event_notifier.h"
|
2016-03-15 18:34:46 +00:00
|
|
|
#include "qom/object_interfaces.h"
|
2013-04-08 14:55:25 +00:00
|
|
|
#include "sysemu/char.h"
|
2015-06-29 22:10:16 +00:00
|
|
|
#include "sysemu/hostmem.h"
|
2016-03-15 18:34:51 +00:00
|
|
|
#include "sysemu/qtest.h"
|
2015-06-29 22:10:16 +00:00
|
|
|
#include "qapi/visitor.h"
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
|
2015-06-16 15:43:34 +00:00
|
|
|
#include "hw/misc/ivshmem.h"
|
|
|
|
|
2012-12-13 09:19:37 +00:00
|
|
|
#define PCI_VENDOR_ID_IVSHMEM PCI_VENDOR_ID_REDHAT_QUMRANET
|
|
|
|
#define PCI_DEVICE_ID_IVSHMEM 0x1110
|
|
|
|
|
2016-03-15 18:34:37 +00:00
|
|
|
#define IVSHMEM_MAX_PEERS UINT16_MAX
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
#define IVSHMEM_IOEVENTFD 0
|
|
|
|
#define IVSHMEM_MSI 1
|
|
|
|
|
|
|
|
#define IVSHMEM_REG_BAR_SIZE 0x100
|
|
|
|
|
2016-03-15 18:34:27 +00:00
|
|
|
#define IVSHMEM_DEBUG 0
|
|
|
|
#define IVSHMEM_DPRINTF(fmt, ...) \
|
|
|
|
do { \
|
|
|
|
if (IVSHMEM_DEBUG) { \
|
|
|
|
printf("IVSHMEM: " fmt, ## __VA_ARGS__); \
|
|
|
|
} \
|
|
|
|
} while (0)
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
|
2016-03-15 18:34:51 +00:00
|
|
|
#define TYPE_IVSHMEM_COMMON "ivshmem-common"
|
|
|
|
#define IVSHMEM_COMMON(obj) \
|
|
|
|
OBJECT_CHECK(IVShmemState, (obj), TYPE_IVSHMEM_COMMON)
|
|
|
|
|
|
|
|
#define TYPE_IVSHMEM_PLAIN "ivshmem-plain"
|
|
|
|
#define IVSHMEM_PLAIN(obj) \
|
|
|
|
OBJECT_CHECK(IVShmemState, (obj), TYPE_IVSHMEM_PLAIN)
|
|
|
|
|
|
|
|
#define TYPE_IVSHMEM_DOORBELL "ivshmem-doorbell"
|
|
|
|
#define IVSHMEM_DOORBELL(obj) \
|
|
|
|
OBJECT_CHECK(IVShmemState, (obj), TYPE_IVSHMEM_DOORBELL)
|
|
|
|
|
2013-06-24 06:59:29 +00:00
|
|
|
#define TYPE_IVSHMEM "ivshmem"
|
|
|
|
#define IVSHMEM(obj) \
|
|
|
|
OBJECT_CHECK(IVShmemState, (obj), TYPE_IVSHMEM)
|
|
|
|
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
typedef struct Peer {
|
|
|
|
int nb_eventfds;
|
2012-07-05 15:16:25 +00:00
|
|
|
EventNotifier *eventfds;
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
} Peer;
|
|
|
|
|
2015-07-27 10:59:19 +00:00
|
|
|
typedef struct MSIVector {
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
PCIDevice *pdev;
|
2015-07-09 13:50:13 +00:00
|
|
|
int virq;
|
2015-07-27 10:59:19 +00:00
|
|
|
} MSIVector;
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
|
|
|
|
typedef struct IVShmemState {
|
2013-06-30 13:15:15 +00:00
|
|
|
/*< private >*/
|
|
|
|
PCIDevice parent_obj;
|
|
|
|
/*< public >*/
|
|
|
|
|
2016-03-15 18:34:52 +00:00
|
|
|
uint32_t features;
|
|
|
|
|
|
|
|
/* exactly one of these two may be set */
|
|
|
|
HostMemoryBackend *hostmem; /* with interrupts */
|
|
|
|
CharDriverState *server_chr; /* without interrupts */
|
|
|
|
|
|
|
|
/* registers */
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
uint32_t intrmask;
|
|
|
|
uint32_t intrstatus;
|
2016-03-15 18:34:52 +00:00
|
|
|
int vm_id;
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
|
2016-03-15 18:34:52 +00:00
|
|
|
/* BARs */
|
|
|
|
MemoryRegion ivshmem_mmio; /* BAR 0 (registers) */
|
2016-03-15 18:34:47 +00:00
|
|
|
MemoryRegion *ivshmem_bar2; /* BAR 2 (shared memory) */
|
|
|
|
MemoryRegion server_bar2; /* used with server_chr */
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
|
2016-03-15 18:34:52 +00:00
|
|
|
/* interrupt support */
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
Peer *peers;
|
2016-03-15 18:34:37 +00:00
|
|
|
int nb_peers; /* space in @peers[] */
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
uint32_t vectors;
|
2015-07-27 10:59:19 +00:00
|
|
|
MSIVector *msi_vectors;
|
2016-03-15 18:34:44 +00:00
|
|
|
uint64_t msg_buf; /* buffer for receiving server messages */
|
|
|
|
int msg_buffered_bytes; /* #bytes in @msg_buf */
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
|
2016-03-15 18:34:52 +00:00
|
|
|
/* migration stuff */
|
2016-03-15 18:34:50 +00:00
|
|
|
OnOffAuto master;
|
2011-11-14 21:09:44 +00:00
|
|
|
Error *migration_blocker;
|
|
|
|
|
2016-03-15 18:34:51 +00:00
|
|
|
/* legacy cruft */
|
|
|
|
char *role;
|
|
|
|
char *shmobj;
|
|
|
|
char *sizearg;
|
|
|
|
size_t legacy_size;
|
|
|
|
uint32_t not_legacy_32bit;
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
} IVShmemState;
|
|
|
|
|
|
|
|
/* registers for the Inter-VM shared memory device */
|
|
|
|
enum ivshmem_registers {
|
|
|
|
INTRMASK = 0,
|
|
|
|
INTRSTATUS = 4,
|
|
|
|
IVPOSITION = 8,
|
|
|
|
DOORBELL = 12,
|
|
|
|
};
|
|
|
|
|
|
|
|
static inline uint32_t ivshmem_has_feature(IVShmemState *ivs,
|
|
|
|
unsigned int feature) {
|
|
|
|
return (ivs->features & (1 << feature));
|
|
|
|
}
|
|
|
|
|
2016-03-15 18:34:50 +00:00
|
|
|
static inline bool ivshmem_is_master(IVShmemState *s)
|
|
|
|
{
|
|
|
|
assert(s->master != ON_OFF_AUTO_AUTO);
|
|
|
|
return s->master == ON_OFF_AUTO_ON;
|
|
|
|
}
|
|
|
|
|
2015-06-18 13:00:52 +00:00
|
|
|
static void ivshmem_update_irq(IVShmemState *s)
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
{
|
2013-06-30 13:15:15 +00:00
|
|
|
PCIDevice *d = PCI_DEVICE(s);
|
2016-03-15 18:34:33 +00:00
|
|
|
uint32_t isr = s->intrstatus & s->intrmask;
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
|
2016-03-15 18:34:51 +00:00
|
|
|
/*
|
|
|
|
* Do nothing unless the device actually uses INTx. Here's how
|
|
|
|
* the device variants signal interrupts, what they put in PCI
|
|
|
|
* config space:
|
|
|
|
* Device variant Interrupt Interrupt Pin MSI-X cap.
|
|
|
|
* ivshmem-plain none 0 no
|
|
|
|
* ivshmem-doorbell MSI-X 1 yes(1)
|
|
|
|
* ivshmem,msi=off INTx 1 no
|
|
|
|
* ivshmem,msi=on MSI-X 1(2) yes(1)
|
|
|
|
* (1) if guest enabled MSI-X
|
|
|
|
* (2) the device lies
|
|
|
|
* Leads to the condition for doing nothing:
|
|
|
|
*/
|
|
|
|
if (ivshmem_has_feature(s, IVSHMEM_MSI)
|
|
|
|
|| !d->config[PCI_INTERRUPT_PIN]) {
|
2016-03-15 18:34:35 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
/* don't print ISR resets */
|
|
|
|
if (isr) {
|
|
|
|
IVSHMEM_DPRINTF("Set IRQ to %d (%04x %04x)\n",
|
2014-10-07 11:24:02 +00:00
|
|
|
isr ? 1 : 0, s->intrstatus, s->intrmask);
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
}
|
|
|
|
|
2016-03-15 18:34:33 +00:00
|
|
|
pci_set_irq(d, isr != 0);
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void ivshmem_IntrMask_write(IVShmemState *s, uint32_t val)
|
|
|
|
{
|
|
|
|
IVSHMEM_DPRINTF("IntrMask write(w) val = 0x%04x\n", val);
|
|
|
|
|
|
|
|
s->intrmask = val;
|
2015-06-18 13:00:52 +00:00
|
|
|
ivshmem_update_irq(s);
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static uint32_t ivshmem_IntrMask_read(IVShmemState *s)
|
|
|
|
{
|
|
|
|
uint32_t ret = s->intrmask;
|
|
|
|
|
|
|
|
IVSHMEM_DPRINTF("intrmask read(w) val = 0x%04x\n", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ivshmem_IntrStatus_write(IVShmemState *s, uint32_t val)
|
|
|
|
{
|
|
|
|
IVSHMEM_DPRINTF("IntrStatus write(w) val = 0x%04x\n", val);
|
|
|
|
|
|
|
|
s->intrstatus = val;
|
2015-06-18 13:00:52 +00:00
|
|
|
ivshmem_update_irq(s);
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static uint32_t ivshmem_IntrStatus_read(IVShmemState *s)
|
|
|
|
{
|
|
|
|
uint32_t ret = s->intrstatus;
|
|
|
|
|
|
|
|
/* reading ISR clears all interrupts */
|
|
|
|
s->intrstatus = 0;
|
2015-06-18 13:00:52 +00:00
|
|
|
ivshmem_update_irq(s);
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-10-23 10:30:10 +00:00
|
|
|
static void ivshmem_io_write(void *opaque, hwaddr addr,
|
2011-08-08 13:09:12 +00:00
|
|
|
uint64_t val, unsigned size)
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
{
|
|
|
|
IVShmemState *s = opaque;
|
|
|
|
|
|
|
|
uint16_t dest = val >> 16;
|
|
|
|
uint16_t vector = val & 0xff;
|
|
|
|
|
|
|
|
addr &= 0xfc;
|
|
|
|
|
|
|
|
IVSHMEM_DPRINTF("writing to addr " TARGET_FMT_plx "\n", addr);
|
|
|
|
switch (addr)
|
|
|
|
{
|
|
|
|
case INTRMASK:
|
|
|
|
ivshmem_IntrMask_write(s, val);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case INTRSTATUS:
|
|
|
|
ivshmem_IntrStatus_write(s, val);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DOORBELL:
|
|
|
|
/* check that dest VM ID is reasonable */
|
2015-06-19 10:17:26 +00:00
|
|
|
if (dest >= s->nb_peers) {
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
IVSHMEM_DPRINTF("Invalid destination VM ID (%d)\n", dest);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check doorbell range */
|
2010-08-30 10:31:33 +00:00
|
|
|
if (vector < s->peers[dest].nb_eventfds) {
|
2012-07-05 15:16:25 +00:00
|
|
|
IVSHMEM_DPRINTF("Notifying VM %d on vector %d\n", dest, vector);
|
|
|
|
event_notifier_set(&s->peers[dest].eventfds[vector]);
|
2015-06-18 13:04:13 +00:00
|
|
|
} else {
|
|
|
|
IVSHMEM_DPRINTF("Invalid destination vector %d on VM %d\n",
|
|
|
|
vector, dest);
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
2015-06-18 13:04:13 +00:00
|
|
|
IVSHMEM_DPRINTF("Unhandled write " TARGET_FMT_plx "\n", addr);
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-23 10:30:10 +00:00
|
|
|
static uint64_t ivshmem_io_read(void *opaque, hwaddr addr,
|
2011-08-08 13:09:12 +00:00
|
|
|
unsigned size)
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
IVShmemState *s = opaque;
|
|
|
|
uint32_t ret;
|
|
|
|
|
|
|
|
switch (addr)
|
|
|
|
{
|
|
|
|
case INTRMASK:
|
|
|
|
ret = ivshmem_IntrMask_read(s);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case INTRSTATUS:
|
|
|
|
ret = ivshmem_IntrStatus_read(s);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IVPOSITION:
|
2016-03-15 18:34:41 +00:00
|
|
|
ret = s->vm_id;
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
IVSHMEM_DPRINTF("why are we reading " TARGET_FMT_plx "\n", addr);
|
|
|
|
ret = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2011-08-08 13:09:12 +00:00
|
|
|
static const MemoryRegionOps ivshmem_mmio_ops = {
|
|
|
|
.read = ivshmem_io_read,
|
|
|
|
.write = ivshmem_io_write,
|
|
|
|
.endianness = DEVICE_NATIVE_ENDIAN,
|
|
|
|
.impl = {
|
|
|
|
.min_access_size = 4,
|
|
|
|
.max_access_size = 4,
|
|
|
|
},
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
};
|
|
|
|
|
2015-12-21 11:10:13 +00:00
|
|
|
static void ivshmem_vector_notify(void *opaque)
|
|
|
|
{
|
2015-07-27 10:59:19 +00:00
|
|
|
MSIVector *entry = opaque;
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
PCIDevice *pdev = entry->pdev;
|
2016-03-15 18:34:51 +00:00
|
|
|
IVShmemState *s = IVSHMEM_COMMON(pdev);
|
2015-07-27 10:59:19 +00:00
|
|
|
int vector = entry - s->msi_vectors;
|
2015-12-21 11:10:13 +00:00
|
|
|
EventNotifier *n = &s->peers[s->vm_id].eventfds[vector];
|
|
|
|
|
|
|
|
if (!event_notifier_test_and_clear(n)) {
|
|
|
|
return;
|
|
|
|
}
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
|
2015-07-24 16:52:19 +00:00
|
|
|
IVSHMEM_DPRINTF("interrupt on vector %p %d\n", pdev, vector);
|
2015-12-21 11:10:13 +00:00
|
|
|
if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
|
ivshmem: Clean up MSI-X conditions
There are three predicates related to MSI-X:
* ivshmem_has_feature(s, IVSHMEM_MSI) is true unless the non-MSI-X
variant of the device is selected with msi=off.
* msix_present() is true when the device has the PCI capability MSI-X.
It's initially false, and becomes true during successful realize of
the MSI-X variant of the device. Thus, it's the same as
ivshmem_has_feature(s, IVSHMEM_MSI) for realized devices.
* msix_enabled() is true when msix_present() is true and guest software
has enabled MSI-X.
Code that differs between the non-MSI-X and the MSI-X variant of the
device needs to be guarded by ivshmem_has_feature(s, IVSHMEM_MSI) or
by msix_present(), except the latter works only for realized devices.
Code that depends on whether MSI-X is in use needs to be guarded with
msix_enabled().
Code review led me to two minor messes:
* ivshmem_vector_notify() calls msix_notify() even when
!msix_enabled(), unlike most other MSI-X-capable devices. As far as
I can tell, msix_notify() does nothing when !msix_enabled(). Add
the guard anyway.
* Most callers of ivshmem_use_msix() guard it with
ivshmem_has_feature(s, IVSHMEM_MSI). Not necessary, because
ivshmem_use_msix() does nothing when !msix_present(). That's
ivshmem's only use of msix_present(), though. Guard it
consistently, and drop the now redundant msix_present() check.
While there, rename ivshmem_use_msix() to ivshmem_msix_vector_use().
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <1458066895-20632-20-git-send-email-armbru@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
2016-03-15 18:34:34 +00:00
|
|
|
if (msix_enabled(pdev)) {
|
|
|
|
msix_notify(pdev, vector);
|
|
|
|
}
|
2015-12-21 11:10:13 +00:00
|
|
|
} else {
|
|
|
|
ivshmem_IntrStatus_write(s, 1);
|
|
|
|
}
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
}
|
|
|
|
|
2015-07-09 13:50:13 +00:00
|
|
|
static int ivshmem_vector_unmask(PCIDevice *dev, unsigned vector,
|
|
|
|
MSIMessage msg)
|
|
|
|
{
|
2016-03-15 18:34:51 +00:00
|
|
|
IVShmemState *s = IVSHMEM_COMMON(dev);
|
2015-07-09 13:50:13 +00:00
|
|
|
EventNotifier *n = &s->peers[s->vm_id].eventfds[vector];
|
|
|
|
MSIVector *v = &s->msi_vectors[vector];
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
IVSHMEM_DPRINTF("vector unmask %p %d\n", dev, vector);
|
|
|
|
|
|
|
|
ret = kvm_irqchip_update_msi_route(kvm_state, v->virq, msg, dev);
|
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
return kvm_irqchip_add_irqfd_notifier_gsi(kvm_state, n, NULL, v->virq);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ivshmem_vector_mask(PCIDevice *dev, unsigned vector)
|
|
|
|
{
|
2016-03-15 18:34:51 +00:00
|
|
|
IVShmemState *s = IVSHMEM_COMMON(dev);
|
2015-07-09 13:50:13 +00:00
|
|
|
EventNotifier *n = &s->peers[s->vm_id].eventfds[vector];
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
IVSHMEM_DPRINTF("vector mask %p %d\n", dev, vector);
|
|
|
|
|
|
|
|
ret = kvm_irqchip_remove_irqfd_notifier_gsi(kvm_state, n,
|
|
|
|
s->msi_vectors[vector].virq);
|
|
|
|
if (ret != 0) {
|
|
|
|
error_report("remove_irqfd_notifier_gsi failed");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ivshmem_vector_poll(PCIDevice *dev,
|
|
|
|
unsigned int vector_start,
|
|
|
|
unsigned int vector_end)
|
|
|
|
{
|
2016-03-15 18:34:51 +00:00
|
|
|
IVShmemState *s = IVSHMEM_COMMON(dev);
|
2015-07-09 13:50:13 +00:00
|
|
|
unsigned int vector;
|
|
|
|
|
|
|
|
IVSHMEM_DPRINTF("vector poll %p %d-%d\n", dev, vector_start, vector_end);
|
|
|
|
|
|
|
|
vector_end = MIN(vector_end, s->vectors);
|
|
|
|
|
|
|
|
for (vector = vector_start; vector < vector_end; vector++) {
|
|
|
|
EventNotifier *notifier = &s->peers[s->vm_id].eventfds[vector];
|
|
|
|
|
|
|
|
if (!msix_is_masked(dev, vector)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (event_notifier_test_and_clear(notifier)) {
|
|
|
|
msix_set_pending(dev, vector);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-21 11:10:13 +00:00
|
|
|
static void watch_vector_notifier(IVShmemState *s, EventNotifier *n,
|
|
|
|
int vector)
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
{
|
2012-07-05 15:16:25 +00:00
|
|
|
int eventfd = event_notifier_get_fd(n);
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
|
2016-03-15 18:34:36 +00:00
|
|
|
assert(!s->msi_vectors[vector].pdev);
|
2015-12-21 11:10:13 +00:00
|
|
|
s->msi_vectors[vector].pdev = PCI_DEVICE(s);
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
|
2015-12-21 11:10:13 +00:00
|
|
|
qemu_set_fd_handler(eventfd, ivshmem_vector_notify,
|
|
|
|
NULL, &s->msi_vectors[vector]);
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
}
|
|
|
|
|
2012-07-05 15:16:25 +00:00
|
|
|
static void ivshmem_add_eventfd(IVShmemState *s, int posn, int i)
|
|
|
|
{
|
|
|
|
memory_region_add_eventfd(&s->ivshmem_mmio,
|
|
|
|
DOORBELL,
|
|
|
|
4,
|
|
|
|
true,
|
|
|
|
(posn << 16) | i,
|
2012-07-05 15:16:27 +00:00
|
|
|
&s->peers[posn].eventfds[i]);
|
2012-07-05 15:16:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void ivshmem_del_eventfd(IVShmemState *s, int posn, int i)
|
|
|
|
{
|
|
|
|
memory_region_del_eventfd(&s->ivshmem_mmio,
|
|
|
|
DOORBELL,
|
|
|
|
4,
|
|
|
|
true,
|
|
|
|
(posn << 16) | i,
|
2012-07-05 15:16:27 +00:00
|
|
|
&s->peers[posn].eventfds[i]);
|
2012-07-05 15:16:25 +00:00
|
|
|
}
|
|
|
|
|
2015-06-23 11:38:46 +00:00
|
|
|
static void close_peer_eventfds(IVShmemState *s, int posn)
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
{
|
2015-06-23 11:38:46 +00:00
|
|
|
int i, n;
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
|
ivshmem: Plug leaks on unplug, fix peer disconnect
close_peer_eventfds() cleans up three things: ioeventfd triggers if
they exist, eventfds, and the array to store them.
Commit 98609cd (v1.2.0) fixed it not to clean up ioeventfd triggers
when they don't exist (property ioeventfd=off, which is the default).
Unfortunately, the fix also made it skip cleanup of the eventfds and
the array then. This is a memory and file descriptor leak on unplug.
Additionally, the reset of nb_eventfds is skipped. Doesn't matter on
unplug. On peer disconnect, however, this permanently wedges the
interrupt vectors used for that peer's ID. The eventfds stay behind,
but aren't connected to a peer anymore. When the ID gets recycled for
a new peer, the new peer's eventfds get assigned to vectors after the
old ones. Commonly, the device's number of vectors matches the
server's, so the new ones get dropped with a "Too many eventfd
received" message. Interrupts either don't work (common case) or go
to the wrong vector.
Fix by narrowing the conditional to just the ioeventfd trigger
cleanup.
While there, move the "invalid" peer check to the only caller where it
can actually happen, and tighten it to reject own ID.
Cc: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1458066895-20632-25-git-send-email-armbru@redhat.com>
2016-03-15 18:34:39 +00:00
|
|
|
assert(posn >= 0 && posn < s->nb_peers);
|
2015-06-23 11:38:46 +00:00
|
|
|
n = s->peers[posn].nb_eventfds;
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
|
ivshmem: Plug leaks on unplug, fix peer disconnect
close_peer_eventfds() cleans up three things: ioeventfd triggers if
they exist, eventfds, and the array to store them.
Commit 98609cd (v1.2.0) fixed it not to clean up ioeventfd triggers
when they don't exist (property ioeventfd=off, which is the default).
Unfortunately, the fix also made it skip cleanup of the eventfds and
the array then. This is a memory and file descriptor leak on unplug.
Additionally, the reset of nb_eventfds is skipped. Doesn't matter on
unplug. On peer disconnect, however, this permanently wedges the
interrupt vectors used for that peer's ID. The eventfds stay behind,
but aren't connected to a peer anymore. When the ID gets recycled for
a new peer, the new peer's eventfds get assigned to vectors after the
old ones. Commonly, the device's number of vectors matches the
server's, so the new ones get dropped with a "Too many eventfd
received" message. Interrupts either don't work (common case) or go
to the wrong vector.
Fix by narrowing the conditional to just the ioeventfd trigger
cleanup.
While there, move the "invalid" peer check to the only caller where it
can actually happen, and tighten it to reject own ID.
Cc: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1458066895-20632-25-git-send-email-armbru@redhat.com>
2016-03-15 18:34:39 +00:00
|
|
|
if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) {
|
|
|
|
memory_region_transaction_begin();
|
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
ivshmem_del_eventfd(s, posn, i);
|
|
|
|
}
|
|
|
|
memory_region_transaction_commit();
|
2012-07-05 15:16:26 +00:00
|
|
|
}
|
ivshmem: Plug leaks on unplug, fix peer disconnect
close_peer_eventfds() cleans up three things: ioeventfd triggers if
they exist, eventfds, and the array to store them.
Commit 98609cd (v1.2.0) fixed it not to clean up ioeventfd triggers
when they don't exist (property ioeventfd=off, which is the default).
Unfortunately, the fix also made it skip cleanup of the eventfds and
the array then. This is a memory and file descriptor leak on unplug.
Additionally, the reset of nb_eventfds is skipped. Doesn't matter on
unplug. On peer disconnect, however, this permanently wedges the
interrupt vectors used for that peer's ID. The eventfds stay behind,
but aren't connected to a peer anymore. When the ID gets recycled for
a new peer, the new peer's eventfds get assigned to vectors after the
old ones. Commonly, the device's number of vectors matches the
server's, so the new ones get dropped with a "Too many eventfd
received" message. Interrupts either don't work (common case) or go
to the wrong vector.
Fix by narrowing the conditional to just the ioeventfd trigger
cleanup.
While there, move the "invalid" peer check to the only caller where it
can actually happen, and tighten it to reject own ID.
Cc: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1458066895-20632-25-git-send-email-armbru@redhat.com>
2016-03-15 18:34:39 +00:00
|
|
|
|
2015-06-23 11:38:46 +00:00
|
|
|
for (i = 0; i < n; i++) {
|
2012-07-05 15:16:25 +00:00
|
|
|
event_notifier_cleanup(&s->peers[posn].eventfds[i]);
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
}
|
|
|
|
|
2011-08-21 03:09:37 +00:00
|
|
|
g_free(s->peers[posn].eventfds);
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
s->peers[posn].nb_eventfds = 0;
|
|
|
|
}
|
|
|
|
|
2016-03-15 18:34:37 +00:00
|
|
|
static void resize_peers(IVShmemState *s, int nb_peers)
|
2014-09-15 16:40:07 +00:00
|
|
|
{
|
2016-03-15 18:34:37 +00:00
|
|
|
int old_nb_peers = s->nb_peers;
|
|
|
|
int i;
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
|
2016-03-15 18:34:37 +00:00
|
|
|
assert(nb_peers > old_nb_peers);
|
|
|
|
IVSHMEM_DPRINTF("bumping storage to %d peers\n", nb_peers);
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
|
2016-03-15 18:34:37 +00:00
|
|
|
s->peers = g_realloc(s->peers, nb_peers * sizeof(Peer));
|
|
|
|
s->nb_peers = nb_peers;
|
2015-09-15 15:21:37 +00:00
|
|
|
|
2016-03-15 18:34:37 +00:00
|
|
|
for (i = old_nb_peers; i < nb_peers; i++) {
|
|
|
|
s->peers[i].eventfds = g_new0(EventNotifier, s->vectors);
|
|
|
|
s->peers[i].nb_eventfds = 0;
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-15 18:34:41 +00:00
|
|
|
static void ivshmem_add_kvm_msi_virq(IVShmemState *s, int vector,
|
|
|
|
Error **errp)
|
2015-07-09 13:50:13 +00:00
|
|
|
{
|
|
|
|
PCIDevice *pdev = PCI_DEVICE(s);
|
|
|
|
MSIMessage msg = msix_get_message(pdev, vector);
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
IVSHMEM_DPRINTF("ivshmem_add_kvm_msi_virq vector:%d\n", vector);
|
2016-03-15 18:34:36 +00:00
|
|
|
assert(!s->msi_vectors[vector].pdev);
|
2015-07-09 13:50:13 +00:00
|
|
|
|
|
|
|
ret = kvm_irqchip_add_msi_route(kvm_state, msg, pdev);
|
|
|
|
if (ret < 0) {
|
2016-03-15 18:34:41 +00:00
|
|
|
error_setg(errp, "kvm_irqchip_add_msi_route failed");
|
|
|
|
return;
|
2015-07-09 13:50:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
s->msi_vectors[vector].virq = ret;
|
|
|
|
s->msi_vectors[vector].pdev = pdev;
|
|
|
|
}
|
|
|
|
|
2016-03-15 18:34:41 +00:00
|
|
|
static void setup_interrupt(IVShmemState *s, int vector, Error **errp)
|
2015-07-09 13:50:13 +00:00
|
|
|
{
|
|
|
|
EventNotifier *n = &s->peers[s->vm_id].eventfds[vector];
|
|
|
|
bool with_irqfd = kvm_msi_via_irqfd_enabled() &&
|
|
|
|
ivshmem_has_feature(s, IVSHMEM_MSI);
|
|
|
|
PCIDevice *pdev = PCI_DEVICE(s);
|
2016-03-15 18:34:41 +00:00
|
|
|
Error *err = NULL;
|
2015-07-09 13:50:13 +00:00
|
|
|
|
|
|
|
IVSHMEM_DPRINTF("setting up interrupt for vector: %d\n", vector);
|
|
|
|
|
|
|
|
if (!with_irqfd) {
|
2016-03-15 18:34:26 +00:00
|
|
|
IVSHMEM_DPRINTF("with eventfd\n");
|
2015-12-21 11:10:13 +00:00
|
|
|
watch_vector_notifier(s, n, vector);
|
2015-07-09 13:50:13 +00:00
|
|
|
} else if (msix_enabled(pdev)) {
|
2016-03-15 18:34:26 +00:00
|
|
|
IVSHMEM_DPRINTF("with irqfd\n");
|
2016-03-15 18:34:41 +00:00
|
|
|
ivshmem_add_kvm_msi_virq(s, vector, &err);
|
|
|
|
if (err) {
|
|
|
|
error_propagate(errp, err);
|
2015-07-09 13:50:13 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!msix_is_masked(pdev, vector)) {
|
|
|
|
kvm_irqchip_add_irqfd_notifier_gsi(kvm_state, n, NULL,
|
|
|
|
s->msi_vectors[vector].virq);
|
2016-03-15 18:34:41 +00:00
|
|
|
/* TODO handle error */
|
2015-07-09 13:50:13 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* it will be delayed until msix is enabled, in write_config */
|
2016-03-15 18:34:26 +00:00
|
|
|
IVSHMEM_DPRINTF("with irqfd, delayed until msix enabled\n");
|
2015-07-09 13:50:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-15 18:34:41 +00:00
|
|
|
static void process_msg_shmem(IVShmemState *s, int fd, Error **errp)
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
{
|
2016-03-15 18:34:48 +00:00
|
|
|
struct stat buf;
|
2016-03-15 18:34:51 +00:00
|
|
|
size_t size;
|
2016-03-15 18:34:38 +00:00
|
|
|
void *ptr;
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
|
2016-03-15 18:34:47 +00:00
|
|
|
if (s->ivshmem_bar2) {
|
2016-03-15 18:34:41 +00:00
|
|
|
error_setg(errp, "server sent unexpected shared memory message");
|
2016-03-15 18:34:38 +00:00
|
|
|
close(fd);
|
2015-06-23 15:56:37 +00:00
|
|
|
return;
|
2014-09-15 16:40:05 +00:00
|
|
|
}
|
|
|
|
|
2016-03-15 18:34:48 +00:00
|
|
|
if (fstat(fd, &buf) < 0) {
|
|
|
|
error_setg_errno(errp, errno,
|
|
|
|
"can't determine size of shared memory sent by server");
|
|
|
|
close(fd);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-03-15 18:34:51 +00:00
|
|
|
size = buf.st_size;
|
|
|
|
|
|
|
|
/* Legacy cruft */
|
|
|
|
if (s->legacy_size != SIZE_MAX) {
|
|
|
|
if (size < s->legacy_size) {
|
|
|
|
error_setg(errp, "server sent only %zd bytes of shared memory",
|
|
|
|
(size_t)buf.st_size);
|
|
|
|
close(fd);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
size = s->legacy_size;
|
2016-03-15 18:34:37 +00:00
|
|
|
}
|
|
|
|
|
2016-03-15 18:34:38 +00:00
|
|
|
/* mmap the region and map into the BAR2 */
|
2016-03-15 18:34:51 +00:00
|
|
|
ptr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
2016-03-15 18:34:38 +00:00
|
|
|
if (ptr == MAP_FAILED) {
|
2016-03-15 18:34:41 +00:00
|
|
|
error_setg_errno(errp, errno, "Failed to mmap shared memory");
|
2016-03-15 18:34:38 +00:00
|
|
|
close(fd);
|
|
|
|
return;
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
}
|
2016-03-15 18:34:47 +00:00
|
|
|
memory_region_init_ram_ptr(&s->server_bar2, OBJECT(s),
|
2016-03-15 18:34:51 +00:00
|
|
|
"ivshmem.bar2", size, ptr);
|
2016-03-25 11:30:16 +00:00
|
|
|
memory_region_set_fd(&s->server_bar2, fd);
|
2016-03-15 18:34:47 +00:00
|
|
|
s->ivshmem_bar2 = &s->server_bar2;
|
2016-03-15 18:34:38 +00:00
|
|
|
}
|
|
|
|
|
2016-03-15 18:34:41 +00:00
|
|
|
static void process_msg_disconnect(IVShmemState *s, uint16_t posn,
|
|
|
|
Error **errp)
|
2016-03-15 18:34:38 +00:00
|
|
|
{
|
|
|
|
IVSHMEM_DPRINTF("posn %d has gone away\n", posn);
|
ivshmem: Plug leaks on unplug, fix peer disconnect
close_peer_eventfds() cleans up three things: ioeventfd triggers if
they exist, eventfds, and the array to store them.
Commit 98609cd (v1.2.0) fixed it not to clean up ioeventfd triggers
when they don't exist (property ioeventfd=off, which is the default).
Unfortunately, the fix also made it skip cleanup of the eventfds and
the array then. This is a memory and file descriptor leak on unplug.
Additionally, the reset of nb_eventfds is skipped. Doesn't matter on
unplug. On peer disconnect, however, this permanently wedges the
interrupt vectors used for that peer's ID. The eventfds stay behind,
but aren't connected to a peer anymore. When the ID gets recycled for
a new peer, the new peer's eventfds get assigned to vectors after the
old ones. Commonly, the device's number of vectors matches the
server's, so the new ones get dropped with a "Too many eventfd
received" message. Interrupts either don't work (common case) or go
to the wrong vector.
Fix by narrowing the conditional to just the ioeventfd trigger
cleanup.
While there, move the "invalid" peer check to the only caller where it
can actually happen, and tighten it to reject own ID.
Cc: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1458066895-20632-25-git-send-email-armbru@redhat.com>
2016-03-15 18:34:39 +00:00
|
|
|
if (posn >= s->nb_peers || posn == s->vm_id) {
|
2016-03-15 18:34:41 +00:00
|
|
|
error_setg(errp, "invalid peer %d", posn);
|
ivshmem: Plug leaks on unplug, fix peer disconnect
close_peer_eventfds() cleans up three things: ioeventfd triggers if
they exist, eventfds, and the array to store them.
Commit 98609cd (v1.2.0) fixed it not to clean up ioeventfd triggers
when they don't exist (property ioeventfd=off, which is the default).
Unfortunately, the fix also made it skip cleanup of the eventfds and
the array then. This is a memory and file descriptor leak on unplug.
Additionally, the reset of nb_eventfds is skipped. Doesn't matter on
unplug. On peer disconnect, however, this permanently wedges the
interrupt vectors used for that peer's ID. The eventfds stay behind,
but aren't connected to a peer anymore. When the ID gets recycled for
a new peer, the new peer's eventfds get assigned to vectors after the
old ones. Commonly, the device's number of vectors matches the
server's, so the new ones get dropped with a "Too many eventfd
received" message. Interrupts either don't work (common case) or go
to the wrong vector.
Fix by narrowing the conditional to just the ioeventfd trigger
cleanup.
While there, move the "invalid" peer check to the only caller where it
can actually happen, and tighten it to reject own ID.
Cc: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1458066895-20632-25-git-send-email-armbru@redhat.com>
2016-03-15 18:34:39 +00:00
|
|
|
return;
|
|
|
|
}
|
2016-03-15 18:34:38 +00:00
|
|
|
close_peer_eventfds(s, posn);
|
|
|
|
}
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
|
2016-03-15 18:34:41 +00:00
|
|
|
static void process_msg_connect(IVShmemState *s, uint16_t posn, int fd,
|
|
|
|
Error **errp)
|
2016-03-15 18:34:38 +00:00
|
|
|
{
|
|
|
|
Peer *peer = &s->peers[posn];
|
|
|
|
int vector;
|
2015-06-19 10:19:55 +00:00
|
|
|
|
2016-03-15 18:34:38 +00:00
|
|
|
/*
|
|
|
|
* The N-th connect message for this peer comes with the file
|
|
|
|
* descriptor for vector N-1. Count messages to find the vector.
|
|
|
|
*/
|
|
|
|
if (peer->nb_eventfds >= s->vectors) {
|
2016-03-15 18:34:41 +00:00
|
|
|
error_setg(errp, "Too many eventfd received, device has %d vectors",
|
|
|
|
s->vectors);
|
2016-03-15 18:34:38 +00:00
|
|
|
close(fd);
|
2015-06-19 10:21:46 +00:00
|
|
|
return;
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
}
|
2016-03-15 18:34:38 +00:00
|
|
|
vector = peer->nb_eventfds++;
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
|
2016-03-15 18:34:38 +00:00
|
|
|
IVSHMEM_DPRINTF("eventfds[%d][%d] = %d\n", posn, vector, fd);
|
|
|
|
event_notifier_init_fd(&peer->eventfds[vector], fd);
|
|
|
|
fcntl_setfl(fd, O_NONBLOCK); /* msix/irqfd poll non block */
|
2015-06-23 10:55:41 +00:00
|
|
|
|
2016-03-15 18:34:38 +00:00
|
|
|
if (posn == s->vm_id) {
|
2016-03-15 18:34:41 +00:00
|
|
|
setup_interrupt(s, vector, errp);
|
|
|
|
/* TODO do we need to handle the error? */
|
2016-03-15 18:34:38 +00:00
|
|
|
}
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
|
2016-03-15 18:34:38 +00:00
|
|
|
if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) {
|
|
|
|
ivshmem_add_eventfd(s, posn, vector);
|
|
|
|
}
|
|
|
|
}
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
|
2016-03-15 18:34:41 +00:00
|
|
|
static void process_msg(IVShmemState *s, int64_t msg, int fd, Error **errp)
|
2016-03-15 18:34:38 +00:00
|
|
|
{
|
|
|
|
IVSHMEM_DPRINTF("posn is %" PRId64 ", fd is %d\n", msg, fd);
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
|
2016-03-15 18:34:38 +00:00
|
|
|
if (msg < -1 || msg > IVSHMEM_MAX_PEERS) {
|
2016-03-15 18:34:41 +00:00
|
|
|
error_setg(errp, "server sent invalid message %" PRId64, msg);
|
2016-03-15 18:34:38 +00:00
|
|
|
close(fd);
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-03-15 18:34:38 +00:00
|
|
|
if (msg == -1) {
|
2016-03-15 18:34:41 +00:00
|
|
|
process_msg_shmem(s, fd, errp);
|
2015-06-23 12:07:11 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-03-15 18:34:38 +00:00
|
|
|
if (msg >= s->nb_peers) {
|
|
|
|
resize_peers(s, msg + 1);
|
|
|
|
}
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
|
2016-03-15 18:34:38 +00:00
|
|
|
if (fd >= 0) {
|
2016-03-15 18:34:41 +00:00
|
|
|
process_msg_connect(s, msg, fd, errp);
|
2016-03-15 18:34:38 +00:00
|
|
|
} else {
|
2016-03-15 18:34:41 +00:00
|
|
|
process_msg_disconnect(s, msg, errp);
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
}
|
2016-03-15 18:34:38 +00:00
|
|
|
}
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
|
2016-03-15 18:34:44 +00:00
|
|
|
static int ivshmem_can_receive(void *opaque)
|
|
|
|
{
|
|
|
|
IVShmemState *s = opaque;
|
|
|
|
|
|
|
|
assert(s->msg_buffered_bytes < sizeof(s->msg_buf));
|
|
|
|
return sizeof(s->msg_buf) - s->msg_buffered_bytes;
|
|
|
|
}
|
|
|
|
|
2016-03-15 18:34:38 +00:00
|
|
|
static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
|
|
|
|
{
|
|
|
|
IVShmemState *s = opaque;
|
2016-03-15 18:34:41 +00:00
|
|
|
Error *err = NULL;
|
2016-03-15 18:34:38 +00:00
|
|
|
int fd;
|
|
|
|
int64_t msg;
|
|
|
|
|
2016-03-15 18:34:44 +00:00
|
|
|
assert(size >= 0 && s->msg_buffered_bytes + size <= sizeof(s->msg_buf));
|
|
|
|
memcpy((unsigned char *)&s->msg_buf + s->msg_buffered_bytes, buf, size);
|
|
|
|
s->msg_buffered_bytes += size;
|
|
|
|
if (s->msg_buffered_bytes < sizeof(s->msg_buf)) {
|
2016-03-15 18:34:38 +00:00
|
|
|
return;
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
}
|
2016-03-15 18:34:44 +00:00
|
|
|
msg = le64_to_cpu(s->msg_buf);
|
|
|
|
s->msg_buffered_bytes = 0;
|
2016-03-15 18:34:38 +00:00
|
|
|
|
|
|
|
fd = qemu_chr_fe_get_msgfd(s->server_chr);
|
|
|
|
IVSHMEM_DPRINTF("posn is %" PRId64 ", fd is %d\n", msg, fd);
|
|
|
|
|
2016-03-15 18:34:41 +00:00
|
|
|
process_msg(s, msg, fd, &err);
|
|
|
|
if (err) {
|
|
|
|
error_report_err(err);
|
|
|
|
}
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
}
|
|
|
|
|
2016-03-15 18:34:41 +00:00
|
|
|
static int64_t ivshmem_recv_msg(IVShmemState *s, int *pfd, Error **errp)
|
2015-06-16 15:43:34 +00:00
|
|
|
{
|
ivshmem: Receive shared memory synchronously in realize()
When configured for interrupts (property "chardev" given), we receive
the shared memory from an ivshmem server. We do so asynchronously
after realize() completes, by setting up callbacks with
qemu_chr_add_handlers().
Keeping server I/O out of realize() that way avoids delays due to a
slow server. This is probably relevant only for hot plug.
However, this funny "no shared memory, yet" state of the device also
causes a raft of issues that are hard or impossible to work around:
* The guest is exposed to this state: when we enter and leave it its
shared memory contents is apruptly replaced, and device register
IVPosition changes.
This is a known issue. We document that guests should not access
the shared memory after device initialization until the IVPosition
register becomes non-negative.
For cold plug, the funny state is unlikely to be visible in
practice, because we normally receive the shared memory long before
the guest gets around to mess with the device.
For hot plug, the timing is tighter, but the relative slowness of
PCI device configuration has a good chance to hide the funny state.
In either case, guests complying with the documented procedure are
safe.
* Migration becomes racy.
If migration completes before the shared memory setup completes on
the source, shared memory contents is silently lost. Fortunately,
migration is rather unlikely to win this race.
If the shared memory's ramblock arrives at the destination before
shared memory setup completes, migration fails.
There is no known way for a management application to wait for
shared memory setup to complete.
All you can do is retry failed migration. You can improve your
chances by leaving more time between running the destination QEMU
and the migrate command.
To mitigate silent memory loss, you need to ensure the server
initializes shared memory exactly the same on source and
destination.
These issues are entirely undocumented so far.
I'd expect the server to be almost always fast enough to hide these
issues. But then rare catastrophic races are in a way the worst kind.
This is way more trouble than I'm willing to take from any device.
Kill the funny state by receiving shared memory synchronously in
realize(). If your hot plug hangs, go kill your ivshmem server.
For easier review, this commit only makes the receive synchronous, it
doesn't add the necessary error propagation. Without that, the funny
state persists. The next commit will do that, and kill it off for
real.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1458066895-20632-26-git-send-email-armbru@redhat.com>
2016-03-15 18:34:40 +00:00
|
|
|
int64_t msg;
|
|
|
|
int n, ret;
|
|
|
|
|
|
|
|
n = 0;
|
|
|
|
do {
|
|
|
|
ret = qemu_chr_fe_read_all(s->server_chr, (uint8_t *)&msg + n,
|
|
|
|
sizeof(msg) - n);
|
|
|
|
if (ret < 0 && ret != -EINTR) {
|
2016-03-15 18:34:41 +00:00
|
|
|
error_setg_errno(errp, -ret, "read from server failed");
|
ivshmem: Receive shared memory synchronously in realize()
When configured for interrupts (property "chardev" given), we receive
the shared memory from an ivshmem server. We do so asynchronously
after realize() completes, by setting up callbacks with
qemu_chr_add_handlers().
Keeping server I/O out of realize() that way avoids delays due to a
slow server. This is probably relevant only for hot plug.
However, this funny "no shared memory, yet" state of the device also
causes a raft of issues that are hard or impossible to work around:
* The guest is exposed to this state: when we enter and leave it its
shared memory contents is apruptly replaced, and device register
IVPosition changes.
This is a known issue. We document that guests should not access
the shared memory after device initialization until the IVPosition
register becomes non-negative.
For cold plug, the funny state is unlikely to be visible in
practice, because we normally receive the shared memory long before
the guest gets around to mess with the device.
For hot plug, the timing is tighter, but the relative slowness of
PCI device configuration has a good chance to hide the funny state.
In either case, guests complying with the documented procedure are
safe.
* Migration becomes racy.
If migration completes before the shared memory setup completes on
the source, shared memory contents is silently lost. Fortunately,
migration is rather unlikely to win this race.
If the shared memory's ramblock arrives at the destination before
shared memory setup completes, migration fails.
There is no known way for a management application to wait for
shared memory setup to complete.
All you can do is retry failed migration. You can improve your
chances by leaving more time between running the destination QEMU
and the migrate command.
To mitigate silent memory loss, you need to ensure the server
initializes shared memory exactly the same on source and
destination.
These issues are entirely undocumented so far.
I'd expect the server to be almost always fast enough to hide these
issues. But then rare catastrophic races are in a way the worst kind.
This is way more trouble than I'm willing to take from any device.
Kill the funny state by receiving shared memory synchronously in
realize(). If your hot plug hangs, go kill your ivshmem server.
For easier review, this commit only makes the receive synchronous, it
doesn't add the necessary error propagation. Without that, the funny
state persists. The next commit will do that, and kill it off for
real.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1458066895-20632-26-git-send-email-armbru@redhat.com>
2016-03-15 18:34:40 +00:00
|
|
|
return INT64_MIN;
|
|
|
|
}
|
|
|
|
n += ret;
|
|
|
|
} while (n < sizeof(msg));
|
2015-06-16 15:43:34 +00:00
|
|
|
|
ivshmem: Receive shared memory synchronously in realize()
When configured for interrupts (property "chardev" given), we receive
the shared memory from an ivshmem server. We do so asynchronously
after realize() completes, by setting up callbacks with
qemu_chr_add_handlers().
Keeping server I/O out of realize() that way avoids delays due to a
slow server. This is probably relevant only for hot plug.
However, this funny "no shared memory, yet" state of the device also
causes a raft of issues that are hard or impossible to work around:
* The guest is exposed to this state: when we enter and leave it its
shared memory contents is apruptly replaced, and device register
IVPosition changes.
This is a known issue. We document that guests should not access
the shared memory after device initialization until the IVPosition
register becomes non-negative.
For cold plug, the funny state is unlikely to be visible in
practice, because we normally receive the shared memory long before
the guest gets around to mess with the device.
For hot plug, the timing is tighter, but the relative slowness of
PCI device configuration has a good chance to hide the funny state.
In either case, guests complying with the documented procedure are
safe.
* Migration becomes racy.
If migration completes before the shared memory setup completes on
the source, shared memory contents is silently lost. Fortunately,
migration is rather unlikely to win this race.
If the shared memory's ramblock arrives at the destination before
shared memory setup completes, migration fails.
There is no known way for a management application to wait for
shared memory setup to complete.
All you can do is retry failed migration. You can improve your
chances by leaving more time between running the destination QEMU
and the migrate command.
To mitigate silent memory loss, you need to ensure the server
initializes shared memory exactly the same on source and
destination.
These issues are entirely undocumented so far.
I'd expect the server to be almost always fast enough to hide these
issues. But then rare catastrophic races are in a way the worst kind.
This is way more trouble than I'm willing to take from any device.
Kill the funny state by receiving shared memory synchronously in
realize(). If your hot plug hangs, go kill your ivshmem server.
For easier review, this commit only makes the receive synchronous, it
doesn't add the necessary error propagation. Without that, the funny
state persists. The next commit will do that, and kill it off for
real.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1458066895-20632-26-git-send-email-armbru@redhat.com>
2016-03-15 18:34:40 +00:00
|
|
|
*pfd = qemu_chr_fe_get_msgfd(s->server_chr);
|
|
|
|
return msg;
|
|
|
|
}
|
2015-06-16 15:43:34 +00:00
|
|
|
|
2016-03-15 18:34:41 +00:00
|
|
|
static void ivshmem_recv_setup(IVShmemState *s, Error **errp)
|
ivshmem: Receive shared memory synchronously in realize()
When configured for interrupts (property "chardev" given), we receive
the shared memory from an ivshmem server. We do so asynchronously
after realize() completes, by setting up callbacks with
qemu_chr_add_handlers().
Keeping server I/O out of realize() that way avoids delays due to a
slow server. This is probably relevant only for hot plug.
However, this funny "no shared memory, yet" state of the device also
causes a raft of issues that are hard or impossible to work around:
* The guest is exposed to this state: when we enter and leave it its
shared memory contents is apruptly replaced, and device register
IVPosition changes.
This is a known issue. We document that guests should not access
the shared memory after device initialization until the IVPosition
register becomes non-negative.
For cold plug, the funny state is unlikely to be visible in
practice, because we normally receive the shared memory long before
the guest gets around to mess with the device.
For hot plug, the timing is tighter, but the relative slowness of
PCI device configuration has a good chance to hide the funny state.
In either case, guests complying with the documented procedure are
safe.
* Migration becomes racy.
If migration completes before the shared memory setup completes on
the source, shared memory contents is silently lost. Fortunately,
migration is rather unlikely to win this race.
If the shared memory's ramblock arrives at the destination before
shared memory setup completes, migration fails.
There is no known way for a management application to wait for
shared memory setup to complete.
All you can do is retry failed migration. You can improve your
chances by leaving more time between running the destination QEMU
and the migrate command.
To mitigate silent memory loss, you need to ensure the server
initializes shared memory exactly the same on source and
destination.
These issues are entirely undocumented so far.
I'd expect the server to be almost always fast enough to hide these
issues. But then rare catastrophic races are in a way the worst kind.
This is way more trouble than I'm willing to take from any device.
Kill the funny state by receiving shared memory synchronously in
realize(). If your hot plug hangs, go kill your ivshmem server.
For easier review, this commit only makes the receive synchronous, it
doesn't add the necessary error propagation. Without that, the funny
state persists. The next commit will do that, and kill it off for
real.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1458066895-20632-26-git-send-email-armbru@redhat.com>
2016-03-15 18:34:40 +00:00
|
|
|
{
|
2016-03-15 18:34:41 +00:00
|
|
|
Error *err = NULL;
|
ivshmem: Receive shared memory synchronously in realize()
When configured for interrupts (property "chardev" given), we receive
the shared memory from an ivshmem server. We do so asynchronously
after realize() completes, by setting up callbacks with
qemu_chr_add_handlers().
Keeping server I/O out of realize() that way avoids delays due to a
slow server. This is probably relevant only for hot plug.
However, this funny "no shared memory, yet" state of the device also
causes a raft of issues that are hard or impossible to work around:
* The guest is exposed to this state: when we enter and leave it its
shared memory contents is apruptly replaced, and device register
IVPosition changes.
This is a known issue. We document that guests should not access
the shared memory after device initialization until the IVPosition
register becomes non-negative.
For cold plug, the funny state is unlikely to be visible in
practice, because we normally receive the shared memory long before
the guest gets around to mess with the device.
For hot plug, the timing is tighter, but the relative slowness of
PCI device configuration has a good chance to hide the funny state.
In either case, guests complying with the documented procedure are
safe.
* Migration becomes racy.
If migration completes before the shared memory setup completes on
the source, shared memory contents is silently lost. Fortunately,
migration is rather unlikely to win this race.
If the shared memory's ramblock arrives at the destination before
shared memory setup completes, migration fails.
There is no known way for a management application to wait for
shared memory setup to complete.
All you can do is retry failed migration. You can improve your
chances by leaving more time between running the destination QEMU
and the migrate command.
To mitigate silent memory loss, you need to ensure the server
initializes shared memory exactly the same on source and
destination.
These issues are entirely undocumented so far.
I'd expect the server to be almost always fast enough to hide these
issues. But then rare catastrophic races are in a way the worst kind.
This is way more trouble than I'm willing to take from any device.
Kill the funny state by receiving shared memory synchronously in
realize(). If your hot plug hangs, go kill your ivshmem server.
For easier review, this commit only makes the receive synchronous, it
doesn't add the necessary error propagation. Without that, the funny
state persists. The next commit will do that, and kill it off for
real.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1458066895-20632-26-git-send-email-armbru@redhat.com>
2016-03-15 18:34:40 +00:00
|
|
|
int64_t msg;
|
|
|
|
int fd;
|
|
|
|
|
2016-03-15 18:34:41 +00:00
|
|
|
msg = ivshmem_recv_msg(s, &fd, &err);
|
|
|
|
if (err) {
|
|
|
|
error_propagate(errp, err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (msg != IVSHMEM_PROTOCOL_VERSION) {
|
|
|
|
error_setg(errp, "server sent version %" PRId64 ", expecting %d",
|
|
|
|
msg, IVSHMEM_PROTOCOL_VERSION);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (fd != -1) {
|
|
|
|
error_setg(errp, "server sent invalid version message");
|
2015-06-16 15:43:34 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-03-15 18:34:42 +00:00
|
|
|
/*
|
|
|
|
* ivshmem-server sends the remaining initial messages in a fixed
|
|
|
|
* order, but the device has always accepted them in any order.
|
|
|
|
* Stay as compatible as practical, just in case people use
|
|
|
|
* servers that behave differently.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ivshmem_device_spec.txt has always required the ID message
|
|
|
|
* right here, and ivshmem-server has always complied. However,
|
|
|
|
* older versions of the device accepted it out of order, but
|
|
|
|
* broke when an interrupt setup message arrived before it.
|
|
|
|
*/
|
|
|
|
msg = ivshmem_recv_msg(s, &fd, &err);
|
|
|
|
if (err) {
|
|
|
|
error_propagate(errp, err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (fd != -1 || msg < 0 || msg > IVSHMEM_MAX_PEERS) {
|
|
|
|
error_setg(errp, "server sent invalid ID message");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
s->vm_id = msg;
|
|
|
|
|
ivshmem: Receive shared memory synchronously in realize()
When configured for interrupts (property "chardev" given), we receive
the shared memory from an ivshmem server. We do so asynchronously
after realize() completes, by setting up callbacks with
qemu_chr_add_handlers().
Keeping server I/O out of realize() that way avoids delays due to a
slow server. This is probably relevant only for hot plug.
However, this funny "no shared memory, yet" state of the device also
causes a raft of issues that are hard or impossible to work around:
* The guest is exposed to this state: when we enter and leave it its
shared memory contents is apruptly replaced, and device register
IVPosition changes.
This is a known issue. We document that guests should not access
the shared memory after device initialization until the IVPosition
register becomes non-negative.
For cold plug, the funny state is unlikely to be visible in
practice, because we normally receive the shared memory long before
the guest gets around to mess with the device.
For hot plug, the timing is tighter, but the relative slowness of
PCI device configuration has a good chance to hide the funny state.
In either case, guests complying with the documented procedure are
safe.
* Migration becomes racy.
If migration completes before the shared memory setup completes on
the source, shared memory contents is silently lost. Fortunately,
migration is rather unlikely to win this race.
If the shared memory's ramblock arrives at the destination before
shared memory setup completes, migration fails.
There is no known way for a management application to wait for
shared memory setup to complete.
All you can do is retry failed migration. You can improve your
chances by leaving more time between running the destination QEMU
and the migrate command.
To mitigate silent memory loss, you need to ensure the server
initializes shared memory exactly the same on source and
destination.
These issues are entirely undocumented so far.
I'd expect the server to be almost always fast enough to hide these
issues. But then rare catastrophic races are in a way the worst kind.
This is way more trouble than I'm willing to take from any device.
Kill the funny state by receiving shared memory synchronously in
realize(). If your hot plug hangs, go kill your ivshmem server.
For easier review, this commit only makes the receive synchronous, it
doesn't add the necessary error propagation. Without that, the funny
state persists. The next commit will do that, and kill it off for
real.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1458066895-20632-26-git-send-email-armbru@redhat.com>
2016-03-15 18:34:40 +00:00
|
|
|
/*
|
|
|
|
* Receive more messages until we got shared memory.
|
|
|
|
*/
|
|
|
|
do {
|
2016-03-15 18:34:41 +00:00
|
|
|
msg = ivshmem_recv_msg(s, &fd, &err);
|
|
|
|
if (err) {
|
|
|
|
error_propagate(errp, err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
process_msg(s, msg, fd, &err);
|
|
|
|
if (err) {
|
|
|
|
error_propagate(errp, err);
|
|
|
|
return;
|
|
|
|
}
|
ivshmem: Receive shared memory synchronously in realize()
When configured for interrupts (property "chardev" given), we receive
the shared memory from an ivshmem server. We do so asynchronously
after realize() completes, by setting up callbacks with
qemu_chr_add_handlers().
Keeping server I/O out of realize() that way avoids delays due to a
slow server. This is probably relevant only for hot plug.
However, this funny "no shared memory, yet" state of the device also
causes a raft of issues that are hard or impossible to work around:
* The guest is exposed to this state: when we enter and leave it its
shared memory contents is apruptly replaced, and device register
IVPosition changes.
This is a known issue. We document that guests should not access
the shared memory after device initialization until the IVPosition
register becomes non-negative.
For cold plug, the funny state is unlikely to be visible in
practice, because we normally receive the shared memory long before
the guest gets around to mess with the device.
For hot plug, the timing is tighter, but the relative slowness of
PCI device configuration has a good chance to hide the funny state.
In either case, guests complying with the documented procedure are
safe.
* Migration becomes racy.
If migration completes before the shared memory setup completes on
the source, shared memory contents is silently lost. Fortunately,
migration is rather unlikely to win this race.
If the shared memory's ramblock arrives at the destination before
shared memory setup completes, migration fails.
There is no known way for a management application to wait for
shared memory setup to complete.
All you can do is retry failed migration. You can improve your
chances by leaving more time between running the destination QEMU
and the migrate command.
To mitigate silent memory loss, you need to ensure the server
initializes shared memory exactly the same on source and
destination.
These issues are entirely undocumented so far.
I'd expect the server to be almost always fast enough to hide these
issues. But then rare catastrophic races are in a way the worst kind.
This is way more trouble than I'm willing to take from any device.
Kill the funny state by receiving shared memory synchronously in
realize(). If your hot plug hangs, go kill your ivshmem server.
For easier review, this commit only makes the receive synchronous, it
doesn't add the necessary error propagation. Without that, the funny
state persists. The next commit will do that, and kill it off for
real.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1458066895-20632-26-git-send-email-armbru@redhat.com>
2016-03-15 18:34:40 +00:00
|
|
|
} while (msg != -1);
|
2016-03-15 18:34:41 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* This function must either map the shared memory or fail. The
|
|
|
|
* loop above ensures that: it terminates normally only after it
|
|
|
|
* successfully processed the server's shared memory message.
|
|
|
|
* Assert that actually mapped the shared memory:
|
|
|
|
*/
|
2016-03-15 18:34:47 +00:00
|
|
|
assert(s->ivshmem_bar2);
|
2015-06-16 15:43:34 +00:00
|
|
|
}
|
|
|
|
|
2011-12-05 19:48:43 +00:00
|
|
|
/* Select the MSI-X vectors used by device.
|
|
|
|
* ivshmem maps events to vectors statically, so
|
|
|
|
* we just enable all vectors on init and after reset. */
|
ivshmem: Clean up MSI-X conditions
There are three predicates related to MSI-X:
* ivshmem_has_feature(s, IVSHMEM_MSI) is true unless the non-MSI-X
variant of the device is selected with msi=off.
* msix_present() is true when the device has the PCI capability MSI-X.
It's initially false, and becomes true during successful realize of
the MSI-X variant of the device. Thus, it's the same as
ivshmem_has_feature(s, IVSHMEM_MSI) for realized devices.
* msix_enabled() is true when msix_present() is true and guest software
has enabled MSI-X.
Code that differs between the non-MSI-X and the MSI-X variant of the
device needs to be guarded by ivshmem_has_feature(s, IVSHMEM_MSI) or
by msix_present(), except the latter works only for realized devices.
Code that depends on whether MSI-X is in use needs to be guarded with
msix_enabled().
Code review led me to two minor messes:
* ivshmem_vector_notify() calls msix_notify() even when
!msix_enabled(), unlike most other MSI-X-capable devices. As far as
I can tell, msix_notify() does nothing when !msix_enabled(). Add
the guard anyway.
* Most callers of ivshmem_use_msix() guard it with
ivshmem_has_feature(s, IVSHMEM_MSI). Not necessary, because
ivshmem_use_msix() does nothing when !msix_present(). That's
ivshmem's only use of msix_present(), though. Guard it
consistently, and drop the now redundant msix_present() check.
While there, rename ivshmem_use_msix() to ivshmem_msix_vector_use().
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <1458066895-20632-20-git-send-email-armbru@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
2016-03-15 18:34:34 +00:00
|
|
|
static void ivshmem_msix_vector_use(IVShmemState *s)
|
2011-12-05 19:48:43 +00:00
|
|
|
{
|
2013-06-30 13:15:15 +00:00
|
|
|
PCIDevice *d = PCI_DEVICE(s);
|
2011-12-05 19:48:43 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < s->vectors; i++) {
|
2013-06-30 13:15:15 +00:00
|
|
|
msix_vector_use(d, i);
|
2011-12-05 19:48:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
static void ivshmem_reset(DeviceState *d)
|
|
|
|
{
|
2016-03-15 18:34:51 +00:00
|
|
|
IVShmemState *s = IVSHMEM_COMMON(d);
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
|
|
|
|
s->intrstatus = 0;
|
2015-06-23 12:13:08 +00:00
|
|
|
s->intrmask = 0;
|
ivshmem: Clean up MSI-X conditions
There are three predicates related to MSI-X:
* ivshmem_has_feature(s, IVSHMEM_MSI) is true unless the non-MSI-X
variant of the device is selected with msi=off.
* msix_present() is true when the device has the PCI capability MSI-X.
It's initially false, and becomes true during successful realize of
the MSI-X variant of the device. Thus, it's the same as
ivshmem_has_feature(s, IVSHMEM_MSI) for realized devices.
* msix_enabled() is true when msix_present() is true and guest software
has enabled MSI-X.
Code that differs between the non-MSI-X and the MSI-X variant of the
device needs to be guarded by ivshmem_has_feature(s, IVSHMEM_MSI) or
by msix_present(), except the latter works only for realized devices.
Code that depends on whether MSI-X is in use needs to be guarded with
msix_enabled().
Code review led me to two minor messes:
* ivshmem_vector_notify() calls msix_notify() even when
!msix_enabled(), unlike most other MSI-X-capable devices. As far as
I can tell, msix_notify() does nothing when !msix_enabled(). Add
the guard anyway.
* Most callers of ivshmem_use_msix() guard it with
ivshmem_has_feature(s, IVSHMEM_MSI). Not necessary, because
ivshmem_use_msix() does nothing when !msix_present(). That's
ivshmem's only use of msix_present(), though. Guard it
consistently, and drop the now redundant msix_present() check.
While there, rename ivshmem_use_msix() to ivshmem_msix_vector_use().
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <1458066895-20632-20-git-send-email-armbru@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
2016-03-15 18:34:34 +00:00
|
|
|
if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
|
|
|
|
ivshmem_msix_vector_use(s);
|
|
|
|
}
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
}
|
|
|
|
|
2015-12-21 11:08:54 +00:00
|
|
|
static int ivshmem_setup_interrupts(IVShmemState *s)
|
2011-12-05 19:48:43 +00:00
|
|
|
{
|
2015-12-21 11:08:54 +00:00
|
|
|
/* allocate QEMU callback data for receiving interrupts */
|
|
|
|
s->msi_vectors = g_malloc0(s->vectors * sizeof(MSIVector));
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
|
2015-12-21 11:08:54 +00:00
|
|
|
if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
|
|
|
|
if (msix_init_exclusive_bar(PCI_DEVICE(s), s->vectors, 1)) {
|
|
|
|
return -1;
|
|
|
|
}
|
2012-06-14 18:16:01 +00:00
|
|
|
|
2015-12-21 11:08:54 +00:00
|
|
|
IVSHMEM_DPRINTF("msix initialized (%d vectors)\n", s->vectors);
|
ivshmem: Clean up MSI-X conditions
There are three predicates related to MSI-X:
* ivshmem_has_feature(s, IVSHMEM_MSI) is true unless the non-MSI-X
variant of the device is selected with msi=off.
* msix_present() is true when the device has the PCI capability MSI-X.
It's initially false, and becomes true during successful realize of
the MSI-X variant of the device. Thus, it's the same as
ivshmem_has_feature(s, IVSHMEM_MSI) for realized devices.
* msix_enabled() is true when msix_present() is true and guest software
has enabled MSI-X.
Code that differs between the non-MSI-X and the MSI-X variant of the
device needs to be guarded by ivshmem_has_feature(s, IVSHMEM_MSI) or
by msix_present(), except the latter works only for realized devices.
Code that depends on whether MSI-X is in use needs to be guarded with
msix_enabled().
Code review led me to two minor messes:
* ivshmem_vector_notify() calls msix_notify() even when
!msix_enabled(), unlike most other MSI-X-capable devices. As far as
I can tell, msix_notify() does nothing when !msix_enabled(). Add
the guard anyway.
* Most callers of ivshmem_use_msix() guard it with
ivshmem_has_feature(s, IVSHMEM_MSI). Not necessary, because
ivshmem_use_msix() does nothing when !msix_present(). That's
ivshmem's only use of msix_present(), though. Guard it
consistently, and drop the now redundant msix_present() check.
While there, rename ivshmem_use_msix() to ivshmem_msix_vector_use().
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <1458066895-20632-20-git-send-email-armbru@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
2016-03-15 18:34:34 +00:00
|
|
|
ivshmem_msix_vector_use(s);
|
2015-12-21 11:08:54 +00:00
|
|
|
}
|
2011-12-05 19:48:43 +00:00
|
|
|
|
2015-06-18 12:59:28 +00:00
|
|
|
return 0;
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
}
|
|
|
|
|
2015-07-09 13:50:13 +00:00
|
|
|
static void ivshmem_enable_irqfd(IVShmemState *s)
|
|
|
|
{
|
|
|
|
PCIDevice *pdev = PCI_DEVICE(s);
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < s->peers[s->vm_id].nb_eventfds; i++) {
|
2016-03-15 18:34:41 +00:00
|
|
|
Error *err = NULL;
|
|
|
|
|
|
|
|
ivshmem_add_kvm_msi_virq(s, i, &err);
|
|
|
|
if (err) {
|
|
|
|
error_report_err(err);
|
|
|
|
/* TODO do we need to handle the error? */
|
|
|
|
}
|
2015-07-09 13:50:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (msix_set_vector_notifiers(pdev,
|
|
|
|
ivshmem_vector_unmask,
|
|
|
|
ivshmem_vector_mask,
|
|
|
|
ivshmem_vector_poll)) {
|
|
|
|
error_report("ivshmem: msix_set_vector_notifiers failed");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ivshmem_remove_kvm_msi_virq(IVShmemState *s, int vector)
|
|
|
|
{
|
|
|
|
IVSHMEM_DPRINTF("ivshmem_remove_kvm_msi_virq vector:%d\n", vector);
|
|
|
|
|
|
|
|
if (s->msi_vectors[vector].pdev == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* it was cleaned when masked in the frontend. */
|
|
|
|
kvm_irqchip_release_virq(kvm_state, s->msi_vectors[vector].virq);
|
|
|
|
|
|
|
|
s->msi_vectors[vector].pdev = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ivshmem_disable_irqfd(IVShmemState *s)
|
|
|
|
{
|
|
|
|
PCIDevice *pdev = PCI_DEVICE(s);
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < s->peers[s->vm_id].nb_eventfds; i++) {
|
|
|
|
ivshmem_remove_kvm_msi_virq(s, i);
|
|
|
|
}
|
|
|
|
|
|
|
|
msix_unset_vector_notifiers(pdev);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ivshmem_write_config(PCIDevice *pdev, uint32_t address,
|
2015-06-18 12:59:28 +00:00
|
|
|
uint32_t val, int len)
|
2011-12-05 19:48:43 +00:00
|
|
|
{
|
2016-03-15 18:34:51 +00:00
|
|
|
IVShmemState *s = IVSHMEM_COMMON(pdev);
|
2015-07-09 13:50:13 +00:00
|
|
|
int is_enabled, was_enabled = msix_enabled(pdev);
|
|
|
|
|
|
|
|
pci_default_write_config(pdev, address, val, len);
|
|
|
|
is_enabled = msix_enabled(pdev);
|
|
|
|
|
2016-03-15 18:34:41 +00:00
|
|
|
if (kvm_msi_via_irqfd_enabled()) {
|
2015-07-09 13:50:13 +00:00
|
|
|
if (!was_enabled && is_enabled) {
|
|
|
|
ivshmem_enable_irqfd(s);
|
|
|
|
} else if (was_enabled && !is_enabled) {
|
|
|
|
ivshmem_disable_irqfd(s);
|
|
|
|
}
|
|
|
|
}
|
2011-12-05 19:48:43 +00:00
|
|
|
}
|
|
|
|
|
2016-03-15 18:34:51 +00:00
|
|
|
static void ivshmem_common_realize(PCIDevice *dev, Error **errp)
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
{
|
2016-03-15 18:34:51 +00:00
|
|
|
IVShmemState *s = IVSHMEM_COMMON(dev);
|
2016-03-15 18:34:32 +00:00
|
|
|
Error *err = NULL;
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
uint8_t *pci_conf;
|
2015-06-18 14:24:33 +00:00
|
|
|
uint8_t attr = PCI_BASE_ADDRESS_SPACE_MEMORY |
|
|
|
|
PCI_BASE_ADDRESS_MEM_PREFETCH;
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
|
|
|
|
/* IRQFD requires MSI */
|
|
|
|
if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD) &&
|
|
|
|
!ivshmem_has_feature(s, IVSHMEM_MSI)) {
|
2015-06-18 12:59:28 +00:00
|
|
|
error_setg(errp, "ioeventfd/irqfd requires MSI");
|
|
|
|
return;
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
}
|
|
|
|
|
2013-06-30 13:15:15 +00:00
|
|
|
pci_conf = dev->config;
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
pci_conf[PCI_COMMAND] = PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
|
|
|
|
|
2013-06-07 01:25:08 +00:00
|
|
|
memory_region_init_io(&s->ivshmem_mmio, OBJECT(s), &ivshmem_mmio_ops, s,
|
2011-08-08 13:09:12 +00:00
|
|
|
"ivshmem-mmio", IVSHMEM_REG_BAR_SIZE);
|
|
|
|
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
/* region for registers*/
|
2013-06-30 13:15:15 +00:00
|
|
|
pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY,
|
2011-08-08 13:09:31 +00:00
|
|
|
&s->ivshmem_mmio);
|
2011-08-08 13:09:12 +00:00
|
|
|
|
2016-03-15 18:34:51 +00:00
|
|
|
if (!s->not_legacy_32bit) {
|
2015-06-18 14:24:33 +00:00
|
|
|
attr |= PCI_BASE_ADDRESS_MEM_TYPE_64;
|
2012-09-13 09:08:02 +00:00
|
|
|
}
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
|
2015-06-29 22:10:16 +00:00
|
|
|
if (s->hostmem != NULL) {
|
|
|
|
IVSHMEM_DPRINTF("using hostmem\n");
|
|
|
|
|
2016-03-15 18:34:47 +00:00
|
|
|
s->ivshmem_bar2 = host_memory_backend_get_memory(s->hostmem,
|
|
|
|
&error_abort);
|
2016-03-15 18:34:46 +00:00
|
|
|
} else {
|
2016-04-12 13:33:10 +00:00
|
|
|
assert(s->server_chr);
|
|
|
|
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
IVSHMEM_DPRINTF("using shared memory server (socket = %s)\n",
|
2014-10-07 11:24:02 +00:00
|
|
|
s->server_chr->filename);
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
|
2015-06-23 11:38:46 +00:00
|
|
|
/* we allocate enough space for 16 peers and grow as needed */
|
2015-09-15 15:21:37 +00:00
|
|
|
resize_peers(s, 16);
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
|
ivshmem: Receive shared memory synchronously in realize()
When configured for interrupts (property "chardev" given), we receive
the shared memory from an ivshmem server. We do so asynchronously
after realize() completes, by setting up callbacks with
qemu_chr_add_handlers().
Keeping server I/O out of realize() that way avoids delays due to a
slow server. This is probably relevant only for hot plug.
However, this funny "no shared memory, yet" state of the device also
causes a raft of issues that are hard or impossible to work around:
* The guest is exposed to this state: when we enter and leave it its
shared memory contents is apruptly replaced, and device register
IVPosition changes.
This is a known issue. We document that guests should not access
the shared memory after device initialization until the IVPosition
register becomes non-negative.
For cold plug, the funny state is unlikely to be visible in
practice, because we normally receive the shared memory long before
the guest gets around to mess with the device.
For hot plug, the timing is tighter, but the relative slowness of
PCI device configuration has a good chance to hide the funny state.
In either case, guests complying with the documented procedure are
safe.
* Migration becomes racy.
If migration completes before the shared memory setup completes on
the source, shared memory contents is silently lost. Fortunately,
migration is rather unlikely to win this race.
If the shared memory's ramblock arrives at the destination before
shared memory setup completes, migration fails.
There is no known way for a management application to wait for
shared memory setup to complete.
All you can do is retry failed migration. You can improve your
chances by leaving more time between running the destination QEMU
and the migrate command.
To mitigate silent memory loss, you need to ensure the server
initializes shared memory exactly the same on source and
destination.
These issues are entirely undocumented so far.
I'd expect the server to be almost always fast enough to hide these
issues. But then rare catastrophic races are in a way the worst kind.
This is way more trouble than I'm willing to take from any device.
Kill the funny state by receiving shared memory synchronously in
realize(). If your hot plug hangs, go kill your ivshmem server.
For easier review, this commit only makes the receive synchronous, it
doesn't add the necessary error propagation. Without that, the funny
state persists. The next commit will do that, and kill it off for
real.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1458066895-20632-26-git-send-email-armbru@redhat.com>
2016-03-15 18:34:40 +00:00
|
|
|
/*
|
|
|
|
* Receive setup messages from server synchronously.
|
|
|
|
* Older versions did it asynchronously, but that creates a
|
|
|
|
* number of entertaining race conditions.
|
|
|
|
*/
|
2016-03-15 18:34:41 +00:00
|
|
|
ivshmem_recv_setup(s, &err);
|
|
|
|
if (err) {
|
|
|
|
error_propagate(errp, err);
|
|
|
|
return;
|
ivshmem: Receive shared memory synchronously in realize()
When configured for interrupts (property "chardev" given), we receive
the shared memory from an ivshmem server. We do so asynchronously
after realize() completes, by setting up callbacks with
qemu_chr_add_handlers().
Keeping server I/O out of realize() that way avoids delays due to a
slow server. This is probably relevant only for hot plug.
However, this funny "no shared memory, yet" state of the device also
causes a raft of issues that are hard or impossible to work around:
* The guest is exposed to this state: when we enter and leave it its
shared memory contents is apruptly replaced, and device register
IVPosition changes.
This is a known issue. We document that guests should not access
the shared memory after device initialization until the IVPosition
register becomes non-negative.
For cold plug, the funny state is unlikely to be visible in
practice, because we normally receive the shared memory long before
the guest gets around to mess with the device.
For hot plug, the timing is tighter, but the relative slowness of
PCI device configuration has a good chance to hide the funny state.
In either case, guests complying with the documented procedure are
safe.
* Migration becomes racy.
If migration completes before the shared memory setup completes on
the source, shared memory contents is silently lost. Fortunately,
migration is rather unlikely to win this race.
If the shared memory's ramblock arrives at the destination before
shared memory setup completes, migration fails.
There is no known way for a management application to wait for
shared memory setup to complete.
All you can do is retry failed migration. You can improve your
chances by leaving more time between running the destination QEMU
and the migrate command.
To mitigate silent memory loss, you need to ensure the server
initializes shared memory exactly the same on source and
destination.
These issues are entirely undocumented so far.
I'd expect the server to be almost always fast enough to hide these
issues. But then rare catastrophic races are in a way the worst kind.
This is way more trouble than I'm willing to take from any device.
Kill the funny state by receiving shared memory synchronously in
realize(). If your hot plug hangs, go kill your ivshmem server.
For easier review, this commit only makes the receive synchronous, it
doesn't add the necessary error propagation. Without that, the funny
state persists. The next commit will do that, and kill it off for
real.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1458066895-20632-26-git-send-email-armbru@redhat.com>
2016-03-15 18:34:40 +00:00
|
|
|
}
|
|
|
|
|
2016-03-15 18:34:54 +00:00
|
|
|
if (s->master == ON_OFF_AUTO_ON && s->vm_id != 0) {
|
|
|
|
error_setg(errp,
|
|
|
|
"master must connect to the server before any peers");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-03-15 18:34:41 +00:00
|
|
|
qemu_chr_add_handlers(s->server_chr, ivshmem_can_receive,
|
|
|
|
ivshmem_read, NULL, s);
|
|
|
|
|
ivshmem: Receive shared memory synchronously in realize()
When configured for interrupts (property "chardev" given), we receive
the shared memory from an ivshmem server. We do so asynchronously
after realize() completes, by setting up callbacks with
qemu_chr_add_handlers().
Keeping server I/O out of realize() that way avoids delays due to a
slow server. This is probably relevant only for hot plug.
However, this funny "no shared memory, yet" state of the device also
causes a raft of issues that are hard or impossible to work around:
* The guest is exposed to this state: when we enter and leave it its
shared memory contents is apruptly replaced, and device register
IVPosition changes.
This is a known issue. We document that guests should not access
the shared memory after device initialization until the IVPosition
register becomes non-negative.
For cold plug, the funny state is unlikely to be visible in
practice, because we normally receive the shared memory long before
the guest gets around to mess with the device.
For hot plug, the timing is tighter, but the relative slowness of
PCI device configuration has a good chance to hide the funny state.
In either case, guests complying with the documented procedure are
safe.
* Migration becomes racy.
If migration completes before the shared memory setup completes on
the source, shared memory contents is silently lost. Fortunately,
migration is rather unlikely to win this race.
If the shared memory's ramblock arrives at the destination before
shared memory setup completes, migration fails.
There is no known way for a management application to wait for
shared memory setup to complete.
All you can do is retry failed migration. You can improve your
chances by leaving more time between running the destination QEMU
and the migrate command.
To mitigate silent memory loss, you need to ensure the server
initializes shared memory exactly the same on source and
destination.
These issues are entirely undocumented so far.
I'd expect the server to be almost always fast enough to hide these
issues. But then rare catastrophic races are in a way the worst kind.
This is way more trouble than I'm willing to take from any device.
Kill the funny state by receiving shared memory synchronously in
realize(). If your hot plug hangs, go kill your ivshmem server.
For easier review, this commit only makes the receive synchronous, it
doesn't add the necessary error propagation. Without that, the funny
state persists. The next commit will do that, and kill it off for
real.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1458066895-20632-26-git-send-email-armbru@redhat.com>
2016-03-15 18:34:40 +00:00
|
|
|
if (ivshmem_setup_interrupts(s) < 0) {
|
|
|
|
error_setg(errp, "failed to initialize interrupts");
|
|
|
|
return;
|
|
|
|
}
|
2016-03-15 18:34:32 +00:00
|
|
|
}
|
|
|
|
|
2016-03-15 18:34:47 +00:00
|
|
|
vmstate_register_ram(s->ivshmem_bar2, DEVICE(s));
|
|
|
|
pci_register_bar(PCI_DEVICE(s), 2, attr, s->ivshmem_bar2);
|
|
|
|
|
2016-03-15 18:34:50 +00:00
|
|
|
if (s->master == ON_OFF_AUTO_AUTO) {
|
|
|
|
s->master = s->vm_id == 0 ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ivshmem_is_master(s)) {
|
2016-03-15 18:34:32 +00:00
|
|
|
error_setg(&s->migration_blocker,
|
|
|
|
"Migration is disabled when using feature 'peer mode' in device 'ivshmem'");
|
|
|
|
migrate_add_blocker(s->migration_blocker);
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-15 18:34:51 +00:00
|
|
|
static void ivshmem_exit(PCIDevice *dev)
|
|
|
|
{
|
|
|
|
IVShmemState *s = IVSHMEM_COMMON(dev);
|
2015-06-23 10:57:16 +00:00
|
|
|
int i;
|
|
|
|
|
2011-11-14 21:09:44 +00:00
|
|
|
if (s->migration_blocker) {
|
|
|
|
migrate_del_blocker(s->migration_blocker);
|
|
|
|
error_free(s->migration_blocker);
|
|
|
|
}
|
|
|
|
|
2016-03-15 18:34:47 +00:00
|
|
|
if (memory_region_is_mapped(s->ivshmem_bar2)) {
|
2015-06-29 22:10:16 +00:00
|
|
|
if (!s->hostmem) {
|
2016-03-15 18:34:47 +00:00
|
|
|
void *addr = memory_region_get_ram_ptr(s->ivshmem_bar2);
|
2015-12-21 03:47:34 +00:00
|
|
|
int fd;
|
2015-06-29 22:10:16 +00:00
|
|
|
|
2016-03-15 18:34:51 +00:00
|
|
|
if (munmap(addr, memory_region_size(s->ivshmem_bar2) == -1)) {
|
2015-06-29 22:10:16 +00:00
|
|
|
error_report("Failed to munmap shared memory %s",
|
|
|
|
strerror(errno));
|
|
|
|
}
|
2015-12-21 03:47:34 +00:00
|
|
|
|
2016-03-25 11:30:16 +00:00
|
|
|
fd = memory_region_get_fd(s->ivshmem_bar2);
|
2016-03-15 18:34:47 +00:00
|
|
|
close(fd);
|
2015-06-29 22:10:16 +00:00
|
|
|
}
|
2015-06-23 10:57:16 +00:00
|
|
|
|
2016-03-15 18:34:47 +00:00
|
|
|
vmstate_unregister_ram(s->ivshmem_bar2, DEVICE(dev));
|
2015-06-23 10:57:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (s->peers) {
|
|
|
|
for (i = 0; i < s->nb_peers; i++) {
|
2015-06-23 11:38:46 +00:00
|
|
|
close_peer_eventfds(s, i);
|
2015-06-23 10:57:16 +00:00
|
|
|
}
|
|
|
|
g_free(s->peers);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
|
|
|
|
msix_uninit_exclusive_bar(dev);
|
|
|
|
}
|
|
|
|
|
2015-07-27 10:59:19 +00:00
|
|
|
g_free(s->msi_vectors);
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
}
|
|
|
|
|
2015-06-18 12:05:46 +00:00
|
|
|
static int ivshmem_pre_load(void *opaque)
|
|
|
|
{
|
|
|
|
IVShmemState *s = opaque;
|
|
|
|
|
2016-03-15 18:34:50 +00:00
|
|
|
if (!ivshmem_is_master(s)) {
|
2015-06-18 12:05:46 +00:00
|
|
|
error_report("'peer' devices are not migratable");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ivshmem_post_load(void *opaque, int version_id)
|
|
|
|
{
|
|
|
|
IVShmemState *s = opaque;
|
|
|
|
|
|
|
|
if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
|
ivshmem: Clean up MSI-X conditions
There are three predicates related to MSI-X:
* ivshmem_has_feature(s, IVSHMEM_MSI) is true unless the non-MSI-X
variant of the device is selected with msi=off.
* msix_present() is true when the device has the PCI capability MSI-X.
It's initially false, and becomes true during successful realize of
the MSI-X variant of the device. Thus, it's the same as
ivshmem_has_feature(s, IVSHMEM_MSI) for realized devices.
* msix_enabled() is true when msix_present() is true and guest software
has enabled MSI-X.
Code that differs between the non-MSI-X and the MSI-X variant of the
device needs to be guarded by ivshmem_has_feature(s, IVSHMEM_MSI) or
by msix_present(), except the latter works only for realized devices.
Code that depends on whether MSI-X is in use needs to be guarded with
msix_enabled().
Code review led me to two minor messes:
* ivshmem_vector_notify() calls msix_notify() even when
!msix_enabled(), unlike most other MSI-X-capable devices. As far as
I can tell, msix_notify() does nothing when !msix_enabled(). Add
the guard anyway.
* Most callers of ivshmem_use_msix() guard it with
ivshmem_has_feature(s, IVSHMEM_MSI). Not necessary, because
ivshmem_use_msix() does nothing when !msix_present(). That's
ivshmem's only use of msix_present(), though. Guard it
consistently, and drop the now redundant msix_present() check.
While there, rename ivshmem_use_msix() to ivshmem_msix_vector_use().
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <1458066895-20632-20-git-send-email-armbru@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
2016-03-15 18:34:34 +00:00
|
|
|
ivshmem_msix_vector_use(s);
|
2015-06-18 12:05:46 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-03-15 18:34:51 +00:00
|
|
|
static void ivshmem_common_class_init(ObjectClass *klass, void *data)
|
2011-12-04 18:22:06 +00:00
|
|
|
{
|
2011-12-08 03:34:16 +00:00
|
|
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
2011-12-04 18:22:06 +00:00
|
|
|
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
|
|
|
|
|
2016-03-15 18:34:51 +00:00
|
|
|
k->realize = ivshmem_common_realize;
|
|
|
|
k->exit = ivshmem_exit;
|
2015-06-18 12:59:28 +00:00
|
|
|
k->config_write = ivshmem_write_config;
|
2012-12-13 09:19:37 +00:00
|
|
|
k->vendor_id = PCI_VENDOR_ID_IVSHMEM;
|
|
|
|
k->device_id = PCI_DEVICE_ID_IVSHMEM;
|
2011-12-04 18:22:06 +00:00
|
|
|
k->class_id = PCI_CLASS_MEMORY_RAM;
|
2016-03-15 18:34:51 +00:00
|
|
|
k->revision = 1;
|
2011-12-08 03:34:16 +00:00
|
|
|
dc->reset = ivshmem_reset;
|
2013-07-29 14:17:45 +00:00
|
|
|
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
|
2015-06-23 11:01:40 +00:00
|
|
|
dc->desc = "Inter-VM shared memory";
|
2011-12-04 18:22:06 +00:00
|
|
|
}
|
|
|
|
|
2016-03-15 18:34:52 +00:00
|
|
|
static const TypeInfo ivshmem_common_info = {
|
|
|
|
.name = TYPE_IVSHMEM_COMMON,
|
|
|
|
.parent = TYPE_PCI_DEVICE,
|
|
|
|
.instance_size = sizeof(IVShmemState),
|
|
|
|
.abstract = true,
|
|
|
|
.class_init = ivshmem_common_class_init,
|
|
|
|
};
|
2016-03-15 18:34:51 +00:00
|
|
|
|
2015-06-29 22:10:16 +00:00
|
|
|
static void ivshmem_check_memdev_is_busy(Object *obj, const char *name,
|
|
|
|
Object *val, Error **errp)
|
|
|
|
{
|
|
|
|
MemoryRegion *mr;
|
|
|
|
|
2016-03-15 18:34:31 +00:00
|
|
|
mr = host_memory_backend_get_memory(MEMORY_BACKEND(val), &error_abort);
|
2015-06-29 22:10:16 +00:00
|
|
|
if (memory_region_is_mapped(mr)) {
|
|
|
|
char *path = object_get_canonical_path_component(val);
|
|
|
|
error_setg(errp, "can't use already busy memdev: %s", path);
|
|
|
|
g_free(path);
|
|
|
|
} else {
|
|
|
|
qdev_prop_allow_set_link_before_realize(obj, name, val, errp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-15 18:34:51 +00:00
|
|
|
static const VMStateDescription ivshmem_plain_vmsd = {
|
|
|
|
.name = TYPE_IVSHMEM_PLAIN,
|
|
|
|
.version_id = 0,
|
|
|
|
.minimum_version_id = 0,
|
|
|
|
.pre_load = ivshmem_pre_load,
|
|
|
|
.post_load = ivshmem_post_load,
|
|
|
|
.fields = (VMStateField[]) {
|
|
|
|
VMSTATE_PCI_DEVICE(parent_obj, IVShmemState),
|
|
|
|
VMSTATE_UINT32(intrstatus, IVShmemState),
|
|
|
|
VMSTATE_UINT32(intrmask, IVShmemState),
|
|
|
|
VMSTATE_END_OF_LIST()
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
static Property ivshmem_plain_properties[] = {
|
|
|
|
DEFINE_PROP_ON_OFF_AUTO("master", IVShmemState, master, ON_OFF_AUTO_OFF),
|
|
|
|
DEFINE_PROP_END_OF_LIST(),
|
|
|
|
};
|
|
|
|
|
|
|
|
static void ivshmem_plain_init(Object *obj)
|
|
|
|
{
|
|
|
|
IVShmemState *s = IVSHMEM_PLAIN(obj);
|
|
|
|
|
|
|
|
object_property_add_link(obj, "memdev", TYPE_MEMORY_BACKEND,
|
|
|
|
(Object **)&s->hostmem,
|
|
|
|
ivshmem_check_memdev_is_busy,
|
|
|
|
OBJ_PROP_LINK_UNREF_ON_RELEASE,
|
|
|
|
&error_abort);
|
|
|
|
}
|
|
|
|
|
2016-04-12 13:33:10 +00:00
|
|
|
static void ivshmem_plain_realize(PCIDevice *dev, Error **errp)
|
|
|
|
{
|
|
|
|
IVShmemState *s = IVSHMEM_COMMON(dev);
|
|
|
|
|
|
|
|
if (!s->hostmem) {
|
|
|
|
error_setg(errp, "You must specify a 'memdev'");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ivshmem_common_realize(dev, errp);
|
|
|
|
}
|
|
|
|
|
2016-03-15 18:34:51 +00:00
|
|
|
static void ivshmem_plain_class_init(ObjectClass *klass, void *data)
|
|
|
|
{
|
|
|
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
2016-04-12 13:33:10 +00:00
|
|
|
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
|
2016-03-15 18:34:51 +00:00
|
|
|
|
2016-04-12 13:33:10 +00:00
|
|
|
k->realize = ivshmem_plain_realize;
|
2016-03-15 18:34:51 +00:00
|
|
|
dc->props = ivshmem_plain_properties;
|
|
|
|
dc->vmsd = &ivshmem_plain_vmsd;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const TypeInfo ivshmem_plain_info = {
|
|
|
|
.name = TYPE_IVSHMEM_PLAIN,
|
|
|
|
.parent = TYPE_IVSHMEM_COMMON,
|
|
|
|
.instance_size = sizeof(IVShmemState),
|
|
|
|
.instance_init = ivshmem_plain_init,
|
|
|
|
.class_init = ivshmem_plain_class_init,
|
|
|
|
};
|
|
|
|
|
|
|
|
static const VMStateDescription ivshmem_doorbell_vmsd = {
|
|
|
|
.name = TYPE_IVSHMEM_DOORBELL,
|
|
|
|
.version_id = 0,
|
|
|
|
.minimum_version_id = 0,
|
|
|
|
.pre_load = ivshmem_pre_load,
|
|
|
|
.post_load = ivshmem_post_load,
|
|
|
|
.fields = (VMStateField[]) {
|
|
|
|
VMSTATE_PCI_DEVICE(parent_obj, IVShmemState),
|
|
|
|
VMSTATE_MSIX(parent_obj, IVShmemState),
|
|
|
|
VMSTATE_UINT32(intrstatus, IVShmemState),
|
|
|
|
VMSTATE_UINT32(intrmask, IVShmemState),
|
|
|
|
VMSTATE_END_OF_LIST()
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
static Property ivshmem_doorbell_properties[] = {
|
|
|
|
DEFINE_PROP_CHR("chardev", IVShmemState, server_chr),
|
|
|
|
DEFINE_PROP_UINT32("vectors", IVShmemState, vectors, 1),
|
|
|
|
DEFINE_PROP_BIT("ioeventfd", IVShmemState, features, IVSHMEM_IOEVENTFD,
|
|
|
|
true),
|
|
|
|
DEFINE_PROP_ON_OFF_AUTO("master", IVShmemState, master, ON_OFF_AUTO_OFF),
|
|
|
|
DEFINE_PROP_END_OF_LIST(),
|
|
|
|
};
|
|
|
|
|
|
|
|
static void ivshmem_doorbell_init(Object *obj)
|
|
|
|
{
|
|
|
|
IVShmemState *s = IVSHMEM_DOORBELL(obj);
|
|
|
|
|
|
|
|
s->features |= (1 << IVSHMEM_MSI);
|
|
|
|
s->legacy_size = SIZE_MAX; /* whatever the server sends */
|
|
|
|
}
|
|
|
|
|
2016-04-12 13:33:10 +00:00
|
|
|
static void ivshmem_doorbell_realize(PCIDevice *dev, Error **errp)
|
|
|
|
{
|
|
|
|
IVShmemState *s = IVSHMEM_COMMON(dev);
|
|
|
|
|
|
|
|
if (!s->server_chr) {
|
|
|
|
error_setg(errp, "You must specify a 'chardev'");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ivshmem_common_realize(dev, errp);
|
|
|
|
}
|
|
|
|
|
2016-03-15 18:34:51 +00:00
|
|
|
static void ivshmem_doorbell_class_init(ObjectClass *klass, void *data)
|
|
|
|
{
|
|
|
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
2016-04-12 13:33:10 +00:00
|
|
|
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
|
2016-03-15 18:34:51 +00:00
|
|
|
|
2016-04-12 13:33:10 +00:00
|
|
|
k->realize = ivshmem_doorbell_realize;
|
2016-03-15 18:34:51 +00:00
|
|
|
dc->props = ivshmem_doorbell_properties;
|
|
|
|
dc->vmsd = &ivshmem_doorbell_vmsd;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const TypeInfo ivshmem_doorbell_info = {
|
|
|
|
.name = TYPE_IVSHMEM_DOORBELL,
|
|
|
|
.parent = TYPE_IVSHMEM_COMMON,
|
|
|
|
.instance_size = sizeof(IVShmemState),
|
|
|
|
.instance_init = ivshmem_doorbell_init,
|
|
|
|
.class_init = ivshmem_doorbell_class_init,
|
|
|
|
};
|
|
|
|
|
2016-03-15 18:34:52 +00:00
|
|
|
static int ivshmem_load_old(QEMUFile *f, void *opaque, int version_id)
|
|
|
|
{
|
|
|
|
IVShmemState *s = opaque;
|
|
|
|
PCIDevice *pdev = PCI_DEVICE(s);
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
IVSHMEM_DPRINTF("ivshmem_load_old\n");
|
|
|
|
|
|
|
|
if (version_id != 0) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = ivshmem_pre_load(s);
|
|
|
|
if (ret) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = pci_device_load(pdev, f);
|
|
|
|
if (ret) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
|
|
|
|
msix_load(pdev, f);
|
|
|
|
ivshmem_msix_vector_use(s);
|
|
|
|
} else {
|
|
|
|
s->intrstatus = qemu_get_be32(f);
|
|
|
|
s->intrmask = qemu_get_be32(f);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool test_msix(void *opaque, int version_id)
|
|
|
|
{
|
|
|
|
IVShmemState *s = opaque;
|
|
|
|
|
|
|
|
return ivshmem_has_feature(s, IVSHMEM_MSI);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool test_no_msix(void *opaque, int version_id)
|
|
|
|
{
|
|
|
|
return !test_msix(opaque, version_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
static const VMStateDescription ivshmem_vmsd = {
|
|
|
|
.name = "ivshmem",
|
|
|
|
.version_id = 1,
|
|
|
|
.minimum_version_id = 1,
|
|
|
|
.pre_load = ivshmem_pre_load,
|
|
|
|
.post_load = ivshmem_post_load,
|
|
|
|
.fields = (VMStateField[]) {
|
|
|
|
VMSTATE_PCI_DEVICE(parent_obj, IVShmemState),
|
|
|
|
|
|
|
|
VMSTATE_MSIX_TEST(parent_obj, IVShmemState, test_msix),
|
|
|
|
VMSTATE_UINT32_TEST(intrstatus, IVShmemState, test_no_msix),
|
|
|
|
VMSTATE_UINT32_TEST(intrmask, IVShmemState, test_no_msix),
|
|
|
|
|
|
|
|
VMSTATE_END_OF_LIST()
|
|
|
|
},
|
|
|
|
.load_state_old = ivshmem_load_old,
|
|
|
|
.minimum_version_id_old = 0
|
|
|
|
};
|
|
|
|
|
|
|
|
static Property ivshmem_properties[] = {
|
|
|
|
DEFINE_PROP_CHR("chardev", IVShmemState, server_chr),
|
|
|
|
DEFINE_PROP_STRING("size", IVShmemState, sizearg),
|
|
|
|
DEFINE_PROP_UINT32("vectors", IVShmemState, vectors, 1),
|
|
|
|
DEFINE_PROP_BIT("ioeventfd", IVShmemState, features, IVSHMEM_IOEVENTFD,
|
|
|
|
false),
|
|
|
|
DEFINE_PROP_BIT("msi", IVShmemState, features, IVSHMEM_MSI, true),
|
|
|
|
DEFINE_PROP_STRING("shm", IVShmemState, shmobj),
|
|
|
|
DEFINE_PROP_STRING("role", IVShmemState, role),
|
|
|
|
DEFINE_PROP_UINT32("use64", IVShmemState, not_legacy_32bit, 1),
|
|
|
|
DEFINE_PROP_END_OF_LIST(),
|
|
|
|
};
|
|
|
|
|
|
|
|
static void desugar_shm(IVShmemState *s)
|
|
|
|
{
|
|
|
|
Object *obj;
|
|
|
|
char *path;
|
|
|
|
|
|
|
|
obj = object_new("memory-backend-file");
|
|
|
|
path = g_strdup_printf("/dev/shm/%s", s->shmobj);
|
|
|
|
object_property_set_str(obj, path, "mem-path", &error_abort);
|
|
|
|
g_free(path);
|
|
|
|
object_property_set_int(obj, s->legacy_size, "size", &error_abort);
|
|
|
|
object_property_set_bool(obj, true, "share", &error_abort);
|
|
|
|
object_property_add_child(OBJECT(s), "internal-shm-backend", obj,
|
|
|
|
&error_abort);
|
|
|
|
user_creatable_complete(obj, &error_abort);
|
|
|
|
s->hostmem = MEMORY_BACKEND(obj);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ivshmem_realize(PCIDevice *dev, Error **errp)
|
|
|
|
{
|
|
|
|
IVShmemState *s = IVSHMEM_COMMON(dev);
|
|
|
|
|
|
|
|
if (!qtest_enabled()) {
|
|
|
|
error_report("ivshmem is deprecated, please use ivshmem-plain"
|
|
|
|
" or ivshmem-doorbell instead");
|
|
|
|
}
|
|
|
|
|
2016-03-15 18:34:53 +00:00
|
|
|
if (!!s->server_chr + !!s->shmobj != 1) {
|
|
|
|
error_setg(errp, "You must specify either 'shm' or 'chardev'");
|
2016-03-15 18:34:52 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-03-15 18:34:53 +00:00
|
|
|
if (s->sizearg == NULL) {
|
2016-03-15 18:34:52 +00:00
|
|
|
s->legacy_size = 4 << 20; /* 4 MB default */
|
|
|
|
} else {
|
|
|
|
char *end;
|
|
|
|
int64_t size = qemu_strtosz(s->sizearg, &end);
|
|
|
|
if (size < 0 || (size_t)size != size || *end != '\0'
|
|
|
|
|| !is_power_of_2(size)) {
|
|
|
|
error_setg(errp, "Invalid size %s", s->sizearg);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
s->legacy_size = size;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check that role is reasonable */
|
|
|
|
if (s->role) {
|
|
|
|
if (strncmp(s->role, "peer", 5) == 0) {
|
|
|
|
s->master = ON_OFF_AUTO_OFF;
|
|
|
|
} else if (strncmp(s->role, "master", 7) == 0) {
|
|
|
|
s->master = ON_OFF_AUTO_ON;
|
|
|
|
} else {
|
|
|
|
error_setg(errp, "'role' must be 'peer' or 'master'");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
s->master = ON_OFF_AUTO_AUTO;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (s->shmobj) {
|
|
|
|
desugar_shm(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Note: we don't use INTx with IVSHMEM_MSI at all, so this is a
|
|
|
|
* bald-faced lie then. But it's a backwards compatible lie.
|
|
|
|
*/
|
|
|
|
pci_config_set_interrupt_pin(dev->config, 1);
|
|
|
|
|
|
|
|
ivshmem_common_realize(dev, errp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ivshmem_class_init(ObjectClass *klass, void *data)
|
|
|
|
{
|
|
|
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
|
|
|
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
|
|
|
|
|
|
|
|
k->realize = ivshmem_realize;
|
|
|
|
k->revision = 0;
|
|
|
|
dc->desc = "Inter-VM shared memory (legacy)";
|
|
|
|
dc->props = ivshmem_properties;
|
|
|
|
dc->vmsd = &ivshmem_vmsd;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const TypeInfo ivshmem_info = {
|
|
|
|
.name = TYPE_IVSHMEM,
|
|
|
|
.parent = TYPE_IVSHMEM_COMMON,
|
|
|
|
.instance_size = sizeof(IVShmemState),
|
|
|
|
.class_init = ivshmem_class_init,
|
|
|
|
};
|
|
|
|
|
2012-02-09 14:20:55 +00:00
|
|
|
static void ivshmem_register_types(void)
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
{
|
2016-03-15 18:34:51 +00:00
|
|
|
type_register_static(&ivshmem_common_info);
|
|
|
|
type_register_static(&ivshmem_plain_info);
|
|
|
|
type_register_static(&ivshmem_doorbell_info);
|
2011-12-08 03:34:16 +00:00
|
|
|
type_register_static(&ivshmem_info);
|
RESEND: Inter-VM shared memory PCI device
resend for bug fix related to removal of irqfd
Support an inter-vm shared memory device that maps a shared-memory object as a
PCI device in the guest. This patch also supports interrupts between guest by
communicating over a unix domain socket. This patch applies to the qemu-kvm
repository.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
Interrupts are supported between multiple VMs by using a shared memory server
by using a chardev socket.
-device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
[,chardev=<id>][,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-chardev socket,path=<path>,id=<id>
The shared memory server, sample programs and init scripts are in a git repo here:
www.gitorious.org/nahanni
Signed-off-by: Cam Macdonell <cam@cs.ualberta.ca>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-07-27 16:54:13 +00:00
|
|
|
}
|
|
|
|
|
2012-02-09 14:20:55 +00:00
|
|
|
type_init(ivshmem_register_types)
|