Merge remote-tracking branch 'remotes/mst/tags/for_upstream' into staging

pc, pci, virtio: new features, cleanups, fixes

- interrupt remapping for intel iommus
- a bunch of virtio cleanups
- fixes all over the place

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>

# gpg: Signature made Thu 21 Jul 2016 18:49:30 BST
# gpg:                using RSA key 0x281F0DB8D28D5469
# gpg: Good signature from "Michael S. Tsirkin <mst@kernel.org>"
# gpg:                 aka "Michael S. Tsirkin <mst@redhat.com>"
# Primary key fingerprint: 0270 606B 6F3C DF3D 0B17  0970 C350 3912 AFBE 8E67
#      Subkey fingerprint: 5D09 FD08 71C8 F85B 94CA  8A0D 281F 0DB8 D28D 5469

* remotes/mst/tags/for_upstream: (57 commits)
  intel_iommu: avoid unnamed fields
  virtio: Update migration docs
  virtio-gpu: Wrap in vmstate
  virtio-gpu: Use migrate_add_blocker for virgl migration blocking
  virtio-input: Wrap in vmstate
  9pfs: Wrap in vmstate
  virtio-serial: Wrap in vmstate
  virtio-net: Wrap in vmstate
  virtio-balloon: Wrap in vmstate
  virtio-rng: Wrap in vmstate
  virtio-blk: Wrap in vmstate
  virtio-scsi: Wrap in vmstate
  virtio: Migration helper function and macro
  virtio-serial: Remove old migration version support
  virtio-net: Remove old migration version support
  virtio-scsi: Replace HandleOutput typedef
  Revert "mirror: Workaround for unexpected iohandler events during completion"
  virtio-scsi: Call virtio_add_queue_aio
  virtio-blk: Call virtio_add_queue_aio
  virtio: Introduce virtio_add_queue_aio
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell
2016-07-21 20:12:37 +01:00
55 changed files with 1476 additions and 347 deletions
+1
View File
@@ -153,6 +153,7 @@ trace-events-y += hw/alpha/trace-events
trace-events-y += ui/trace-events
trace-events-y += audio/trace-events
trace-events-y += net/trace-events
trace-events-y += target-i386/trace-events
trace-events-y += target-sparc/trace-events
trace-events-y += target-s390x/trace-events
trace-events-y += target-ppc/trace-events
-9
View File
@@ -521,9 +521,6 @@ static void mirror_exit(BlockJob *job, void *opaque)
block_job_completed(&s->common, data->ret);
g_free(data);
bdrv_drained_end(src);
if (qemu_get_aio_context() == bdrv_get_aio_context(src)) {
aio_enable_external(iohandler_get_aio_context());
}
bdrv_unref(src);
}
@@ -793,12 +790,6 @@ immediate_exit:
/* Before we switch to target in mirror_exit, make sure data doesn't
* change. */
bdrv_drained_begin(bs);
if (qemu_get_aio_context() == bdrv_get_aio_context(bs)) {
/* FIXME: virtio host notifiers run on iohandler_ctx, therefore the
* above bdrv_drained_end isn't enough to quiesce it. This is ugly, we
* need a block layer API change to achieve this. */
aio_disable_external(iohandler_get_aio_context());
}
block_job_defer_to_main_loop(&s->common, mirror_exit, data);
}
+4 -2
View File
@@ -28,7 +28,8 @@ virtio core virtio transport virtio device
----------- ---------------- -------------
save() function registered
via register_savevm()
via VMState wrapper on
device class
virtio_save() <----------
------> save_config()
- save proxy device
@@ -63,7 +64,8 @@ virtio core virtio transport virtio device
----------- ---------------- -------------
load() function registered
via register_savevm()
via VMState wrapper on
device class
virtio_load() <----------
------> load_config()
- load proxy device
+5 -9
View File
@@ -97,14 +97,9 @@ static void virtio_9p_get_config(VirtIODevice *vdev, uint8_t *config)
g_free(cfg);
}
static void virtio_9p_save(QEMUFile *f, void *opaque)
static int virtio_9p_load(QEMUFile *f, void *opaque, size_t size)
{
virtio_save(VIRTIO_DEVICE(opaque), f);
}
static int virtio_9p_load(QEMUFile *f, void *opaque, int version_id)
{
return virtio_load(VIRTIO_DEVICE(opaque), f, version_id);
return virtio_load(VIRTIO_DEVICE(opaque), f, 1);
}
static void virtio_9p_device_realize(DeviceState *dev, Error **errp)
@@ -120,7 +115,6 @@ static void virtio_9p_device_realize(DeviceState *dev, Error **errp)
v->config_size = sizeof(struct virtio_9p_config) + strlen(s->fsconf.tag);
virtio_init(vdev, "virtio-9p", VIRTIO_ID_9P, v->config_size);
v->vq = virtio_add_queue(vdev, MAX_REQ, handle_9p_output);
register_savevm(dev, "virtio-9p", -1, 1, virtio_9p_save, virtio_9p_load, v);
out:
return;
@@ -133,7 +127,6 @@ static void virtio_9p_device_unrealize(DeviceState *dev, Error **errp)
V9fsState *s = &v->state;
virtio_cleanup(vdev);
unregister_savevm(dev, "virtio-9p", v);
v9fs_device_unrealize_common(s, errp);
}
@@ -175,6 +168,8 @@ void virtio_init_iov_from_pdu(V9fsPDU *pdu, struct iovec **piov,
/* virtio-9p device */
VMSTATE_VIRTIO_DEVICE(9p, 1, virtio_9p_load, virtio_vmstate_save);
static Property virtio_9p_properties[] = {
DEFINE_PROP_STRING("mount_tag", V9fsVirtioState, state.fsconf.tag),
DEFINE_PROP_STRING("fsdev", V9fsVirtioState, state.fsconf.fsdev_id),
@@ -187,6 +182,7 @@ static void virtio_9p_class_init(ObjectClass *klass, void *data)
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
dc->props = virtio_9p_properties;
dc->vmsd = &vmstate_virtio_9p;
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
vdc->realize = virtio_9p_device_realize;
vdc->unrealize = virtio_9p_device_unrealize;
+1 -1
View File
@@ -824,7 +824,6 @@ PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus,
int i;
dev = qdev_create(NULL, TYPE_TYPHOON_PCI_HOST_BRIDGE);
qdev_init_nofail(dev);
s = TYPHOON_PCI_HOST_BRIDGE(dev);
phb = PCI_HOST_BRIDGE(dev);
@@ -889,6 +888,7 @@ PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus,
&s->pchip.reg_mem, &s->pchip.reg_io,
0, 64, TYPE_PCI_BUS);
phb->bus = b;
qdev_init_nofail(dev);
/* Host memory as seen from the PCI side, via the IOMMU. */
memory_region_init_iommu(&s->pchip.iommu, OBJECT(s), &typhoon_iommu_ops,
+7 -11
View File
@@ -798,7 +798,7 @@ static void virtio_blk_set_status(VirtIODevice *vdev, uint8_t status)
}
}
static void virtio_blk_save(QEMUFile *f, void *opaque)
static void virtio_blk_save(QEMUFile *f, void *opaque, size_t size)
{
VirtIODevice *vdev = VIRTIO_DEVICE(opaque);
@@ -823,15 +823,12 @@ static void virtio_blk_save_device(VirtIODevice *vdev, QEMUFile *f)
qemu_put_sbyte(f, 0);
}
static int virtio_blk_load(QEMUFile *f, void *opaque, int version_id)
static int virtio_blk_load(QEMUFile *f, void *opaque, size_t size)
{
VirtIOBlock *s = opaque;
VirtIODevice *vdev = VIRTIO_DEVICE(s);
if (version_id != 2)
return -EINVAL;
return virtio_load(vdev, f, version_id);
return virtio_load(vdev, f, 2);
}
static int virtio_blk_load_device(VirtIODevice *vdev, QEMUFile *f,
@@ -880,7 +877,6 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
VirtIOBlock *s = VIRTIO_BLK(dev);
VirtIOBlkConf *conf = &s->conf;
Error *err = NULL;
static int virtio_blk_id;
unsigned i;
if (!conf->conf.blk) {
@@ -914,7 +910,7 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
s->sector_mask = (s->conf.conf.logical_block_size / BDRV_SECTOR_SIZE) - 1;
for (i = 0; i < conf->num_queues; i++) {
virtio_add_queue(vdev, 128, virtio_blk_handle_output);
virtio_add_queue_aio(vdev, 128, virtio_blk_handle_output);
}
virtio_blk_data_plane_create(vdev, conf, &s->dataplane, &err);
if (err != NULL) {
@@ -924,8 +920,6 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
}
s->change = qemu_add_vm_change_state_handler(virtio_blk_dma_restart_cb, s);
register_savevm(dev, "virtio-blk", virtio_blk_id++, 2,
virtio_blk_save, virtio_blk_load, s);
blk_set_dev_ops(s->blk, &virtio_block_ops, s);
blk_set_guest_block_size(s->blk, s->conf.conf.logical_block_size);
@@ -940,7 +934,6 @@ static void virtio_blk_device_unrealize(DeviceState *dev, Error **errp)
virtio_blk_data_plane_destroy(s->dataplane);
s->dataplane = NULL;
qemu_del_vm_change_state_handler(s->change);
unregister_savevm(dev, "virtio-blk", s);
blockdev_mark_auto_del(s->blk);
virtio_cleanup(vdev);
}
@@ -958,6 +951,8 @@ static void virtio_blk_instance_init(Object *obj)
DEVICE(obj), NULL);
}
VMSTATE_VIRTIO_DEVICE(blk, 2, virtio_blk_load, virtio_blk_save);
static Property virtio_blk_properties[] = {
DEFINE_BLOCK_PROPERTIES(VirtIOBlock, conf.conf),
DEFINE_BLOCK_ERROR_PROPERTIES(VirtIOBlock, conf.conf),
@@ -979,6 +974,7 @@ static void virtio_blk_class_init(ObjectClass *klass, void *data)
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
dc->props = virtio_blk_properties;
dc->vmsd = &vmstate_virtio_blk;
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
vdc->realize = virtio_blk_device_realize;
vdc->unrealize = virtio_blk_device_unrealize;
+20 -42
View File
@@ -594,12 +594,6 @@ static void vser_reset(VirtIODevice *vdev)
guest_reset(vser);
}
static void virtio_serial_save(QEMUFile *f, void *opaque)
{
/* The virtio device */
virtio_save(VIRTIO_DEVICE(opaque), f);
}
static void virtio_serial_save_device(VirtIODevice *vdev, QEMUFile *f)
{
VirtIOSerial *s = VIRTIO_SERIAL(vdev);
@@ -685,7 +679,7 @@ static void virtio_serial_post_load_timer_cb(void *opaque)
s->post_load = NULL;
}
static int fetch_active_ports_list(QEMUFile *f, int version_id,
static int fetch_active_ports_list(QEMUFile *f,
VirtIOSerial *s, uint32_t nr_active_ports)
{
uint32_t i;
@@ -702,6 +696,7 @@ static int fetch_active_ports_list(QEMUFile *f, int version_id,
/* Items in struct VirtIOSerialPort */
for (i = 0; i < nr_active_ports; i++) {
VirtIOSerialPort *port;
uint32_t elem_popped;
uint32_t id;
id = qemu_get_be32(f);
@@ -714,37 +709,29 @@ static int fetch_active_ports_list(QEMUFile *f, int version_id,
s->post_load->connected[i].port = port;
s->post_load->connected[i].host_connected = qemu_get_byte(f);
if (version_id > 2) {
uint32_t elem_popped;
qemu_get_be32s(f, &elem_popped);
if (elem_popped) {
qemu_get_be32s(f, &port->iov_idx);
qemu_get_be64s(f, &port->iov_offset);
qemu_get_be32s(f, &elem_popped);
if (elem_popped) {
qemu_get_be32s(f, &port->iov_idx);
qemu_get_be64s(f, &port->iov_offset);
port->elem =
qemu_get_virtqueue_element(f, sizeof(VirtQueueElement));
port->elem =
qemu_get_virtqueue_element(f, sizeof(VirtQueueElement));
/*
* Port was throttled on source machine. Let's
* unthrottle it here so data starts flowing again.
*/
virtio_serial_throttle_port(port, false);
}
/*
* Port was throttled on source machine. Let's
* unthrottle it here so data starts flowing again.
*/
virtio_serial_throttle_port(port, false);
}
}
timer_mod(s->post_load->timer, 1);
return 0;
}
static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id)
static int virtio_serial_load(QEMUFile *f, void *opaque, size_t size)
{
if (version_id > 3) {
return -EINVAL;
}
/* The virtio device */
return virtio_load(VIRTIO_DEVICE(opaque), f, version_id);
return virtio_load(VIRTIO_DEVICE(opaque), f, 3);
}
static int virtio_serial_load_device(VirtIODevice *vdev, QEMUFile *f,
@@ -756,10 +743,6 @@ static int virtio_serial_load_device(VirtIODevice *vdev, QEMUFile *f,
int ret;
uint32_t tmp;
if (version_id < 2) {
return 0;
}
/* Unused */
qemu_get_be16s(f, (uint16_t *) &tmp);
qemu_get_be16s(f, (uint16_t *) &tmp);
@@ -781,7 +764,7 @@ static int virtio_serial_load_device(VirtIODevice *vdev, QEMUFile *f,
qemu_get_be32s(f, &nr_active_ports);
if (nr_active_ports) {
ret = fetch_active_ports_list(f, version_id, s, nr_active_ports);
ret = fetch_active_ports_list(f, s, nr_active_ports);
if (ret) {
return ret;
}
@@ -1049,13 +1032,6 @@ static void virtio_serial_device_realize(DeviceState *dev, Error **errp)
vser->post_load = NULL;
/*
* Register for the savevm section with the virtio-console name
* to preserve backward compat
*/
register_savevm(dev, "virtio-console", -1, 3, virtio_serial_save,
virtio_serial_load, vser);
QLIST_INSERT_HEAD(&vserdevices.devices, vser, next);
}
@@ -1086,8 +1062,6 @@ static void virtio_serial_device_unrealize(DeviceState *dev, Error **errp)
QLIST_REMOVE(vser, next);
unregister_savevm(dev, "virtio-console", vser);
g_free(vser->ivqs);
g_free(vser->ovqs);
g_free(vser->ports_map);
@@ -1100,6 +1074,9 @@ static void virtio_serial_device_unrealize(DeviceState *dev, Error **errp)
virtio_cleanup(vdev);
}
/* Note: 'console' is used for backwards compatibility */
VMSTATE_VIRTIO_DEVICE(console, 3, virtio_serial_load, virtio_vmstate_save);
static Property virtio_serial_properties[] = {
DEFINE_PROP_UINT32("max_ports", VirtIOSerial, serial.max_virtserial_ports,
31),
@@ -1115,6 +1092,7 @@ static void virtio_serial_class_init(ObjectClass *klass, void *data)
QLIST_INIT(&vserdevices.devices);
dc->props = virtio_serial_properties;
dc->vmsd = &vmstate_virtio_console;
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
vdc->realize = virtio_serial_device_realize;
vdc->unrealize = virtio_serial_device_unrealize;
+20 -16
View File
@@ -19,6 +19,7 @@
#include "hw/virtio/virtio.h"
#include "hw/virtio/virtio-gpu.h"
#include "hw/virtio/virtio-bus.h"
#include "migration/migration.h"
#include "qemu/log.h"
#include "qapi/error.h"
@@ -986,12 +987,7 @@ static const VMStateDescription vmstate_virtio_gpu_scanouts = {
},
};
static const VMStateDescription vmstate_virtio_gpu_unmigratable = {
.name = "virtio-gpu-with-virgl",
.unmigratable = 1,
};
static void virtio_gpu_save(QEMUFile *f, void *opaque)
static void virtio_gpu_save(QEMUFile *f, void *opaque, size_t size)
{
VirtIOGPU *g = opaque;
VirtIODevice *vdev = VIRTIO_DEVICE(g);
@@ -1021,7 +1017,7 @@ static void virtio_gpu_save(QEMUFile *f, void *opaque)
vmstate_save_state(f, &vmstate_virtio_gpu_scanouts, g, NULL);
}
static int virtio_gpu_load(QEMUFile *f, void *opaque, int version_id)
static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size)
{
VirtIOGPU *g = opaque;
VirtIODevice *vdev = VIRTIO_DEVICE(g);
@@ -1030,11 +1026,7 @@ static int virtio_gpu_load(QEMUFile *f, void *opaque, int version_id)
uint32_t resource_id, pformat;
int i, ret;
if (version_id != VIRTIO_GPU_VM_VERSION) {
return -EINVAL;
}
ret = virtio_load(vdev, f, version_id);
ret = virtio_load(vdev, f, VIRTIO_GPU_VM_VERSION);
if (ret) {
return ret;
}
@@ -1169,10 +1161,17 @@ static void virtio_gpu_device_realize(DeviceState *qdev, Error **errp)
}
if (virtio_gpu_virgl_enabled(g->conf)) {
vmstate_register(qdev, -1, &vmstate_virtio_gpu_unmigratable, g);
} else {
register_savevm(qdev, "virtio-gpu", -1, VIRTIO_GPU_VM_VERSION,
virtio_gpu_save, virtio_gpu_load, g);
error_setg(&g->migration_blocker, "virgl is not yet migratable");
migrate_add_blocker(g->migration_blocker);
}
}
static void virtio_gpu_device_unrealize(DeviceState *qdev, Error **errp)
{
VirtIOGPU *g = VIRTIO_GPU(qdev);
if (g->migration_blocker) {
migrate_del_blocker(g->migration_blocker);
error_free(g->migration_blocker);
}
}
@@ -1220,6 +1219,9 @@ static void virtio_gpu_reset(VirtIODevice *vdev)
#endif
}
VMSTATE_VIRTIO_DEVICE(gpu, VIRTIO_GPU_VM_VERSION, virtio_gpu_load,
virtio_gpu_save);
static Property virtio_gpu_properties[] = {
DEFINE_PROP_UINT32("max_outputs", VirtIOGPU, conf.max_outputs, 1),
#ifdef CONFIG_VIRGL
@@ -1237,6 +1239,7 @@ static void virtio_gpu_class_init(ObjectClass *klass, void *data)
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
vdc->realize = virtio_gpu_device_realize;
vdc->unrealize = virtio_gpu_device_unrealize;
vdc->get_config = virtio_gpu_get_config;
vdc->set_config = virtio_gpu_set_config;
vdc->get_features = virtio_gpu_get_features;
@@ -1245,6 +1248,7 @@ static void virtio_gpu_class_init(ObjectClass *klass, void *data)
vdc->reset = virtio_gpu_reset;
dc->props = virtio_gpu_properties;
dc->vmsd = &vmstate_virtio_gpu;
}
static const TypeInfo virtio_gpu_info = {
+1 -1
View File
@@ -2,7 +2,7 @@ obj-$(CONFIG_KVM) += kvm/
obj-y += multiboot.o
obj-y += pc.o pc_piix.o pc_q35.o
obj-y += pc_sysfw.o
obj-y += intel_iommu.o
obj-y += x86-iommu.o intel_iommu.o
obj-$(CONFIG_XEN) += ../xenpv/ xen/
obj-y += kvmvapic.o
+32 -11
View File
@@ -52,13 +52,14 @@
#include "hw/i386/ich9.h"
#include "hw/pci/pci_bus.h"
#include "hw/pci-host/q35.h"
#include "hw/i386/intel_iommu.h"
#include "hw/i386/x86-iommu.h"
#include "hw/timer/hpet.h"
#include "hw/acpi/aml-build.h"
#include "qapi/qmp/qint.h"
#include "qom/qom-qobject.h"
#include "hw/i386/x86-iommu.h"
#include "hw/acpi/ipmi.h"
@@ -80,6 +81,9 @@
#define ACPI_BUILD_DPRINTF(fmt, ...)
#endif
/* Default IOAPIC ID */
#define ACPI_BUILD_IOAPIC_ID 0x0
typedef struct AcpiMcfgInfo {
uint64_t mcfg_base;
uint32_t mcfg_size;
@@ -383,7 +387,6 @@ build_madt(GArray *table_data, BIOSLinker *linker, PCMachineState *pcms)
io_apic = acpi_data_push(table_data, sizeof *io_apic);
io_apic->type = ACPI_APIC_IO;
io_apic->length = sizeof(*io_apic);
#define ACPI_BUILD_IOAPIC_ID 0x0
io_apic->io_apic_id = ACPI_BUILD_IOAPIC_ID;
io_apic->address = cpu_to_le32(IO_APIC_DEFAULT_ADDRESS);
io_apic->interrupt = cpu_to_le32(0);
@@ -2454,6 +2457,10 @@ build_mcfg_q35(GArray *table_data, BIOSLinker *linker, AcpiMcfgInfo *info)
build_header(linker, table_data, (void *)mcfg, sig, len, 1, NULL, NULL);
}
/*
* VT-d spec 8.1 DMA Remapping Reporting Structure
* (version Oct. 2014 or later)
*/
static void
build_dmar_q35(GArray *table_data, BIOSLinker *linker)
{
@@ -2461,19 +2468,38 @@ build_dmar_q35(GArray *table_data, BIOSLinker *linker)
AcpiTableDmar *dmar;
AcpiDmarHardwareUnit *drhd;
uint8_t dmar_flags = 0;
X86IOMMUState *iommu = x86_iommu_get_default();
AcpiDmarDeviceScope *scope = NULL;
/* Root complex IOAPIC use one path[0] only */
size_t ioapic_scope_size = sizeof(*scope) + sizeof(scope->path[0]);
assert(iommu);
if (iommu->intr_supported) {
dmar_flags |= 0x1; /* Flags: 0x1: INT_REMAP */
}
dmar = acpi_data_push(table_data, sizeof(*dmar));
dmar->host_address_width = VTD_HOST_ADDRESS_WIDTH - 1;
dmar->flags = 0; /* No intr_remap for now */
dmar->flags = dmar_flags;
/* DMAR Remapping Hardware Unit Definition structure */
drhd = acpi_data_push(table_data, sizeof(*drhd));
drhd = acpi_data_push(table_data, sizeof(*drhd) + ioapic_scope_size);
drhd->type = cpu_to_le16(ACPI_DMAR_TYPE_HARDWARE_UNIT);
drhd->length = cpu_to_le16(sizeof(*drhd)); /* No device scope now */
drhd->length = cpu_to_le16(sizeof(*drhd) + ioapic_scope_size);
drhd->flags = ACPI_DMAR_INCLUDE_PCI_ALL;
drhd->pci_segment = cpu_to_le16(0);
drhd->address = cpu_to_le64(Q35_HOST_BRIDGE_IOMMU_ADDR);
/* Scope definition for the root-complex IOAPIC. See VT-d spec
* 8.3.1 (version Oct. 2014 or later). */
scope = &drhd->scope[0];
scope->entry_type = 0x03; /* Type: 0x03 for IOAPIC */
scope->length = ioapic_scope_size;
scope->enumeration_id = ACPI_BUILD_IOAPIC_ID;
scope->bus = Q35_PSEUDO_BUS_PLATFORM;
scope->path[0] = cpu_to_le16(Q35_PSEUDO_DEVFN_IOAPIC);
build_header(linker, table_data, (void *)(table_data->data + dmar_start),
"DMAR", table_data->len - dmar_start, 1, NULL, NULL);
}
@@ -2539,12 +2565,7 @@ static bool acpi_get_mcfg(AcpiMcfgInfo *mcfg)
static bool acpi_has_iommu(void)
{
bool ambiguous;
Object *intel_iommu;
intel_iommu = object_resolve_path_type("", TYPE_INTEL_IOMMU_DEVICE,
&ambiguous);
return intel_iommu && !ambiguous;
return !!x86_iommu_get_default();
}
static
+429 -8
View File
File diff suppressed because it is too large Load Diff
+47 -5
View File
@@ -110,6 +110,8 @@
/* Interrupt Address Range */
#define VTD_INTERRUPT_ADDR_FIRST 0xfee00000ULL
#define VTD_INTERRUPT_ADDR_LAST 0xfeefffffULL
#define VTD_INTERRUPT_ADDR_SIZE (VTD_INTERRUPT_ADDR_LAST - \
VTD_INTERRUPT_ADDR_FIRST + 1)
/* The shift of source_id in the key of IOTLB hash table */
#define VTD_IOTLB_SID_SHIFT 36
@@ -172,10 +174,19 @@
#define VTD_RTADDR_RTT (1ULL << 11)
#define VTD_RTADDR_ADDR_MASK (VTD_HAW_MASK ^ 0xfffULL)
/* IRTA_REG */
#define VTD_IRTA_ADDR_MASK (VTD_HAW_MASK ^ 0xfffULL)
#define VTD_IRTA_EIME (1ULL << 11)
#define VTD_IRTA_SIZE_MASK (0xfULL)
/* ECAP_REG */
/* (offset >> 4) << 8 */
#define VTD_ECAP_IRO (DMAR_IOTLB_REG_OFFSET << 4)
#define VTD_ECAP_QI (1ULL << 1)
/* Interrupt Remapping support */
#define VTD_ECAP_IR (1ULL << 3)
#define VTD_ECAP_EIM (1ULL << 4)
#define VTD_ECAP_MHMV (15ULL << 20)
/* CAP_REG */
/* (offset >> 4) << 24 */
@@ -265,6 +276,19 @@ typedef enum VTDFaultReason {
* context-entry.
*/
VTD_FR_CONTEXT_ENTRY_TT,
/* Interrupt remapping transition faults */
VTD_FR_IR_REQ_RSVD = 0x20, /* One or more IR request reserved
* fields set */
VTD_FR_IR_INDEX_OVER = 0x21, /* Index value greater than max */
VTD_FR_IR_ENTRY_P = 0x22, /* Present (P) not set in IRTE */
VTD_FR_IR_ROOT_INVAL = 0x23, /* IR Root table invalid */
VTD_FR_IR_IRTE_RSVD = 0x24, /* IRTE Rsvd field non-zero with
* Present flag set */
VTD_FR_IR_REQ_COMPAT = 0x25, /* Encountered compatible IR
* request while disabled */
VTD_FR_IR_SID_ERR = 0x26, /* Invalid Source-ID */
/* This is not a normal fault reason. We use this to indicate some faults
* that are not referenced by the VT-d specification.
* Fault event with such reason should not be recorded.
@@ -275,17 +299,35 @@ typedef enum VTDFaultReason {
#define VTD_CONTEXT_CACHE_GEN_MAX 0xffffffffUL
/* Queued Invalidation Descriptor */
struct VTDInvDesc {
uint64_t lo;
uint64_t hi;
/* Interrupt Entry Cache Invalidation Descriptor: VT-d 6.5.2.7. */
struct VTDInvDescIEC {
uint32_t type:4; /* Should always be 0x4 */
uint32_t granularity:1; /* If set, it's global IR invalidation */
uint32_t resved_1:22;
uint32_t index_mask:5; /* 2^N for continuous int invalidation */
uint32_t index:16; /* Start index to invalidate */
uint32_t reserved_2:16;
};
typedef struct VTDInvDesc VTDInvDesc;
typedef struct VTDInvDescIEC VTDInvDescIEC;
/* Queued Invalidation Descriptor */
union VTDInvDesc {
struct {
uint64_t lo;
uint64_t hi;
};
union {
VTDInvDescIEC iec;
};
};
typedef union VTDInvDesc VTDInvDesc;
/* Masks for struct VTDInvDesc */
#define VTD_INV_DESC_TYPE 0xf
#define VTD_INV_DESC_CC 0x1 /* Context-cache Invalidate Desc */
#define VTD_INV_DESC_IOTLB 0x2
#define VTD_INV_DESC_IEC 0x4 /* Interrupt Entry Cache
Invalidate Descriptor */
#define VTD_INV_DESC_WAIT 0x5 /* Invalidation Wait Descriptor */
#define VTD_INV_DESC_NONE 0 /* Not an Invalidate Descriptor */
+4 -6
View File
@@ -974,10 +974,9 @@ static void assigned_dev_update_msi(PCIDevice *pci_dev)
}
if (ctrl_byte & PCI_MSI_FLAGS_ENABLE) {
MSIMessage msg = msi_get_message(pci_dev, 0);
int virq;
virq = kvm_irqchip_add_msi_route(kvm_state, msg, pci_dev);
virq = kvm_irqchip_add_msi_route(kvm_state, 0, pci_dev);
if (virq < 0) {
perror("assigned_dev_update_msi: kvm_irqchip_add_msi_route");
return;
@@ -1016,6 +1015,7 @@ static void assigned_dev_update_msi_msg(PCIDevice *pci_dev)
kvm_irqchip_update_msi_route(kvm_state, assigned_dev->msi_virq[0],
msi_get_message(pci_dev, 0), pci_dev);
kvm_irqchip_commit_routes(kvm_state);
}
static bool assigned_dev_msix_masked(MSIXTableEntry *entry)
@@ -1042,7 +1042,6 @@ static int assigned_dev_update_msix_mmio(PCIDevice *pci_dev)
uint16_t entries_nr = 0;
int i, r = 0;
MSIXTableEntry *entry = adev->msix_table;
MSIMessage msg;
/* Get the usable entry number for allocating */
for (i = 0; i < adev->msix_max; i++, entry++) {
@@ -1079,9 +1078,7 @@ static int assigned_dev_update_msix_mmio(PCIDevice *pci_dev)
continue;
}
msg.address = entry->addr_lo | ((uint64_t)entry->addr_hi << 32);
msg.data = entry->data;
r = kvm_irqchip_add_msi_route(kvm_state, msg, pci_dev);
r = kvm_irqchip_add_msi_route(kvm_state, i, pci_dev);
if (r < 0) {
return r;
}
@@ -1606,6 +1603,7 @@ static void assigned_dev_msix_mmio_write(void *opaque, hwaddr addr,
if (ret) {
error_report("Error updating irq routing entry (%d)", ret);
}
kvm_irqchip_commit_routes(kvm_state);
}
}
}
+3
View File
@@ -1473,6 +1473,9 @@ void pc_memory_init(PCMachineState *pcms,
rom_add_option(option_rom[i].name, option_rom[i].bootindex);
}
pcms->fw_cfg = fw_cfg;
/* Init default IOAPIC address space */
pcms->ioapic_as = &address_space_memory;
}
qemu_irq pc_allocate_cpu_irq(void)
+3
View File
@@ -10,3 +10,6 @@ xen_pv_mmio_write(uint64_t addr) "WARNING: write to Xen PV Device MMIO space (ad
# hw/i386/pc.c
mhp_pc_dimm_assigned_slot(int slot) "0x%d"
mhp_pc_dimm_assigned_address(uint64_t addr) "0x%"PRIx64
# hw/i386/x86-iommu.c
x86_iommu_iec_notify(bool global, uint32_t index, uint32_t mask) "Notify IEC invalidation: global=%d index=%" PRIu32 " mask=%" PRIu32
+128
View File
@@ -0,0 +1,128 @@
/*
* QEMU emulation of common X86 IOMMU
*
* Copyright (C) 2016 Peter Xu, Red Hat <peterx@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License along
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
#include "hw/sysbus.h"
#include "hw/boards.h"
#include "hw/i386/x86-iommu.h"
#include "qemu/error-report.h"
#include "trace.h"
void x86_iommu_iec_register_notifier(X86IOMMUState *iommu,
iec_notify_fn fn, void *data)
{
IEC_Notifier *notifier = g_new0(IEC_Notifier, 1);
notifier->iec_notify = fn;
notifier->private = data;
QLIST_INSERT_HEAD(&iommu->iec_notifiers, notifier, list);
}
void x86_iommu_iec_notify_all(X86IOMMUState *iommu, bool global,
uint32_t index, uint32_t mask)
{
IEC_Notifier *notifier;
trace_x86_iommu_iec_notify(global, index, mask);
QLIST_FOREACH(notifier, &iommu->iec_notifiers, list) {
if (notifier->iec_notify) {
notifier->iec_notify(notifier->private, global,
index, mask);
}
}
}
/* Default X86 IOMMU device */
static X86IOMMUState *x86_iommu_default = NULL;
static void x86_iommu_set_default(X86IOMMUState *x86_iommu)
{
assert(x86_iommu);
if (x86_iommu_default) {
error_report("QEMU does not support multiple vIOMMUs "
"for x86 yet.");
exit(1);
}
x86_iommu_default = x86_iommu;
}
X86IOMMUState *x86_iommu_get_default(void)
{
return x86_iommu_default;
}
static void x86_iommu_realize(DeviceState *dev, Error **errp)
{
X86IOMMUState *x86_iommu = X86_IOMMU_DEVICE(dev);
X86IOMMUClass *x86_class = X86_IOMMU_GET_CLASS(dev);
QLIST_INIT(&x86_iommu->iec_notifiers);
if (x86_class->realize) {
x86_class->realize(dev, errp);
}
x86_iommu_set_default(X86_IOMMU_DEVICE(dev));
}
static void x86_iommu_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = x86_iommu_realize;
}
static bool x86_iommu_intremap_prop_get(Object *o, Error **errp)
{
X86IOMMUState *s = X86_IOMMU_DEVICE(o);
return s->intr_supported;
}
static void x86_iommu_intremap_prop_set(Object *o, bool value, Error **errp)
{
X86IOMMUState *s = X86_IOMMU_DEVICE(o);
s->intr_supported = value;
}
static void x86_iommu_instance_init(Object *o)
{
X86IOMMUState *s = X86_IOMMU_DEVICE(o);
/* By default, do not support IR */
s->intr_supported = false;
object_property_add_bool(o, "intremap", x86_iommu_intremap_prop_get,
x86_iommu_intremap_prop_set, NULL);
}
static const TypeInfo x86_iommu_info = {
.name = TYPE_X86_IOMMU_DEVICE,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_init = x86_iommu_instance_init,
.instance_size = sizeof(X86IOMMUState),
.class_init = x86_iommu_class_init,
.class_size = sizeof(X86IOMMUClass),
.abstract = true,
};
static void x86_iommu_register_types(void)
{
type_register_static(&x86_iommu_info);
}
type_init(x86_iommu_register_types)
+6 -20
View File
@@ -217,26 +217,14 @@ static void virtio_input_reset(VirtIODevice *vdev)
}
}
static void virtio_input_save(QEMUFile *f, void *opaque)
{
VirtIOInput *vinput = opaque;
VirtIODevice *vdev = VIRTIO_DEVICE(vinput);
virtio_save(vdev, f);
}
static int virtio_input_load(QEMUFile *f, void *opaque, int version_id)
static int virtio_input_load(QEMUFile *f, void *opaque, size_t size)
{
VirtIOInput *vinput = opaque;
VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(vinput);
VirtIODevice *vdev = VIRTIO_DEVICE(vinput);
int ret;
if (version_id != VIRTIO_INPUT_VM_VERSION) {
return -EINVAL;
}
ret = virtio_load(vdev, f, version_id);
ret = virtio_load(vdev, f, VIRTIO_INPUT_VM_VERSION);
if (ret) {
return ret;
}
@@ -280,20 +268,14 @@ static void virtio_input_device_realize(DeviceState *dev, Error **errp)
vinput->cfg_size);
vinput->evt = virtio_add_queue(vdev, 64, virtio_input_handle_evt);
vinput->sts = virtio_add_queue(vdev, 64, virtio_input_handle_sts);
register_savevm(dev, "virtio-input", -1, VIRTIO_INPUT_VM_VERSION,
virtio_input_save, virtio_input_load, vinput);
}
static void virtio_input_device_unrealize(DeviceState *dev, Error **errp)
{
VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(dev);
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VirtIOInput *vinput = VIRTIO_INPUT(dev);
Error *local_err = NULL;
unregister_savevm(dev, "virtio-input", vinput);
if (vic->unrealize) {
vic->unrealize(dev, &local_err);
if (local_err) {
@@ -304,6 +286,9 @@ static void virtio_input_device_unrealize(DeviceState *dev, Error **errp)
virtio_cleanup(vdev);
}
VMSTATE_VIRTIO_DEVICE(input, VIRTIO_INPUT_VM_VERSION, virtio_input_load,
virtio_vmstate_save);
static Property virtio_input_properties[] = {
DEFINE_PROP_STRING("serial", VirtIOInput, serial),
DEFINE_PROP_END_OF_LIST(),
@@ -315,6 +300,7 @@ static void virtio_input_class_init(ObjectClass *klass, void *data)
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
dc->props = virtio_input_properties;
dc->vmsd = &vmstate_virtio_input;
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
vdc->realize = virtio_input_device_realize;
vdc->unrealize = virtio_input_device_unrealize;
+92 -43
View File
@@ -29,6 +29,9 @@
#include "hw/i386/ioapic_internal.h"
#include "include/hw/pci/msi.h"
#include "sysemu/kvm.h"
#include "target-i386/cpu.h"
#include "hw/i386/apic-msidef.h"
#include "hw/i386/x86-iommu.h"
//#define DEBUG_IOAPIC
@@ -48,16 +51,56 @@ static IOAPICCommonState *ioapics[MAX_IOAPICS];
/* global variable from ioapic_common.c */
extern int ioapic_no;
struct ioapic_entry_info {
/* fields parsed from IOAPIC entries */
uint8_t masked;
uint8_t trig_mode;
uint16_t dest_idx;
uint8_t dest_mode;
uint8_t delivery_mode;
uint8_t vector;
/* MSI message generated from above parsed fields */
uint32_t addr;
uint32_t data;
};
static void ioapic_entry_parse(uint64_t entry, struct ioapic_entry_info *info)
{
memset(info, 0, sizeof(*info));
info->masked = (entry >> IOAPIC_LVT_MASKED_SHIFT) & 1;
info->trig_mode = (entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1;
/*
* By default, this would be dest_id[8] + reserved[8]. When IR
* is enabled, this would be interrupt_index[15] +
* interrupt_format[1]. This field never means anything, but
* only used to generate corresponding MSI.
*/
info->dest_idx = (entry >> IOAPIC_LVT_DEST_IDX_SHIFT) & 0xffff;
info->dest_mode = (entry >> IOAPIC_LVT_DEST_MODE_SHIFT) & 1;
info->delivery_mode = (entry >> IOAPIC_LVT_DELIV_MODE_SHIFT) \
& IOAPIC_DM_MASK;
if (info->delivery_mode == IOAPIC_DM_EXTINT) {
info->vector = pic_read_irq(isa_pic);
} else {
info->vector = entry & IOAPIC_VECTOR_MASK;
}
info->addr = APIC_DEFAULT_ADDRESS | \
(info->dest_idx << MSI_ADDR_DEST_IDX_SHIFT) | \
(info->dest_mode << MSI_ADDR_DEST_MODE_SHIFT);
info->data = (info->vector << MSI_DATA_VECTOR_SHIFT) | \
(info->trig_mode << MSI_DATA_TRIGGER_SHIFT) | \
(info->delivery_mode << MSI_DATA_DELIVERY_MODE_SHIFT);
}
static void ioapic_service(IOAPICCommonState *s)
{
AddressSpace *ioapic_as = PC_MACHINE(qdev_get_machine())->ioapic_as;
struct ioapic_entry_info info;
uint8_t i;
uint8_t trig_mode;
uint8_t vector;
uint8_t delivery_mode;
uint32_t mask;
uint64_t entry;
uint8_t dest;
uint8_t dest_mode;
for (i = 0; i < IOAPIC_NUM_PINS; i++) {
mask = 1 << i;
@@ -65,26 +108,18 @@ static void ioapic_service(IOAPICCommonState *s)
int coalesce = 0;
entry = s->ioredtbl[i];
if (!(entry & IOAPIC_LVT_MASKED)) {
trig_mode = ((entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1);
dest = entry >> IOAPIC_LVT_DEST_SHIFT;
dest_mode = (entry >> IOAPIC_LVT_DEST_MODE_SHIFT) & 1;
delivery_mode =
(entry >> IOAPIC_LVT_DELIV_MODE_SHIFT) & IOAPIC_DM_MASK;
if (trig_mode == IOAPIC_TRIGGER_EDGE) {
ioapic_entry_parse(entry, &info);
if (!info.masked) {
if (info.trig_mode == IOAPIC_TRIGGER_EDGE) {
s->irr &= ~mask;
} else {
coalesce = s->ioredtbl[i] & IOAPIC_LVT_REMOTE_IRR;
s->ioredtbl[i] |= IOAPIC_LVT_REMOTE_IRR;
}
if (delivery_mode == IOAPIC_DM_EXTINT) {
vector = pic_read_irq(isa_pic);
} else {
vector = entry & IOAPIC_VECTOR_MASK;
}
#ifdef CONFIG_KVM
if (kvm_irqchip_is_split()) {
if (trig_mode == IOAPIC_TRIGGER_EDGE) {
if (info.trig_mode == IOAPIC_TRIGGER_EDGE) {
kvm_set_irq(kvm_state, i, 1);
kvm_set_irq(kvm_state, i, 0);
} else {
@@ -97,8 +132,11 @@ static void ioapic_service(IOAPICCommonState *s)
#else
(void)coalesce;
#endif
apic_deliver_irq(dest, dest_mode, delivery_mode, vector,
trig_mode);
/* No matter whether IR is enabled, we translate
* the IOAPIC message into a MSI one, and its
* address space will decide whether we need a
* translation. */
stl_le_phys(ioapic_as, info.addr, info.data);
}
}
}
@@ -149,30 +187,11 @@ static void ioapic_update_kvm_routes(IOAPICCommonState *s)
if (kvm_irqchip_is_split()) {
for (i = 0; i < IOAPIC_NUM_PINS; i++) {
uint64_t entry = s->ioredtbl[i];
uint8_t trig_mode;
uint8_t delivery_mode;
uint8_t dest;
uint8_t dest_mode;
uint64_t pin_polarity;
MSIMessage msg;
trig_mode = ((entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1);
dest = entry >> IOAPIC_LVT_DEST_SHIFT;
dest_mode = (entry >> IOAPIC_LVT_DEST_MODE_SHIFT) & 1;
pin_polarity = (entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1;
delivery_mode =
(entry >> IOAPIC_LVT_DELIV_MODE_SHIFT) & IOAPIC_DM_MASK;
msg.address = APIC_DEFAULT_ADDRESS;
msg.address |= dest_mode << 2;
msg.address |= dest << 12;
msg.data = entry & IOAPIC_VECTOR_MASK;
msg.data |= delivery_mode << APIC_DELIVERY_MODE_SHIFT;
msg.data |= pin_polarity << APIC_POLARITY_SHIFT;
msg.data |= trig_mode << APIC_TRIG_MODE_SHIFT;
struct ioapic_entry_info info;
ioapic_entry_parse(s->ioredtbl[i], &info);
msg.address = info.addr;
msg.data = info.data;
kvm_irqchip_update_msi_route(kvm_state, i, msg, NULL);
}
kvm_irqchip_commit_routes(kvm_state);
@@ -180,6 +199,16 @@ static void ioapic_update_kvm_routes(IOAPICCommonState *s)
#endif
}
#ifdef CONFIG_KVM
static void ioapic_iec_notifier(void *private, bool global,
uint32_t index, uint32_t mask)
{
IOAPICCommonState *s = (IOAPICCommonState *)private;
/* For simplicity, we just update all the routes */
ioapic_update_kvm_routes(s);
}
#endif
void ioapic_eoi_broadcast(int vector)
{
IOAPICCommonState *s;
@@ -336,6 +365,24 @@ static const MemoryRegionOps ioapic_io_ops = {
.endianness = DEVICE_NATIVE_ENDIAN,
};
static void ioapic_machine_done_notify(Notifier *notifier, void *data)
{
#ifdef CONFIG_KVM
IOAPICCommonState *s = container_of(notifier, IOAPICCommonState,
machine_done);
if (kvm_irqchip_is_split()) {
X86IOMMUState *iommu = x86_iommu_get_default();
if (iommu) {
/* Register this IOAPIC with IOMMU IEC notifier, so that
* when there are IR invalidates, we can be notified to
* update kernel IR cache. */
x86_iommu_iec_register_notifier(iommu, ioapic_iec_notifier, s);
}
}
#endif
}
static void ioapic_realize(DeviceState *dev, Error **errp)
{
IOAPICCommonState *s = IOAPIC_COMMON(dev);
@@ -346,6 +393,8 @@ static void ioapic_realize(DeviceState *dev, Error **errp)
qdev_init_gpio_in(dev, ioapic_set_irq, IOAPIC_NUM_PINS);
ioapics[ioapic_no] = s;
s->machine_done.notify = ioapic_machine_done_notify;
qemu_add_machine_init_done_notifier(&s->machine_done);
}
static void ioapic_class_init(ObjectClass *klass, void *data)
+1
View File
@@ -98,6 +98,7 @@ static void nvdimm_realize(PCDIMMDevice *dimm, Error **errp)
"small to contain nvdimm label (0x%" PRIx64 ") and "
"aligned PMEM (0x%" PRIx64 ")",
path, memory_region_size(mr), nvdimm->label_size, align);
g_free(path);
return;
}
+1 -1
View File
@@ -1167,7 +1167,6 @@ PCIBus *gt64120_register(qemu_irq *pic)
DeviceState *dev;
dev = qdev_create(NULL, TYPE_GT64120_PCI_HOST_BRIDGE);
qdev_init_nofail(dev);
d = GT64120_PCI_HOST_BRIDGE(dev);
phb = PCI_HOST_BRIDGE(dev);
memory_region_init(&d->pci0_mem, OBJECT(dev), "pci0-mem", UINT32_MAX);
@@ -1178,6 +1177,7 @@ PCIBus *gt64120_register(qemu_irq *pic)
&d->pci0_mem,
get_system_io(),
PCI_DEVFN(18, 0), 4, TYPE_PCI_BUS);
qdev_init_nofail(dev);
memory_region_init_io(&d->ISD_mem, OBJECT(dev), &isd_mem_ops, d, "isd-mem", 0x1000);
pci_create_simple(phb->bus, PCI_DEVFN(0, 0), "gt64120_pci");

Some files were not shown because too many files have changed in this diff Show More