aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/bt/hci.c4
-rw-r--r--hw/i386/pc_piix.c22
-rw-r--r--hw/i386/pc_q35.c22
-rw-r--r--hw/mips/cputimer.c19
-rw-r--r--hw/net/pcnet.c3
-rw-r--r--hw/net/rtl8139.c14
-rw-r--r--hw/net/vhost_net.c44
-rw-r--r--hw/net/virtio-net.c48
-rw-r--r--hw/openrisc/cputimer.c7
-rw-r--r--hw/s390x/s390-virtio-ccw.c20
-rw-r--r--hw/s390x/virtio-ccw.c64
-rw-r--r--hw/s390x/virtio-ccw.h6
-rw-r--r--hw/timer/hpet.c6
-rw-r--r--hw/vfio/pci-quirks.c16
-rw-r--r--hw/virtio/vhost-backend.c10
-rw-r--r--hw/virtio/vhost-user.c139
-rw-r--r--hw/virtio/vhost.c20
-rw-r--r--hw/virtio/virtio.c66
-rw-r--r--hw/watchdog/wdt_i6300esb.c11
19 files changed, 409 insertions, 132 deletions
diff --git a/hw/bt/hci.c b/hw/bt/hci.c
index 3fec435378..6a88d492ac 100644
--- a/hw/bt/hci.c
+++ b/hw/bt/hci.c
@@ -595,7 +595,7 @@ static void bt_hci_inquiry_result(struct bt_hci_s *hci,
static void bt_hci_mod_timer_1280ms(QEMUTimer *timer, int period)
{
timer_mod(timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- muldiv64(period << 7, get_ticks_per_sec(), 100));
+ (uint64_t)(period << 7) * 10000000);
}
static void bt_hci_inquiry_start(struct bt_hci_s *hci, int length)
@@ -1099,7 +1099,7 @@ static int bt_hci_mode_change(struct bt_hci_s *hci, uint16_t handle,
bt_hci_event_status(hci, HCI_SUCCESS);
timer_mod(link->acl_mode_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- muldiv64(interval * 625, get_ticks_per_sec(), 1000000));
+ ((uint64_t)interval * 625) * 1000);
bt_hci_lmp_mode_change_master(hci, link->link, mode, interval);
return 0;
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 3f925b26db..3ffb05f93e 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -460,19 +460,31 @@ static void pc_i440fx_machine_options(MachineClass *m)
m->family = "pc_piix";
m->desc = "Standard PC (i440FX + PIIX, 1996)";
m->hot_add_cpu = pc_hot_add_cpu;
+ m->default_machine_opts = "firmware=bios-256k.bin";
+ m->default_display = "std";
}
-static void pc_i440fx_2_4_machine_options(MachineClass *m)
+static void pc_i440fx_2_5_machine_options(MachineClass *m)
{
- PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
pc_i440fx_machine_options(m);
- pcmc->broken_reserved_end = true;
- m->default_machine_opts = "firmware=bios-256k.bin";
- m->default_display = "std";
m->alias = "pc";
m->is_default = 1;
}
+DEFINE_I440FX_MACHINE(v2_5, "pc-i440fx-2.5", NULL,
+ pc_i440fx_2_5_machine_options);
+
+
+static void pc_i440fx_2_4_machine_options(MachineClass *m)
+{
+ PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
+ pc_i440fx_2_5_machine_options(m);
+ m->alias = NULL;
+ m->is_default = 0;
+ pcmc->broken_reserved_end = true;
+ SET_MACHINE_COMPAT(m, PC_COMPAT_2_4);
+}
+
DEFINE_I440FX_MACHINE(v2_4, "pc-i440fx-2.4", NULL,
pc_i440fx_2_4_machine_options)
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index 11601ab005..1b7d3b644e 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -364,18 +364,28 @@ static void pc_q35_machine_options(MachineClass *m)
m->desc = "Standard PC (Q35 + ICH9, 2009)";
m->hot_add_cpu = pc_hot_add_cpu;
m->units_per_default_bus = 1;
+ m->default_machine_opts = "firmware=bios-256k.bin";
+ m->default_display = "std";
+ m->no_floppy = 1;
+ m->no_tco = 0;
+}
+
+static void pc_q35_2_5_machine_options(MachineClass *m)
+{
+ pc_q35_machine_options(m);
+ m->alias = "q35";
}
+DEFINE_Q35_MACHINE(v2_5, "pc-q35-2.5", NULL,
+ pc_q35_2_5_machine_options);
+
static void pc_q35_2_4_machine_options(MachineClass *m)
{
PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
- pc_q35_machine_options(m);
+ pc_q35_2_5_machine_options(m);
+ m->alias = NULL;
pcmc->broken_reserved_end = true;
- m->default_machine_opts = "firmware=bios-256k.bin";
- m->default_display = "std";
- m->no_floppy = 1;
- m->no_tco = 0;
- m->alias = "q35";
+ SET_MACHINE_COMPAT(m, PC_COMPAT_2_4);
}
DEFINE_Q35_MACHINE(v2_4, "pc-q35-2.4", NULL,
diff --git a/hw/mips/cputimer.c b/hw/mips/cputimer.c
index ba9264b415..f046588ada 100644
--- a/hw/mips/cputimer.c
+++ b/hw/mips/cputimer.c
@@ -25,7 +25,7 @@
#include "qemu/timer.h"
#include "sysemu/kvm.h"
-#define TIMER_FREQ 100 * 1000 * 1000
+#define TIMER_PERIOD 10 /* 10 ns period for 100 Mhz frequency */
/* XXX: do not use a global */
uint32_t cpu_mips_get_random (CPUMIPSState *env)
@@ -57,9 +57,8 @@ static void cpu_mips_timer_update(CPUMIPSState *env)
uint32_t wait;
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- wait = env->CP0_Compare - env->CP0_Count -
- (uint32_t)muldiv64(now, TIMER_FREQ, get_ticks_per_sec());
- next = now + muldiv64(wait, get_ticks_per_sec(), TIMER_FREQ);
+ wait = env->CP0_Compare - env->CP0_Count - (uint32_t)(now / TIMER_PERIOD);
+ next = now + (uint64_t)wait * TIMER_PERIOD;
timer_mod(env->timer, next);
}
@@ -87,8 +86,7 @@ uint32_t cpu_mips_get_count (CPUMIPSState *env)
cpu_mips_timer_expire(env);
}
- return env->CP0_Count +
- (uint32_t)muldiv64(now, TIMER_FREQ, get_ticks_per_sec());
+ return env->CP0_Count + (uint32_t)(now / TIMER_PERIOD);
}
}
@@ -103,9 +101,8 @@ void cpu_mips_store_count (CPUMIPSState *env, uint32_t count)
env->CP0_Count = count;
else {
/* Store new count register */
- env->CP0_Count =
- count - (uint32_t)muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
- TIMER_FREQ, get_ticks_per_sec());
+ env->CP0_Count = count -
+ (uint32_t)(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / TIMER_PERIOD);
/* Update timer timer */
cpu_mips_timer_update(env);
}
@@ -129,8 +126,8 @@ void cpu_mips_start_count(CPUMIPSState *env)
void cpu_mips_stop_count(CPUMIPSState *env)
{
/* Store the current value */
- env->CP0_Count += (uint32_t)muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
- TIMER_FREQ, get_ticks_per_sec());
+ env->CP0_Count += (uint32_t)(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) /
+ TIMER_PERIOD);
}
static void mips_timer_cb (void *opaque)
diff --git a/hw/net/pcnet.c b/hw/net/pcnet.c
index 34373767d9..0eb3cc4d5b 100644
--- a/hw/net/pcnet.c
+++ b/hw/net/pcnet.c
@@ -670,8 +670,7 @@ static inline hwaddr pcnet_rdra_addr(PCNetState *s, int idx)
static inline int64_t pcnet_get_next_poll_time(PCNetState *s, int64_t current_time)
{
int64_t next_time = current_time +
- muldiv64(65536 - (CSR_SPND(s) ? 0 : CSR_POLL(s)),
- get_ticks_per_sec(), 33000000L);
+ (65536 - (CSR_SPND(s) ? 0 : CSR_POLL(s))) * 30;
if (next_time <= current_time)
next_time = current_time + 1;
return next_time;
diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c
index b0d6c40f58..68e43f3d48 100644
--- a/hw/net/rtl8139.c
+++ b/hw/net/rtl8139.c
@@ -64,7 +64,7 @@
/* debug RTL8139 card */
//#define DEBUG_RTL8139 1
-#define PCI_FREQUENCY 33000000L
+#define PCI_PERIOD 30 /* 30 ns period = 33.333333 Mhz frequency */
#define SET_MASKED(input, mask, curr) \
( ( (input) & ~(mask) ) | ( (curr) & (mask) ) )
@@ -2834,8 +2834,7 @@ static void rtl8139_io_writew(void *opaque, uint8_t addr, uint32_t val)
static void rtl8139_set_next_tctr_time(RTL8139State *s)
{
- const uint64_t ns_per_period =
- muldiv64(0x100000000LL, get_ticks_per_sec(), PCI_FREQUENCY);
+ const uint64_t ns_per_period = (uint64_t)PCI_PERIOD << 32;
DPRINTF("entered rtl8139_set_next_tctr_time\n");
@@ -2853,7 +2852,7 @@ static void rtl8139_set_next_tctr_time(RTL8139State *s)
if (!s->TimerInt) {
timer_del(s->timer);
} else {
- uint64_t delta = muldiv64(s->TimerInt, get_ticks_per_sec(), PCI_FREQUENCY);
+ uint64_t delta = (uint64_t)s->TimerInt * PCI_PERIOD;
if (s->TCTR_base + delta <= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)) {
delta += ns_per_period;
}
@@ -3127,8 +3126,8 @@ static uint32_t rtl8139_io_readl(void *opaque, uint8_t addr)
break;
case Timer:
- ret = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - s->TCTR_base,
- PCI_FREQUENCY, get_ticks_per_sec());
+ ret = (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - s->TCTR_base) /
+ PCI_PERIOD;
DPRINTF("TCTR Timer read val=0x%08x\n", ret);
break;
@@ -3222,8 +3221,7 @@ static void rtl8139_pre_save(void *opaque)
int64_t current_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
/* for migration to older versions */
- s->TCTR = muldiv64(current_time - s->TCTR_base, PCI_FREQUENCY,
- get_ticks_per_sec());
+ s->TCTR = (current_time - s->TCTR_base) / PCI_PERIOD;
s->rtl8139_mmio_io_addr_dummy = 0;
}
diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
index 1d76b94c84..2bce89129d 100644
--- a/hw/net/vhost_net.c
+++ b/hw/net/vhost_net.c
@@ -122,6 +122,11 @@ void vhost_net_ack_features(struct vhost_net *net, uint64_t features)
vhost_ack_features(&net->dev, vhost_net_get_feature_bits(net), features);
}
+uint64_t vhost_net_get_max_queues(VHostNetState *net)
+{
+ return net->dev.max_queues;
+}
+
static int vhost_net_get_fd(NetClientState *backend)
{
switch (backend->info->type) {
@@ -143,6 +148,11 @@ struct vhost_net *vhost_net_init(VhostNetOptions *options)
fprintf(stderr, "vhost-net requires net backend to be setup\n");
goto fail;
}
+ net->nc = options->net_backend;
+
+ net->dev.max_queues = 1;
+ net->dev.nvqs = 2;
+ net->dev.vqs = net->vqs;
if (backend_kernel) {
r = vhost_net_get_fd(options->net_backend);
@@ -152,14 +162,15 @@ struct vhost_net *vhost_net_init(VhostNetOptions *options)
net->dev.backend_features = qemu_has_vnet_hdr(options->net_backend)
? 0 : (1ULL << VHOST_NET_F_VIRTIO_NET_HDR);
net->backend = r;
+ net->dev.protocol_features = 0;
} else {
net->dev.backend_features = 0;
+ net->dev.protocol_features = 0;
net->backend = -1;
- }
- net->nc = options->net_backend;
- net->dev.nvqs = 2;
- net->dev.vqs = net->vqs;
+ /* vhost-user needs vq_index to initiate a specific queue pair */
+ net->dev.vq_index = net->nc->queue_index * net->dev.nvqs;
+ }
r = vhost_dev_init(&net->dev, options->opaque,
options->backend_type);
@@ -285,7 +296,7 @@ static void vhost_net_stop_one(struct vhost_net *net,
} else if (net->nc->info->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER) {
for (file.index = 0; file.index < net->dev.nvqs; ++file.index) {
const VhostOps *vhost_ops = net->dev.vhost_ops;
- int r = vhost_ops->vhost_call(&net->dev, VHOST_RESET_OWNER,
+ int r = vhost_ops->vhost_call(&net->dev, VHOST_RESET_DEVICE,
NULL);
assert(r >= 0);
}
@@ -411,7 +422,25 @@ VHostNetState *get_vhost_net(NetClientState *nc)
return vhost_net;
}
+
+int vhost_set_vring_enable(NetClientState *nc, int enable)
+{
+ VHostNetState *net = get_vhost_net(nc);
+ const VhostOps *vhost_ops = net->dev.vhost_ops;
+
+ if (vhost_ops->vhost_backend_set_vring_enable) {
+ return vhost_ops->vhost_backend_set_vring_enable(&net->dev, enable);
+ }
+
+ return 0;
+}
+
#else
+uint64_t vhost_net_get_max_queues(VHostNetState *net)
+{
+ return 1;
+}
+
struct vhost_net *vhost_net_init(VhostNetOptions *options)
{
error_report("vhost-net support is not compiled in");
@@ -456,4 +485,9 @@ VHostNetState *get_vhost_net(NetClientState *nc)
{
return 0;
}
+
+int vhost_set_vring_enable(NetClientState *nc, int enable)
+{
+ return 0;
+}
#endif
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index f72eebff2b..d388c5571d 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -406,6 +406,10 @@ static int peer_attach(VirtIONet *n, int index)
return 0;
}
+ if (nc->peer->info->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER) {
+ vhost_set_vring_enable(nc->peer, 1);
+ }
+
if (nc->peer->info->type != NET_CLIENT_OPTIONS_KIND_TAP) {
return 0;
}
@@ -421,6 +425,10 @@ static int peer_detach(VirtIONet *n, int index)
return 0;
}
+ if (nc->peer->info->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER) {
+ vhost_set_vring_enable(nc->peer, 0);
+ }
+
if (nc->peer->info->type != NET_CLIENT_OPTIONS_KIND_TAP) {
return 0;
}
@@ -1458,11 +1466,33 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id)
{
VirtIONet *n = opaque;
VirtIODevice *vdev = VIRTIO_DEVICE(n);
+ int ret;
if (version_id < 2 || version_id > VIRTIO_NET_VM_VERSION)
return -EINVAL;
- return virtio_load(vdev, f, version_id);
+ ret = virtio_load(vdev, f, version_id);
+ if (ret) {
+ return ret;
+ }
+
+ if (virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)) {
+ n->curr_guest_offloads = qemu_get_be64(f);
+ } else {
+ n->curr_guest_offloads = virtio_net_supported_guest_offloads(n);
+ }
+
+ if (peer_has_vnet_hdr(n)) {
+ virtio_net_apply_guest_offloads(n);
+ }
+
+ if (virtio_vdev_has_feature(vdev, VIRTIO_NET_F_GUEST_ANNOUNCE) &&
+ virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ)) {
+ n->announce_counter = SELF_ANNOUNCE_ROUNDS;
+ timer_mod(n->announce_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL));
+ }
+
+ return 0;
}
static int virtio_net_load_device(VirtIODevice *vdev, QEMUFile *f,
@@ -1559,16 +1589,6 @@ static int virtio_net_load_device(VirtIODevice *vdev, QEMUFile *f,
}
}
- if (virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)) {
- n->curr_guest_offloads = qemu_get_be64(f);
- } else {
- n->curr_guest_offloads = virtio_net_supported_guest_offloads(n);
- }
-
- if (peer_has_vnet_hdr(n)) {
- virtio_net_apply_guest_offloads(n);
- }
-
virtio_net_set_queues(n);
/* Find the first multicast entry in the saved MAC filter */
@@ -1586,12 +1606,6 @@ static int virtio_net_load_device(VirtIODevice *vdev, QEMUFile *f,
qemu_get_subqueue(n->nic, i)->link_down = link_down;
}
- if (virtio_vdev_has_feature(vdev, VIRTIO_NET_F_GUEST_ANNOUNCE) &&
- virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ)) {
- n->announce_counter = SELF_ANNOUNCE_ROUNDS;
- timer_mod(n->announce_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL));
- }
-
return 0;
}
diff --git a/hw/openrisc/cputimer.c b/hw/openrisc/cputimer.c
index 9c54945107..560cb914c5 100644
--- a/hw/openrisc/cputimer.c
+++ b/hw/openrisc/cputimer.c
@@ -22,7 +22,7 @@
#include "hw/hw.h"
#include "qemu/timer.h"
-#define TIMER_FREQ (20 * 1000 * 1000) /* 20MHz */
+#define TIMER_PERIOD 50 /* 50 ns period for 20 MHz timer */
/* The time when TTCR changes */
static uint64_t last_clk;
@@ -36,8 +36,7 @@ void cpu_openrisc_count_update(OpenRISCCPU *cpu)
return;
}
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- cpu->env.ttcr += (uint32_t)muldiv64(now - last_clk, TIMER_FREQ,
- get_ticks_per_sec());
+ cpu->env.ttcr += (uint32_t)((now - last_clk) / TIMER_PERIOD);
last_clk = now;
}
@@ -59,7 +58,7 @@ void cpu_openrisc_timer_update(OpenRISCCPU *cpu)
} else {
wait = (cpu->env.ttmr & TTMR_TP) - (cpu->env.ttcr & TTMR_TP);
}
- next = now + muldiv64(wait, get_ticks_per_sec(), TIMER_FREQ);
+ next = now + (uint64_t)wait * TIMER_PERIOD;
timer_mod(cpu->env.timer, next);
}
diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index 36f78b417c..c53ebc1ae1 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -242,6 +242,26 @@ static const TypeInfo ccw_machine_info = {
.driver = TYPE_S390_SKEYS,\
.property = "migration-enabled",\
.value = "off",\
+ },{\
+ .driver = "virtio-blk-ccw",\
+ .property = "max_revision",\
+ .value = "0",\
+ },{\
+ .driver = "virtio-balloon-ccw",\
+ .property = "max_revision",\
+ .value = "0",\
+ },{\
+ .driver = "virtio-serial-ccw",\
+ .property = "max_revision",\
+ .value = "0",\
+ },{\
+ .driver = "virtio-9p-ccw",\
+ .property = "max_revision",\
+ .value = "0",\
+ },{\
+ .driver = "virtio-rng-ccw",\
+ .property = "max_revision",\
+ .value = "0",\
},
static void ccw_machine_2_4_class_init(ObjectClass *oc, void *data)
diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c
index d36373e88a..fb103b78ac 100644
--- a/hw/s390x/virtio-ccw.c
+++ b/hw/s390x/virtio-ccw.c
@@ -307,11 +307,18 @@ static int virtio_ccw_set_vqs(SubchDev *sch, VqInfoBlock *info,
if (!desc) {
virtio_queue_set_vector(vdev, index, VIRTIO_NO_VECTOR);
} else {
- /* Fail if we don't have a big enough queue. */
- /* TODO: Add interface to handle vring.num changing */
- if (virtio_queue_get_num(vdev, index) > num) {
+ if (info) {
+ /* virtio-1 allows changing the ring size. */
+ if (virtio_queue_get_num(vdev, index) < num) {
+ /* Fail if we exceed the maximum number. */
+ return -EINVAL;
+ }
+ virtio_queue_set_num(vdev, index, num);
+ } else if (virtio_queue_get_num(vdev, index) > num) {
+ /* Fail if we don't have a big enough queue. */
return -EINVAL;
}
+ /* We ignore possible increased num for legacy for compatibility. */
virtio_queue_set_vector(vdev, index, index);
}
/* tell notify handler in case of config change */
@@ -460,16 +467,19 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
MEMTXATTRS_UNSPECIFIED,
NULL);
if (features.index == 0) {
- features.features = (uint32_t)vdev->host_features;
- } else if (features.index == 1) {
- features.features = (uint32_t)(vdev->host_features >> 32);
+ if (dev->revision >= 1) {
+ /* Don't offer legacy features for modern devices. */
+ features.features = (uint32_t)
+ (vdev->host_features & ~VIRTIO_LEGACY_FEATURES);
+ } else {
+ features.features = (uint32_t)vdev->host_features;
+ }
+ } else if ((features.index == 1) && (dev->revision >= 1)) {
/*
- * Don't offer version 1 to the guest if it did not
- * negotiate at least revision 1.
+ * Only offer feature bits beyond 31 if the guest has
+ * negotiated at least revision 1.
*/
- if (dev->revision <= 0) {
- features.features &= ~(1 << (VIRTIO_F_VERSION_1 - 32));
- }
+ features.features = (uint32_t)(vdev->host_features >> 32);
} else {
/* Return zeroes if the guest supports more feature bits. */
features.features = 0;
@@ -508,14 +518,12 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
virtio_set_features(vdev,
(vdev->guest_features & 0xffffffff00000000ULL) |
features.features);
- } else if (features.index == 1) {
+ } else if ((features.index == 1) && (dev->revision >= 1)) {
/*
- * The guest should not set version 1 if it didn't
- * negotiate a revision >= 1.
+ * If the guest did not negotiate at least revision 1,
+ * we did not offer it any feature bits beyond 31. Such a
+ * guest passing us any bit here is therefore buggy.
*/
- if (dev->revision <= 0) {
- features.features &= ~(1 << (VIRTIO_F_VERSION_1 - 32));
- }
virtio_set_features(vdev,
(vdev->guest_features & 0x00000000ffffffffULL) |
((uint64_t)features.features << 32));
@@ -766,7 +774,7 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
* need to fetch it here. Nothing to do for now, though.
*/
if (dev->revision >= 0 ||
- revinfo.revision > virtio_ccw_rev_max(vdev)) {
+ revinfo.revision > virtio_ccw_rev_max(dev)) {
ret = -ENOSYS;
break;
}
@@ -1539,6 +1547,10 @@ static void virtio_ccw_device_plugged(DeviceState *d, Error **errp)
sch->id.cu_model = virtio_bus_get_vdev_id(&dev->bus);
+ if (dev->max_rev >= 1) {
+ virtio_add_feature(&vdev->host_features, VIRTIO_F_VERSION_1);
+ }
+
css_generate_sch_crws(sch->cssid, sch->ssid, sch->schid,
d->hotplugged, 1);
}
@@ -1555,6 +1567,8 @@ static Property virtio_ccw_net_properties[] = {
DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
+ DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
+ VIRTIO_CCW_MAX_REV),
DEFINE_PROP_END_OF_LIST(),
};
@@ -1582,6 +1596,8 @@ static Property virtio_ccw_blk_properties[] = {
DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
+ DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
+ VIRTIO_CCW_MAX_REV),
DEFINE_PROP_END_OF_LIST(),
};
@@ -1609,6 +1625,8 @@ static Property virtio_ccw_serial_properties[] = {
DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
+ DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
+ VIRTIO_CCW_MAX_REV),
DEFINE_PROP_END_OF_LIST(),
};
@@ -1636,6 +1654,8 @@ static Property virtio_ccw_balloon_properties[] = {
DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
+ DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
+ VIRTIO_CCW_MAX_REV),
DEFINE_PROP_END_OF_LIST(),
};
@@ -1663,6 +1683,8 @@ static Property virtio_ccw_scsi_properties[] = {
DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
+ DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
+ VIRTIO_CCW_MAX_REV),
DEFINE_PROP_END_OF_LIST(),
};
@@ -1689,6 +1711,8 @@ static const TypeInfo virtio_ccw_scsi = {
#ifdef CONFIG_VHOST_SCSI
static Property vhost_ccw_scsi_properties[] = {
DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
+ DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
+ VIRTIO_CCW_MAX_REV),
DEFINE_PROP_END_OF_LIST(),
};
@@ -1727,6 +1751,8 @@ static Property virtio_ccw_rng_properties[] = {
DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
+ DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
+ VIRTIO_CCW_MAX_REV),
DEFINE_PROP_END_OF_LIST(),
};
@@ -1880,6 +1906,8 @@ static Property virtio_ccw_9p_properties[] = {
DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
+ DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
+ VIRTIO_CCW_MAX_REV),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/s390x/virtio-ccw.h b/hw/s390x/virtio-ccw.h
index 692ddd7318..7ab8367baa 100644
--- a/hw/s390x/virtio-ccw.h
+++ b/hw/s390x/virtio-ccw.h
@@ -88,6 +88,7 @@ struct VirtioCcwDevice {
SubchDev *sch;
char *bus_id;
int revision;
+ uint32_t max_rev;
VirtioBusState bus;
bool ioeventfd_started;
bool ioeventfd_disabled;
@@ -102,9 +103,10 @@ struct VirtioCcwDevice {
};
/* The maximum virtio revision we support. */
-static inline int virtio_ccw_rev_max(VirtIODevice *vdev)
+#define VIRTIO_CCW_MAX_REV 1
+static inline int virtio_ccw_rev_max(VirtioCcwDevice *dev)
{
- return 0;
+ return dev->max_rev;
}
/* virtual css bus type */
diff --git a/hw/timer/hpet.c b/hw/timer/hpet.c
index 2bb62211c3..3037bef72e 100644
--- a/hw/timer/hpet.c
+++ b/hw/timer/hpet.c
@@ -126,12 +126,12 @@ static uint32_t hpet_time_after64(uint64_t a, uint64_t b)
static uint64_t ticks_to_ns(uint64_t value)
{
- return (muldiv64(value, HPET_CLK_PERIOD, FS_PER_NS));
+ return value * HPET_CLK_PERIOD;
}
static uint64_t ns_to_ticks(uint64_t value)
{
- return (muldiv64(value, FS_PER_NS, HPET_CLK_PERIOD));
+ return value / HPET_CLK_PERIOD;
}
static uint64_t hpet_fixup_reg(uint64_t new, uint64_t old, uint64_t mask)
@@ -758,7 +758,7 @@ static void hpet_realize(DeviceState *dev, Error **errp)
/* 64-bit main counter; LegacyReplacementRoute. */
s->capability = 0x8086a001ULL;
s->capability |= (s->num_timers - 1) << HPET_ID_NUM_TIM_SHIFT;
- s->capability |= ((HPET_CLK_PERIOD) << 32);
+ s->capability |= ((uint64_t)(HPET_CLK_PERIOD * FS_PER_NS) << 32);
qdev_init_gpio_in(dev, hpet_handle_legacy_irq, 2);
qdev_init_gpio_out(dev, &s->pit_enabled, 1);
diff --git a/hw/vfio/pci-quirks.c b/hw/vfio/pci-quirks.c
index 2bdaef19f1..c675d1bc30 100644
--- a/hw/vfio/pci-quirks.c
+++ b/hw/vfio/pci-quirks.c
@@ -284,7 +284,7 @@ static void vfio_vga_probe_ati_3c3_quirk(VFIOPCIDevice *vdev)
}
quirk = g_malloc0(sizeof(*quirk));
- quirk->mem = g_malloc0_n(sizeof(MemoryRegion), 1);
+ quirk->mem = g_malloc0(sizeof(MemoryRegion));
quirk->nr_mem = 1;
memory_region_init_io(quirk->mem, OBJECT(vdev), &vfio_ati_3c3_quirk, vdev,
@@ -319,7 +319,7 @@ static void vfio_probe_ati_bar4_quirk(VFIOPCIDevice *vdev, int nr)
}
quirk = g_malloc0(sizeof(*quirk));
- quirk->mem = g_malloc0_n(sizeof(MemoryRegion), 2);
+ quirk->mem = g_malloc0(sizeof(MemoryRegion) * 2);
quirk->nr_mem = 2;
window = quirk->data = g_malloc0(sizeof(*window) +
sizeof(VFIOConfigWindowMatch));
@@ -368,7 +368,7 @@ static void vfio_probe_ati_bar2_quirk(VFIOPCIDevice *vdev, int nr)
quirk = g_malloc0(sizeof(*quirk));
mirror = quirk->data = g_malloc0(sizeof(*mirror));
- mirror->mem = quirk->mem = g_malloc0_n(sizeof(MemoryRegion), 1);
+ mirror->mem = quirk->mem = g_malloc0(sizeof(MemoryRegion));
quirk->nr_mem = 1;
mirror->vdev = vdev;
mirror->offset = 0x4000;
@@ -544,7 +544,7 @@ static void vfio_vga_probe_nvidia_3d0_quirk(VFIOPCIDevice *vdev)
quirk = g_malloc0(sizeof(*quirk));
quirk->data = data = g_malloc0(sizeof(*data));
- quirk->mem = g_malloc0_n(sizeof(MemoryRegion), 2);
+ quirk->mem = g_malloc0(sizeof(MemoryRegion) * 2);
quirk->nr_mem = 2;
data->vdev = vdev;
@@ -661,7 +661,7 @@ static void vfio_probe_nvidia_bar5_quirk(VFIOPCIDevice *vdev, int nr)
}
quirk = g_malloc0(sizeof(*quirk));
- quirk->mem = g_malloc0_n(sizeof(MemoryRegion), 4);
+ quirk->mem = g_malloc0(sizeof(MemoryRegion) * 4);
quirk->nr_mem = 4;
bar5 = quirk->data = g_malloc0(sizeof(*bar5) +
(sizeof(VFIOConfigWindowMatch) * 2));
@@ -756,7 +756,7 @@ static void vfio_probe_nvidia_bar0_quirk(VFIOPCIDevice *vdev, int nr)
quirk = g_malloc0(sizeof(*quirk));
mirror = quirk->data = g_malloc0(sizeof(*mirror));
- mirror->mem = quirk->mem = g_malloc0_n(sizeof(MemoryRegion), 1);
+ mirror->mem = quirk->mem = g_malloc0(sizeof(MemoryRegion));
quirk->nr_mem = 1;
mirror->vdev = vdev;
mirror->offset = 0x88000;
@@ -775,7 +775,7 @@ static void vfio_probe_nvidia_bar0_quirk(VFIOPCIDevice *vdev, int nr)
if (vdev->has_vga) {
quirk = g_malloc0(sizeof(*quirk));
mirror = quirk->data = g_malloc0(sizeof(*mirror));
- mirror->mem = quirk->mem = g_malloc0_n(sizeof(MemoryRegion), 1);
+ mirror->mem = quirk->mem = g_malloc0(sizeof(MemoryRegion));
quirk->nr_mem = 1;
mirror->vdev = vdev;
mirror->offset = 0x1800;
@@ -938,7 +938,7 @@ static void vfio_probe_rtl8168_bar2_quirk(VFIOPCIDevice *vdev, int nr)
}
quirk = g_malloc0(sizeof(*quirk));
- quirk->mem = g_malloc0_n(sizeof(MemoryRegion), 2);
+ quirk->mem = g_malloc0(sizeof(MemoryRegion) * 2);
quirk->nr_mem = 2;
quirk->data = rtl = g_malloc0(sizeof(*rtl));
rtl->vdev = vdev;
diff --git a/hw/virtio/vhost-backend.c b/hw/virtio/vhost-backend.c
index 4d68a27658..72d1392b35 100644
--- a/hw/virtio/vhost-backend.c
+++ b/hw/virtio/vhost-backend.c
@@ -42,11 +42,19 @@ static int vhost_kernel_cleanup(struct vhost_dev *dev)
return close(fd);
}
+static int vhost_kernel_get_vq_index(struct vhost_dev *dev, int idx)
+{
+ assert(idx >= dev->vq_index && idx < dev->vq_index + dev->nvqs);
+
+ return idx - dev->vq_index;
+}
+
static const VhostOps kernel_ops = {
.backend_type = VHOST_BACKEND_TYPE_KERNEL,
.vhost_call = vhost_kernel_call,
.vhost_backend_init = vhost_kernel_init,
- .vhost_backend_cleanup = vhost_kernel_cleanup
+ .vhost_backend_cleanup = vhost_kernel_cleanup,
+ .vhost_backend_get_vq_index = vhost_kernel_get_vq_index,
};
int vhost_set_backend_type(struct vhost_dev *dev, VhostBackendType backend_type)
diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index e7ab8293d1..b11c0d21a0 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -24,13 +24,17 @@
#include <linux/vhost.h>
#define VHOST_MEMORY_MAX_NREGIONS 8
+#define VHOST_USER_F_PROTOCOL_FEATURES 30
+#define VHOST_USER_PROTOCOL_FEATURE_MASK 0x1ULL
+
+#define VHOST_USER_PROTOCOL_F_MQ 0
typedef enum VhostUserRequest {
VHOST_USER_NONE = 0,
VHOST_USER_GET_FEATURES = 1,
VHOST_USER_SET_FEATURES = 2,
VHOST_USER_SET_OWNER = 3,
- VHOST_USER_RESET_OWNER = 4,
+ VHOST_USER_RESET_DEVICE = 4,
VHOST_USER_SET_MEM_TABLE = 5,
VHOST_USER_SET_LOG_BASE = 6,
VHOST_USER_SET_LOG_FD = 7,
@@ -41,6 +45,10 @@ typedef enum VhostUserRequest {
VHOST_USER_SET_VRING_KICK = 12,
VHOST_USER_SET_VRING_CALL = 13,
VHOST_USER_SET_VRING_ERR = 14,
+ VHOST_USER_GET_PROTOCOL_FEATURES = 15,
+ VHOST_USER_SET_PROTOCOL_FEATURES = 16,
+ VHOST_USER_GET_QUEUE_NUM = 17,
+ VHOST_USER_SET_VRING_ENABLE = 18,
VHOST_USER_MAX
} VhostUserRequest;
@@ -94,7 +102,7 @@ static unsigned long int ioctl_to_vhost_user_request[VHOST_USER_MAX] = {
VHOST_GET_FEATURES, /* VHOST_USER_GET_FEATURES */
VHOST_SET_FEATURES, /* VHOST_USER_SET_FEATURES */
VHOST_SET_OWNER, /* VHOST_USER_SET_OWNER */
- VHOST_RESET_OWNER, /* VHOST_USER_RESET_OWNER */
+ VHOST_RESET_DEVICE, /* VHOST_USER_RESET_DEVICE */
VHOST_SET_MEM_TABLE, /* VHOST_USER_SET_MEM_TABLE */
VHOST_SET_LOG_BASE, /* VHOST_USER_SET_LOG_BASE */
VHOST_SET_LOG_FD, /* VHOST_USER_SET_LOG_FD */
@@ -180,6 +188,19 @@ static int vhost_user_write(struct vhost_dev *dev, VhostUserMsg *msg,
0 : -1;
}
+static bool vhost_user_one_time_request(VhostUserRequest request)
+{
+ switch (request) {
+ case VHOST_USER_SET_OWNER:
+ case VHOST_USER_RESET_DEVICE:
+ case VHOST_USER_SET_MEM_TABLE:
+ case VHOST_USER_GET_QUEUE_NUM:
+ return true;
+ default:
+ return false;
+ }
+}
+
static int vhost_user_call(struct vhost_dev *dev, unsigned long int request,
void *arg)
{
@@ -193,27 +214,45 @@ static int vhost_user_call(struct vhost_dev *dev, unsigned long int request,
assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER);
- msg_request = vhost_user_request_translate(request);
+ /* only translate vhost ioctl requests */
+ if (request > VHOST_USER_MAX) {
+ msg_request = vhost_user_request_translate(request);
+ } else {
+ msg_request = request;
+ }
+
+ /*
+ * For non-vring specific requests, like VHOST_USER_SET_MEM_TABLE,
+ * we just need send it once in the first time. For later such
+ * request, we just ignore it.
+ */
+ if (vhost_user_one_time_request(msg_request) && dev->vq_index != 0) {
+ return 0;
+ }
+
msg.request = msg_request;
msg.flags = VHOST_USER_VERSION;
msg.size = 0;
- switch (request) {
- case VHOST_GET_FEATURES:
+ switch (msg_request) {
+ case VHOST_USER_GET_FEATURES:
+ case VHOST_USER_GET_PROTOCOL_FEATURES:
+ case VHOST_USER_GET_QUEUE_NUM:
need_reply = 1;
break;
- case VHOST_SET_FEATURES:
- case VHOST_SET_LOG_BASE:
+ case VHOST_USER_SET_FEATURES:
+ case VHOST_USER_SET_LOG_BASE:
+ case VHOST_USER_SET_PROTOCOL_FEATURES:
msg.u64 = *((__u64 *) arg);
msg.size = sizeof(m.u64);
break;
- case VHOST_SET_OWNER:
- case VHOST_RESET_OWNER:
+ case VHOST_USER_SET_OWNER:
+ case VHOST_USER_RESET_DEVICE:
break;
- case VHOST_SET_MEM_TABLE:
+ case VHOST_USER_SET_MEM_TABLE:
for (i = 0; i < dev->mem->nregions; ++i) {
struct vhost_memory_region *reg = dev->mem->regions + i;
ram_addr_t ram_addr;
@@ -246,30 +285,31 @@ static int vhost_user_call(struct vhost_dev *dev, unsigned long int request,
break;
- case VHOST_SET_LOG_FD:
+ case VHOST_USER_SET_LOG_FD:
fds[fd_num++] = *((int *) arg);
break;
- case VHOST_SET_VRING_NUM:
- case VHOST_SET_VRING_BASE:
+ case VHOST_USER_SET_VRING_NUM:
+ case VHOST_USER_SET_VRING_BASE:
+ case VHOST_USER_SET_VRING_ENABLE:
memcpy(&msg.state, arg, sizeof(struct vhost_vring_state));
msg.size = sizeof(m.state);
break;
- case VHOST_GET_VRING_BASE:
+ case VHOST_USER_GET_VRING_BASE:
memcpy(&msg.state, arg, sizeof(struct vhost_vring_state));
msg.size = sizeof(m.state);
need_reply = 1;
break;
- case VHOST_SET_VRING_ADDR:
+ case VHOST_USER_SET_VRING_ADDR:
memcpy(&msg.addr, arg, sizeof(struct vhost_vring_addr));
msg.size = sizeof(m.addr);
break;
- case VHOST_SET_VRING_KICK:
- case VHOST_SET_VRING_CALL:
- case VHOST_SET_VRING_ERR:
+ case VHOST_USER_SET_VRING_KICK:
+ case VHOST_USER_SET_VRING_CALL:
+ case VHOST_USER_SET_VRING_ERR:
file = arg;
msg.u64 = file->index & VHOST_USER_VRING_IDX_MASK;
msg.size = sizeof(m.u64);
@@ -302,6 +342,8 @@ static int vhost_user_call(struct vhost_dev *dev, unsigned long int request,
switch (msg_request) {
case VHOST_USER_GET_FEATURES:
+ case VHOST_USER_GET_PROTOCOL_FEATURES:
+ case VHOST_USER_GET_QUEUE_NUM:
if (msg.size != sizeof(m.u64)) {
error_report("Received bad msg size.");
return -1;
@@ -327,13 +369,61 @@ static int vhost_user_call(struct vhost_dev *dev, unsigned long int request,
static int vhost_user_init(struct vhost_dev *dev, void *opaque)
{
+ unsigned long long features;
+ int err;
+
assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER);
dev->opaque = opaque;
+ err = vhost_user_call(dev, VHOST_USER_GET_FEATURES, &features);
+ if (err < 0) {
+ return err;
+ }
+
+ if (virtio_has_feature(features, VHOST_USER_F_PROTOCOL_FEATURES)) {
+ dev->backend_features |= 1ULL << VHOST_USER_F_PROTOCOL_FEATURES;
+
+ err = vhost_user_call(dev, VHOST_USER_GET_PROTOCOL_FEATURES, &features);
+ if (err < 0) {
+ return err;
+ }
+
+ dev->protocol_features = features & VHOST_USER_PROTOCOL_FEATURE_MASK;
+ err = vhost_user_call(dev, VHOST_USER_SET_PROTOCOL_FEATURES,
+ &dev->protocol_features);
+ if (err < 0) {
+ return err;
+ }
+
+ /* query the max queues we support if backend supports Multiple Queue */
+ if (dev->protocol_features & (1ULL << VHOST_USER_PROTOCOL_F_MQ)) {
+ err = vhost_user_call(dev, VHOST_USER_GET_QUEUE_NUM, &dev->max_queues);
+ if (err < 0) {
+ return err;
+ }
+ }
+ }
+
return 0;
}
+static int vhost_user_set_vring_enable(struct vhost_dev *dev, int enable)
+{
+ struct vhost_vring_state state = {
+ .index = dev->vq_index,
+ .num = enable,
+ };
+
+ assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER);
+
+ if (!(dev->protocol_features & (1ULL << VHOST_USER_PROTOCOL_F_MQ))) {
+ return -1;
+ }
+
+ return vhost_user_call(dev, VHOST_USER_SET_VRING_ENABLE, &state);
+}
+
static int vhost_user_cleanup(struct vhost_dev *dev)
{
assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER);
@@ -343,9 +433,18 @@ static int vhost_user_cleanup(struct vhost_dev *dev)
return 0;
}
+static int vhost_user_get_vq_index(struct vhost_dev *dev, int idx)
+{
+ assert(idx >= dev->vq_index && idx < dev->vq_index + dev->nvqs);
+
+ return idx;
+}
+
const VhostOps user_ops = {
.backend_type = VHOST_BACKEND_TYPE_USER,
.vhost_call = vhost_user_call,
.vhost_backend_init = vhost_user_init,
- .vhost_backend_cleanup = vhost_user_cleanup
- };
+ .vhost_backend_cleanup = vhost_user_cleanup,
+ .vhost_backend_get_vq_index = vhost_user_get_vq_index,
+ .vhost_backend_set_vring_enable = vhost_user_set_vring_enable,
+};
diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index a08c36bb45..c0ed5b263f 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -719,7 +719,7 @@ static int vhost_virtqueue_start(struct vhost_dev *dev,
{
hwaddr s, l, a;
int r;
- int vhost_vq_index = idx - dev->vq_index;
+ int vhost_vq_index = dev->vhost_ops->vhost_backend_get_vq_index(dev, idx);
struct vhost_vring_file file = {
.index = vhost_vq_index
};
@@ -728,7 +728,6 @@ static int vhost_virtqueue_start(struct vhost_dev *dev,
};
struct VirtQueue *vvq = virtio_get_queue(vdev, idx);
- assert(idx >= dev->vq_index && idx < dev->vq_index + dev->nvqs);
vq->num = state.num = virtio_queue_get_num(vdev, idx);
r = dev->vhost_ops->vhost_call(dev, VHOST_SET_VRING_NUM, &state);
@@ -822,12 +821,12 @@ static void vhost_virtqueue_stop(struct vhost_dev *dev,
struct vhost_virtqueue *vq,
unsigned idx)
{
- int vhost_vq_index = idx - dev->vq_index;
+ int vhost_vq_index = dev->vhost_ops->vhost_backend_get_vq_index(dev, idx);
struct vhost_vring_state state = {
.index = vhost_vq_index,
};
int r;
- assert(idx >= dev->vq_index && idx < dev->vq_index + dev->nvqs);
+
r = dev->vhost_ops->vhost_call(dev, VHOST_GET_VRING_BASE, &state);
if (r < 0) {
fprintf(stderr, "vhost VQ %d ring restore failed: %d\n", idx, r);
@@ -875,8 +874,9 @@ static void vhost_eventfd_del(MemoryListener *listener,
static int vhost_virtqueue_init(struct vhost_dev *dev,
struct vhost_virtqueue *vq, int n)
{
+ int vhost_vq_index = dev->vhost_ops->vhost_backend_get_vq_index(dev, n);
struct vhost_vring_file file = {
- .index = n,
+ .index = vhost_vq_index,
};
int r = event_notifier_init(&vq->masked_notifier, 0);
if (r < 0) {
@@ -927,7 +927,7 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque,
}
for (i = 0; i < hdev->nvqs; ++i) {
- r = vhost_virtqueue_init(hdev, hdev->vqs + i, i);
+ r = vhost_virtqueue_init(hdev, hdev->vqs + i, hdev->vq_index + i);
if (r < 0) {
goto fail_vq;
}
@@ -1066,17 +1066,15 @@ void vhost_virtqueue_mask(struct vhost_dev *hdev, VirtIODevice *vdev, int n,
{
struct VirtQueue *vvq = virtio_get_queue(vdev, n);
int r, index = n - hdev->vq_index;
+ struct vhost_vring_file file;
- assert(n >= hdev->vq_index && n < hdev->vq_index + hdev->nvqs);
-
- struct vhost_vring_file file = {
- .index = index
- };
if (mask) {
file.fd = event_notifier_get_fd(&hdev->vqs[index].masked_notifier);
} else {
file.fd = event_notifier_get_fd(virtio_queue_get_guest_notifier(vvq));
}
+
+ file.index = hdev->vhost_ops->vhost_backend_get_vq_index(hdev, n);
r = hdev->vhost_ops->vhost_call(hdev, VHOST_SET_VRING_CALL, &file);
assert(r >= 0);
}
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 0832db9935..7504f8b33a 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -60,6 +60,7 @@ typedef struct VRingUsed
typedef struct VRing
{
unsigned int num;
+ unsigned int num_default;
unsigned int align;
hwaddr desc;
hwaddr avail;
@@ -633,6 +634,7 @@ void virtio_reset(void *opaque)
vdev->vq[i].signalled_used = 0;
vdev->vq[i].signalled_used_valid = false;
vdev->vq[i].notification = true;
+ vdev->vq[i].vring.num = vdev->vq[i].vring.num_default;
}
}
@@ -964,6 +966,7 @@ VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size,
abort();
vdev->vq[i].vring.num = queue_size;
+ vdev->vq[i].vring.num_default = queue_size;
vdev->vq[i].vring.align = VIRTIO_PCI_VRING_ALIGN;
vdev->vq[i].handle_output = handle_output;
@@ -977,6 +980,7 @@ void virtio_del_queue(VirtIODevice *vdev, int n)
}
vdev->vq[n].vring.num = 0;
+ vdev->vq[n].vring.num_default = 0;
}
void virtio_irq(VirtQueue *vq)
@@ -1056,6 +1060,19 @@ static bool virtio_virtqueue_needed(void *opaque)
return virtio_host_has_feature(vdev, VIRTIO_F_VERSION_1);
}
+static bool virtio_ringsize_needed(void *opaque)
+{
+ VirtIODevice *vdev = opaque;
+ int i;
+
+ for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
+ if (vdev->vq[i].vring.num != vdev->vq[i].vring.num_default) {
+ return true;
+ }
+ }
+ return false;
+}
+
static void put_virtqueue_state(QEMUFile *f, void *pv, size_t size)
{
VirtIODevice *vdev = pv;
@@ -1104,6 +1121,52 @@ static const VMStateDescription vmstate_virtio_virtqueues = {
}
};
+static void put_ringsize_state(QEMUFile *f, void *pv, size_t size)
+{
+ VirtIODevice *vdev = pv;
+ int i;
+
+ for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
+ qemu_put_be32(f, vdev->vq[i].vring.num_default);
+ }
+}
+
+static int get_ringsize_state(QEMUFile *f, void *pv, size_t size)
+{
+ VirtIODevice *vdev = pv;
+ int i;
+
+ for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
+ vdev->vq[i].vring.num_default = qemu_get_be32(f);
+ }
+ return 0;
+}
+
+static VMStateInfo vmstate_info_ringsize = {
+ .name = "ringsize_state",
+ .get = get_ringsize_state,
+ .put = put_ringsize_state,
+};
+
+static const VMStateDescription vmstate_virtio_ringsize = {
+ .name = "virtio/ringsize",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = &virtio_ringsize_needed,
+ .fields = (VMStateField[]) {
+ {
+ .name = "ringsize",
+ .version_id = 0,
+ .field_exists = NULL,
+ .size = 0,
+ .info = &vmstate_info_ringsize,
+ .flags = VMS_SINGLE,
+ .offset = 0,
+ },
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static const VMStateDescription vmstate_virtio_device_endian = {
.name = "virtio/device_endian",
.version_id = 1,
@@ -1138,6 +1201,7 @@ static const VMStateDescription vmstate_virtio = {
&vmstate_virtio_device_endian,
&vmstate_virtio_64bit_features,
&vmstate_virtio_virtqueues,
+ &vmstate_virtio_ringsize,
NULL
}
};
@@ -1460,7 +1524,7 @@ hwaddr virtio_queue_get_desc_size(VirtIODevice *vdev, int n)
hwaddr virtio_queue_get_avail_size(VirtIODevice *vdev, int n)
{
return offsetof(VRingAvail, ring) +
- sizeof(uint64_t) * vdev->vq[n].vring.num;
+ sizeof(uint16_t) * vdev->vq[n].vring.num;
}
hwaddr virtio_queue_get_used_size(VirtIODevice *vdev, int n)
diff --git a/hw/watchdog/wdt_i6300esb.c b/hw/watchdog/wdt_i6300esb.c
index 3e07d44878..a91c8fdad0 100644
--- a/hw/watchdog/wdt_i6300esb.c
+++ b/hw/watchdog/wdt_i6300esb.c
@@ -129,14 +129,9 @@ static void i6300esb_restart_timer(I6300State *d, int stage)
else
timeout <<= 5;
- /* Get the timeout in units of ticks_per_sec.
- *
- * ticks_per_sec is typically 10^9 == 0x3B9ACA00 (30 bits), with
- * 20 bits of user supplied preload, and 15 bits of scale, the
- * multiply here can exceed 64-bits, before we divide by 33MHz, so
- * we use a higher-precision intermediate result.
- */
- timeout = muldiv64(timeout, get_ticks_per_sec(), 33000000);
+ /* Get the timeout in nanoseconds. */
+
+ timeout = timeout * 30; /* on a PCI bus, 1 tick is 30 ns*/
i6300esb_debug("stage %d, timeout %" PRIi64 "\n", d->stage, timeout);