mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
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:
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 = {
|
||||
|
||||
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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 */
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user