Add vhost net support.
This commit is contained in:
parent
c03c84ed12
commit
2e83913678
|
@ -0,0 +1,199 @@
|
|||
This adds notifiers for phys memory changes: a set of callbacks that
|
||||
vhost can register and update kernel accordingly. Down the road, kvm
|
||||
code can be switched to use these as well, instead of calling kvm code
|
||||
directly from exec.c as is done now.
|
||||
|
||||
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
---
|
||||
cpu-common.h | 19 ++++++++++
|
||||
exec.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
|
||||
2 files changed, 130 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/cpu-common.h b/cpu-common.h
|
||||
index 5e59564..326513d 100644
|
||||
--- a/cpu-common.h
|
||||
+++ b/cpu-common.h
|
||||
@@ -8,6 +8,7 @@
|
||||
#endif
|
||||
|
||||
#include "bswap.h"
|
||||
+#include "qemu-queue.h"
|
||||
|
||||
/* address in the RAM (different from a physical address) */
|
||||
typedef unsigned long ram_addr_t;
|
||||
@@ -62,6 +63,24 @@ void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len,
|
||||
void *cpu_register_map_client(void *opaque, void (*callback)(void *opaque));
|
||||
void cpu_unregister_map_client(void *cookie);
|
||||
|
||||
+struct CPUPhysMemoryClient;
|
||||
+typedef struct CPUPhysMemoryClient CPUPhysMemoryClient;
|
||||
+struct CPUPhysMemoryClient {
|
||||
+ void (*set_memory)(struct CPUPhysMemoryClient *client,
|
||||
+ target_phys_addr_t start_addr,
|
||||
+ ram_addr_t size,
|
||||
+ ram_addr_t phys_offset);
|
||||
+ int (*sync_dirty_bitmap)(struct CPUPhysMemoryClient *client,
|
||||
+ target_phys_addr_t start_addr,
|
||||
+ target_phys_addr_t end_addr);
|
||||
+ int (*migration_log)(struct CPUPhysMemoryClient *client,
|
||||
+ int enable);
|
||||
+ QLIST_ENTRY(CPUPhysMemoryClient) list;
|
||||
+};
|
||||
+
|
||||
+void cpu_register_phys_memory_client(CPUPhysMemoryClient *);
|
||||
+void cpu_unregister_phys_memory_client(CPUPhysMemoryClient *);
|
||||
+
|
||||
uint32_t ldub_phys(target_phys_addr_t addr);
|
||||
uint32_t lduw_phys(target_phys_addr_t addr);
|
||||
uint32_t ldl_phys(target_phys_addr_t addr);
|
||||
diff --git a/exec.c b/exec.c
|
||||
index 8f873ab..cbba15e 100644
|
||||
--- a/exec.c
|
||||
+++ b/exec.c
|
||||
@@ -1640,6 +1640,101 @@ const CPULogItem cpu_log_items[] = {
|
||||
{ 0, NULL, NULL },
|
||||
};
|
||||
|
||||
+#ifndef CONFIG_USER_ONLY
|
||||
+static QLIST_HEAD(memory_client_list, CPUPhysMemoryClient) memory_client_list
|
||||
+ = QLIST_HEAD_INITIALIZER(memory_client_list);
|
||||
+
|
||||
+static void cpu_notify_set_memory(target_phys_addr_t start_addr,
|
||||
+ ram_addr_t size,
|
||||
+ ram_addr_t phys_offset)
|
||||
+{
|
||||
+ CPUPhysMemoryClient *client;
|
||||
+ QLIST_FOREACH(client, &memory_client_list, list) {
|
||||
+ client->set_memory(client, start_addr, size, phys_offset);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static int cpu_notify_sync_dirty_bitmap(target_phys_addr_t start,
|
||||
+ target_phys_addr_t end)
|
||||
+{
|
||||
+ CPUPhysMemoryClient *client;
|
||||
+ QLIST_FOREACH(client, &memory_client_list, list) {
|
||||
+ int r = client->sync_dirty_bitmap(client, start, end);
|
||||
+ if (r < 0)
|
||||
+ return r;
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int cpu_notify_migration_log(int enable)
|
||||
+{
|
||||
+ CPUPhysMemoryClient *client;
|
||||
+ QLIST_FOREACH(client, &memory_client_list, list) {
|
||||
+ int r = client->migration_log(client, enable);
|
||||
+ if (r < 0)
|
||||
+ return r;
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void phys_page_for_each_in_l1_map(PhysPageDesc **phys_map,
|
||||
+ CPUPhysMemoryClient *client)
|
||||
+{
|
||||
+ PhysPageDesc *pd;
|
||||
+ int l1, l2;
|
||||
+
|
||||
+ for (l1 = 0; l1 < L1_SIZE; ++l1) {
|
||||
+ pd = phys_map[l1];
|
||||
+ if (!pd) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ for (l2 = 0; l2 < L2_SIZE; ++l2) {
|
||||
+ if (pd[l2].phys_offset == IO_MEM_UNASSIGNED) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ client->set_memory(client, pd[l2].region_offset,
|
||||
+ TARGET_PAGE_SIZE, pd[l2].phys_offset);
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void phys_page_for_each(CPUPhysMemoryClient *client)
|
||||
+{
|
||||
+#if TARGET_PHYS_ADDR_SPACE_BITS > 32
|
||||
+
|
||||
+#if TARGET_PHYS_ADDR_SPACE_BITS > (32 + L1_BITS)
|
||||
+#error unsupported TARGET_PHYS_ADDR_SPACE_BITS
|
||||
+#endif
|
||||
+ void **phys_map = (void **)l1_phys_map;
|
||||
+ int l1;
|
||||
+ if (!l1_phys_map) {
|
||||
+ return;
|
||||
+ }
|
||||
+ for (l1 = 0; l1 < L1_SIZE; ++l1) {
|
||||
+ if (phys_map[l1]) {
|
||||
+ phys_page_for_each_in_l1_map(phys_map[l1], client);
|
||||
+ }
|
||||
+ }
|
||||
+#else
|
||||
+ if (!l1_phys_map) {
|
||||
+ return;
|
||||
+ }
|
||||
+ phys_page_for_each_in_l1_map(l1_phys_map, client);
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
+void cpu_register_phys_memory_client(CPUPhysMemoryClient *client)
|
||||
+{
|
||||
+ QLIST_INSERT_HEAD(&memory_client_list, client, list);
|
||||
+ phys_page_for_each(client);
|
||||
+}
|
||||
+
|
||||
+void cpu_unregister_phys_memory_client(CPUPhysMemoryClient *client)
|
||||
+{
|
||||
+ QLIST_REMOVE(client, list);
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
static int cmp1(const char *s1, int n, const char *s2)
|
||||
{
|
||||
if (strlen(s2) != n)
|
||||
@@ -1899,10 +1994,16 @@ void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
|
||||
|
||||
int cpu_physical_memory_set_dirty_tracking(int enable)
|
||||
{
|
||||
+ int ret = 0;
|
||||
+ in_migration = enable;
|
||||
if (kvm_enabled()) {
|
||||
- return kvm_set_migration_log(enable);
|
||||
+ ret = kvm_set_migration_log(enable);
|
||||
}
|
||||
- return 0;
|
||||
+ if (ret < 0) {
|
||||
+ return ret;
|
||||
+ }
|
||||
+ ret = cpu_notify_migration_log(!!enable);
|
||||
+ return ret;
|
||||
}
|
||||
|
||||
int cpu_physical_memory_get_dirty_tracking(void)
|
||||
@@ -1915,8 +2016,13 @@ int cpu_physical_sync_dirty_bitmap(target_phys_addr_t start_addr,
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
- if (kvm_enabled())
|
||||
+ if (kvm_enabled()) {
|
||||
ret = kvm_physical_sync_dirty_bitmap(start_addr, end_addr);
|
||||
+ }
|
||||
+ if (ret < 0) {
|
||||
+ return ret;
|
||||
+ }
|
||||
+ ret = cpu_notify_sync_dirty_bitmap(start_addr, end_addr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -2331,6 +2437,8 @@ void cpu_register_physical_memory_offset(target_phys_addr_t start_addr,
|
||||
if (kvm_enabled())
|
||||
kvm_set_phys_mem(start_addr, size, phys_offset);
|
||||
|
||||
+ cpu_notify_set_memory(start_addr, size, phys_offset);
|
||||
+
|
||||
if (phys_offset == IO_MEM_UNASSIGNED) {
|
||||
region_offset = start_addr;
|
||||
}
|
||||
--
|
||||
1.6.6.144.g5c3af
|
|
@ -0,0 +1,81 @@
|
|||
This adds API to set ioeventfd to kvm,
|
||||
as well as stubs for non-eventfd case,
|
||||
making it possible for users to use this API
|
||||
without ifdefs.
|
||||
|
||||
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
---
|
||||
kvm-all.c | 20 ++++++++++++++++++++
|
||||
kvm.h | 16 ++++++++++++++++
|
||||
2 files changed, 36 insertions(+), 0 deletions(-)
|
||||
|
||||
diff --git a/kvm-all.c b/kvm-all.c
|
||||
index 0423fff..efdf40c 100644
|
||||
--- a/kvm-all.c
|
||||
+++ b/kvm-all.c
|
||||
@@ -1102,4 +1102,24 @@ void kvm_remove_all_breakpoints(CPUState *current_env)
|
||||
}
|
||||
#endif /* !KVM_CAP_SET_GUEST_DEBUG */
|
||||
|
||||
+#ifdef KVM_IOEVENTFD
|
||||
+int kvm_set_ioeventfd(uint16_t addr, uint16_t data, int fd, bool assigned)
|
||||
+{
|
||||
+ struct kvm_ioeventfd kick = {
|
||||
+ .datamatch = data,
|
||||
+ .addr = addr,
|
||||
+ .len = 2,
|
||||
+ .flags = KVM_IOEVENTFD_FLAG_DATAMATCH | KVM_IOEVENTFD_FLAG_PIO,
|
||||
+ .fd = fd,
|
||||
+ };
|
||||
+ int r;
|
||||
+ if (!assigned)
|
||||
+ kick.flags |= KVM_IOEVENTFD_FLAG_DEASSIGN;
|
||||
+ r = kvm_vm_ioctl(kvm_state, KVM_IOEVENTFD, &kick);
|
||||
+ if (r < 0)
|
||||
+ return r;
|
||||
+ return 0;
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
#include "qemu-kvm.c"
|
||||
diff --git a/kvm.h b/kvm.h
|
||||
index 9fa4e25..e98b5c8 100644
|
||||
--- a/kvm.h
|
||||
+++ b/kvm.h
|
||||
@@ -14,6 +14,8 @@
|
||||
#ifndef QEMU_KVM_H
|
||||
#define QEMU_KVM_H
|
||||
|
||||
+#include <stdbool.h>
|
||||
+#include <errno.h>
|
||||
#include "config.h"
|
||||
#include "qemu-queue.h"
|
||||
#include "qemu-kvm.h"
|
||||
@@ -21,6 +23,10 @@
|
||||
#ifdef KVM_UPSTREAM
|
||||
|
||||
#ifdef CONFIG_KVM
|
||||
+#include <linux/kvm.h>
|
||||
+#endif
|
||||
+
|
||||
+#ifdef CONFIG_KVM
|
||||
extern int kvm_allowed;
|
||||
|
||||
#define kvm_enabled() (kvm_allowed)
|
||||
@@ -151,4 +157,14 @@ static inline void cpu_synchronize_state(CPUState *env)
|
||||
|
||||
#endif
|
||||
|
||||
+#if defined(KVM_IOEVENTFD) && defined(CONFIG_KVM)
|
||||
+int kvm_set_ioeventfd(uint16_t addr, uint16_t data, int fd, bool assigned);
|
||||
+#else
|
||||
+static inline
|
||||
+int kvm_set_ioeventfd(uint16_t data, uint16_t addr, int fd, bool assigned)
|
||||
+{
|
||||
+ return -ENOSYS;
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
#endif
|
||||
--
|
||||
1.6.6.144.g5c3af
|
|
@ -0,0 +1,147 @@
|
|||
This makes it possible to build vhost support
|
||||
on systems which do not have this header.
|
||||
|
||||
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
---
|
||||
kvm/include/linux/vhost.h | 130 +++++++++++++++++++++++++++++++++++++++++++++
|
||||
1 files changed, 130 insertions(+), 0 deletions(-)
|
||||
create mode 100644 kvm/include/linux/vhost.h
|
||||
|
||||
diff --git a/kvm/include/linux/vhost.h b/kvm/include/linux/vhost.h
|
||||
new file mode 100644
|
||||
index 0000000..165a484
|
||||
--- /dev/null
|
||||
+++ b/kvm/include/linux/vhost.h
|
||||
@@ -0,0 +1,130 @@
|
||||
+#ifndef _LINUX_VHOST_H
|
||||
+#define _LINUX_VHOST_H
|
||||
+/* Userspace interface for in-kernel virtio accelerators. */
|
||||
+
|
||||
+/* vhost is used to reduce the number of system calls involved in virtio.
|
||||
+ *
|
||||
+ * Existing virtio net code is used in the guest without modification.
|
||||
+ *
|
||||
+ * This header includes interface used by userspace hypervisor for
|
||||
+ * device configuration.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/types.h>
|
||||
+
|
||||
+#include <linux/ioctl.h>
|
||||
+#include <linux/virtio_config.h>
|
||||
+#include <linux/virtio_ring.h>
|
||||
+
|
||||
+struct vhost_vring_state {
|
||||
+ unsigned int index;
|
||||
+ unsigned int num;
|
||||
+};
|
||||
+
|
||||
+struct vhost_vring_file {
|
||||
+ unsigned int index;
|
||||
+ int fd; /* Pass -1 to unbind from file. */
|
||||
+
|
||||
+};
|
||||
+
|
||||
+struct vhost_vring_addr {
|
||||
+ unsigned int index;
|
||||
+ /* Option flags. */
|
||||
+ unsigned int flags;
|
||||
+ /* Flag values: */
|
||||
+ /* Whether log address is valid. If set enables logging. */
|
||||
+#define VHOST_VRING_F_LOG 0
|
||||
+
|
||||
+ /* Start of array of descriptors (virtually contiguous) */
|
||||
+ __u64 desc_user_addr;
|
||||
+ /* Used structure address. Must be 32 bit aligned */
|
||||
+ __u64 used_user_addr;
|
||||
+ /* Available structure address. Must be 16 bit aligned */
|
||||
+ __u64 avail_user_addr;
|
||||
+ /* Logging support. */
|
||||
+ /* Log writes to used structure, at offset calculated from specified
|
||||
+ * address. Address must be 32 bit aligned. */
|
||||
+ __u64 log_guest_addr;
|
||||
+};
|
||||
+
|
||||
+struct vhost_memory_region {
|
||||
+ __u64 guest_phys_addr;
|
||||
+ __u64 memory_size; /* bytes */
|
||||
+ __u64 userspace_addr;
|
||||
+ __u64 flags_padding; /* No flags are currently specified. */
|
||||
+};
|
||||
+
|
||||
+/* All region addresses and sizes must be 4K aligned. */
|
||||
+#define VHOST_PAGE_SIZE 0x1000
|
||||
+
|
||||
+struct vhost_memory {
|
||||
+ __u32 nregions;
|
||||
+ __u32 padding;
|
||||
+ struct vhost_memory_region regions[0];
|
||||
+};
|
||||
+
|
||||
+/* ioctls */
|
||||
+
|
||||
+#define VHOST_VIRTIO 0xAF
|
||||
+
|
||||
+/* Features bitmask for forward compatibility. Transport bits are used for
|
||||
+ * vhost specific features. */
|
||||
+#define VHOST_GET_FEATURES _IOR(VHOST_VIRTIO, 0x00, __u64)
|
||||
+#define VHOST_SET_FEATURES _IOW(VHOST_VIRTIO, 0x00, __u64)
|
||||
+
|
||||
+/* Set current process as the (exclusive) owner of this file descriptor. This
|
||||
+ * must be called before any other vhost command. Further calls to
|
||||
+ * VHOST_OWNER_SET fail until VHOST_OWNER_RESET is called. */
|
||||
+#define VHOST_SET_OWNER _IO(VHOST_VIRTIO, 0x01)
|
||||
+/* Give up ownership, and reset the device to default values.
|
||||
+ * Allows subsequent call to VHOST_OWNER_SET to succeed. */
|
||||
+#define VHOST_RESET_OWNER _IO(VHOST_VIRTIO, 0x02)
|
||||
+
|
||||
+/* Set up/modify memory layout */
|
||||
+#define VHOST_SET_MEM_TABLE _IOW(VHOST_VIRTIO, 0x03, struct vhost_memory)
|
||||
+
|
||||
+/* Write logging setup. */
|
||||
+/* Memory writes can optionally be logged by setting bit at an offset
|
||||
+ * (calculated from the physical address) from specified log base.
|
||||
+ * The bit is set using an atomic 32 bit operation. */
|
||||
+/* Set base address for logging. */
|
||||
+#define VHOST_SET_LOG_BASE _IOW(VHOST_VIRTIO, 0x04, __u64)
|
||||
+/* Specify an eventfd file descriptor to signal on log write. */
|
||||
+#define VHOST_SET_LOG_FD _IOW(VHOST_VIRTIO, 0x07, int)
|
||||
+
|
||||
+/* Ring setup. */
|
||||
+/* Set number of descriptors in ring. This parameter can not
|
||||
+ * be modified while ring is running (bound to a device). */
|
||||
+#define VHOST_SET_VRING_NUM _IOW(VHOST_VIRTIO, 0x10, struct vhost_vring_state)
|
||||
+/* Set addresses for the ring. */
|
||||
+#define VHOST_SET_VRING_ADDR _IOW(VHOST_VIRTIO, 0x11, struct vhost_vring_addr)
|
||||
+/* Base value where queue looks for available descriptors */
|
||||
+#define VHOST_SET_VRING_BASE _IOW(VHOST_VIRTIO, 0x12, struct vhost_vring_state)
|
||||
+/* Get accessor: reads index, writes value in num */
|
||||
+#define VHOST_GET_VRING_BASE _IOWR(VHOST_VIRTIO, 0x12, struct vhost_vring_state)
|
||||
+
|
||||
+/* The following ioctls use eventfd file descriptors to signal and poll
|
||||
+ * for events. */
|
||||
+
|
||||
+/* Set eventfd to poll for added buffers */
|
||||
+#define VHOST_SET_VRING_KICK _IOW(VHOST_VIRTIO, 0x20, struct vhost_vring_file)
|
||||
+/* Set eventfd to signal when buffers have beed used */
|
||||
+#define VHOST_SET_VRING_CALL _IOW(VHOST_VIRTIO, 0x21, struct vhost_vring_file)
|
||||
+/* Set eventfd to signal an error */
|
||||
+#define VHOST_SET_VRING_ERR _IOW(VHOST_VIRTIO, 0x22, struct vhost_vring_file)
|
||||
+
|
||||
+/* VHOST_NET specific defines */
|
||||
+
|
||||
+/* Attach virtio net ring to a raw socket, or tap device.
|
||||
+ * The socket must be already bound to an ethernet device, this device will be
|
||||
+ * used for transmit. Pass fd -1 to unbind from the socket and the transmit
|
||||
+ * device. This can be used to stop the ring (e.g. for migration). */
|
||||
+#define VHOST_NET_SET_BACKEND _IOW(VHOST_VIRTIO, 0x30, struct vhost_vring_file)
|
||||
+
|
||||
+/* Feature bits */
|
||||
+/* Log all write descriptors. Can be changed while device is active. */
|
||||
+#define VHOST_F_LOG_ALL 26
|
||||
+/* vhost-net should add virtio_net_hdr for RX, and strip for TX packets. */
|
||||
+#define VHOST_NET_F_VIRTIO_NET_HDR 27
|
||||
+
|
||||
+#endif
|
||||
--
|
||||
1.6.6.144.g5c3af
|
|
@ -0,0 +1,59 @@
|
|||
Add API to assign/deassign irqfd to kvm.
|
||||
Add stub so that users do not have to use
|
||||
ifdefs.
|
||||
|
||||
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
---
|
||||
kvm-all.c | 19 +++++++++++++++++++
|
||||
kvm.h | 10 ++++++++++
|
||||
2 files changed, 29 insertions(+), 0 deletions(-)
|
||||
|
||||
diff --git a/kvm-all.c b/kvm-all.c
|
||||
index efdf40c..b3fdf29 100644
|
||||
--- a/kvm-all.c
|
||||
+++ b/kvm-all.c
|
||||
@@ -1122,4 +1122,23 @@ int kvm_set_ioeventfd(uint16_t addr, uint16_t data, int fd, bool assigned)
|
||||
}
|
||||
#endif
|
||||
|
||||
+#if defined(KVM_IRQFD)
|
||||
+int kvm_set_irqfd(int gsi, int fd, bool assigned)
|
||||
+{
|
||||
+ struct kvm_irqfd irqfd = {
|
||||
+ .fd = fd,
|
||||
+ .gsi = gsi,
|
||||
+ .flags = assigned ? 0 : KVM_IRQFD_FLAG_DEASSIGN,
|
||||
+ };
|
||||
+ int r;
|
||||
+ if (!kvm_irqchip_in_kernel())
|
||||
+ return -ENOSYS;
|
||||
+
|
||||
+ r = kvm_vm_ioctl(kvm_state, KVM_IRQFD, &irqfd);
|
||||
+ if (r < 0)
|
||||
+ return r;
|
||||
+ return 0;
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
#include "qemu-kvm.c"
|
||||
diff --git a/kvm.h b/kvm.h
|
||||
index e98b5c8..ad8d122 100644
|
||||
--- a/kvm.h
|
||||
+++ b/kvm.h
|
||||
@@ -167,4 +167,14 @@ int kvm_set_ioeventfd(uint16_t data, uint16_t addr, int fd, bool assigned)
|
||||
}
|
||||
#endif
|
||||
|
||||
+#if defined(KVM_IRQFD) && defined(CONFIG_KVM)
|
||||
+int kvm_set_irqfd(int gsi, int fd, bool assigned);
|
||||
+#else
|
||||
+static inline
|
||||
+int kvm_set_irqfd(int gsi, int fd, bool assigned)
|
||||
+{
|
||||
+ return -ENOSYS;
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
#endif
|
||||
--
|
||||
1.6.6.144.g5c3af
|
|
@ -0,0 +1,121 @@
|
|||
Support per-vector callbacks for msix mask/unmask.
|
||||
Will be used for vhost net.
|
||||
|
||||
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
---
|
||||
hw/msix.c | 36 +++++++++++++++++++++++++++++++++++-
|
||||
hw/msix.h | 1 +
|
||||
hw/pci.h | 6 ++++++
|
||||
3 files changed, 42 insertions(+), 1 deletions(-)
|
||||
|
||||
diff --git a/hw/msix.c b/hw/msix.c
|
||||
index d117bcf..3fcf3a1 100644
|
||||
--- a/hw/msix.c
|
||||
+++ b/hw/msix.c
|
||||
@@ -318,6 +318,13 @@ static void msix_mmio_writel(void *opaque, target_phys_addr_t addr,
|
||||
if (kvm_enabled() && kvm_irqchip_in_kernel()) {
|
||||
kvm_msix_update(dev, vector, was_masked, msix_is_masked(dev, vector));
|
||||
}
|
||||
+ if (was_masked != msix_is_masked(dev, vector) &&
|
||||
+ dev->msix_mask_notifier && dev->msix_mask_notifier_opaque[vector]) {
|
||||
+ int r = dev->msix_mask_notifier(dev, vector,
|
||||
+ dev->msix_mask_notifier_opaque[vector],
|
||||
+ msix_is_masked(dev, vector));
|
||||
+ assert(r >= 0);
|
||||
+ }
|
||||
msix_handle_mask_update(dev, vector);
|
||||
}
|
||||
|
||||
@@ -356,10 +363,18 @@ void msix_mmio_map(PCIDevice *d, int region_num,
|
||||
|
||||
static void msix_mask_all(struct PCIDevice *dev, unsigned nentries)
|
||||
{
|
||||
- int vector;
|
||||
+ int vector, r;
|
||||
for (vector = 0; vector < nentries; ++vector) {
|
||||
unsigned offset = vector * MSIX_ENTRY_SIZE + MSIX_VECTOR_CTRL;
|
||||
+ int was_masked = msix_is_masked(dev, vector);
|
||||
dev->msix_table_page[offset] |= MSIX_VECTOR_MASK;
|
||||
+ if (was_masked != msix_is_masked(dev, vector) &&
|
||||
+ dev->msix_mask_notifier && dev->msix_mask_notifier_opaque[vector]) {
|
||||
+ r = dev->msix_mask_notifier(dev, vector,
|
||||
+ dev->msix_mask_notifier_opaque[vector],
|
||||
+ msix_is_masked(dev, vector));
|
||||
+ assert(r >= 0);
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -382,6 +397,9 @@ int msix_init(struct PCIDevice *dev, unsigned short nentries,
|
||||
sizeof *dev->msix_irq_entries);
|
||||
}
|
||||
#endif
|
||||
+ dev->msix_mask_notifier_opaque =
|
||||
+ qemu_mallocz(nentries * sizeof *dev->msix_mask_notifier_opaque);
|
||||
+ dev->msix_mask_notifier = NULL;
|
||||
dev->msix_entry_used = qemu_mallocz(MSIX_MAX_ENTRIES *
|
||||
sizeof *dev->msix_entry_used);
|
||||
|
||||
@@ -444,6 +462,8 @@ int msix_uninit(PCIDevice *dev)
|
||||
dev->msix_entry_used = NULL;
|
||||
qemu_free(dev->msix_irq_entries);
|
||||
dev->msix_irq_entries = NULL;
|
||||
+ qemu_free(dev->msix_mask_notifier_opaque);
|
||||
+ dev->msix_mask_notifier_opaque = NULL;
|
||||
dev->cap_present &= ~QEMU_PCI_CAP_MSIX;
|
||||
return 0;
|
||||
}
|
||||
@@ -587,3 +607,17 @@ void msix_unuse_all_vectors(PCIDevice *dev)
|
||||
return;
|
||||
msix_free_irq_entries(dev);
|
||||
}
|
||||
+
|
||||
+int msix_set_mask_notifier(PCIDevice *dev, unsigned vector, void *opaque)
|
||||
+{
|
||||
+ int r = 0;
|
||||
+ if (vector >= dev->msix_entries_nr || !dev->msix_entry_used[vector])
|
||||
+ return 0;
|
||||
+
|
||||
+ if (dev->msix_mask_notifier)
|
||||
+ r = dev->msix_mask_notifier(dev, vector, opaque,
|
||||
+ msix_is_masked(dev, vector));
|
||||
+ if (r >= 0)
|
||||
+ dev->msix_mask_notifier_opaque[vector] = opaque;
|
||||
+ return r;
|
||||
+}
|
||||
diff --git a/hw/msix.h b/hw/msix.h
|
||||
index a9f7993..f167231 100644
|
||||
--- a/hw/msix.h
|
||||
+++ b/hw/msix.h
|
||||
@@ -33,4 +33,5 @@ void msix_reset(PCIDevice *dev);
|
||||
|
||||
extern int msix_supported;
|
||||
|
||||
+int msix_set_mask_notifier(PCIDevice *dev, unsigned vector, void *opaque);
|
||||
#endif
|
||||
diff --git a/hw/pci.h b/hw/pci.h
|
||||
index a225a6a..bf722ca 100644
|
||||
--- a/hw/pci.h
|
||||
+++ b/hw/pci.h
|
||||
@@ -217,6 +217,9 @@ enum {
|
||||
#define PCI_CAPABILITY_CONFIG_MSI_LENGTH 0x10
|
||||
#define PCI_CAPABILITY_CONFIG_MSIX_LENGTH 0x10
|
||||
|
||||
+typedef int (*msix_mask_notifier_func)(PCIDevice *, unsigned vector,
|
||||
+ void *opaque, int masked);
|
||||
+
|
||||
struct PCIDevice {
|
||||
DeviceState qdev;
|
||||
/* PCI config space */
|
||||
@@ -282,6 +285,9 @@ struct PCIDevice {
|
||||
|
||||
struct kvm_irq_routing_entry *msix_irq_entries;
|
||||
|
||||
+ void **msix_mask_notifier_opaque;
|
||||
+ msix_mask_notifier_func msix_mask_notifier;
|
||||
+
|
||||
/* Device capability configuration space */
|
||||
struct {
|
||||
int supported;
|
||||
--
|
||||
1.6.6.144.g5c3af
|
|
@ -0,0 +1,68 @@
|
|||
When vhost is bound to a backend device, we need to stop polling it when
|
||||
vhost is started, and restart polling when vhost is stopped.
|
||||
Add an API for that for use by vhost, and implement in tap backend.
|
||||
|
||||
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
|
||||
(cherry picked from commit ceb696159d569db5b2a7659ce38752398c236742)
|
||||
---
|
||||
net.h | 3 +++
|
||||
net/tap.c | 8 ++++++++
|
||||
2 files changed, 11 insertions(+), 0 deletions(-)
|
||||
|
||||
diff --git a/net.h b/net.h
|
||||
index 4971fcb..116bb80 100644
|
||||
--- a/net.h
|
||||
+++ b/net.h
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifndef QEMU_NET_H
|
||||
#define QEMU_NET_H
|
||||
|
||||
+#include <stdbool.h>
|
||||
#include "qemu-queue.h"
|
||||
#include "qemu-common.h"
|
||||
#include "qdict.h"
|
||||
@@ -36,6 +37,7 @@ typedef enum {
|
||||
NET_CLIENT_TYPE_DUMP
|
||||
} net_client_type;
|
||||
|
||||
+typedef void (NetPoll)(VLANClientState *, bool enable);
|
||||
typedef int (NetCanReceive)(VLANClientState *);
|
||||
typedef ssize_t (NetReceive)(VLANClientState *, const uint8_t *, size_t);
|
||||
typedef ssize_t (NetReceiveIOV)(VLANClientState *, const struct iovec *, int);
|
||||
@@ -51,6 +53,7 @@ typedef struct NetClientInfo {
|
||||
NetCanReceive *can_receive;
|
||||
NetCleanup *cleanup;
|
||||
LinkStatusChanged *link_status_changed;
|
||||
+ NetPoll *poll;
|
||||
} NetClientInfo;
|
||||
|
||||
struct VLANClientState {
|
||||
diff --git a/net/tap.c b/net/tap.c
|
||||
index 0d8b424..d3492de 100644
|
||||
--- a/net/tap.c
|
||||
+++ b/net/tap.c
|
||||
@@ -262,6 +262,13 @@ static void tap_cleanup(VLANClientState *nc)
|
||||
close(s->fd);
|
||||
}
|
||||
|
||||
+static void tap_poll(VLANClientState *nc, bool enable)
|
||||
+{
|
||||
+ TAPState *s = DO_UPCAST(TAPState, nc, nc);
|
||||
+ tap_read_poll(s, enable);
|
||||
+ tap_write_poll(s, enable);
|
||||
+}
|
||||
+
|
||||
/* fd support */
|
||||
|
||||
static NetClientInfo net_tap_info = {
|
||||
@@ -270,6 +277,7 @@ static NetClientInfo net_tap_info = {
|
||||
.receive = tap_receive,
|
||||
.receive_raw = tap_receive_raw,
|
||||
.receive_iov = tap_receive_iov,
|
||||
+ .poll = tap_poll,
|
||||
.cleanup = tap_cleanup,
|
||||
};
|
||||
|
||||
--
|
||||
1.6.6.144.g5c3af
|
|
@ -0,0 +1,122 @@
|
|||
event notifiers are slightly generalized eventfd descriptors. Current
|
||||
implementation depends on eventfd because vhost is the only user, and
|
||||
vhost depends on eventfd anyway, but a stub is provided for non-eventfd
|
||||
case.
|
||||
|
||||
We'll be able to further generalize this when another user comes along
|
||||
and we see how to best do this.
|
||||
|
||||
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
---
|
||||
Makefile.target | 1 +
|
||||
hw/notifier.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
hw/notifier.h | 16 ++++++++++++++++
|
||||
qemu-common.h | 1 +
|
||||
4 files changed, 68 insertions(+), 0 deletions(-)
|
||||
create mode 100644 hw/notifier.c
|
||||
create mode 100644 hw/notifier.h
|
||||
|
||||
diff --git a/Makefile.target b/Makefile.target
|
||||
index 6037fed..0c844a9 100644
|
||||
--- a/Makefile.target
|
||||
+++ b/Makefile.target
|
||||
@@ -167,6 +167,7 @@ obj-y = vl.o async.o monitor.o pci.o pci_host.o pcie_host.o machine.o gdbstub.o
|
||||
# virtio has to be here due to weird dependency between PCI and virtio-net.
|
||||
# need to fix this properly
|
||||
obj-y += virtio-blk.o virtio-balloon.o virtio-net.o virtio-pci.o virtio-serial-bus.o
|
||||
+obj-y += notifier.o
|
||||
obj-$(CONFIG_KVM) += kvm.o kvm-all.o
|
||||
# MSI-X depends on kvm for interrupt injection,
|
||||
# so moved it from Makefile.hw to Makefile.target for now
|
||||
diff --git a/hw/notifier.c b/hw/notifier.c
|
||||
new file mode 100644
|
||||
index 0000000..dff38de
|
||||
--- /dev/null
|
||||
+++ b/hw/notifier.c
|
||||
@@ -0,0 +1,50 @@
|
||||
+#include "hw.h"
|
||||
+#include "notifier.h"
|
||||
+#ifdef CONFIG_EVENTFD
|
||||
+#include <sys/eventfd.h>
|
||||
+#endif
|
||||
+
|
||||
+int event_notifier_init(EventNotifier *e, int active)
|
||||
+{
|
||||
+#ifdef CONFIG_EVENTFD
|
||||
+ int fd = eventfd(!!active, EFD_NONBLOCK | EFD_CLOEXEC);
|
||||
+ if (fd < 0)
|
||||
+ return -errno;
|
||||
+ e->fd = fd;
|
||||
+ return 0;
|
||||
+#else
|
||||
+ return -ENOSYS;
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
+void event_notifier_cleanup(EventNotifier *e)
|
||||
+{
|
||||
+ close(e->fd);
|
||||
+}
|
||||
+
|
||||
+int event_notifier_get_fd(EventNotifier *e)
|
||||
+{
|
||||
+ return e->fd;
|
||||
+}
|
||||
+
|
||||
+int event_notifier_test_and_clear(EventNotifier *e)
|
||||
+{
|
||||
+ uint64_t value;
|
||||
+ int r = read(e->fd, &value, sizeof value);
|
||||
+ return r == sizeof value;
|
||||
+}
|
||||
+
|
||||
+int event_notifier_test(EventNotifier *e)
|
||||
+{
|
||||
+ uint64_t value;
|
||||
+ int r = read(e->fd, &value, sizeof value);
|
||||
+ if (r == sizeof value) {
|
||||
+ /* restore previous value. */
|
||||
+ int s = write(e->fd, &value, sizeof value);
|
||||
+ /* never blocks because we use EFD_SEMAPHORE.
|
||||
+ * If we didn't we'd get EAGAIN on overflow
|
||||
+ * and we'd have to write code to ignore it. */
|
||||
+ assert(s == sizeof value);
|
||||
+ }
|
||||
+ return r == sizeof value;
|
||||
+}
|
||||
diff --git a/hw/notifier.h b/hw/notifier.h
|
||||
new file mode 100644
|
||||
index 0000000..24117ea
|
||||
--- /dev/null
|
||||
+++ b/hw/notifier.h
|
||||
@@ -0,0 +1,16 @@
|
||||
+#ifndef QEMU_EVENT_NOTIFIER_H
|
||||
+#define QEMU_EVENT_NOTIFIER_H
|
||||
+
|
||||
+#include "qemu-common.h"
|
||||
+
|
||||
+struct EventNotifier {
|
||||
+ int fd;
|
||||
+};
|
||||
+
|
||||
+int event_notifier_init(EventNotifier *, int active);
|
||||
+void event_notifier_cleanup(EventNotifier *);
|
||||
+int event_notifier_get_fd(EventNotifier *);
|
||||
+int event_notifier_test_and_clear(EventNotifier *);
|
||||
+int event_notifier_test(EventNotifier *);
|
||||
+
|
||||
+#endif
|
||||
diff --git a/qemu-common.h b/qemu-common.h
|
||||
index 5fbe0f9..cdead98 100644
|
||||
--- a/qemu-common.h
|
||||
+++ b/qemu-common.h
|
||||
@@ -217,6 +217,7 @@ typedef struct uWireSlave uWireSlave;
|
||||
typedef struct I2SCodec I2SCodec;
|
||||
typedef struct DeviceState DeviceState;
|
||||
typedef struct SSIBus SSIBus;
|
||||
+typedef struct EventNotifier EventNotifier;
|
||||
|
||||
/* CPU save/load. */
|
||||
void cpu_save(QEMUFile *f, void *opaque);
|
||||
--
|
||||
1.6.6.144.g5c3af
|
|
@ -0,0 +1,156 @@
|
|||
This adds "bit" property type, which is a boolean stored in a 32 bit
|
||||
integer field, with legal values on and off. Will be used by virtio for
|
||||
feature bits.
|
||||
|
||||
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
|
||||
(cherry picked from commit d2364ee424ebf9180afaf21128a71da55321ad00)
|
||||
---
|
||||
hw/qdev-properties.c | 62 ++++++++++++++++++++++++++++++++++++++++++++-----
|
||||
hw/qdev.h | 11 +++++++++
|
||||
2 files changed, 66 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c
|
||||
index 217ddc0..9e123ae 100644
|
||||
--- a/hw/qdev-properties.c
|
||||
+++ b/hw/qdev-properties.c
|
||||
@@ -9,6 +9,59 @@ void *qdev_get_prop_ptr(DeviceState *dev, Property *prop)
|
||||
return ptr;
|
||||
}
|
||||
|
||||
+static uint32_t qdev_get_prop_mask(Property *prop)
|
||||
+{
|
||||
+ assert(prop->info->type == PROP_TYPE_BIT);
|
||||
+ return 0x1 << prop->bitnr;
|
||||
+}
|
||||
+
|
||||
+static void bit_prop_set(DeviceState *dev, Property *props, bool val)
|
||||
+{
|
||||
+ uint32_t *p = qdev_get_prop_ptr(dev, props);
|
||||
+ uint32_t mask = qdev_get_prop_mask(props);
|
||||
+ if (val)
|
||||
+ *p |= ~mask;
|
||||
+ else
|
||||
+ *p &= ~mask;
|
||||
+}
|
||||
+
|
||||
+static void qdev_prop_cpy(DeviceState *dev, Property *props, void *src)
|
||||
+{
|
||||
+ if (props->info->type == PROP_TYPE_BIT) {
|
||||
+ bool *defval = src;
|
||||
+ bit_prop_set(dev, props, *defval);
|
||||
+ } else {
|
||||
+ char *dst = qdev_get_prop_ptr(dev, props);
|
||||
+ memcpy(dst, src, props->info->size);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/* Bit */
|
||||
+static int parse_bit(DeviceState *dev, Property *prop, const char *str)
|
||||
+{
|
||||
+ if (!strncasecmp(str, "on", 2))
|
||||
+ bit_prop_set(dev, prop, true);
|
||||
+ else if (!strncasecmp(str, "off", 3))
|
||||
+ bit_prop_set(dev, prop, false);
|
||||
+ else
|
||||
+ return -1;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int print_bit(DeviceState *dev, Property *prop, char *dest, size_t len)
|
||||
+{
|
||||
+ uint8_t *p = qdev_get_prop_ptr(dev, prop);
|
||||
+ return snprintf(dest, len, (*p & qdev_get_prop_mask(prop)) ? "on" : "off");
|
||||
+}
|
||||
+
|
||||
+PropertyInfo qdev_prop_bit = {
|
||||
+ .name = "on/off",
|
||||
+ .type = PROP_TYPE_BIT,
|
||||
+ .size = sizeof(uint32_t),
|
||||
+ .parse = parse_bit,
|
||||
+ .print = print_bit,
|
||||
+};
|
||||
+
|
||||
/* --- 8bit integer --- */
|
||||
|
||||
static int parse_uint8(DeviceState *dev, Property *prop, const char *str)
|
||||
@@ -511,7 +564,6 @@ int qdev_prop_parse(DeviceState *dev, const char *name, const char *value)
|
||||
void qdev_prop_set(DeviceState *dev, const char *name, void *src, enum PropertyType type)
|
||||
{
|
||||
Property *prop;
|
||||
- void *dst;
|
||||
|
||||
prop = qdev_prop_find(dev, name);
|
||||
if (!prop) {
|
||||
@@ -524,8 +576,7 @@ void qdev_prop_set(DeviceState *dev, const char *name, void *src, enum PropertyT
|
||||
__FUNCTION__, dev->info->name, name);
|
||||
abort();
|
||||
}
|
||||
- dst = qdev_get_prop_ptr(dev, prop);
|
||||
- memcpy(dst, src, prop->info->size);
|
||||
+ qdev_prop_cpy(dev, prop, src);
|
||||
}
|
||||
|
||||
void qdev_prop_set_uint8(DeviceState *dev, const char *name, uint8_t value)
|
||||
@@ -585,14 +636,11 @@ void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value)
|
||||
|
||||
void qdev_prop_set_defaults(DeviceState *dev, Property *props)
|
||||
{
|
||||
- char *dst;
|
||||
-
|
||||
if (!props)
|
||||
return;
|
||||
while (props->name) {
|
||||
if (props->defval) {
|
||||
- dst = qdev_get_prop_ptr(dev, props);
|
||||
- memcpy(dst, props->defval, props->info->size);
|
||||
+ qdev_prop_cpy(dev, props, props->defval);
|
||||
}
|
||||
props++;
|
||||
}
|
||||
diff --git a/hw/qdev.h b/hw/qdev.h
|
||||
index bbcdba1..07b9603 100644
|
||||
--- a/hw/qdev.h
|
||||
+++ b/hw/qdev.h
|
||||
@@ -64,6 +64,7 @@ struct Property {
|
||||
const char *name;
|
||||
PropertyInfo *info;
|
||||
int offset;
|
||||
+ int bitnr;
|
||||
void *defval;
|
||||
};
|
||||
|
||||
@@ -82,6 +83,7 @@ enum PropertyType {
|
||||
PROP_TYPE_NETDEV,
|
||||
PROP_TYPE_VLAN,
|
||||
PROP_TYPE_PTR,
|
||||
+ PROP_TYPE_BIT,
|
||||
};
|
||||
|
||||
struct PropertyInfo {
|
||||
@@ -173,6 +175,7 @@ void do_device_del(Monitor *mon, const QDict *qdict);
|
||||
|
||||
/*** qdev-properties.c ***/
|
||||
|
||||
+extern PropertyInfo qdev_prop_bit;
|
||||
extern PropertyInfo qdev_prop_uint8;
|
||||
extern PropertyInfo qdev_prop_uint16;
|
||||
extern PropertyInfo qdev_prop_uint32;
|
||||
@@ -202,6 +205,14 @@ extern PropertyInfo qdev_prop_pci_devfn;
|
||||
+ type_check(_type,typeof_field(_state, _field)), \
|
||||
.defval = (_type[]) { _defval }, \
|
||||
}
|
||||
+#define DEFINE_PROP_BIT(_name, _state, _field, _bit, _defval) { \
|
||||
+ .name = (_name), \
|
||||
+ .info = &(qdev_prop_bit), \
|
||||
+ .bitnr = (_bit), \
|
||||
+ .offset = offsetof(_state, _field) \
|
||||
+ + type_check(uint32_t,typeof_field(_state, _field)), \
|
||||
+ .defval = (bool[]) { (_defval) }, \
|
||||
+ }
|
||||
|
||||
#define DEFINE_PROP_UINT8(_n, _s, _f, _d) \
|
||||
DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint8, uint8_t)
|
||||
--
|
||||
1.6.6.144.g5c3af
|
|
@ -0,0 +1,24 @@
|
|||
Without this fix, guest crashes with drive=virtio.
|
||||
|
||||
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
|
||||
(cherry picked from commit dbd483242c2e6dfaacb9fd3d20c333bbdad87243)
|
||||
---
|
||||
hw/qdev-properties.c | 2 +-
|
||||
1 files changed, 1 insertions(+), 1 deletions(-)
|
||||
|
||||
diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c
|
||||
index 9e123ae..277ff9e 100644
|
||||
--- a/hw/qdev-properties.c
|
||||
+++ b/hw/qdev-properties.c
|
||||
@@ -20,7 +20,7 @@ static void bit_prop_set(DeviceState *dev, Property *props, bool val)
|
||||
uint32_t *p = qdev_get_prop_ptr(dev, props);
|
||||
uint32_t mask = qdev_get_prop_mask(props);
|
||||
if (val)
|
||||
- *p |= ~mask;
|
||||
+ *p |= mask;
|
||||
else
|
||||
*p &= ~mask;
|
||||
}
|
||||
--
|
||||
1.6.6.144.g5c3af
|
|
@ -0,0 +1,37 @@
|
|||
will be used by virtio-net for vhost net support
|
||||
|
||||
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
---
|
||||
net/tap.c | 7 +++++++
|
||||
net/tap.h | 3 +++
|
||||
2 files changed, 10 insertions(+), 0 deletions(-)
|
||||
|
||||
diff --git a/net/tap.c b/net/tap.c
|
||||
index d9f2e41..166cf05 100644
|
||||
--- a/net/tap.c
|
||||
+++ b/net/tap.c
|
||||
@@ -491,3 +491,10 @@ int net_init_tap(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan
|
||||
|
||||
return 0;
|
||||
}
|
||||
+
|
||||
+struct vhost_net *tap_get_vhost_net(VLANClientState *nc)
|
||||
+{
|
||||
+ TAPState *s = DO_UPCAST(TAPState, nc, nc);
|
||||
+ assert(nc->info->type == NET_CLIENT_TYPE_TAP);
|
||||
+ return s->vhost_net;
|
||||
+}
|
||||
diff --git a/net/tap.h b/net/tap.h
|
||||
index a244b28..b8cec83 100644
|
||||
--- a/net/tap.h
|
||||
+++ b/net/tap.h
|
||||
@@ -50,4 +50,7 @@ void tap_fd_set_offload(int fd, int csum, int tso4, int tso6, int ecn, int ufo);
|
||||
|
||||
int tap_get_fd(VLANClientState *vc);
|
||||
|
||||
+struct vhost_net;
|
||||
+struct vhost_net *tap_get_vhost_net(VLANClientState *vc);
|
||||
+
|
||||
#endif /* QEMU_NET_TAP_H */
|
||||
--
|
||||
1.6.6.144.g5c3af
|
|
@ -0,0 +1,39 @@
|
|||
Will be used by vhost to attach/detach to backend.
|
||||
|
||||
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
---
|
||||
net/tap.c | 7 +++++++
|
||||
net/tap.h | 2 ++
|
||||
2 files changed, 9 insertions(+), 0 deletions(-)
|
||||
|
||||
diff --git a/net/tap.c b/net/tap.c
|
||||
index d3492de..7e9ca79 100644
|
||||
--- a/net/tap.c
|
||||
+++ b/net/tap.c
|
||||
@@ -269,6 +269,13 @@ static void tap_poll(VLANClientState *nc, bool enable)
|
||||
tap_write_poll(s, enable);
|
||||
}
|
||||
|
||||
+int tap_get_fd(VLANClientState *nc)
|
||||
+{
|
||||
+ TAPState *s = DO_UPCAST(TAPState, nc, nc);
|
||||
+ assert(nc->info->type == NET_CLIENT_TYPE_TAP);
|
||||
+ return s->fd;
|
||||
+}
|
||||
+
|
||||
/* fd support */
|
||||
|
||||
static NetClientInfo net_tap_info = {
|
||||
diff --git a/net/tap.h b/net/tap.h
|
||||
index 538a562..a244b28 100644
|
||||
--- a/net/tap.h
|
||||
+++ b/net/tap.h
|
||||
@@ -48,4 +48,6 @@ int tap_probe_vnet_hdr(int fd);
|
||||
int tap_probe_has_ufo(int fd);
|
||||
void tap_fd_set_offload(int fd, int csum, int tso4, int tso6, int ecn, int ufo);
|
||||
|
||||
+int tap_get_fd(VLANClientState *vc);
|
||||
+
|
||||
#endif /* QEMU_NET_TAP_H */
|
||||
--
|
||||
1.6.6.144.g5c3af
|
|
@ -0,0 +1,118 @@
|
|||
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
---
|
||||
net.c | 8 ++++++++
|
||||
net/tap.c | 29 +++++++++++++++++++++++++++++
|
||||
qemu-options.hx | 4 +++-
|
||||
3 files changed, 40 insertions(+), 1 deletions(-)
|
||||
|
||||
diff --git a/net.c b/net.c
|
||||
index 6ef93e6..b942d03 100644
|
||||
--- a/net.c
|
||||
+++ b/net.c
|
||||
@@ -976,6 +976,14 @@ static struct {
|
||||
.name = "vnet_hdr",
|
||||
.type = QEMU_OPT_BOOL,
|
||||
.help = "enable the IFF_VNET_HDR flag on the tap interface"
|
||||
+ }, {
|
||||
+ .name = "vhost",
|
||||
+ .type = QEMU_OPT_BOOL,
|
||||
+ .help = "enable vhost-net network accelerator",
|
||||
+ }, {
|
||||
+ .name = "vhostfd",
|
||||
+ .type = QEMU_OPT_STRING,
|
||||
+ .help = "file descriptor of an already opened vhost net device",
|
||||
},
|
||||
#endif /* _WIN32 */
|
||||
{ /* end of list */ }
|
||||
diff --git a/net/tap.c b/net/tap.c
|
||||
index 7e9ca79..d9f2e41 100644
|
||||
--- a/net/tap.c
|
||||
+++ b/net/tap.c
|
||||
@@ -41,6 +41,8 @@
|
||||
|
||||
#include "net/tap-linux.h"
|
||||
|
||||
+#include "hw/vhost_net.h"
|
||||
+
|
||||
/* Maximum GSO packet size (64k) plus plenty of room for
|
||||
* the ethernet and virtio_net headers
|
||||
*/
|
||||
@@ -57,6 +59,7 @@ typedef struct TAPState {
|
||||
unsigned int has_vnet_hdr : 1;
|
||||
unsigned int using_vnet_hdr : 1;
|
||||
unsigned int has_ufo: 1;
|
||||
+ struct vhost_net *vhost_net;
|
||||
} TAPState;
|
||||
|
||||
static int launch_script(const char *setup_script, const char *ifname, int fd);
|
||||
@@ -252,6 +255,10 @@ static void tap_cleanup(VLANClientState *nc)
|
||||
{
|
||||
TAPState *s = DO_UPCAST(TAPState, nc, nc);
|
||||
|
||||
+ if (s->vhost_net) {
|
||||
+ vhost_net_cleanup(s->vhost_net);
|
||||
+ }
|
||||
+
|
||||
qemu_purge_queued_packets(nc);
|
||||
|
||||
if (s->down_script[0])
|
||||
@@ -307,6 +314,7 @@ static TAPState *net_tap_fd_init(VLANState *vlan,
|
||||
s->has_ufo = tap_probe_has_ufo(s->fd);
|
||||
tap_set_offload(&s->nc, 0, 0, 0, 0, 0);
|
||||
tap_read_poll(s, 1);
|
||||
+ s->vhost_net = NULL;
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -456,6 +464,27 @@ int net_init_tap(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan
|
||||
}
|
||||
}
|
||||
|
||||
+ if (qemu_opt_get_bool(opts, "vhost", 0)) {
|
||||
+ int vhostfd, r;
|
||||
+ if (qemu_opt_get(opts, "vhostfd")) {
|
||||
+ r = net_handle_fd_param(mon, qemu_opt_get(opts, "vhostfd"));
|
||||
+ if (r == -1) {
|
||||
+ return -1;
|
||||
+ }
|
||||
+ vhostfd = r;
|
||||
+ } else {
|
||||
+ vhostfd = -1;
|
||||
+ }
|
||||
+ s->vhost_net = vhost_net_init(&s->nc, vhostfd);
|
||||
+ if (!s->vhost_net) {
|
||||
+ qemu_error("vhost-net requested but could not be initialized\n");
|
||||
+ return -1;
|
||||
+ }
|
||||
+ } else if (qemu_opt_get(opts, "vhostfd")) {
|
||||
+ qemu_error("vhostfd= is not valid without vhost\n");
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
if (vlan) {
|
||||
vlan->nb_host_devs++;
|
||||
}
|
||||
diff --git a/qemu-options.hx b/qemu-options.hx
|
||||
index ca73ba5..2b3d9b8 100644
|
||||
--- a/qemu-options.hx
|
||||
+++ b/qemu-options.hx
|
||||
@@ -814,7 +814,7 @@ DEF("net", HAS_ARG, QEMU_OPTION_net,
|
||||
"-net tap[,vlan=n][,name=str],ifname=name\n"
|
||||
" connect the host TAP network interface to VLAN 'n'\n"
|
||||
#else
|
||||
- "-net tap[,vlan=n][,name=str][,fd=h][,ifname=name][,script=file][,downscript=dfile][,sndbuf=nbytes][,vnet_hdr=on|off]\n"
|
||||
+ "-net tap[,vlan=n][,name=str][,fd=h][,ifname=name][,script=file][,downscript=dfile][,sndbuf=nbytes][,vnet_hdr=on|off][,vhost=on|off][,vhostfd=h]\n"
|
||||
" connect the host TAP network interface to VLAN 'n' and use the\n"
|
||||
" network scripts 'file' (default=%s)\n"
|
||||
" and 'dfile' (default=%s);\n"
|
||||
@@ -824,6 +824,8 @@ DEF("net", HAS_ARG, QEMU_OPTION_net,
|
||||
" default of 'sndbuf=1048576' can be disabled using 'sndbuf=0'\n"
|
||||
" use vnet_hdr=off to avoid enabling the IFF_VNET_HDR tap flag; use\n"
|
||||
" vnet_hdr=on to make the lack of IFF_VNET_HDR support an error condition\n"
|
||||
+ " use vhost=on to enable experimental in kernel accelerator\n"
|
||||
+ " use 'vhostfd=h' to connect to an already opened vhost net device\n"
|
||||
#endif
|
||||
"-net socket[,vlan=n][,name=str][,fd=h][,listen=[host]:port][,connect=host:port]\n"
|
||||
" connect the vlan 'n' to another VLAN using a socket connection\n"
|
||||
--
|
||||
1.6.6.144.g5c3af
|
|
@ -0,0 +1,118 @@
|
|||
Teach configure to check for vhost.h
|
||||
and disable vhost_net if not present.
|
||||
|
||||
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>'
|
||||
|
||||
---
|
||||
|
||||
diff --git a/Makefile.target b/Makefile.target
|
||||
index 2ebd30c..38783da 100644
|
||||
--- a/Makefile.target
|
||||
+++ b/Makefile.target
|
||||
@@ -168,7 +168,8 @@ obj-y = vl.o async.o monitor.o pci.o pci_host.o pcie_host.o machine.o gdbstub.o
|
||||
# need to fix this properly
|
||||
obj-y += virtio-blk.o virtio-balloon.o virtio-net.o virtio-pci.o virtio-serial-bus.o
|
||||
obj-y += notifier.o
|
||||
-obj-y += vhost_net.o vhost.o
|
||||
+obj-y += vhost_net.o
|
||||
+obj-$(CONFIG_VHOST_NET) += vhost.o
|
||||
obj-$(CONFIG_KVM) += kvm.o kvm-all.o
|
||||
# MSI-X depends on kvm for interrupt injection,
|
||||
# so moved it from Makefile.hw to Makefile.target for now
|
||||
diff --git a/configure b/configure
|
||||
index 88ba002..4994506 100755
|
||||
--- a/configure
|
||||
+++ b/configure
|
||||
@@ -1510,6 +1510,23 @@ EOF
|
||||
fi
|
||||
|
||||
##########################################
|
||||
+# test for vhost net
|
||||
+
|
||||
+if test "$kvm" != "no"; then
|
||||
+ cat > $TMPC <<EOF
|
||||
+#include <linux/vhost.h>
|
||||
+int main(void) { return 0; }
|
||||
+EOF
|
||||
+ if compile_prog "$kvm_cflags" "" ; then
|
||||
+ vhost_net=yes
|
||||
+ else
|
||||
+ vhost_net=no
|
||||
+ fi
|
||||
+else
|
||||
+ vhost_net=no
|
||||
+fi
|
||||
+
|
||||
+##########################################
|
||||
# libpci probe for kvm_cap_device_assignment
|
||||
if test $kvm_cap_device_assignment = "yes" ; then
|
||||
cat > $TMPC << EOF
|
||||
@@ -2058,6 +2075,7 @@ echo "fdt support $fdt"
|
||||
echo "preadv support $preadv"
|
||||
echo "fdatasync $fdatasync"
|
||||
echo "uuid support $uuid"
|
||||
+echo "vhost-net support $vhost_net"
|
||||
|
||||
if test $sdl_too_old = "yes"; then
|
||||
echo "-> Your SDL version is too old - please upgrade to have SDL support"
|
||||
@@ -2593,6 +2611,9 @@ case "$target_arch2" in
|
||||
if test $kvm_cap_device_assignment = "yes" ; then
|
||||
echo "CONFIG_KVM_DEVICE_ASSIGNMENT=y" >> $config_target_mak
|
||||
fi
|
||||
+ if test $vhost_net = "yes" ; then
|
||||
+ echo "CONFIG_VHOST_NET=y" >> $config_target_mak
|
||||
+ fi
|
||||
fi
|
||||
esac
|
||||
echo "TARGET_PHYS_ADDR_BITS=$target_phys_bits" >> $config_target_mak
|
||||
diff --git a/hw/vhost_net.c b/hw/vhost_net.c
|
||||
index c89ff40..cab9a0a 100644
|
||||
--- a/hw/vhost_net.c
|
||||
+++ b/hw/vhost_net.c
|
||||
@@ -16,9 +16,13 @@
|
||||
#include "net/tap.h"
|
||||
|
||||
#include "virtio-net.h"
|
||||
-#include "vhost.h"
|
||||
#include "vhost_net.h"
|
||||
|
||||
+#include "config.h"
|
||||
+
|
||||
+#ifdef CONFIG_VHOST_NET
|
||||
+#include "vhost.h"
|
||||
+
|
||||
struct vhost_net {
|
||||
struct vhost_dev dev;
|
||||
struct vhost_virtqueue vqs[2];
|
||||
@@ -145,3 +149,31 @@ void vhost_net_cleanup(struct vhost_net *net)
|
||||
qemu_free(net);
|
||||
}
|
||||
/* TODO: log */
|
||||
+#else
|
||||
+struct vhost_net *vhost_net_init(VLANClientState *backend, int devfd)
|
||||
+{
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+int vhost_net_start(struct vhost_net *net,
|
||||
+ VirtIODevice *dev)
|
||||
+{
|
||||
+ return -ENOSYS;
|
||||
+}
|
||||
+void vhost_net_stop(struct vhost_net *net,
|
||||
+ VirtIODevice *dev)
|
||||
+{
|
||||
+}
|
||||
+
|
||||
+void vhost_net_cleanup(struct vhost_net *net)
|
||||
+{
|
||||
+}
|
||||
+
|
||||
+unsigned vhost_net_get_features(struct vhost_net *net, unsigned features)
|
||||
+{
|
||||
+ return features;
|
||||
+}
|
||||
+void vhost_net_ack_features(struct vhost_net *net, unsigned features)
|
||||
+{
|
||||
+}
|
||||
+#endif
|
|
@ -0,0 +1,869 @@
|
|||
This adds vhost net support in qemu. Will be tied to tap device and
|
||||
virtio by following patches. Raw backend is currently missing, will be
|
||||
worked on/submitted separately.
|
||||
|
||||
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
---
|
||||
Makefile.target | 1 +
|
||||
hw/vhost.c | 603 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
hw/vhost.h | 44 ++++
|
||||
hw/vhost_net.c | 147 ++++++++++++++
|
||||
hw/vhost_net.h | 20 ++
|
||||
5 files changed, 815 insertions(+), 0 deletions(-)
|
||||
create mode 100644 hw/vhost.c
|
||||
create mode 100644 hw/vhost.h
|
||||
create mode 100644 hw/vhost_net.c
|
||||
create mode 100644 hw/vhost_net.h
|
||||
|
||||
diff --git a/Makefile.target b/Makefile.target
|
||||
index 0c844a9..2ebd30c 100644
|
||||
--- a/Makefile.target
|
||||
+++ b/Makefile.target
|
||||
@@ -168,6 +168,7 @@ obj-y = vl.o async.o monitor.o pci.o pci_host.o pcie_host.o machine.o gdbstub.o
|
||||
# need to fix this properly
|
||||
obj-y += virtio-blk.o virtio-balloon.o virtio-net.o virtio-pci.o virtio-serial-bus.o
|
||||
obj-y += notifier.o
|
||||
+obj-y += vhost_net.o vhost.o
|
||||
obj-$(CONFIG_KVM) += kvm.o kvm-all.o
|
||||
# MSI-X depends on kvm for interrupt injection,
|
||||
# so moved it from Makefile.hw to Makefile.target for now
|
||||
diff --git a/hw/vhost.c b/hw/vhost.c
|
||||
new file mode 100644
|
||||
index 0000000..e5c1ead
|
||||
--- /dev/null
|
||||
+++ b/hw/vhost.c
|
||||
@@ -0,0 +1,603 @@
|
||||
+#include "linux/vhost.h"
|
||||
+#include <sys/ioctl.h>
|
||||
+#include <sys/eventfd.h>
|
||||
+#include "vhost.h"
|
||||
+#include "hw/hw.h"
|
||||
+/* For range_get_last */
|
||||
+#include "pci.h"
|
||||
+
|
||||
+static void vhost_dev_sync_region(struct vhost_dev *dev,
|
||||
+ uint64_t mfirst, uint64_t mlast,
|
||||
+ uint64_t rfirst, uint64_t rlast)
|
||||
+{
|
||||
+ uint64_t start = MAX(mfirst, rfirst);
|
||||
+ uint64_t end = MIN(mlast, rlast);
|
||||
+ vhost_log_chunk_t *from = dev->log + start / VHOST_LOG_CHUNK;
|
||||
+ vhost_log_chunk_t *to = dev->log + end / VHOST_LOG_CHUNK + 1;
|
||||
+ uint64_t addr = (start / VHOST_LOG_CHUNK) * VHOST_LOG_CHUNK;
|
||||
+
|
||||
+ assert(end / VHOST_LOG_CHUNK < dev->log_size);
|
||||
+ assert(start / VHOST_LOG_CHUNK < dev->log_size);
|
||||
+ if (end < start) {
|
||||
+ return;
|
||||
+ }
|
||||
+ for (;from < to; ++from) {
|
||||
+ vhost_log_chunk_t log;
|
||||
+ int bit;
|
||||
+ /* We first check with non-atomic: much cheaper,
|
||||
+ * and we expect non-dirty to be the common case. */
|
||||
+ if (!*from) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ /* Data must be read atomically. We don't really
|
||||
+ * need the barrier semantics of __sync
|
||||
+ * builtins, but it's easier to use them than
|
||||
+ * roll our own. */
|
||||
+ log = __sync_fetch_and_and(from, 0);
|
||||
+ while ((bit = sizeof(log) > sizeof(int) ?
|
||||
+ ffsll(log) : ffs(log))) {
|
||||
+ bit -= 1;
|
||||
+ cpu_physical_memory_set_dirty(addr + bit * VHOST_LOG_PAGE);
|
||||
+ log &= ~(0x1ull << bit);
|
||||
+ }
|
||||
+ addr += VHOST_LOG_CHUNK;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static int vhost_client_sync_dirty_bitmap(struct CPUPhysMemoryClient *client,
|
||||
+ target_phys_addr_t start_addr,
|
||||
+ target_phys_addr_t end_addr)
|
||||
+{
|
||||
+ struct vhost_dev *dev = container_of(client, struct vhost_dev, client);
|
||||
+ int i;
|
||||
+ if (!dev->log_enabled || !dev->started) {
|
||||
+ return 0;
|
||||
+ }
|
||||
+ for (i = 0; i < dev->mem->nregions; ++i) {
|
||||
+ struct vhost_memory_region *reg = dev->mem->regions + i;
|
||||
+ vhost_dev_sync_region(dev, start_addr, end_addr,
|
||||
+ reg->guest_phys_addr,
|
||||
+ range_get_last(reg->guest_phys_addr,
|
||||
+ reg->memory_size));
|
||||
+ }
|
||||
+ for (i = 0; i < dev->nvqs; ++i) {
|
||||
+ struct vhost_virtqueue *vq = dev->vqs + i;
|
||||
+ unsigned size = sizeof(struct vring_used_elem) * vq->num;
|
||||
+ vhost_dev_sync_region(dev, start_addr, end_addr, vq->used_phys,
|
||||
+ range_get_last(vq->used_phys, size));
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/* Assign/unassign. Keep an unsorted array of non-overlapping
|
||||
+ * memory regions in dev->mem. */
|
||||
+static void vhost_dev_unassign_memory(struct vhost_dev *dev,
|
||||
+ uint64_t start_addr,
|
||||
+ uint64_t size)
|
||||
+{
|
||||
+ int from, to, n = dev->mem->nregions;
|
||||
+ /* Track overlapping/split regions for sanity checking. */
|
||||
+ int overlap_start = 0, overlap_end = 0, overlap_middle = 0, split = 0;
|
||||
+
|
||||
+ for (from = 0, to = 0; from < n; ++from, ++to) {
|
||||
+ struct vhost_memory_region *reg = dev->mem->regions + to;
|
||||
+ uint64_t reglast;
|
||||
+ uint64_t memlast;
|
||||
+ uint64_t change;
|
||||
+
|
||||
+ /* clone old region */
|
||||
+ if (to != from) {
|
||||
+ memcpy(reg, dev->mem->regions + from, sizeof *reg);
|
||||
+ }
|
||||
+
|
||||
+ /* No overlap is simple */
|
||||
+ if (!ranges_overlap(reg->guest_phys_addr, reg->memory_size,
|
||||
+ start_addr, size)) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ /* Split only happens if supplied region
|
||||
+ * is in the middle of an existing one. Thus it can not
|
||||
+ * overlap with any other existing region. */
|
||||
+ assert(!split);
|
||||
+
|
||||
+ reglast = range_get_last(reg->guest_phys_addr, reg->memory_size);
|
||||
+ memlast = range_get_last(start_addr, size);
|
||||
+
|
||||
+ /* Remove whole region */
|
||||
+ if (start_addr <= reg->guest_phys_addr && memlast >= reglast) {
|
||||
+ --dev->mem->nregions;
|
||||
+ --to;
|
||||
+ assert(to >= 0);
|
||||
+ ++overlap_middle;
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ /* Shrink region */
|
||||
+ if (memlast >= reglast) {
|
||||
+ reg->memory_size = start_addr - reg->guest_phys_addr;
|
||||
+ assert(reg->memory_size);
|
||||
+ assert(!overlap_end);
|
||||
+ ++overlap_end;
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ /* Shift region */
|
||||
+ if (start_addr <= reg->guest_phys_addr) {
|
||||
+ change = memlast + 1 - reg->guest_phys_addr;
|
||||
+ reg->memory_size -= change;
|
||||
+ reg->guest_phys_addr += change;
|
||||
+ reg->userspace_addr += change;
|
||||
+ assert(reg->memory_size);
|
||||
+ assert(!overlap_start);
|
||||
+ ++overlap_start;
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ /* This only happens if supplied region
|
||||
+ * is in the middle of an existing one. Thus it can not
|
||||
+ * overlap with any other existing region. */
|
||||
+ assert(!overlap_start);
|
||||
+ assert(!overlap_end);
|
||||
+ assert(!overlap_middle);
|
||||
+ /* Split region: shrink first part, shift second part. */
|
||||
+ memcpy(dev->mem->regions + n, reg, sizeof *reg);
|
||||
+ reg->memory_size = start_addr - reg->guest_phys_addr;
|
||||
+ assert(reg->memory_size);
|
||||
+ change = memlast + 1 - reg->guest_phys_addr;
|
||||
+ reg = dev->mem->regions + n;
|
||||
+ reg->memory_size -= change;
|
||||
+ assert(reg->memory_size);
|
||||
+ reg->guest_phys_addr += change;
|
||||
+ reg->userspace_addr += change;
|
||||
+ /* Never add more than 1 region */
|
||||
+ assert(dev->mem->nregions == n);
|
||||
+ ++dev->mem->nregions;
|
||||
+ ++split;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/* Called after unassign, so no regions overlap the given range. */
|
||||
+static void vhost_dev_assign_memory(struct vhost_dev *dev,
|
||||
+ uint64_t start_addr,
|
||||
+ uint64_t size,
|
||||
+ uint64_t uaddr)
|
||||
+{
|
||||
+ int from, to;
|
||||
+ struct vhost_memory_region *merged = NULL;
|
||||
+ for (from = 0, to = 0; from < dev->mem->nregions; ++from, ++to) {
|
||||
+ struct vhost_memory_region *reg = dev->mem->regions + to;
|
||||
+ uint64_t prlast, urlast;
|
||||
+ uint64_t pmlast, umlast;
|
||||
+ uint64_t s, e, u;
|
||||
+
|
||||
+ /* clone old region */
|
||||
+ if (to != from) {
|
||||
+ memcpy(reg, dev->mem->regions + from, sizeof *reg);
|
||||
+ }
|
||||
+ prlast = range_get_last(reg->guest_phys_addr, reg->memory_size);
|
||||
+ pmlast = range_get_last(start_addr, size);
|
||||
+ urlast = range_get_last(reg->userspace_addr, reg->memory_size);
|
||||
+ umlast = range_get_last(uaddr, size);
|
||||
+
|
||||
+ /* check for overlapping regions: should never happen. */
|
||||
+ assert(prlast < start_addr || pmlast < reg->guest_phys_addr);
|
||||
+ /* Not an adjacent or overlapping region - do not merge. */
|
||||
+ if ((prlast + 1 != start_addr || urlast + 1 != uaddr) &&
|
||||
+ (pmlast + 1 != reg->guest_phys_addr ||
|
||||
+ umlast + 1 != reg->userspace_addr)) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (merged) {
|
||||
+ --to;
|
||||
+ assert(to >= 0);
|
||||
+ } else {
|
||||
+ merged = reg;
|
||||
+ }
|
||||
+ u = MIN(uaddr, reg->userspace_addr);
|
||||
+ s = MIN(start_addr, reg->guest_phys_addr);
|
||||
+ e = MAX(pmlast, prlast);
|
||||
+ uaddr = merged->userspace_addr = u;
|
||||
+ start_addr = merged->guest_phys_addr = s;
|
||||
+ size = merged->memory_size = e - s + 1;
|
||||
+ assert(merged->memory_size);
|
||||
+ }
|
||||
+
|
||||
+ if (!merged) {
|
||||
+ struct vhost_memory_region *reg = dev->mem->regions + to;
|
||||
+ memset(reg, 0, sizeof *reg);
|
||||
+ reg->memory_size = size;
|
||||
+ assert(reg->memory_size);
|
||||
+ reg->guest_phys_addr = start_addr;
|
||||
+ reg->userspace_addr = uaddr;
|
||||
+ ++to;
|
||||
+ }
|
||||
+ assert(to <= dev->mem->nregions + 1);
|
||||
+ dev->mem->nregions = to;
|
||||
+}
|
||||
+
|
||||
+static uint64_t vhost_get_log_size(struct vhost_dev *dev)
|
||||
+{
|
||||
+ uint64_t log_size = 0;
|
||||
+ int i;
|
||||
+ for (i = 0; i < dev->mem->nregions; ++i) {
|
||||
+ struct vhost_memory_region *reg = dev->mem->regions + i;
|
||||
+ uint64_t last = range_get_last(reg->guest_phys_addr,
|
||||
+ reg->memory_size);
|
||||
+ log_size = MAX(log_size, last / VHOST_LOG_CHUNK + 1);
|
||||
+ }
|
||||
+ for (i = 0; i < dev->nvqs; ++i) {
|
||||
+ struct vhost_virtqueue *vq = dev->vqs + i;
|
||||
+ uint64_t last = vq->used_phys +
|
||||
+ sizeof(struct vring_used_elem) * vq->num - 1;
|
||||
+ log_size = MAX(log_size, last / VHOST_LOG_CHUNK + 1);
|
||||
+ }
|
||||
+ return log_size;
|
||||
+}
|
||||
+
|
||||
+static inline void vhost_dev_log_resize(struct vhost_dev* dev, uint64_t size)
|
||||
+{
|
||||
+ vhost_log_chunk_t *log;
|
||||
+ int r;
|
||||
+ if (size) {
|
||||
+ log = qemu_mallocz(size * sizeof *log);
|
||||
+ } else {
|
||||
+ log = NULL;
|
||||
+ }
|
||||
+ r = ioctl(dev->control, VHOST_SET_LOG_BASE,
|
||||
+ (uint64_t)(unsigned long)log);
|
||||
+ assert(r >= 0);
|
||||
+ vhost_client_sync_dirty_bitmap(&dev->client, 0,
|
||||
+ (target_phys_addr_t)~0x0ull);
|
||||
+ if (dev->log) {
|
||||
+ qemu_free(dev->log);
|
||||
+ }
|
||||
+ dev->log = log;
|
||||
+ dev->log_size = size;
|
||||
+}
|
||||
+
|
||||
+static void vhost_client_set_memory(CPUPhysMemoryClient *client,
|
||||
+ target_phys_addr_t start_addr,
|
||||
+ ram_addr_t size,
|
||||
+ ram_addr_t phys_offset)
|
||||
+{
|
||||
+ struct vhost_dev *dev = container_of(client, struct vhost_dev, client);
|
||||
+ ram_addr_t flags = phys_offset & ~TARGET_PAGE_MASK;
|
||||
+ int s = offsetof(struct vhost_memory, regions) +
|
||||
+ (dev->mem->nregions + 1) * sizeof dev->mem->regions[0];
|
||||
+ uint64_t log_size;
|
||||
+ int r;
|
||||
+ dev->mem = qemu_realloc(dev->mem, s);
|
||||
+
|
||||
+ assert(size);
|
||||
+
|
||||
+ vhost_dev_unassign_memory(dev, start_addr, size);
|
||||
+ if (flags == IO_MEM_RAM) {
|
||||
+ /* Add given mapping, merging adjacent regions if any */
|
||||
+ vhost_dev_assign_memory(dev, start_addr, size,
|
||||
+ (uintptr_t)qemu_get_ram_ptr(phys_offset));
|
||||
+ } else {
|
||||
+ /* Remove old mapping for this memory, if any. */
|
||||
+ vhost_dev_unassign_memory(dev, start_addr, size);
|
||||
+ }
|
||||
+
|
||||
+ if (!dev->started) {
|
||||
+ return;
|
||||
+ }
|
||||
+ if (!dev->log_enabled) {
|
||||
+ r = ioctl(dev->control, VHOST_SET_MEM_TABLE, dev->mem);
|
||||
+ assert(r >= 0);
|
||||
+ return;
|
||||
+ }
|
||||
+ log_size = vhost_get_log_size(dev);
|
||||
+ /* We allocate an extra 4K bytes to log,
|
||||
+ * to reduce the * number of reallocations. */
|
||||
+#define VHOST_LOG_BUFFER (0x1000 / sizeof *dev->log)
|
||||
+ /* To log more, must increase log size before table update. */
|
||||
+ if (dev->log_size < log_size) {
|
||||
+ vhost_dev_log_resize(dev, log_size + VHOST_LOG_BUFFER);
|
||||
+ }
|
||||
+ r = ioctl(dev->control, VHOST_SET_MEM_TABLE, dev->mem);
|
||||
+ assert(r >= 0);
|
||||
+ /* To log less, can only decrease log size after table update. */
|
||||
+ if (dev->log_size > log_size + VHOST_LOG_BUFFER) {
|
||||
+ vhost_dev_log_resize(dev, log_size);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static int vhost_dev_set_log(struct vhost_dev *dev, bool enable_log)
|
||||
+{
|
||||
+ uint64_t features = dev->acked_features;
|
||||
+ int r;
|
||||
+ if (dev->log_enabled) {
|
||||
+ features |= 0x1 << VHOST_F_LOG_ALL;
|
||||
+ }
|
||||
+ r = ioctl(dev->control, VHOST_SET_FEATURES, &features);
|
||||
+ return r < 0 ? -errno : 0;
|
||||
+}
|
||||
+
|
||||
+static int vhost_client_migration_log(struct CPUPhysMemoryClient *client,
|
||||
+ int enable)
|
||||
+{
|
||||
+ struct vhost_dev *dev = container_of(client, struct vhost_dev, client);
|
||||
+ int r;
|
||||
+ if (!!enable == dev->log_enabled) {
|
||||
+ return 0;
|
||||
+ }
|
||||
+ if (!dev->started) {
|
||||
+ dev->log_enabled = enable;
|
||||
+ return 0;
|
||||
+ }
|
||||
+ if (!enable) {
|
||||
+ r = vhost_dev_set_log(dev, false);
|
||||
+ if (r < 0) {
|
||||
+ return r;
|
||||
+ }
|
||||
+ if (dev->log) {
|
||||
+ qemu_free(dev->log);
|
||||
+ }
|
||||
+ dev->log = NULL;
|
||||
+ dev->log_size = 0;
|
||||
+ } else {
|
||||
+ vhost_dev_log_resize(dev, vhost_get_log_size(dev));
|
||||
+ r = vhost_dev_set_log(dev, false);
|
||||
+ if (r < 0) {
|
||||
+ return r;
|
||||
+ }
|
||||
+ }
|
||||
+ dev->log_enabled = enable;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int vhost_virtqueue_set_addr(struct vhost_dev *dev,
|
||||
+ struct vhost_virtqueue *vq,
|
||||
+ unsigned idx, bool enable_log)
|
||||
+{
|
||||
+ struct vhost_vring_addr addr = {
|
||||
+ .index = idx,
|
||||
+ .desc_user_addr = (u_int64_t)(unsigned long)vq->desc,
|
||||
+ .avail_user_addr = (u_int64_t)(unsigned long)vq->avail,
|
||||
+ .used_user_addr = (u_int64_t)(unsigned long)vq->used,
|
||||
+ .log_guest_addr = vq->used_phys,
|
||||
+ .flags = enable_log ? (1 << VHOST_VRING_F_LOG) : 0,
|
||||
+ };
|
||||
+ int r = ioctl(dev->control, VHOST_SET_VRING_ADDR, &addr);
|
||||
+ if (r < 0) {
|
||||
+ return -errno;
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int vhost_virtqueue_init(struct vhost_dev *dev,
|
||||
+ struct VirtIODevice *vdev,
|
||||
+ struct vhost_virtqueue *vq,
|
||||
+ unsigned idx)
|
||||
+{
|
||||
+ target_phys_addr_t s, l, a;
|
||||
+ int r;
|
||||
+ struct vhost_vring_file file = {
|
||||
+ .index = idx,
|
||||
+ };
|
||||
+ struct vhost_vring_state state = {
|
||||
+ .index = idx,
|
||||
+ };
|
||||
+ struct VirtQueue *q = virtio_queue(vdev, idx);
|
||||
+
|
||||
+ vq->num = state.num = virtio_queue_get_num(vdev, idx);
|
||||
+ r = ioctl(dev->control, VHOST_SET_VRING_NUM, &state);
|
||||
+ if (r) {
|
||||
+ return -errno;
|
||||
+ }
|
||||
+
|
||||
+ state.num = virtio_queue_last_avail_idx(vdev, idx);
|
||||
+ r = ioctl(dev->control, VHOST_SET_VRING_BASE, &state);
|
||||
+ if (r) {
|
||||
+ return -errno;
|
||||
+ }
|
||||
+
|
||||
+ s = l = sizeof(struct vring_desc) * vq->num;
|
||||
+ a = virtio_queue_get_desc(vdev, idx);
|
||||
+ vq->desc = cpu_physical_memory_map(a, &l, 0);
|
||||
+ if (!vq->desc || l != s) {
|
||||
+ r = -ENOMEM;
|
||||
+ goto fail_alloc;
|
||||
+ }
|
||||
+ s = l = offsetof(struct vring_avail, ring) +
|
||||
+ sizeof(u_int64_t) * vq->num;
|
||||
+ a = virtio_queue_get_avail(vdev, idx);
|
||||
+ vq->avail = cpu_physical_memory_map(a, &l, 0);
|
||||
+ if (!vq->avail || l != s) {
|
||||
+ r = -ENOMEM;
|
||||
+ goto fail_alloc;
|
||||
+ }
|
||||
+ s = l = offsetof(struct vring_used, ring) +
|
||||
+ sizeof(struct vring_used_elem) * vq->num;
|
||||
+ vq->used_phys = a = virtio_queue_get_used(vdev, idx);
|
||||
+ vq->used = cpu_physical_memory_map(a, &l, 1);
|
||||
+ if (!vq->used || l != s) {
|
||||
+ r = -ENOMEM;
|
||||
+ goto fail_alloc;
|
||||
+ }
|
||||
+
|
||||
+ r = vhost_virtqueue_set_addr(dev, vq, idx, dev->log_enabled);
|
||||
+ if (r < 0) {
|
||||
+ r = -errno;
|
||||
+ goto fail_alloc;
|
||||
+ }
|
||||
+ if (!vdev->binding->guest_notifier || !vdev->binding->host_notifier) {
|
||||
+ fprintf(stderr, "binding does not support irqfd/queuefd\n");
|
||||
+ r = -ENOSYS;
|
||||
+ goto fail_alloc;
|
||||
+ }
|
||||
+ r = vdev->binding->guest_notifier(vdev->binding_opaque, idx, true);
|
||||
+ if (r < 0) {
|
||||
+ fprintf(stderr, "Error binding guest notifier: %d\n", -r);
|
||||
+ goto fail_guest_notifier;
|
||||
+ }
|
||||
+
|
||||
+ r = vdev->binding->host_notifier(vdev->binding_opaque, idx, true);
|
||||
+ if (r < 0) {
|
||||
+ fprintf(stderr, "Error binding host notifier: %d\n", -r);
|
||||
+ goto fail_host_notifier;
|
||||
+ }
|
||||
+
|
||||
+ file.fd = event_notifier_get_fd(virtio_queue_host_notifier(q));
|
||||
+ r = ioctl(dev->control, VHOST_SET_VRING_KICK, &file);
|
||||
+ if (r) {
|
||||
+ goto fail_kick;
|
||||
+ }
|
||||
+
|
||||
+ file.fd = event_notifier_get_fd(virtio_queue_guest_notifier(q));
|
||||
+ r = ioctl(dev->control, VHOST_SET_VRING_CALL, &file);
|
||||
+ if (r) {
|
||||
+ goto fail_call;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+fail_call:
|
||||
+fail_kick:
|
||||
+ vdev->binding->host_notifier(vdev->binding_opaque, idx, false);
|
||||
+fail_host_notifier:
|
||||
+ vdev->binding->guest_notifier(vdev->binding_opaque, idx, false);
|
||||
+fail_guest_notifier:
|
||||
+fail_alloc:
|
||||
+ return r;
|
||||
+}
|
||||
+
|
||||
+static void vhost_virtqueue_cleanup(struct vhost_dev *dev,
|
||||
+ struct VirtIODevice *vdev,
|
||||
+ struct vhost_virtqueue *vq,
|
||||
+ unsigned idx)
|
||||
+{
|
||||
+ struct vhost_vring_state state = {
|
||||
+ .index = idx,
|
||||
+ };
|
||||
+ int r;
|
||||
+ r = vdev->binding->guest_notifier(vdev->binding_opaque, idx, false);
|
||||
+ if (r < 0) {
|
||||
+ fprintf(stderr, "vhost VQ %d guest cleanup failed: %d\n", idx, r);
|
||||
+ fflush(stderr);
|
||||
+ }
|
||||
+ assert (r >= 0);
|
||||
+
|
||||
+ r = vdev->binding->host_notifier(vdev->binding_opaque, idx, false);
|
||||
+ if (r < 0) {
|
||||
+ fprintf(stderr, "vhost VQ %d host cleanup failed: %d\n", idx, r);
|
||||
+ fflush(stderr);
|
||||
+ }
|
||||
+ assert (r >= 0);
|
||||
+ r = ioctl(dev->control, VHOST_GET_VRING_BASE, &state);
|
||||
+ if (r < 0) {
|
||||
+ fprintf(stderr, "vhost VQ %d ring restore failed: %d\n", idx, r);
|
||||
+ fflush(stderr);
|
||||
+ }
|
||||
+ virtio_queue_set_last_avail_idx(vdev, idx, state.num);
|
||||
+ assert (r >= 0);
|
||||
+}
|
||||
+
|
||||
+int vhost_dev_init(struct vhost_dev *hdev, int devfd)
|
||||
+{
|
||||
+ uint64_t features;
|
||||
+ int r;
|
||||
+ if (devfd >= 0) {
|
||||
+ hdev->control = devfd;
|
||||
+ } else {
|
||||
+ hdev->control = open("/dev/vhost-net", O_RDWR);
|
||||
+ if (hdev->control < 0)
|
||||
+ return -errno;
|
||||
+ }
|
||||
+ r = ioctl(hdev->control, VHOST_SET_OWNER, NULL);
|
||||
+ if (r < 0)
|
||||
+ goto fail;
|
||||
+
|
||||
+ r = ioctl(hdev->control, VHOST_GET_FEATURES, &features);
|
||||
+ if (r < 0)
|
||||
+ goto fail;
|
||||
+ hdev->features = features;
|
||||
+
|
||||
+ hdev->client.set_memory = vhost_client_set_memory;
|
||||
+ hdev->client.sync_dirty_bitmap = vhost_client_sync_dirty_bitmap;
|
||||
+ hdev->client.migration_log = vhost_client_migration_log;
|
||||
+ hdev->mem = qemu_mallocz(offsetof(struct vhost_memory, regions));
|
||||
+ hdev->log = NULL;
|
||||
+ hdev->log_size = 0;
|
||||
+ hdev->log_enabled = false;
|
||||
+ hdev->started = false;
|
||||
+ cpu_register_phys_memory_client(&hdev->client);
|
||||
+ return 0;
|
||||
+fail:
|
||||
+ r = -errno;
|
||||
+ close(hdev->control);
|
||||
+ return r;
|
||||
+}
|
||||
+
|
||||
+void vhost_dev_cleanup(struct vhost_dev *hdev)
|
||||
+{
|
||||
+ cpu_unregister_phys_memory_client(&hdev->client);
|
||||
+ qemu_free(hdev->mem);
|
||||
+ close(hdev->control);
|
||||
+}
|
||||
+
|
||||
+int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev)
|
||||
+{
|
||||
+ int i, r;
|
||||
+
|
||||
+ r = vhost_dev_set_log(hdev, hdev->log_enabled);
|
||||
+ if (r < 0)
|
||||
+ goto fail;
|
||||
+ r = ioctl(hdev->control, VHOST_SET_MEM_TABLE, hdev->mem);
|
||||
+ if (r < 0) {
|
||||
+ r = -errno;
|
||||
+ goto fail;
|
||||
+ }
|
||||
+ if (hdev->log_enabled) {
|
||||
+ hdev->log_size = vhost_get_log_size(hdev);
|
||||
+ hdev->log = hdev->log_size ?
|
||||
+ qemu_mallocz(hdev->log_size * sizeof *hdev->log) : NULL;
|
||||
+ r = ioctl(hdev->control, VHOST_SET_LOG_BASE,
|
||||
+ (uint64_t)(unsigned long)hdev->log);
|
||||
+ if (r < 0) {
|
||||
+ r = -errno;
|
||||
+ goto fail;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ for (i = 0; i < hdev->nvqs; ++i) {
|
||||
+ r = vhost_virtqueue_init(hdev,
|
||||
+ vdev,
|
||||
+ hdev->vqs + i,
|
||||
+ i);
|
||||
+ if (r < 0)
|
||||
+ goto fail_vq;
|
||||
+ }
|
||||
+ hdev->started = true;
|
||||
+
|
||||
+ return 0;
|
||||
+fail_vq:
|
||||
+ while (--i >= 0) {
|
||||
+ vhost_virtqueue_cleanup(hdev,
|
||||
+ vdev,
|
||||
+ hdev->vqs + i,
|
||||
+ i);
|
||||
+ }
|
||||
+fail:
|
||||
+ return r;
|
||||
+}
|
||||
+
|
||||
+void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev)
|
||||
+{
|
||||
+ int i;
|
||||
+ for (i = 0; i < hdev->nvqs; ++i) {
|
||||
+ vhost_virtqueue_cleanup(hdev,
|
||||
+ vdev,
|
||||
+ hdev->vqs + i,
|
||||
+ i);
|
||||
+ }
|
||||
+ vhost_client_sync_dirty_bitmap(&hdev->client, 0,
|
||||
+ (target_phys_addr_t)~0x0ull);
|
||||
+ hdev->started = false;
|
||||
+ qemu_free(hdev->log);
|
||||
+ hdev->log_size = 0;
|
||||
+}
|
||||
diff --git a/hw/vhost.h b/hw/vhost.h
|
||||
new file mode 100644
|
||||
index 0000000..2ed3933
|
||||
--- /dev/null
|
||||
+++ b/hw/vhost.h
|
||||
@@ -0,0 +1,44 @@
|
||||
+#ifndef VHOST_H
|
||||
+#define VHOST_H
|
||||
+
|
||||
+#include "hw/hw.h"
|
||||
+#include "hw/virtio.h"
|
||||
+
|
||||
+/* Generic structures common for any vhost based device. */
|
||||
+struct vhost_virtqueue {
|
||||
+ int kick;
|
||||
+ int call;
|
||||
+ void *desc;
|
||||
+ void *avail;
|
||||
+ void *used;
|
||||
+ int num;
|
||||
+ unsigned long long used_phys;
|
||||
+};
|
||||
+
|
||||
+typedef unsigned long vhost_log_chunk_t;
|
||||
+#define VHOST_LOG_PAGE 0x1000
|
||||
+#define VHOST_LOG_BITS (8 * sizeof(vhost_log_chunk_t))
|
||||
+#define VHOST_LOG_CHUNK (VHOST_LOG_PAGE * VHOST_LOG_BITS)
|
||||
+
|
||||
+struct vhost_memory;
|
||||
+struct vhost_dev {
|
||||
+ CPUPhysMemoryClient client;
|
||||
+ int control;
|
||||
+ struct vhost_memory *mem;
|
||||
+ struct vhost_virtqueue *vqs;
|
||||
+ int nvqs;
|
||||
+ unsigned long long features;
|
||||
+ unsigned long long acked_features;
|
||||
+ unsigned long long backend_features;
|
||||
+ bool started;
|
||||
+ bool log_enabled;
|
||||
+ vhost_log_chunk_t *log;
|
||||
+ unsigned long long log_size;
|
||||
+};
|
||||
+
|
||||
+int vhost_dev_init(struct vhost_dev *hdev, int devfd);
|
||||
+void vhost_dev_cleanup(struct vhost_dev *hdev);
|
||||
+int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev);
|
||||
+void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev);
|
||||
+
|
||||
+#endif
|
||||
diff --git a/hw/vhost_net.c b/hw/vhost_net.c
|
||||
new file mode 100644
|
||||
index 0000000..c89ff40
|
||||
--- /dev/null
|
||||
+++ b/hw/vhost_net.c
|
||||
@@ -0,0 +1,147 @@
|
||||
+#include <sys/eventfd.h>
|
||||
+#include <sys/socket.h>
|
||||
+#include <linux/kvm.h>
|
||||
+#include <fcntl.h>
|
||||
+#include <sys/ioctl.h>
|
||||
+#include <linux/vhost.h>
|
||||
+#include <linux/virtio_ring.h>
|
||||
+#include <netpacket/packet.h>
|
||||
+#include <net/ethernet.h>
|
||||
+#include <net/if.h>
|
||||
+#include <netinet/in.h>
|
||||
+
|
||||
+#include <stdio.h>
|
||||
+
|
||||
+#include "net.h"
|
||||
+#include "net/tap.h"
|
||||
+
|
||||
+#include "virtio-net.h"
|
||||
+#include "vhost.h"
|
||||
+#include "vhost_net.h"
|
||||
+
|
||||
+struct vhost_net {
|
||||
+ struct vhost_dev dev;
|
||||
+ struct vhost_virtqueue vqs[2];
|
||||
+ int backend;
|
||||
+ VLANClientState *vc;
|
||||
+};
|
||||
+
|
||||
+unsigned vhost_net_get_features(struct vhost_net *net, unsigned features)
|
||||
+{
|
||||
+ /* Clear features not supported by host kernel. */
|
||||
+ if (!(net->dev.features & (1 << VIRTIO_F_NOTIFY_ON_EMPTY)))
|
||||
+ features &= ~(1 << VIRTIO_F_NOTIFY_ON_EMPTY);
|
||||
+ if (!(net->dev.features & (1 << VIRTIO_RING_F_INDIRECT_DESC)))
|
||||
+ features &= ~(1 << VIRTIO_RING_F_INDIRECT_DESC);
|
||||
+ if (!(net->dev.features & (1 << VIRTIO_NET_F_MRG_RXBUF)))
|
||||
+ features &= ~(1 << VIRTIO_NET_F_MRG_RXBUF);
|
||||
+ return features;
|
||||
+}
|
||||
+
|
||||
+void vhost_net_ack_features(struct vhost_net *net, unsigned features)
|
||||
+{
|
||||
+ net->dev.acked_features = net->dev.backend_features;
|
||||
+ if (features & (1 << VIRTIO_F_NOTIFY_ON_EMPTY))
|
||||
+ net->dev.acked_features |= (1 << VIRTIO_F_NOTIFY_ON_EMPTY);
|
||||
+ if (features & (1 << VIRTIO_RING_F_INDIRECT_DESC))
|
||||
+ net->dev.acked_features |= (1 << VIRTIO_RING_F_INDIRECT_DESC);
|
||||
+}
|
||||
+
|
||||
+static int vhost_net_get_fd(VLANClientState *backend)
|
||||
+{
|
||||
+ switch (backend->info->type) {
|
||||
+ case NET_CLIENT_TYPE_TAP:
|
||||
+ return tap_get_fd(backend);
|
||||
+ default:
|
||||
+ fprintf(stderr, "vhost-net requires tap backend\n");
|
||||
+ return -EBADFD;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+struct vhost_net *vhost_net_init(VLANClientState *backend, int devfd)
|
||||
+{
|
||||
+ int r;
|
||||
+ struct vhost_net *net = qemu_malloc(sizeof *net);
|
||||
+ if (!backend) {
|
||||
+ fprintf(stderr, "vhost-net requires backend to be setup\n");
|
||||
+ goto fail;
|
||||
+ }
|
||||
+ r = vhost_net_get_fd(backend);
|
||||
+ if (r < 0)
|
||||
+ goto fail;
|
||||
+ net->vc = backend;
|
||||
+ net->dev.backend_features = tap_has_vnet_hdr(backend) ? 0 :
|
||||
+ (1 << VHOST_NET_F_VIRTIO_NET_HDR);
|
||||
+ net->backend = r;
|
||||
+
|
||||
+ r = vhost_dev_init(&net->dev, devfd);
|
||||
+ if (r < 0)
|
||||
+ goto fail;
|
||||
+ if (~net->dev.features & net->dev.backend_features) {
|
||||
+ fprintf(stderr, "vhost lacks feature mask %llu for backend\n",
|
||||
+ ~net->dev.features & net->dev.backend_features);
|
||||
+ vhost_dev_cleanup(&net->dev);
|
||||
+ goto fail;
|
||||
+ }
|
||||
+
|
||||
+ /* Set sane init value. Override when guest acks. */
|
||||
+ vhost_net_ack_features(net, 0);
|
||||
+ return net;
|
||||
+fail:
|
||||
+ qemu_free(net);
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+int vhost_net_start(struct vhost_net *net,
|
||||
+ VirtIODevice *dev)
|
||||
+{
|
||||
+ struct vhost_vring_file file = { };
|
||||
+ int r;
|
||||
+
|
||||
+ net->dev.nvqs = 2;
|
||||
+ net->dev.vqs = net->vqs;
|
||||
+ r = vhost_dev_start(&net->dev, dev);
|
||||
+ if (r < 0)
|
||||
+ return r;
|
||||
+
|
||||
+ net->vc->info->poll(net->vc, false);
|
||||
+ qemu_set_fd_handler(net->backend, NULL, NULL, NULL);
|
||||
+ file.fd = net->backend;
|
||||
+ for (file.index = 0; file.index < net->dev.nvqs; ++file.index) {
|
||||
+ r = ioctl(net->dev.control, VHOST_NET_SET_BACKEND, &file);
|
||||
+ if (r < 0) {
|
||||
+ r = -errno;
|
||||
+ goto fail;
|
||||
+ }
|
||||
+ }
|
||||
+ return 0;
|
||||
+fail:
|
||||
+ file.fd = -1;
|
||||
+ while (--file.index >= 0) {
|
||||
+ int r = ioctl(net->dev.control, VHOST_NET_SET_BACKEND, &file);
|
||||
+ assert(r >= 0);
|
||||
+ }
|
||||
+ net->vc->info->poll(net->vc, true);
|
||||
+ vhost_dev_stop(&net->dev, dev);
|
||||
+ return r;
|
||||
+}
|
||||
+
|
||||
+void vhost_net_stop(struct vhost_net *net,
|
||||
+ VirtIODevice *dev)
|
||||
+{
|
||||
+ struct vhost_vring_file file = { .fd = -1 };
|
||||
+
|
||||
+ for (file.index = 0; file.index < net->dev.nvqs; ++file.index) {
|
||||
+ int r = ioctl(net->dev.control, VHOST_NET_SET_BACKEND, &file);
|
||||
+ assert(r >= 0);
|
||||
+ }
|
||||
+ net->vc->info->poll(net->vc, true);
|
||||
+ vhost_dev_stop(&net->dev, dev);
|
||||
+}
|
||||
+
|
||||
+void vhost_net_cleanup(struct vhost_net *net)
|
||||
+{
|
||||
+ vhost_dev_cleanup(&net->dev);
|
||||
+ qemu_free(net);
|
||||
+}
|
||||
+/* TODO: log */
|
||||
diff --git a/hw/vhost_net.h b/hw/vhost_net.h
|
||||
new file mode 100644
|
||||
index 0000000..21f0277
|
||||
--- /dev/null
|
||||
+++ b/hw/vhost_net.h
|
||||
@@ -0,0 +1,20 @@
|
||||
+#ifndef VHOST_NET_H
|
||||
+#define VHOST_NET_H
|
||||
+
|
||||
+#include "net.h"
|
||||
+
|
||||
+struct vhost_net;
|
||||
+
|
||||
+struct vhost_net *vhost_net_init(VLANClientState *backend, int devfd);
|
||||
+
|
||||
+int vhost_net_start(struct vhost_net *net,
|
||||
+ VirtIODevice *dev);
|
||||
+void vhost_net_stop(struct vhost_net *net,
|
||||
+ VirtIODevice *dev);
|
||||
+
|
||||
+void vhost_net_cleanup(struct vhost_net *net);
|
||||
+
|
||||
+unsigned vhost_net_get_features(struct vhost_net *net, unsigned features);
|
||||
+void vhost_net_ack_features(struct vhost_net *net, unsigned features);
|
||||
+
|
||||
+#endif
|
||||
--
|
||||
1.6.6.144.g5c3af
|
|
@ -0,0 +1,111 @@
|
|||
vhost needs physical addresses for ring and other queue fields,
|
||||
so add APIs for these.
|
||||
|
||||
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
---
|
||||
hw/virtio.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++----
|
||||
hw/virtio.h | 10 +++++++++-
|
||||
2 files changed, 56 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/hw/virtio.c b/hw/virtio.c
|
||||
index c2b80aa..b16ee1a 100644
|
||||
--- a/hw/virtio.c
|
||||
+++ b/hw/virtio.c
|
||||
@@ -73,6 +73,9 @@ struct VirtQueue
|
||||
int inuse;
|
||||
uint16_t vector;
|
||||
void (*handle_output)(VirtIODevice *vdev, VirtQueue *vq);
|
||||
+ VirtIODevice *vdev;
|
||||
+ EventNotifier guest_notifier;
|
||||
+ EventNotifier host_notifier;
|
||||
};
|
||||
|
||||
/* virt queue functions */
|
||||
@@ -594,10 +597,10 @@ VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size,
|
||||
return &vdev->vq[i];
|
||||
}
|
||||
|
||||
-void virtio_irq(VirtIODevice *vdev, VirtQueue *vq)
|
||||
+void virtio_irq(VirtQueue *vq)
|
||||
{
|
||||
- vdev->isr |= 0x01;
|
||||
- virtio_notify_vector(vdev, vq->vector);
|
||||
+ vq->vdev->isr |= 0x01;
|
||||
+ virtio_notify_vector(vq->vdev, vq->vector);
|
||||
}
|
||||
|
||||
void virtio_notify(VirtIODevice *vdev, VirtQueue *vq)
|
||||
@@ -608,7 +611,8 @@ void virtio_notify(VirtIODevice *vdev, VirtQueue *vq)
|
||||
(vq->inuse || vring_avail_idx(vq) != vq->last_avail_idx)))
|
||||
return;
|
||||
|
||||
- virtio_irq(vdev, vq);
|
||||
+ vdev->isr |= 0x01;
|
||||
+ virtio_notify_vector(vdev, vq->vector);
|
||||
}
|
||||
|
||||
void virtio_notify_config(VirtIODevice *vdev)
|
||||
@@ -742,3 +746,42 @@ void virtio_bind_device(VirtIODevice *vdev, const VirtIOBindings *binding,
|
||||
vdev->binding = binding;
|
||||
vdev->binding_opaque = opaque;
|
||||
}
|
||||
+
|
||||
+target_phys_addr_t virtio_queue_get_desc(VirtIODevice *vdev, int n)
|
||||
+{
|
||||
+ return vdev->vq[n].vring.desc;
|
||||
+}
|
||||
+
|
||||
+target_phys_addr_t virtio_queue_get_avail(VirtIODevice *vdev, int n)
|
||||
+{
|
||||
+ return vdev->vq[n].vring.avail;
|
||||
+}
|
||||
+
|
||||
+target_phys_addr_t virtio_queue_get_used(VirtIODevice *vdev, int n)
|
||||
+{
|
||||
+ return vdev->vq[n].vring.used;
|
||||
+}
|
||||
+
|
||||
+uint16_t virtio_queue_last_avail_idx(VirtIODevice *vdev, int n)
|
||||
+{
|
||||
+ return vdev->vq[n].last_avail_idx;
|
||||
+}
|
||||
+
|
||||
+void virtio_queue_set_last_avail_idx(VirtIODevice *vdev, int n, uint16_t idx)
|
||||
+{
|
||||
+ vdev->vq[n].last_avail_idx = idx;
|
||||
+}
|
||||
+
|
||||
+VirtQueue *virtio_queue(VirtIODevice *vdev, int n)
|
||||
+{
|
||||
+ return vdev->vq + n;
|
||||
+}
|
||||
+
|
||||
+EventNotifier *virtio_queue_guest_notifier(VirtQueue *vq)
|
||||
+{
|
||||
+ return &vq->guest_notifier;
|
||||
+}
|
||||
+EventNotifier *virtio_queue_host_notifier(VirtQueue *vq)
|
||||
+{
|
||||
+ return &vq->host_notifier;
|
||||
+}
|
||||
diff --git a/hw/virtio.h b/hw/virtio.h
|
||||
index 10a0959..f140ca3 100644
|
||||
--- a/hw/virtio.h
|
||||
+++ b/hw/virtio.h
|
||||
@@ -183,5 +183,13 @@ void virtio_net_exit(VirtIODevice *vdev);
|
||||
DEFINE_PROP_BIT("indirect_desc", _state, _field, \
|
||||
VIRTIO_RING_F_INDIRECT_DESC, true)
|
||||
|
||||
-void virtio_irq(VirtIODevice *vdev, VirtQueue *vq);
|
||||
+target_phys_addr_t virtio_queue_get_desc(VirtIODevice *vdev, int n);
|
||||
+target_phys_addr_t virtio_queue_get_avail(VirtIODevice *vdev, int n);
|
||||
+target_phys_addr_t virtio_queue_get_used(VirtIODevice *vdev, int n);
|
||||
+uint16_t virtio_queue_last_avail_idx(VirtIODevice *vdev, int n);
|
||||
+void virtio_queue_set_last_avail_idx(VirtIODevice *vdev, int n, uint16_t idx);
|
||||
+VirtQueue *virtio_queue(VirtIODevice *vdev, int n);
|
||||
+EventNotifier *virtio_queue_guest_notifier(VirtQueue *vq);
|
||||
+EventNotifier *virtio_queue_host_notifier(VirtQueue *vq);
|
||||
+void virtio_irq(VirtQueue *vq);
|
||||
#endif
|
||||
--
|
||||
1.6.6.144.g5c3af
|
|
@ -0,0 +1,400 @@
|
|||
Add feature bits as properties to virtio. This makes it possible to e.g. define
|
||||
machine without indirect buffer support, which is required for 0.10
|
||||
compatibility, or without hardware checksum support, which is required for 0.11
|
||||
compatibility. Since default values for optional features are now set by qdev,
|
||||
get_features callback has been modified: it sets non-optional bits, and clears
|
||||
bits not supported by host.
|
||||
|
||||
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
|
||||
(cherry picked from commit 8172539d21a03e982aa7f139ddc1607dc1422045)
|
||||
---
|
||||
hw/s390-virtio-bus.c | 12 +++++++++---
|
||||
hw/s390-virtio-bus.h | 1 +
|
||||
hw/syborg_virtio.c | 13 ++++++++-----
|
||||
hw/virtio-balloon.c | 4 ++--
|
||||
hw/virtio-blk.c | 6 +-----
|
||||
hw/virtio-blk.h | 8 ++++++++
|
||||
hw/virtio-net.c | 39 ++++++++++++++++-----------------------
|
||||
hw/virtio-net.h | 20 ++++++++++++++++++++
|
||||
hw/virtio-pci.c | 25 +++++++++++++++++--------
|
||||
hw/virtio.c | 2 +-
|
||||
hw/virtio.h | 7 ++++++-
|
||||
12 files changed, 91 insertions(+), 50 deletions(-)
|
||||
|
||||
--- a/hw/s390-virtio-bus.c 2010-02-09 00:18:58.000000000 -0600
|
||||
+++ b/hw/s390-virtio-bus.c 2010-02-09 00:02:12.000000000 -0600
|
||||
@@ -101,6 +101,7 @@ static int s390_virtio_device_init(VirtI
|
||||
bus->dev_offs += dev_len;
|
||||
|
||||
virtio_bind_device(vdev, &virtio_s390_bindings, dev);
|
||||
+ dev->host_features = vdev->get_features(vdev, dev->host_features);
|
||||
s390_virtio_device_sync(dev);
|
||||
|
||||
return 0;
|
||||
@@ -222,9 +223,7 @@ static void s390_virtio_device_sync(Virt
|
||||
cur_offs += num_vq * VIRTIO_VQCONFIG_LEN;
|
||||
|
||||
/* Sync feature bitmap */
|
||||
- if (dev->vdev->get_features) {
|
||||
- stl_phys(cur_offs, dev->vdev->get_features(dev->vdev));
|
||||
- }
|
||||
+ stl_phys(cur_offs, dev->host_features);
|
||||
|
||||
dev->feat_offs = cur_offs + dev->feat_len;
|
||||
cur_offs += dev->feat_len * 2;
|
||||
@@ -310,10 +309,17 @@ static void virtio_s390_notify(void *opa
|
||||
kvm_s390_virtio_irq(s390_cpu_addr2state(0), 0, token);
|
||||
}
|
||||
|
||||
+static unsigned virtio_s390_get_features(void *opaque)
|
||||
+{
|
||||
+ VirtIOS390Device *dev = (VirtIOS390Device*)opaque;
|
||||
+ return dev->host_features;
|
||||
+}
|
||||
+
|
||||
/**************** S390 Virtio Bus Device Descriptions *******************/
|
||||
|
||||
static const VirtIOBindings virtio_s390_bindings = {
|
||||
.notify = virtio_s390_notify,
|
||||
+ .get_features = virtio_s390_get_features,
|
||||
};
|
||||
|
||||
static VirtIOS390DeviceInfo s390_virtio_net = {
|
||||
--- a/hw/s390-virtio-bus.h 2010-02-09 00:18:58.000000000 -0600
|
||||
+++ b/s390-virtio-bus.h 2010-02-09 00:18:16.000000000 -0600
|
||||
@@ -40,6 +40,7 @@ typedef struct VirtIOS390Device {
|
||||
VirtIODevice *vdev;
|
||||
DriveInfo *dinfo;
|
||||
NICConf nic;
|
||||
+ uint32_t host_features;
|
||||
/* Max. number of ports we can have for a the virtio-serial device */
|
||||
uint32_t max_virtserial_ports;
|
||||
} VirtIOS390Device;
|
||||
--- a/hw/syborg_virtio.c 2010-02-09 00:18:58.000000000 -0600
|
||||
+++ b/hw/syborg_virtio.c 2010-02-09 00:02:12.000000000 -0600
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "syborg.h"
|
||||
#include "sysbus.h"
|
||||
#include "virtio.h"
|
||||
+#include "virtio-net.h"
|
||||
#include "sysemu.h"
|
||||
|
||||
//#define DEBUG_SYBORG_VIRTIO
|
||||
@@ -66,6 +67,7 @@ typedef struct {
|
||||
uint32_t int_enable;
|
||||
uint32_t id;
|
||||
NICConf nic;
|
||||
+ uint32_t host_features;
|
||||
} SyborgVirtIOProxy;
|
||||
|
||||
static uint32_t syborg_virtio_readl(void *opaque, target_phys_addr_t offset)
|
||||
@@ -86,8 +88,7 @@ static uint32_t syborg_virtio_readl(void
|
||||
ret = s->id;
|
||||
break;
|
||||
case SYBORG_VIRTIO_HOST_FEATURES:
|
||||
- ret = vdev->get_features(vdev);
|
||||
- ret |= vdev->binding->get_features(s);
|
||||
+ ret = s->host_features;
|
||||
break;
|
||||
case SYBORG_VIRTIO_GUEST_FEATURES:
|
||||
ret = vdev->guest_features;
|
||||
@@ -244,9 +245,8 @@ static void syborg_virtio_update_irq(voi
|
||||
|
||||
static unsigned syborg_virtio_get_features(void *opaque)
|
||||
{
|
||||
- unsigned ret = 0;
|
||||
- ret |= (1 << VIRTIO_F_NOTIFY_ON_EMPTY);
|
||||
- return ret;
|
||||
+ SyborgVirtIOProxy *proxy = opaque;
|
||||
+ return proxy->host_features;
|
||||
}
|
||||
|
||||
static VirtIOBindings syborg_virtio_bindings = {
|
||||
@@ -272,6 +272,8 @@ static int syborg_virtio_init(SyborgVirt
|
||||
qemu_register_reset(virtio_reset, vdev);
|
||||
|
||||
virtio_bind_device(vdev, &syborg_virtio_bindings, proxy);
|
||||
+ proxy->host_features |= (0x1 << VIRTIO_F_NOTIFY_ON_EMPTY);
|
||||
+ proxy->host_features = vdev->get_features(vdev, proxy->host_features);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -292,6 +294,7 @@ static SysBusDeviceInfo syborg_virtio_ne
|
||||
.qdev.size = sizeof(SyborgVirtIOProxy),
|
||||
.qdev.props = (Property[]) {
|
||||
DEFINE_NIC_PROPERTIES(SyborgVirtIOProxy, nic),
|
||||
+ DEFINE_VIRTIO_NET_FEATURES(SyborgVirtIOProxy, host_features),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
}
|
||||
};
|
||||
--- a/hw/virtio-balloon.c 2010-01-18 12:48:25.000000000 -0600
|
||||
+++ b/hw/virtio-balloon.c 2010-02-09 00:02:12.000000000 -0600
|
||||
@@ -125,9 +125,9 @@ static void virtio_balloon_set_config(Vi
|
||||
dev->actual = config.actual;
|
||||
}
|
||||
|
||||
-static uint32_t virtio_balloon_get_features(VirtIODevice *vdev)
|
||||
+static uint32_t virtio_balloon_get_features(VirtIODevice *vdev, uint32_t f)
|
||||
{
|
||||
- return 0;
|
||||
+ return f;
|
||||
}
|
||||
|
||||
static ram_addr_t virtio_balloon_to_target(void *opaque, ram_addr_t target)
|
||||
--- a/hw/virtio-blk.c 2010-01-18 12:48:25.000000000 -0600
|
||||
+++ b/hw/virtio-blk.c 2010-02-09 00:02:12.000000000 -0600
|
||||
@@ -432,19 +432,15 @@ static void virtio_blk_update_config(Vir
|
||||
memcpy(config, &blkcfg, s->config_size);
|
||||
}
|
||||
|
||||
-static uint32_t virtio_blk_get_features(VirtIODevice *vdev)
|
||||
+static uint32_t virtio_blk_get_features(VirtIODevice *vdev, uint32_t features)
|
||||
{
|
||||
VirtIOBlock *s = to_virtio_blk(vdev);
|
||||
- uint32_t features = 0;
|
||||
|
||||
features |= (1 << VIRTIO_BLK_F_SEG_MAX);
|
||||
features |= (1 << VIRTIO_BLK_F_GEOMETRY);
|
||||
|
||||
if (bdrv_enable_write_cache(s->bs))
|
||||
features |= (1 << VIRTIO_BLK_F_WCACHE);
|
||||
-#ifdef __linux__
|
||||
- features |= (1 << VIRTIO_BLK_F_SCSI);
|
||||
-#endif
|
||||
if (strcmp(s->serial_str, "0"))
|
||||
features |= 1 << VIRTIO_BLK_F_IDENTIFY;
|
||||
|
||||
--- a/hw/virtio-blk.h 2010-01-18 12:48:25.000000000 -0600
|
||||
+++ b/hw/virtio-blk.h 2010-02-09 00:02:12.000000000 -0600
|
||||
@@ -92,4 +92,12 @@ struct virtio_scsi_inhdr
|
||||
uint32_t residual;
|
||||
};
|
||||
|
||||
+#ifdef __linux__
|
||||
+#define DEFINE_VIRTIO_BLK_FEATURES(_state, _field) \
|
||||
+ DEFINE_VIRTIO_COMMON_FEATURES(_state, _field), \
|
||||
+ DEFINE_PROP_BIT("scsi", _state, _field, VIRTIO_BLK_F_SCSI, true)
|
||||
+#else
|
||||
+#define DEFINE_VIRTIO_BLK_FEATURES(_state, _field) \
|
||||
+ DEFINE_VIRTIO_COMMON_FEATURES(_state, _field)
|
||||
+#endif
|
||||
#endif
|
||||
--- a/hw/virtio.c 2010-02-09 00:18:58.000000000 -0600
|
||||
+++ b/hw/virtio.c 2010-02-09 00:02:12.000000000 -0600
|
||||
@@ -650,7 +650,7 @@ int virtio_load(VirtIODevice *vdev, QEMU
|
||||
{
|
||||
int num, i, ret;
|
||||
uint32_t features;
|
||||
- uint32_t supported_features = vdev->get_features(vdev) |
|
||||
+ uint32_t supported_features =
|
||||
vdev->binding->get_features(vdev->binding_opaque);
|
||||
|
||||
if (vdev->binding->load_config) {
|
||||
--- a/hw/virtio.h 2010-02-09 00:18:58.000000000 -0600
|
||||
+++ bhw/virtio.h 2010-02-09 00:02:12.000000000 -0600
|
||||
@@ -105,7 +105,7 @@ struct VirtIODevice
|
||||
void *config;
|
||||
uint16_t config_vector;
|
||||
int nvectors;
|
||||
- uint32_t (*get_features)(VirtIODevice *vdev);
|
||||
+ uint32_t (*get_features)(VirtIODevice *vdev, uint32_t requested_features);
|
||||
uint32_t (*bad_features)(VirtIODevice *vdev);
|
||||
void (*set_features)(VirtIODevice *vdev, uint32_t val);
|
||||
void (*get_config)(VirtIODevice *vdev, uint8_t *config);
|
||||
@@ -176,4 +176,9 @@ VirtIODevice *virtio_balloon_init(Device
|
||||
|
||||
void virtio_net_exit(VirtIODevice *vdev);
|
||||
|
||||
+#define DEFINE_VIRTIO_COMMON_FEATURES(_state, _field) \
|
||||
+ DEFINE_PROP_BIT("indirect_desc", _state, _field, \
|
||||
+ VIRTIO_RING_F_INDIRECT_DESC, true)
|
||||
+
|
||||
+
|
||||
#endif
|
||||
--- a/hw/virtio-net.c 2010-02-09 00:18:58.000000000 -0600
|
||||
+++ b/hw/virtio-net.c 2010-02-09 00:02:12.000000000 -0600
|
||||
@@ -147,34 +147,27 @@ static int peer_has_ufo(VirtIONet *n)
|
||||
return n->has_ufo;
|
||||
}
|
||||
|
||||
-static uint32_t virtio_net_get_features(VirtIODevice *vdev)
|
||||
+static uint32_t virtio_net_get_features(VirtIODevice *vdev, uint32_t features)
|
||||
{
|
||||
VirtIONet *n = to_virtio_net(vdev);
|
||||
- uint32_t features = (1 << VIRTIO_NET_F_MAC) |
|
||||
- (1 << VIRTIO_NET_F_MRG_RXBUF) |
|
||||
- (1 << VIRTIO_NET_F_STATUS) |
|
||||
- (1 << VIRTIO_NET_F_CTRL_VQ) |
|
||||
- (1 << VIRTIO_NET_F_CTRL_RX) |
|
||||
- (1 << VIRTIO_NET_F_CTRL_VLAN) |
|
||||
- (1 << VIRTIO_NET_F_CTRL_RX_EXTRA);
|
||||
|
||||
if (peer_has_vnet_hdr(n)) {
|
||||
tap_using_vnet_hdr(n->nic->nc.peer, 1);
|
||||
+ } else {
|
||||
+ features &= ~(0x1 << VIRTIO_NET_F_CSUM);
|
||||
+ features &= ~(0x1 << VIRTIO_NET_F_HOST_TSO4);
|
||||
+ features &= ~(0x1 << VIRTIO_NET_F_HOST_TSO6);
|
||||
+ features &= ~(0x1 << VIRTIO_NET_F_HOST_ECN);
|
||||
+
|
||||
+ features &= ~(0x1 << VIRTIO_NET_F_GUEST_CSUM);
|
||||
+ features &= ~(0x1 << VIRTIO_NET_F_GUEST_TSO4);
|
||||
+ features &= ~(0x1 << VIRTIO_NET_F_GUEST_TSO6);
|
||||
+ features &= ~(0x1 << VIRTIO_NET_F_GUEST_ECN);
|
||||
+ }
|
||||
|
||||
- features |= (1 << VIRTIO_NET_F_CSUM);
|
||||
- features |= (1 << VIRTIO_NET_F_HOST_TSO4);
|
||||
- features |= (1 << VIRTIO_NET_F_HOST_TSO6);
|
||||
- features |= (1 << VIRTIO_NET_F_HOST_ECN);
|
||||
-
|
||||
- features |= (1 << VIRTIO_NET_F_GUEST_CSUM);
|
||||
- features |= (1 << VIRTIO_NET_F_GUEST_TSO4);
|
||||
- features |= (1 << VIRTIO_NET_F_GUEST_TSO6);
|
||||
- features |= (1 << VIRTIO_NET_F_GUEST_ECN);
|
||||
-
|
||||
- if (peer_has_ufo(n)) {
|
||||
- features |= (1 << VIRTIO_NET_F_GUEST_UFO);
|
||||
- features |= (1 << VIRTIO_NET_F_HOST_UFO);
|
||||
- }
|
||||
+ if (!peer_has_vnet_hdr(n) || !peer_has_ufo(n)) {
|
||||
+ features &= ~(0x1 << VIRTIO_NET_F_GUEST_UFO);
|
||||
+ features &= ~(0x1 << VIRTIO_NET_F_HOST_UFO);
|
||||
}
|
||||
|
||||
return features;
|
||||
@@ -192,7 +185,7 @@ static uint32_t virtio_net_bad_features(
|
||||
features |= (1 << VIRTIO_NET_F_HOST_TSO6);
|
||||
features |= (1 << VIRTIO_NET_F_HOST_ECN);
|
||||
|
||||
- return features & virtio_net_get_features(vdev);
|
||||
+ return features;
|
||||
}
|
||||
|
||||
static void virtio_net_set_features(VirtIODevice *vdev, uint32_t features)
|
||||
--- a/hw/virtio-net.h 2010-01-18 12:48:25.000000000 -0600
|
||||
+++ b/hw/virtio-net.h 2010-02-09 00:02:12.000000000 -0600
|
||||
@@ -153,4 +153,24 @@ struct virtio_net_ctrl_mac {
|
||||
#define VIRTIO_NET_CTRL_VLAN_ADD 0
|
||||
#define VIRTIO_NET_CTRL_VLAN_DEL 1
|
||||
|
||||
+#define DEFINE_VIRTIO_NET_FEATURES(_state, _field) \
|
||||
+ DEFINE_VIRTIO_COMMON_FEATURES(_state, _field), \
|
||||
+ DEFINE_PROP_BIT("csum", _state, _field, VIRTIO_NET_F_CSUM, true), \
|
||||
+ DEFINE_PROP_BIT("guest_csum", _state, _field, VIRTIO_NET_F_GUEST_CSUM, true), \
|
||||
+ DEFINE_PROP_BIT("mac", _state, _field, VIRTIO_NET_F_MAC, true), \
|
||||
+ DEFINE_PROP_BIT("gso", _state, _field, VIRTIO_NET_F_GSO, true), \
|
||||
+ DEFINE_PROP_BIT("guest_tso4", _state, _field, VIRTIO_NET_F_GUEST_TSO4, true), \
|
||||
+ DEFINE_PROP_BIT("guest_tso6", _state, _field, VIRTIO_NET_F_GUEST_TSO6, true), \
|
||||
+ DEFINE_PROP_BIT("guest_ecn", _state, _field, VIRTIO_NET_F_GUEST_ECN, true), \
|
||||
+ DEFINE_PROP_BIT("guest_ufo", _state, _field, VIRTIO_NET_F_GUEST_UFO, true), \
|
||||
+ DEFINE_PROP_BIT("host_tso4", _state, _field, VIRTIO_NET_F_HOST_TSO4, true), \
|
||||
+ DEFINE_PROP_BIT("host_tso6", _state, _field, VIRTIO_NET_F_HOST_TSO6, true), \
|
||||
+ DEFINE_PROP_BIT("host_ecn", _state, _field, VIRTIO_NET_F_HOST_ECN, true), \
|
||||
+ DEFINE_PROP_BIT("host_ufo", _state, _field, VIRTIO_NET_F_HOST_UFO, true), \
|
||||
+ DEFINE_PROP_BIT("mrg_rxbuf", _state, _field, VIRTIO_NET_F_MRG_RXBUF, true), \
|
||||
+ DEFINE_PROP_BIT("status", _state, _field, VIRTIO_NET_F_STATUS, true), \
|
||||
+ DEFINE_PROP_BIT("ctrl_vq", _state, _field, VIRTIO_NET_F_CTRL_VQ, true), \
|
||||
+ DEFINE_PROP_BIT("ctrl_rx", _state, _field, VIRTIO_NET_F_CTRL_RX, true), \
|
||||
+ DEFINE_PROP_BIT("ctrl_vlan", _state, _field, VIRTIO_NET_F_CTRL_VLAN, true), \
|
||||
+ DEFINE_PROP_BIT("ctrl_rx_extra", _state, _field, VIRTIO_NET_F_CTRL_RX_EXTRA, true)
|
||||
#endif
|
||||
--- a/hw/virtio-pci.c 2010-02-09 00:18:58.000000000 -0600
|
||||
+++ b/hw/virtio-pci.c 2010-02-09 00:16:13.000000000 -0600
|
||||
@@ -16,6 +16,8 @@
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "virtio.h"
|
||||
+#include "virtio-blk.h"
|
||||
+#include "virtio-net.h"
|
||||
#include "pci.h"
|
||||
#include "sysemu.h"
|
||||
#include "msix.h"
|
||||
@@ -92,6 +94,7 @@ typedef struct {
|
||||
uint32_t nvectors;
|
||||
DriveInfo *dinfo;
|
||||
NICConf nic;
|
||||
+ uint32_t host_features;
|
||||
/* Max. number of ports we can have for a the virtio-serial device */
|
||||
uint32_t max_virtserial_ports;
|
||||
} VirtIOPCIProxy;
|
||||
@@ -177,7 +180,7 @@ static void virtio_ioport_write(void *op
|
||||
/* Guest does not negotiate properly? We have to assume nothing. */
|
||||
if (val & (1 << VIRTIO_F_BAD_FEATURE)) {
|
||||
if (vdev->bad_features)
|
||||
- val = vdev->bad_features(vdev);
|
||||
+ val = proxy->host_features & vdev->bad_features(vdev);
|
||||
else
|
||||
val = 0;
|
||||
}
|
||||
@@ -237,8 +240,7 @@ static uint32_t virtio_ioport_read(VirtI
|
||||
|
||||
switch (addr) {
|
||||
case VIRTIO_PCI_HOST_FEATURES:
|
||||
- ret = vdev->get_features(vdev);
|
||||
- ret |= vdev->binding->get_features(proxy);
|
||||
+ ret = proxy->host_features;
|
||||
break;
|
||||
case VIRTIO_PCI_GUEST_FEATURES:
|
||||
ret = vdev->guest_features;
|
||||
@@ -384,11 +386,8 @@ static void virtio_write_config(PCIDevic
|
||||
|
||||
static unsigned virtio_pci_get_features(void *opaque)
|
||||
{
|
||||
- unsigned ret = 0;
|
||||
- ret |= (1 << VIRTIO_F_NOTIFY_ON_EMPTY);
|
||||
- ret |= (1 << VIRTIO_RING_F_INDIRECT_DESC);
|
||||
- ret |= (1 << VIRTIO_F_BAD_FEATURE);
|
||||
- return ret;
|
||||
+ VirtIOPCIProxy *proxy = opaque;
|
||||
+ return proxy->host_features;
|
||||
}
|
||||
|
||||
static const VirtIOBindings virtio_pci_bindings = {
|
||||
@@ -444,6 +443,9 @@ static void virtio_init_pci(VirtIOPCIPro
|
||||
virtio_map);
|
||||
|
||||
virtio_bind_device(vdev, &virtio_pci_bindings, proxy);
|
||||
+ proxy->host_features |= 0x1 << VIRTIO_F_NOTIFY_ON_EMPTY;
|
||||
+ proxy->host_features |= 0x1 << VIRTIO_F_BAD_FEATURE;
|
||||
+ proxy->host_features = vdev->get_features(vdev, proxy->host_features);
|
||||
}
|
||||
|
||||
static int virtio_blk_init_pci(PCIDevice *pci_dev)
|
||||
@@ -558,6 +560,7 @@ static PCIDeviceInfo virtio_info[] = {
|
||||
DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0),
|
||||
DEFINE_PROP_DRIVE("drive", VirtIOPCIProxy, dinfo),
|
||||
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
|
||||
+ DEFINE_VIRTIO_BLK_FEATURES(VirtIOPCIProxy, host_features),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
},
|
||||
.qdev.reset = virtio_pci_reset,
|
||||
@@ -569,6 +572,7 @@ static PCIDeviceInfo virtio_info[] = {
|
||||
.romfile = "pxe-virtio.bin",
|
||||
.qdev.props = (Property[]) {
|
||||
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3),
|
||||
+ DEFINE_VIRTIO_NET_FEATURES(VirtIOPCIProxy, host_features),
|
||||
DEFINE_NIC_PROPERTIES(VirtIOPCIProxy, nic),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
},
|
||||
@@ -582,6 +586,7 @@ static PCIDeviceInfo virtio_info[] = {
|
||||
.qdev.props = (Property[]) {
|
||||
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 0),
|
||||
DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0),
|
||||
+ DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
|
||||
DEFINE_PROP_UINT32("max_ports", VirtIOPCIProxy, max_virtserial_ports,
|
||||
31),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
@@ -592,6 +597,10 @@ static PCIDeviceInfo virtio_info[] = {
|
||||
.qdev.size = sizeof(VirtIOPCIProxy),
|
||||
.init = virtio_balloon_init_pci,
|
||||
.exit = virtio_exit_pci,
|
||||
+ .qdev.props = (Property[]) {
|
||||
+ DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
|
||||
+ DEFINE_PROP_END_OF_LIST(),
|
||||
+ },
|
||||
.qdev.reset = virtio_pci_reset,
|
||||
},{
|
||||
/* end of list */
|
|
@ -0,0 +1,78 @@
|
|||
Add binding API to set host/guest notifiers.
|
||||
Will be used by vhost.
|
||||
|
||||
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
---
|
||||
hw/virtio.c | 13 ++++++++++---
|
||||
hw/virtio.h | 5 ++++-
|
||||
2 files changed, 14 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/hw/virtio.c b/hw/virtio.c
|
||||
index fa7184a..c2b80aa 100644
|
||||
--- a/hw/virtio.c
|
||||
+++ b/hw/virtio.c
|
||||
@@ -594,6 +594,12 @@ VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size,
|
||||
return &vdev->vq[i];
|
||||
}
|
||||
|
||||
+void virtio_irq(VirtIODevice *vdev, VirtQueue *vq)
|
||||
+{
|
||||
+ vdev->isr |= 0x01;
|
||||
+ virtio_notify_vector(vdev, vq->vector);
|
||||
+}
|
||||
+
|
||||
void virtio_notify(VirtIODevice *vdev, VirtQueue *vq)
|
||||
{
|
||||
/* Always notify when queue is empty (when feature acknowledge) */
|
||||
@@ -602,8 +608,7 @@ void virtio_notify(VirtIODevice *vdev, VirtQueue *vq)
|
||||
(vq->inuse || vring_avail_idx(vq) != vq->last_avail_idx)))
|
||||
return;
|
||||
|
||||
- vdev->isr |= 0x01;
|
||||
- virtio_notify_vector(vdev, vq->vector);
|
||||
+ virtio_irq(vdev, vq);
|
||||
}
|
||||
|
||||
void virtio_notify_config(VirtIODevice *vdev)
|
||||
@@ -716,8 +721,10 @@ VirtIODevice *virtio_common_init(const char *name, uint16_t device_id,
|
||||
vdev->queue_sel = 0;
|
||||
vdev->config_vector = VIRTIO_NO_VECTOR;
|
||||
vdev->vq = qemu_mallocz(sizeof(VirtQueue) * VIRTIO_PCI_QUEUE_MAX);
|
||||
- for(i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++)
|
||||
+ for(i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) {
|
||||
vdev->vq[i].vector = VIRTIO_NO_VECTOR;
|
||||
+ vdev->vq[i].vdev = vdev;
|
||||
+ }
|
||||
|
||||
vdev->name = name;
|
||||
vdev->config_len = config_size;
|
||||
diff --git a/hw/virtio.h b/hw/virtio.h
|
||||
index 3994cc9..10a0959 100644
|
||||
--- a/hw/virtio.h
|
||||
+++ b/hw/virtio.h
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "net.h"
|
||||
#include "qdev.h"
|
||||
#include "sysemu.h"
|
||||
+#include "notifier.h"
|
||||
|
||||
/* from Linux's linux/virtio_config.h */
|
||||
|
||||
@@ -88,6 +89,8 @@ typedef struct {
|
||||
int (*load_config)(void * opaque, QEMUFile *f);
|
||||
int (*load_queue)(void * opaque, int n, QEMUFile *f);
|
||||
unsigned (*get_features)(void * opaque);
|
||||
+ int (*guest_notifier)(void * opaque, int n, bool assigned);
|
||||
+ int (*host_notifier)(void * opaque, int n, bool assigned);
|
||||
} VirtIOBindings;
|
||||
|
||||
#define VIRTIO_PCI_QUEUE_MAX 64
|
||||
@@ -180,5 +183,5 @@ void virtio_net_exit(VirtIODevice *vdev);
|
||||
DEFINE_PROP_BIT("indirect_desc", _state, _field, \
|
||||
VIRTIO_RING_F_INDIRECT_DESC, true)
|
||||
|
||||
-
|
||||
+void virtio_irq(VirtIODevice *vdev, VirtQueue *vq);
|
||||
#endif
|
||||
--
|
||||
1.6.6.144.g5c3af
|
|
@ -0,0 +1,76 @@
|
|||
vhost net backend needs to be notified when
|
||||
frontend status changes. Add a callback.
|
||||
|
||||
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
---
|
||||
hw/s390-virtio-bus.c | 3 +++
|
||||
hw/syborg_virtio.c | 2 ++
|
||||
hw/virtio-pci.c | 6 ++++++
|
||||
hw/virtio.h | 1 +
|
||||
4 files changed, 12 insertions(+), 0 deletions(-)
|
||||
|
||||
diff --git a/hw/s390-virtio-bus.c b/hw/s390-virtio-bus.c
|
||||
index 980e7eb..f45b67d 100644
|
||||
--- a/hw/s390-virtio-bus.c
|
||||
+++ b/hw/s390-virtio-bus.c
|
||||
@@ -243,6 +243,9 @@ void s390_virtio_device_update_status(VirtIOS390Device *dev)
|
||||
uint32_t features;
|
||||
|
||||
vdev->status = ldub_phys(dev->dev_offs + VIRTIO_DEV_OFFS_STATUS);
|
||||
+ if (vdev->set_status) {
|
||||
+ vdev->set_status(vdev);
|
||||
+ }
|
||||
|
||||
/* Update guest supported feature bitmap */
|
||||
|
||||
diff --git a/hw/syborg_virtio.c b/hw/syborg_virtio.c
|
||||
index 65239a0..19f6473 100644
|
||||
--- a/hw/syborg_virtio.c
|
||||
+++ b/hw/syborg_virtio.c
|
||||
@@ -152,6 +152,8 @@ static void syborg_virtio_writel(void *opaque, target_phys_addr_t offset,
|
||||
vdev->status = value & 0xFF;
|
||||
if (vdev->status == 0)
|
||||
virtio_reset(vdev);
|
||||
+ if (vdev->set_status)
|
||||
+ vdev->set_status(vdev);
|
||||
break;
|
||||
case SYBORG_VIRTIO_INT_ENABLE:
|
||||
s->int_enable = value;
|
||||
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
|
||||
index 573c98a..05898c8 100644
|
||||
--- a/hw/virtio-pci.c
|
||||
+++ b/hw/virtio-pci.c
|
||||
@@ -208,6 +208,9 @@ static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val)
|
||||
virtio_reset(proxy->vdev);
|
||||
msix_unuse_all_vectors(&proxy->pci_dev);
|
||||
}
|
||||
+ if (vdev->set_status) {
|
||||
+ vdev->set_status(vdev);
|
||||
+ }
|
||||
break;
|
||||
case VIRTIO_MSI_CONFIG_VECTOR:
|
||||
msix_vector_unuse(&proxy->pci_dev, vdev->config_vector);
|
||||
@@ -375,6 +378,9 @@ static void virtio_write_config(PCIDevice *pci_dev, uint32_t address,
|
||||
if (PCI_COMMAND == address) {
|
||||
if (!(val & PCI_COMMAND_MASTER)) {
|
||||
proxy->vdev->status &= ~VIRTIO_CONFIG_S_DRIVER_OK;
|
||||
+ if (proxy->vdev->set_status) {
|
||||
+ proxy->vdev->set_status(proxy->vdev);
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/hw/virtio.h b/hw/virtio.h
|
||||
index f140ca3..39d0763 100644
|
||||
--- a/hw/virtio.h
|
||||
+++ b/hw/virtio.h
|
||||
@@ -114,6 +114,7 @@ struct VirtIODevice
|
||||
void (*get_config)(VirtIODevice *vdev, uint8_t *config);
|
||||
void (*set_config)(VirtIODevice *vdev, const uint8_t *config);
|
||||
void (*reset)(VirtIODevice *vdev);
|
||||
+ void (*set_status)(VirtIODevice *vdev);
|
||||
VirtQueue *vq;
|
||||
const VirtIOBindings *binding;
|
||||
void *binding_opaque;
|
||||
--
|
||||
1.6.6.144.g5c3af
|
|
@ -0,0 +1,25 @@
|
|||
verify that peer is tap before checking for vhost net
|
||||
|
||||
Reported-by: Shirley Ma <mashirle@us.ibm.com>
|
||||
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
---
|
||||
hw/virtio-net.c | 4 ++++
|
||||
1 files changed, 4 insertions(+), 0 deletions(-)
|
||||
|
||||
diff --git a/hw/virtio-net.c b/hw/virtio-net.c
|
||||
index 088029b..b28fd92 100644
|
||||
--- a/hw/virtio-net.c
|
||||
+++ b/hw/virtio-net.c
|
||||
@@ -179,6 +179,10 @@ static uint32_t virtio_net_get_features(VirtIODevice *vdev, uint32_t features)
|
||||
features &= ~(0x1 << VIRTIO_NET_F_HOST_UFO);
|
||||
}
|
||||
|
||||
+ if (!n->nic->nc.peer ||
|
||||
+ n->nic->nc.peer->info->type != NET_CLIENT_TYPE_TAP) {
|
||||
+ return features;
|
||||
+ }
|
||||
if (!tap_get_vhost_net(n->nic->nc.peer)) {
|
||||
return features;
|
||||
}
|
||||
--
|
||||
1.6.6.144.g5c3af
|
|
@ -0,0 +1,34 @@
|
|||
make it possible to use type without header include
|
||||
|
||||
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
---
|
||||
hw/virtio.h | 1 -
|
||||
qemu-common.h | 1 +
|
||||
2 files changed, 1 insertions(+), 1 deletions(-)
|
||||
|
||||
diff --git a/hw/virtio.h b/hw/virtio.h
|
||||
index 39d0763..a5bd0ba 100644
|
||||
--- a/hw/virtio.h
|
||||
+++ b/hw/virtio.h
|
||||
@@ -68,7 +68,6 @@ static inline target_phys_addr_t vring_align(target_phys_addr_t addr,
|
||||
}
|
||||
|
||||
typedef struct VirtQueue VirtQueue;
|
||||
-typedef struct VirtIODevice VirtIODevice;
|
||||
|
||||
#define VIRTQUEUE_MAX_SIZE 1024
|
||||
|
||||
diff --git a/qemu-common.h b/qemu-common.h
|
||||
index cdead98..1a54f9e 100644
|
||||
--- a/qemu-common.h
|
||||
+++ b/qemu-common.h
|
||||
@@ -218,6 +218,7 @@ typedef struct I2SCodec I2SCodec;
|
||||
typedef struct DeviceState DeviceState;
|
||||
typedef struct SSIBus SSIBus;
|
||||
typedef struct EventNotifier EventNotifier;
|
||||
+typedef struct VirtIODevice VirtIODevice;
|
||||
|
||||
/* CPU save/load. */
|
||||
void cpu_save(QEMUFile *f, void *opaque);
|
||||
--
|
||||
1.6.6.144.g5c3af
|
|
@ -0,0 +1,40 @@
|
|||
Mac feature bit isn't going to work as all network cards already have a
|
||||
'mac' property to set the mac address. Remove it from mask and add in
|
||||
get_features.
|
||||
|
||||
Reported-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
|
||||
(cherry picked from commit c9f79a3f79a48de28b4575cb5644bcf45d3754d0)
|
||||
---
|
||||
hw/virtio-net.c | 2 ++
|
||||
hw/virtio-net.h | 1 -
|
||||
2 files changed, 2 insertions(+), 1 deletions(-)
|
||||
|
||||
diff --git a/hw/virtio-net.c b/hw/virtio-net.c
|
||||
index c2a389f..02d9180 100644
|
||||
--- a/hw/virtio-net.c
|
||||
+++ b/hw/virtio-net.c
|
||||
@@ -151,6 +151,8 @@ static uint32_t virtio_net_get_features(VirtIODevice *vdev, uint32_t features)
|
||||
{
|
||||
VirtIONet *n = to_virtio_net(vdev);
|
||||
|
||||
+ features |= (1 << VIRTIO_NET_F_MAC);
|
||||
+
|
||||
if (peer_has_vnet_hdr(n)) {
|
||||
tap_using_vnet_hdr(n->nic->nc.peer, 1);
|
||||
} else {
|
||||
diff --git a/hw/virtio-net.h b/hw/virtio-net.h
|
||||
index 9130d75..e55119b 100644
|
||||
--- a/hw/virtio-net.h
|
||||
+++ b/hw/virtio-net.h
|
||||
@@ -157,7 +157,6 @@ struct virtio_net_ctrl_mac {
|
||||
DEFINE_VIRTIO_COMMON_FEATURES(_state, _field), \
|
||||
DEFINE_PROP_BIT("csum", _state, _field, VIRTIO_NET_F_CSUM, true), \
|
||||
DEFINE_PROP_BIT("guest_csum", _state, _field, VIRTIO_NET_F_GUEST_CSUM, true), \
|
||||
- DEFINE_PROP_BIT("mac", _state, _field, VIRTIO_NET_F_MAC, true), \
|
||||
DEFINE_PROP_BIT("gso", _state, _field, VIRTIO_NET_F_GSO, true), \
|
||||
DEFINE_PROP_BIT("guest_tso4", _state, _field, VIRTIO_NET_F_GUEST_TSO4, true), \
|
||||
DEFINE_PROP_BIT("guest_tso6", _state, _field, VIRTIO_NET_F_GUEST_TSO6, true), \
|
||||
--
|
||||
1.6.6.144.g5c3af
|
|
@ -0,0 +1,153 @@
|
|||
This connects virtio-net to vhost net backend.
|
||||
The code is structured in a way analogous to what we have with vnet
|
||||
header capability in tap. We start/stop backend on driver start/stop as
|
||||
well as on save and vm start (for migration).
|
||||
|
||||
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
---
|
||||
hw/virtio-net.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
|
||||
1 files changed, 65 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/hw/virtio-net.c b/hw/virtio-net.c
|
||||
index 02d9180..088029b 100644
|
||||
--- a/hw/virtio-net.c
|
||||
+++ b/hw/virtio-net.c
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "net/tap.h"
|
||||
#include "qemu-timer.h"
|
||||
#include "virtio-net.h"
|
||||
+#include "vhost_net.h"
|
||||
|
||||
#define VIRTIO_NET_VM_VERSION 11
|
||||
|
||||
@@ -47,6 +48,8 @@ typedef struct VirtIONet
|
||||
uint8_t nomulti;
|
||||
uint8_t nouni;
|
||||
uint8_t nobcast;
|
||||
+ uint8_t vhost_started;
|
||||
+ VMChangeStateEntry *vmstate;
|
||||
struct {
|
||||
int in_use;
|
||||
int first_multi;
|
||||
@@ -114,6 +117,10 @@ static void virtio_net_reset(VirtIODevice *vdev)
|
||||
n->nomulti = 0;
|
||||
n->nouni = 0;
|
||||
n->nobcast = 0;
|
||||
+ if (n->vhost_started) {
|
||||
+ vhost_net_stop(tap_get_vhost_net(n->nic->nc.peer), vdev);
|
||||
+ n->vhost_started = 0;
|
||||
+ }
|
||||
|
||||
/* Flush any MAC and VLAN filter table state */
|
||||
n->mac_table.in_use = 0;
|
||||
@@ -172,7 +179,10 @@ static uint32_t virtio_net_get_features(VirtIODevice *vdev, uint32_t features)
|
||||
features &= ~(0x1 << VIRTIO_NET_F_HOST_UFO);
|
||||
}
|
||||
|
||||
- return features;
|
||||
+ if (!tap_get_vhost_net(n->nic->nc.peer)) {
|
||||
+ return features;
|
||||
+ }
|
||||
+ return vhost_net_get_features(tap_get_vhost_net(n->nic->nc.peer), features);
|
||||
}
|
||||
|
||||
static uint32_t virtio_net_bad_features(VirtIODevice *vdev)
|
||||
@@ -690,6 +700,12 @@ static void virtio_net_save(QEMUFile *f, void *opaque)
|
||||
{
|
||||
VirtIONet *n = opaque;
|
||||
|
||||
+ if (n->vhost_started) {
|
||||
+ /* TODO: should we really stop the backend?
|
||||
+ * If we don't, it might keep writing to memory. */
|
||||
+ vhost_net_stop(tap_get_vhost_net(n->nic->nc.peer), &n->vdev);
|
||||
+ n->vhost_started = 0;
|
||||
+ }
|
||||
virtio_save(&n->vdev, f);
|
||||
|
||||
qemu_put_buffer(f, n->mac, ETH_ALEN);
|
||||
@@ -802,7 +818,6 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id)
|
||||
qemu_mod_timer(n->tx_timer,
|
||||
qemu_get_clock(vm_clock) + TX_TIMER_INTERVAL);
|
||||
}
|
||||
-
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -822,6 +837,47 @@ static NetClientInfo net_virtio_info = {
|
||||
.link_status_changed = virtio_net_set_link_status,
|
||||
};
|
||||
|
||||
+static void virtio_net_set_status(struct VirtIODevice *vdev)
|
||||
+{
|
||||
+ VirtIONet *n = to_virtio_net(vdev);
|
||||
+ if (!n->nic->nc.peer) {
|
||||
+ return;
|
||||
+ }
|
||||
+ if (n->nic->nc.peer->info->type != NET_CLIENT_TYPE_TAP) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ if (!tap_get_vhost_net(n->nic->nc.peer)) {
|
||||
+ return;
|
||||
+ }
|
||||
+ if (!!n->vhost_started == !!(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK)) {
|
||||
+ return;
|
||||
+ }
|
||||
+ if (vdev->status & VIRTIO_CONFIG_S_DRIVER_OK) {
|
||||
+ int r = vhost_net_start(tap_get_vhost_net(n->nic->nc.peer), vdev);
|
||||
+ if (r < 0) {
|
||||
+ fprintf(stderr, "unable to start vhost net: %d: "
|
||||
+ "falling back on userspace virtio\n", -r);
|
||||
+ } else {
|
||||
+ n->vhost_started = 1;
|
||||
+ }
|
||||
+ } else {
|
||||
+ vhost_net_stop(tap_get_vhost_net(n->nic->nc.peer), vdev);
|
||||
+ n->vhost_started = 0;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void virtio_net_vmstate_change(void *opaque, int running, int reason)
|
||||
+{
|
||||
+ VirtIONet *n = opaque;
|
||||
+ if (!running) {
|
||||
+ return;
|
||||
+ }
|
||||
+ /* This is called when vm is started, it will start vhost backend if it
|
||||
+ * appropriate e.g. after migration. */
|
||||
+ virtio_net_set_status(&n->vdev);
|
||||
+}
|
||||
+
|
||||
VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf)
|
||||
{
|
||||
VirtIONet *n;
|
||||
@@ -837,6 +893,7 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf)
|
||||
n->vdev.set_features = virtio_net_set_features;
|
||||
n->vdev.bad_features = virtio_net_bad_features;
|
||||
n->vdev.reset = virtio_net_reset;
|
||||
+ n->vdev.set_status = virtio_net_set_status;
|
||||
n->rx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_rx);
|
||||
n->tx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_tx);
|
||||
n->ctrl_vq = virtio_add_queue(&n->vdev, 64, virtio_net_handle_ctrl);
|
||||
@@ -859,6 +916,7 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf)
|
||||
|
||||
register_savevm("virtio-net", virtio_net_id++, VIRTIO_NET_VM_VERSION,
|
||||
virtio_net_save, virtio_net_load, n);
|
||||
+ n->vmstate = qemu_add_vm_change_state_handler(virtio_net_vmstate_change, n);
|
||||
|
||||
return &n->vdev;
|
||||
}
|
||||
@@ -866,6 +924,11 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf)
|
||||
void virtio_net_exit(VirtIODevice *vdev)
|
||||
{
|
||||
VirtIONet *n = DO_UPCAST(VirtIONet, vdev, vdev);
|
||||
+ qemu_del_vm_change_state_handler(n->vmstate);
|
||||
+
|
||||
+ if (n->vhost_started) {
|
||||
+ vhost_net_stop(tap_get_vhost_net(n->nic->nc.peer), vdev);
|
||||
+ }
|
||||
|
||||
qemu_purge_queued_packets(&n->nic->nc);
|
||||
|
||||
--
|
||||
1.6.6.144.g5c3af
|
|
@ -0,0 +1,98 @@
|
|||
Support host/guest notifiers in virtio-pci.
|
||||
The last one only with kvm, that's okay
|
||||
because vhost relies on kvm anyway.
|
||||
|
||||
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
---
|
||||
hw/virtio-pci.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
1 files changed, 62 insertions(+), 0 deletions(-)
|
||||
|
||||
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
|
||||
index 05898c8..c454093 100644
|
||||
--- a/hw/virtio-pci.c
|
||||
+++ b/hw/virtio-pci.c
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "msix.h"
|
||||
#include "net.h"
|
||||
#include "loader.h"
|
||||
+#include "kvm.h"
|
||||
|
||||
/* from Linux's linux/virtio_pci.h */
|
||||
|
||||
@@ -394,6 +395,65 @@ static unsigned virtio_pci_get_features(void *opaque)
|
||||
return proxy->host_features;
|
||||
}
|
||||
|
||||
+static void virtio_pci_guest_notifier_read(void *opaque)
|
||||
+{
|
||||
+ VirtQueue *vq = opaque;
|
||||
+ EventNotifier *n = virtio_queue_guest_notifier(vq);
|
||||
+ if (event_notifier_test_and_clear(n)) {
|
||||
+ virtio_irq(vq);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static int virtio_pci_guest_notifier(void *opaque, int n, bool assign)
|
||||
+{
|
||||
+ VirtIOPCIProxy *proxy = opaque;
|
||||
+ VirtQueue *vq = virtio_queue(proxy->vdev, n);
|
||||
+ EventNotifier *notifier = virtio_queue_guest_notifier(vq);
|
||||
+
|
||||
+ if (assign) {
|
||||
+ int r = event_notifier_init(notifier, 0);
|
||||
+ if (r < 0)
|
||||
+ return r;
|
||||
+ qemu_set_fd_handler(event_notifier_get_fd(notifier),
|
||||
+ virtio_pci_guest_notifier_read, NULL, vq);
|
||||
+ } else {
|
||||
+ qemu_set_fd_handler(event_notifier_get_fd(notifier),
|
||||
+ NULL, NULL, vq);
|
||||
+ event_notifier_cleanup(notifier);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int virtio_pci_host_notifier(void *opaque, int n, bool assign)
|
||||
+{
|
||||
+ VirtIOPCIProxy *proxy = opaque;
|
||||
+ VirtQueue *vq = virtio_queue(proxy->vdev, n);
|
||||
+ EventNotifier *notifier = virtio_queue_host_notifier(vq);
|
||||
+ int r;
|
||||
+ if (assign) {
|
||||
+ r = event_notifier_init(notifier, 1);
|
||||
+ if (r < 0) {
|
||||
+ return r;
|
||||
+ }
|
||||
+ r = kvm_set_ioeventfd(proxy->addr + VIRTIO_PCI_QUEUE_NOTIFY,
|
||||
+ n, event_notifier_get_fd(notifier),
|
||||
+ assign);
|
||||
+ if (r < 0) {
|
||||
+ event_notifier_cleanup(notifier);
|
||||
+ }
|
||||
+ } else {
|
||||
+ r = kvm_set_ioeventfd(proxy->addr + VIRTIO_PCI_QUEUE_NOTIFY,
|
||||
+ n, event_notifier_get_fd(notifier),
|
||||
+ assign);
|
||||
+ if (r < 0) {
|
||||
+ return r;
|
||||
+ }
|
||||
+ event_notifier_cleanup(notifier);
|
||||
+ }
|
||||
+ return r;
|
||||
+}
|
||||
+
|
||||
static const VirtIOBindings virtio_pci_bindings = {
|
||||
.notify = virtio_pci_notify,
|
||||
.save_config = virtio_pci_save_config,
|
||||
@@ -401,6 +461,8 @@ static const VirtIOBindings virtio_pci_bindings = {
|
||||
.save_queue = virtio_pci_save_queue,
|
||||
.load_queue = virtio_pci_load_queue,
|
||||
.get_features = virtio_pci_get_features,
|
||||
+ .host_notifier = virtio_pci_host_notifier,
|
||||
+ .guest_notifier = virtio_pci_guest_notifier,
|
||||
};
|
||||
|
||||
static void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev,
|
||||
--
|
||||
1.6.6.144.g5c3af
|
|
@ -0,0 +1,34 @@
|
|||
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
|
||||
---
|
||||
|
||||
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
|
||||
index e8e0d82..fd0c73f 100644
|
||||
--- a/hw/virtio-pci.c
|
||||
+++ b/hw/virtio-pci.c
|
||||
@@ -404,6 +404,7 @@ static void virtio_pci_guest_notifier_read(void *opaque)
|
||||
}
|
||||
}
|
||||
|
||||
+#ifdef CONFIG_KVM
|
||||
static int virtio_pci_mask_notifier(PCIDevice *dev, unsigned vector,
|
||||
void *opaque, int masked)
|
||||
{
|
||||
@@ -424,6 +425,7 @@ static int virtio_pci_mask_notifier(PCIDevice *dev, unsigned vector,
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
+#endif
|
||||
|
||||
static int virtio_pci_guest_notifier(void *opaque, int n, bool assign)
|
||||
{
|
||||
@@ -526,7 +528,9 @@ static void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev,
|
||||
|
||||
proxy->pci_dev.config_write = virtio_write_config;
|
||||
|
||||
+#ifdef CONFIG_KVM
|
||||
proxy->pci_dev.msix_mask_notifier = virtio_pci_mask_notifier;
|
||||
+#endif
|
||||
|
||||
size = VIRTIO_PCI_REGION_SIZE(&proxy->pci_dev) + vdev->config_len;
|
||||
if (size & (size-1))
|
|
@ -0,0 +1,70 @@
|
|||
Use irqfd when supported by kernel.
|
||||
This uses msix mask notifiers: when vector is masked, we poll it from
|
||||
userspace. When it is unmasked, we poll it from kernel.
|
||||
|
||||
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
---
|
||||
hw/virtio-pci.c | 31 +++++++++++++++++++++++++++++--
|
||||
1 files changed, 29 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
|
||||
index c454093..e8e0d82 100644
|
||||
--- a/hw/virtio-pci.c
|
||||
+++ b/hw/virtio-pci.c
|
||||
@@ -404,6 +404,27 @@ static void virtio_pci_guest_notifier_read(void *opaque)
|
||||
}
|
||||
}
|
||||
|
||||
+static int virtio_pci_mask_notifier(PCIDevice *dev, unsigned vector,
|
||||
+ void *opaque, int masked)
|
||||
+{
|
||||
+ VirtQueue *vq = opaque;
|
||||
+ EventNotifier *notifier = virtio_queue_guest_notifier(vq);
|
||||
+ int r = kvm_set_irqfd(dev->msix_irq_entries[vector].gsi,
|
||||
+ event_notifier_get_fd(notifier),
|
||||
+ !masked);
|
||||
+ if (r < 0) {
|
||||
+ return (r == -ENOSYS) ? 0 : r;
|
||||
+ }
|
||||
+ if (masked) {
|
||||
+ qemu_set_fd_handler(event_notifier_get_fd(notifier),
|
||||
+ virtio_pci_guest_notifier_read, NULL, vq);
|
||||
+ } else {
|
||||
+ qemu_set_fd_handler(event_notifier_get_fd(notifier),
|
||||
+ NULL, NULL, vq);
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static int virtio_pci_guest_notifier(void *opaque, int n, bool assign)
|
||||
{
|
||||
VirtIOPCIProxy *proxy = opaque;
|
||||
@@ -412,11 +433,15 @@ static int virtio_pci_guest_notifier(void *opaque, int n, bool assign)
|
||||
|
||||
if (assign) {
|
||||
int r = event_notifier_init(notifier, 0);
|
||||
- if (r < 0)
|
||||
- return r;
|
||||
+ if (r < 0)
|
||||
+ return r;
|
||||
qemu_set_fd_handler(event_notifier_get_fd(notifier),
|
||||
virtio_pci_guest_notifier_read, NULL, vq);
|
||||
+ msix_set_mask_notifier(&proxy->pci_dev,
|
||||
+ virtio_queue_vector(proxy->vdev, n), vq);
|
||||
} else {
|
||||
+ msix_set_mask_notifier(&proxy->pci_dev,
|
||||
+ virtio_queue_vector(proxy->vdev, n), NULL);
|
||||
qemu_set_fd_handler(event_notifier_get_fd(notifier),
|
||||
NULL, NULL, vq);
|
||||
event_notifier_cleanup(notifier);
|
||||
@@ -501,6 +526,8 @@ static void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev,
|
||||
|
||||
proxy->pci_dev.config_write = virtio_write_config;
|
||||
|
||||
+ proxy->pci_dev.msix_mask_notifier = virtio_pci_mask_notifier;
|
||||
+
|
||||
size = VIRTIO_PCI_REGION_SIZE(&proxy->pci_dev) + vdev->config_len;
|
||||
if (size & (size-1))
|
||||
size = 1 << qemu_fls(size);
|
||||
--
|
||||
1.6.6.144.g5c3af
|
|
@ -0,0 +1,149 @@
|
|||
Rename features->guest_features. This is
|
||||
what they are, avoid confusion with
|
||||
host features which we also need to keep around.
|
||||
|
||||
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
|
||||
(cherry picked from commit 704a76fcd24372a683652651b4597f6654084975)
|
||||
---
|
||||
hw/s390-virtio-bus.c | 2 +-
|
||||
hw/syborg_virtio.c | 4 ++--
|
||||
hw/virtio-net.c | 10 +++++-----
|
||||
hw/virtio-pci.c | 4 ++--
|
||||
hw/virtio.c | 8 ++++----
|
||||
hw/virtio.h | 2 +-
|
||||
6 files changed, 15 insertions(+), 15 deletions(-)
|
||||
|
||||
diff --git a/hw/s390-virtio-bus.c b/hw/s390-virtio-bus.c
|
||||
index dc154ed..6c0da11 100644
|
||||
--- a/hw/s390-virtio-bus.c
|
||||
+++ b/hw/s390-virtio-bus.c
|
||||
@@ -251,7 +251,7 @@ void s390_virtio_device_update_status(VirtIOS390Device *dev)
|
||||
if (vdev->set_features) {
|
||||
vdev->set_features(vdev, features);
|
||||
}
|
||||
- vdev->features = features;
|
||||
+ vdev->guest_features = features;
|
||||
}
|
||||
|
||||
VirtIOS390Device *s390_virtio_bus_console(VirtIOS390Bus *bus)
|
||||
diff --git a/hw/syborg_virtio.c b/hw/syborg_virtio.c
|
||||
index a84206a..fe6fc23 100644
|
||||
--- a/hw/syborg_virtio.c
|
||||
+++ b/hw/syborg_virtio.c
|
||||
@@ -90,7 +90,7 @@ static uint32_t syborg_virtio_readl(void *opaque, target_phys_addr_t offset)
|
||||
ret |= vdev->binding->get_features(s);
|
||||
break;
|
||||
case SYBORG_VIRTIO_GUEST_FEATURES:
|
||||
- ret = vdev->features;
|
||||
+ ret = vdev->guest_features;
|
||||
break;
|
||||
case SYBORG_VIRTIO_QUEUE_BASE:
|
||||
ret = virtio_queue_get_addr(vdev, vdev->queue_sel);
|
||||
@@ -132,7 +132,7 @@ static void syborg_virtio_writel(void *opaque, target_phys_addr_t offset,
|
||||
case SYBORG_VIRTIO_GUEST_FEATURES:
|
||||
if (vdev->set_features)
|
||||
vdev->set_features(vdev, value);
|
||||
- vdev->features = value;
|
||||
+ vdev->guest_features = value;
|
||||
break;
|
||||
case SYBORG_VIRTIO_QUEUE_BASE:
|
||||
if (value == 0)
|
||||
diff --git a/hw/virtio-net.c b/hw/virtio-net.c
|
||||
index 2f201ff..ab20a33 100644
|
||||
--- a/hw/virtio-net.c
|
||||
+++ b/hw/virtio-net.c
|
||||
@@ -768,11 +768,11 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id)
|
||||
if (n->has_vnet_hdr) {
|
||||
tap_using_vnet_hdr(n->nic->nc.peer, 1);
|
||||
tap_set_offload(n->nic->nc.peer,
|
||||
- (n->vdev.features >> VIRTIO_NET_F_GUEST_CSUM) & 1,
|
||||
- (n->vdev.features >> VIRTIO_NET_F_GUEST_TSO4) & 1,
|
||||
- (n->vdev.features >> VIRTIO_NET_F_GUEST_TSO6) & 1,
|
||||
- (n->vdev.features >> VIRTIO_NET_F_GUEST_ECN) & 1,
|
||||
- (n->vdev.features >> VIRTIO_NET_F_GUEST_UFO) & 1);
|
||||
+ (n->vdev.guest_features >> VIRTIO_NET_F_GUEST_CSUM) & 1,
|
||||
+ (n->vdev.guest_features >> VIRTIO_NET_F_GUEST_TSO4) & 1,
|
||||
+ (n->vdev.guest_features >> VIRTIO_NET_F_GUEST_TSO6) & 1,
|
||||
+ (n->vdev.guest_features >> VIRTIO_NET_F_GUEST_ECN) & 1,
|
||||
+ (n->vdev.guest_features >> VIRTIO_NET_F_GUEST_UFO) & 1);
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
|
||||
index 3594152..c23dbc0 100644
|
||||
--- a/hw/virtio-pci.c
|
||||
+++ b/hw/virtio-pci.c
|
||||
@@ -181,7 +181,7 @@ static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val)
|
||||
}
|
||||
if (vdev->set_features)
|
||||
vdev->set_features(vdev, val);
|
||||
- vdev->features = val;
|
||||
+ vdev->guest_features = val;
|
||||
break;
|
||||
case VIRTIO_PCI_QUEUE_PFN:
|
||||
pa = (target_phys_addr_t)val << VIRTIO_PCI_QUEUE_ADDR_SHIFT;
|
||||
@@ -239,7 +239,7 @@ static uint32_t virtio_ioport_read(VirtIOPCIProxy *proxy, uint32_t addr)
|
||||
ret |= vdev->binding->get_features(proxy);
|
||||
break;
|
||||
case VIRTIO_PCI_GUEST_FEATURES:
|
||||
- ret = vdev->features;
|
||||
+ ret = vdev->guest_features;
|
||||
break;
|
||||
case VIRTIO_PCI_QUEUE_PFN:
|
||||
ret = virtio_queue_get_addr(vdev, vdev->queue_sel)
|
||||
diff --git a/hw/virtio.c b/hw/virtio.c
|
||||
index cecd0dc..c25a5f1 100644
|
||||
--- a/hw/virtio.c
|
||||
+++ b/hw/virtio.c
|
||||
@@ -445,7 +445,7 @@ void virtio_reset(void *opaque)
|
||||
if (vdev->reset)
|
||||
vdev->reset(vdev);
|
||||
|
||||
- vdev->features = 0;
|
||||
+ vdev->guest_features = 0;
|
||||
vdev->queue_sel = 0;
|
||||
vdev->status = 0;
|
||||
vdev->isr = 0;
|
||||
@@ -598,7 +598,7 @@ void virtio_notify(VirtIODevice *vdev, VirtQueue *vq)
|
||||
{
|
||||
/* Always notify when queue is empty (when feature acknowledge) */
|
||||
if ((vring_avail_flags(vq) & VRING_AVAIL_F_NO_INTERRUPT) &&
|
||||
- (!(vdev->features & (1 << VIRTIO_F_NOTIFY_ON_EMPTY)) ||
|
||||
+ (!(vdev->guest_features & (1 << VIRTIO_F_NOTIFY_ON_EMPTY)) ||
|
||||
(vq->inuse || vring_avail_idx(vq) != vq->last_avail_idx)))
|
||||
return;
|
||||
|
||||
@@ -625,7 +625,7 @@ void virtio_save(VirtIODevice *vdev, QEMUFile *f)
|
||||
qemu_put_8s(f, &vdev->status);
|
||||
qemu_put_8s(f, &vdev->isr);
|
||||
qemu_put_be16s(f, &vdev->queue_sel);
|
||||
- qemu_put_be32s(f, &vdev->features);
|
||||
+ qemu_put_be32s(f, &vdev->guest_features);
|
||||
qemu_put_be32(f, vdev->config_len);
|
||||
qemu_put_buffer(f, vdev->config, vdev->config_len);
|
||||
|
||||
@@ -670,7 +670,7 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f)
|
||||
features, supported_features);
|
||||
return -1;
|
||||
}
|
||||
- vdev->features = features;
|
||||
+ vdev->guest_features = features;
|
||||
vdev->config_len = qemu_get_be32(f);
|
||||
qemu_get_buffer(f, vdev->config, vdev->config_len);
|
||||
|
||||
diff --git a/hw/virtio.h b/hw/virtio.h
|
||||
index 35532a6..85ef171 100644
|
||||
--- a/hw/virtio.h
|
||||
+++ b/hw/virtio.h
|
||||
@@ -100,7 +100,7 @@ struct VirtIODevice
|
||||
uint8_t status;
|
||||
uint8_t isr;
|
||||
uint16_t queue_sel;
|
||||
- uint32_t features;
|
||||
+ uint32_t guest_features;
|
||||
size_t config_len;
|
||||
void *config;
|
||||
uint16_t config_vector;
|
||||
--
|
||||
1.6.6.144.g5c3af
|
|
@ -0,0 +1,25 @@
|
|||
--- a/hw/virtio-serial-bus.c 2010-02-09 00:41:21.000000000 -0600
|
||||
+++ b/hw/virtio-serial-bus.c 2010-02-09 00:07:13.000000000 -0600
|
||||
@@ -68,7 +68,7 @@ static VirtIOSerialPort *find_port_by_vq
|
||||
|
||||
static bool use_multiport(VirtIOSerial *vser)
|
||||
{
|
||||
- return vser->vdev.features & (1 << VIRTIO_CONSOLE_F_MULTIPORT);
|
||||
+ return vser->vdev.guest_features & (1 << VIRTIO_CONSOLE_F_MULTIPORT);
|
||||
}
|
||||
|
||||
static size_t write_to_port(VirtIOSerialPort *port,
|
||||
@@ -333,9 +333,11 @@ static void handle_input(VirtIODevice *v
|
||||
{
|
||||
}
|
||||
|
||||
-static uint32_t get_features(VirtIODevice *vdev)
|
||||
+static uint32_t get_features(VirtIODevice *vdev, uint32_t features)
|
||||
{
|
||||
- return 1 << VIRTIO_CONSOLE_F_MULTIPORT;
|
||||
+ features |= (1 << VIRTIO_CONSOLE_F_MULTIPORT);
|
||||
+
|
||||
+ return features;
|
||||
}
|
||||
|
||||
/* Guest requested config info */
|
61
qemu.spec
61
qemu.spec
|
@ -1,7 +1,7 @@
|
|||
Summary: QEMU is a FAST! processor emulator
|
||||
Name: qemu
|
||||
Version: 0.12.2
|
||||
Release: 5%{?dist}
|
||||
Release: 6%{?dist}
|
||||
# Epoch because we pushed a qemu-1.0 package
|
||||
Epoch: 2
|
||||
License: GPLv2+ and LGPLv2+ and BSD
|
||||
|
@ -37,6 +37,35 @@ Patch09: qemu-virtio-console-Rename-virtio-serial.c-back-to-virti.patch
|
|||
|
||||
Patch10: qemu-v2-block-avoid-creating-too-large-iovecs-in-multiwrite_merge.patch
|
||||
|
||||
# VHostNet Patches
|
||||
Patch11: qemu-net-add-API-to-disable-enable-polling.patch
|
||||
Patch12: qemu-virtio-rename-features-guest_features.patch
|
||||
Patch13: qemu-qdev-add-bit-property-type.patch
|
||||
Patch14: qemu-qdev-fix-thinko-leading-to-guest-crashes.patch
|
||||
Patch15: qemu-virtio-add-features-as-qdev-properties.patch
|
||||
Patch16: qemu-virtio-net-mac-property-is-mandatory.patch
|
||||
Patch17: qemu-exec-memory-notifiers.patch
|
||||
Patch18: qemu-kvm-add-API-to-set-ioeventfd.patch
|
||||
Patch19: qemu-notifier-event-notifier-implementation.patch
|
||||
Patch20: qemu-virtio-add-notifier-support.patch
|
||||
Patch21: qemu-virtio-add-APIs-for-queue-fields.patch
|
||||
Patch22: qemu-virtio-add-status-change-callback.patch
|
||||
Patch23: qemu-virtio-move-typedef-to-qemu-common.patch
|
||||
Patch24: qemu-virtio-pci-fill-in-notifier-support.patch
|
||||
Patch25: qemu-tap-add-interface-to-get-device-fd.patch
|
||||
Patch26: qemu-vhost-vhost-net-support.patch
|
||||
Patch27: qemu-tap-add-vhost-vhostfd-options.patch
|
||||
Patch28: qemu-tap-add-API-to-retrieve-vhost-net-header.patch
|
||||
Patch29: qemu-virtio-net-vhost-net-support.patch
|
||||
Patch30: qemu-kvm-add-vhost.h-header.patch
|
||||
Patch31: qemu-kvm-irqfd-support.patch
|
||||
Patch32: qemu-msix-add-mask-unmask-notifiers.patch
|
||||
Patch33: qemu-virtio-pci-irqfd-support.patch
|
||||
Patch34: qemu-virtio-avoid-crash-with-non-tap-backends.patch
|
||||
Patch35: qemu-virtio-serial-features-build-fix.patch
|
||||
Patch36: qemu-virtio-pci-irqfd-fix-nonkvm-build.patch
|
||||
Patch37: qemu-vhost-add-configure-check.patch
|
||||
|
||||
|
||||
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
|
||||
BuildRequires: SDL-devel zlib-devel which texi2html gnutls-devel cyrus-sasl-devel
|
||||
|
@ -235,6 +264,33 @@ such as kvmtrace and kvm_stat.
|
|||
%patch08 -p1
|
||||
%patch09 -p1
|
||||
%patch10 -p1
|
||||
%patch11 -p1
|
||||
%patch12 -p1
|
||||
%patch13 -p1
|
||||
%patch14 -p1
|
||||
%patch15 -p1
|
||||
%patch16 -p1
|
||||
%patch17 -p1
|
||||
%patch18 -p1
|
||||
%patch19 -p1
|
||||
%patch20 -p1
|
||||
%patch21 -p1
|
||||
%patch22 -p1
|
||||
%patch23 -p1
|
||||
%patch24 -p1
|
||||
%patch25 -p1
|
||||
%patch26 -p1
|
||||
%patch27 -p1
|
||||
%patch28 -p1
|
||||
%patch29 -p1
|
||||
%patch30 -p1
|
||||
%patch31 -p1
|
||||
%patch32 -p1
|
||||
%patch33 -p1
|
||||
%patch34 -p1
|
||||
%patch35 -p1
|
||||
%patch36 -p1
|
||||
%patch37 -p1
|
||||
|
||||
%build
|
||||
# --build-id option is used fedora 8 onwards for giving info to the debug packages.
|
||||
|
@ -518,6 +574,9 @@ fi
|
|||
%{_mandir}/man1/qemu-img.1*
|
||||
|
||||
%changelog
|
||||
* Tue Feb 09 2010 Justin M. Forbes <jforbes@redhat.com> - 2:0.12.2-6
|
||||
- Add vhost net support.
|
||||
|
||||
* Thu Feb 04 2010 Justin M. Forbes <jforbes@redhat.com> - 2:0.12.2-5
|
||||
- Avoid creating too large iovecs in multiwrite merge (#559717)
|
||||
- Don't try to set max_kernel_pages during ksm init on newer kernels (#558281)
|
||||
|
|
Loading…
Reference in New Issue