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>
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQEcBAABAgAGBQJXkQsqAAoJECgfDbjSjVRpanoIAJ9JVlc1aEjt9sa0cSBcs+NQ
 J7JmgU9FqFsj+4FrNTouO3AxTjHurd1UAULP1WMPD+V3JpbnHct8r6SCBLQ5EBMN
 VOjYo4DwWs1g+DqnQ9WZmbadu06XvYi/yiAKNUzWfZk0MR11D0D/S5hmarNKw0Kq
 tGHeTWjGeY4WqFLV7m+qB4+cqkAByn6um99UtUvgLL05RgIEIP2IEMKYZ+rXvAa9
 iGUvzqlO7mbq/+LbL18kaWywa4TCwbbd2eSGWaqhX4CuB62Rl33mWTXFcfaYhkyp
 Z3FgwaJ09h0lAjSVEbyAuLFMfO/BnMcsoKqwl4xc4vkn/xBCqFtgH9JcEVm3O8U=
 =ge2D
 -----END PGP SIGNATURE-----

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
commit 206d0c2436
55 changed files with 1478 additions and 349 deletions

View file

@ -571,6 +571,18 @@ enum {
/*
* Sub-structures for DMAR
*/
/* Device scope structure for DRHD. */
struct AcpiDmarDeviceScope {
uint8_t entry_type;
uint8_t length;
uint16_t reserved;
uint8_t enumeration_id;
uint8_t bus;
uint16_t path[0]; /* list of dev:func pairs */
} QEMU_PACKED;
typedef struct AcpiDmarDeviceScope AcpiDmarDeviceScope;
/* Type 0: Hardware Unit Definition */
struct AcpiDmarHardwareUnit {
uint16_t type;
@ -579,6 +591,7 @@ struct AcpiDmarHardwareUnit {
uint8_t reserved;
uint16_t pci_segment; /* The PCI Segment associated with this unit */
uint64_t address; /* Base address of remapping hardware register-set */
AcpiDmarDeviceScope scope[0];
} QEMU_PACKED;
typedef struct AcpiDmarHardwareUnit AcpiDmarHardwareUnit;

View file

@ -25,6 +25,7 @@
#define MSI_ADDR_REDIRECTION_SHIFT 3
#define MSI_ADDR_DEST_ID_SHIFT 12
#define MSI_ADDR_DEST_IDX_SHIFT 4
#define MSI_ADDR_DEST_ID_MASK 0x00ffff0
#endif /* HW_APIC_MSIDEF_H */

View file

@ -23,6 +23,10 @@
#define INTEL_IOMMU_H
#include "hw/qdev.h"
#include "sysemu/dma.h"
#include "hw/i386/x86-iommu.h"
#include "hw/i386/ioapic.h"
#include "hw/pci/msi.h"
#include "hw/sysbus.h"
#define TYPE_INTEL_IOMMU_DEVICE "intel-iommu"
#define INTEL_IOMMU_DEVICE(obj) \
@ -34,7 +38,6 @@
#define VTD_PCI_BUS_MAX 256
#define VTD_PCI_SLOT_MAX 32
#define VTD_PCI_FUNC_MAX 8
#define VTD_PCI_DEVFN_MAX 256
#define VTD_PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f)
#define VTD_PCI_FUNC(devfn) ((devfn) & 0x07)
#define VTD_SID_TO_BUS(sid) (((sid) >> 8) & 0xff)
@ -44,12 +47,22 @@
#define VTD_HOST_ADDRESS_WIDTH 39
#define VTD_HAW_MASK ((1ULL << VTD_HOST_ADDRESS_WIDTH) - 1)
#define DMAR_REPORT_F_INTR (1)
#define VTD_MSI_ADDR_HI_MASK (0xffffffff00000000ULL)
#define VTD_MSI_ADDR_HI_SHIFT (32)
#define VTD_MSI_ADDR_LO_MASK (0x00000000ffffffffULL)
typedef struct VTDContextEntry VTDContextEntry;
typedef struct VTDContextCacheEntry VTDContextCacheEntry;
typedef struct IntelIOMMUState IntelIOMMUState;
typedef struct VTDAddressSpace VTDAddressSpace;
typedef struct VTDIOTLBEntry VTDIOTLBEntry;
typedef struct VTDBus VTDBus;
typedef union VTD_IR_TableEntry VTD_IR_TableEntry;
typedef union VTD_IR_MSIAddress VTD_IR_MSIAddress;
typedef struct VTDIrq VTDIrq;
typedef struct VTD_MSIMessage VTD_MSIMessage;
/* Context-Entry */
struct VTDContextEntry {
@ -70,6 +83,7 @@ struct VTDAddressSpace {
uint8_t devfn;
AddressSpace as;
MemoryRegion iommu;
MemoryRegion iommu_ir; /* Interrupt region: 0xfeeXXXXX */
IntelIOMMUState *iommu_state;
VTDContextCacheEntry context_cache_entry;
};
@ -88,9 +102,155 @@ struct VTDIOTLBEntry {
bool write_flags;
};
/* VT-d Source-ID Qualifier types */
enum {
VTD_SQ_FULL = 0x00, /* Full SID verification */
VTD_SQ_IGN_3 = 0x01, /* Ignore bit 3 */
VTD_SQ_IGN_2_3 = 0x02, /* Ignore bits 2 & 3 */
VTD_SQ_IGN_1_3 = 0x03, /* Ignore bits 1-3 */
VTD_SQ_MAX,
};
/* VT-d Source Validation Types */
enum {
VTD_SVT_NONE = 0x00, /* No validation */
VTD_SVT_ALL = 0x01, /* Do full validation */
VTD_SVT_BUS = 0x02, /* Validate bus range */
VTD_SVT_MAX,
};
/* Interrupt Remapping Table Entry Definition */
union VTD_IR_TableEntry {
struct {
#ifdef HOST_WORDS_BIGENDIAN
uint32_t dest_id:32; /* Destination ID */
uint32_t __reserved_1:8; /* Reserved 1 */
uint32_t vector:8; /* Interrupt Vector */
uint32_t irte_mode:1; /* IRTE Mode */
uint32_t __reserved_0:3; /* Reserved 0 */
uint32_t __avail:4; /* Available spaces for software */
uint32_t delivery_mode:3; /* Delivery Mode */
uint32_t trigger_mode:1; /* Trigger Mode */
uint32_t redir_hint:1; /* Redirection Hint */
uint32_t dest_mode:1; /* Destination Mode */
uint32_t fault_disable:1; /* Fault Processing Disable */
uint32_t present:1; /* Whether entry present/available */
#else
uint32_t present:1; /* Whether entry present/available */
uint32_t fault_disable:1; /* Fault Processing Disable */
uint32_t dest_mode:1; /* Destination Mode */
uint32_t redir_hint:1; /* Redirection Hint */
uint32_t trigger_mode:1; /* Trigger Mode */
uint32_t delivery_mode:3; /* Delivery Mode */
uint32_t __avail:4; /* Available spaces for software */
uint32_t __reserved_0:3; /* Reserved 0 */
uint32_t irte_mode:1; /* IRTE Mode */
uint32_t vector:8; /* Interrupt Vector */
uint32_t __reserved_1:8; /* Reserved 1 */
uint32_t dest_id:32; /* Destination ID */
#endif
uint16_t source_id:16; /* Source-ID */
#ifdef HOST_WORDS_BIGENDIAN
uint64_t __reserved_2:44; /* Reserved 2 */
uint64_t sid_vtype:2; /* Source-ID Validation Type */
uint64_t sid_q:2; /* Source-ID Qualifier */
#else
uint64_t sid_q:2; /* Source-ID Qualifier */
uint64_t sid_vtype:2; /* Source-ID Validation Type */
uint64_t __reserved_2:44; /* Reserved 2 */
#endif
} QEMU_PACKED irte;
uint64_t data[2];
};
#define VTD_IR_INT_FORMAT_COMPAT (0) /* Compatible Interrupt */
#define VTD_IR_INT_FORMAT_REMAP (1) /* Remappable Interrupt */
/* Programming format for MSI/MSI-X addresses */
union VTD_IR_MSIAddress {
struct {
#ifdef HOST_WORDS_BIGENDIAN
uint32_t __head:12; /* Should always be: 0x0fee */
uint32_t index_l:15; /* Interrupt index bit 14-0 */
uint32_t int_mode:1; /* Interrupt format */
uint32_t sub_valid:1; /* SHV: Sub-Handle Valid bit */
uint32_t index_h:1; /* Interrupt index bit 15 */
uint32_t __not_care:2;
#else
uint32_t __not_care:2;
uint32_t index_h:1; /* Interrupt index bit 15 */
uint32_t sub_valid:1; /* SHV: Sub-Handle Valid bit */
uint32_t int_mode:1; /* Interrupt format */
uint32_t index_l:15; /* Interrupt index bit 14-0 */
uint32_t __head:12; /* Should always be: 0x0fee */
#endif
} QEMU_PACKED addr;
uint32_t data;
};
/* Generic IRQ entry information */
struct VTDIrq {
/* Used by both IOAPIC/MSI interrupt remapping */
uint8_t trigger_mode;
uint8_t vector;
uint8_t delivery_mode;
uint32_t dest;
uint8_t dest_mode;
/* only used by MSI interrupt remapping */
uint8_t redir_hint;
uint8_t msi_addr_last_bits;
};
struct VTD_MSIMessage {
union {
struct {
#ifdef HOST_WORDS_BIGENDIAN
uint32_t __addr_head:12; /* 0xfee */
uint32_t dest:8;
uint32_t __reserved:8;
uint32_t redir_hint:1;
uint32_t dest_mode:1;
uint32_t __not_used:2;
#else
uint32_t __not_used:2;
uint32_t dest_mode:1;
uint32_t redir_hint:1;
uint32_t __reserved:8;
uint32_t dest:8;
uint32_t __addr_head:12; /* 0xfee */
#endif
uint32_t __addr_hi:32;
} QEMU_PACKED;
uint64_t msi_addr;
};
union {
struct {
#ifdef HOST_WORDS_BIGENDIAN
uint16_t trigger_mode:1;
uint16_t level:1;
uint16_t __resved:3;
uint16_t delivery_mode:3;
uint16_t vector:8;
#else
uint16_t vector:8;
uint16_t delivery_mode:3;
uint16_t __resved:3;
uint16_t level:1;
uint16_t trigger_mode:1;
#endif
uint16_t __resved1:16;
} QEMU_PACKED;
uint32_t msi_data;
};
};
/* When IR is enabled, all MSI/MSI-X data bits should be zero */
#define VTD_IR_MSI_DATA (0)
/* The iommu (DMAR) device state struct */
struct IntelIOMMUState {
SysBusDevice busdev;
X86IOMMUState x86_iommu;
MemoryRegion csrmem;
uint8_t csr[DMAR_REG_SIZE]; /* register values */
uint8_t wmask[DMAR_REG_SIZE]; /* R/W bytes */
@ -123,6 +283,12 @@ struct IntelIOMMUState {
MemoryRegionIOMMUOps iommu_ops;
GHashTable *vtd_as_by_busptr; /* VTDBus objects indexed by PCIBus* reference */
VTDBus *vtd_as_by_bus_num[VTD_PCI_BUS_MAX]; /* VTDBus objects indexed by bus number */
/* interrupt remapping */
bool intr_enabled; /* Whether guest enabled IR */
dma_addr_t intr_root; /* Interrupt remapping table pointer */
uint32_t intr_size; /* Number of IR table entries */
bool intr_eime; /* Extended interrupt mode enabled */
};
/* Find the VTD Address space associated with the given bus pointer,

View file

@ -25,12 +25,14 @@
#include "hw/hw.h"
#include "exec/memory.h"
#include "hw/sysbus.h"
#include "qemu/notify.h"
#define MAX_IOAPICS 1
#define IOAPIC_VERSION 0x11
#define IOAPIC_LVT_DEST_SHIFT 56
#define IOAPIC_LVT_DEST_IDX_SHIFT 48
#define IOAPIC_LVT_MASKED_SHIFT 16
#define IOAPIC_LVT_TRIGGER_MODE_SHIFT 15
#define IOAPIC_LVT_REMOTE_IRR_SHIFT 14
@ -106,6 +108,7 @@ struct IOAPICCommonState {
uint8_t ioregsel;
uint32_t irr;
uint64_t ioredtbl[IOAPIC_NUM_PINS];
Notifier machine_done;
};
void ioapic_reset_common(DeviceState *dev);

View file

@ -72,6 +72,10 @@ struct PCMachineState {
/* NUMA information: */
uint64_t numa_nodes;
uint64_t *node_mem;
/* Address space used by IOAPIC device. All IOAPIC interrupts
* will be translated to MSI messages in the address space. */
AddressSpace *ioapic_as;
};
#define PC_MACHINE_ACPI_DEVICE_PROP "acpi-device"

100
include/hw/i386/x86-iommu.h Normal file
View file

@ -0,0 +1,100 @@
/*
* Common IOMMU interface for X86 platform
*
* 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/>.
*/
#ifndef IOMMU_COMMON_H
#define IOMMU_COMMON_H
#include "hw/sysbus.h"
#include "hw/pci/pci.h"
#define TYPE_X86_IOMMU_DEVICE ("x86-iommu")
#define X86_IOMMU_DEVICE(obj) \
OBJECT_CHECK(X86IOMMUState, (obj), TYPE_X86_IOMMU_DEVICE)
#define X86_IOMMU_CLASS(klass) \
OBJECT_CLASS_CHECK(X86IOMMUClass, (klass), TYPE_X86_IOMMU_DEVICE)
#define X86_IOMMU_GET_CLASS(obj) \
OBJECT_GET_CLASS(X86IOMMUClass, obj, TYPE_X86_IOMMU_DEVICE)
#define X86_IOMMU_PCI_DEVFN_MAX 256
#define X86_IOMMU_SID_INVALID (0xffff)
typedef struct X86IOMMUState X86IOMMUState;
typedef struct X86IOMMUClass X86IOMMUClass;
struct X86IOMMUClass {
SysBusDeviceClass parent;
/* Intel/AMD specific realize() hook */
DeviceRealize realize;
/* MSI-based interrupt remapping */
int (*int_remap)(X86IOMMUState *iommu, MSIMessage *src,
MSIMessage *dst, uint16_t sid);
};
/**
* iec_notify_fn - IEC (Interrupt Entry Cache) notifier hook,
* triggered when IR invalidation happens.
* @private: private data
* @global: whether this is a global IEC invalidation
* @index: IRTE index to invalidate (start from)
* @mask: invalidation mask
*/
typedef void (*iec_notify_fn)(void *private, bool global,
uint32_t index, uint32_t mask);
struct IEC_Notifier {
iec_notify_fn iec_notify;
void *private;
QLIST_ENTRY(IEC_Notifier) list;
};
typedef struct IEC_Notifier IEC_Notifier;
struct X86IOMMUState {
SysBusDevice busdev;
bool intr_supported; /* Whether vIOMMU supports IR */
QLIST_HEAD(, IEC_Notifier) iec_notifiers; /* IEC notify list */
};
/**
* x86_iommu_get_default - get default IOMMU device
* @return: pointer to default IOMMU device
*/
X86IOMMUState *x86_iommu_get_default(void);
/**
* x86_iommu_iec_register_notifier - register IEC (Interrupt Entry
* Cache) notifiers
* @iommu: IOMMU device to register
* @fn: IEC notifier hook function
* @data: notifier private data
*/
void x86_iommu_iec_register_notifier(X86IOMMUState *iommu,
iec_notify_fn fn, void *data);
/**
* x86_iommu_iec_notify_all - Notify IEC invalidations
* @iommu: IOMMU device that sends the notification
* @global: whether this is a global invalidation. If true, @index
* and @mask are undefined.
* @index: starting index of interrupt entry to invalidate
* @mask: index mask for the invalidation
*/
void x86_iommu_iec_notify_all(X86IOMMUState *iommu, bool global,
uint32_t index, uint32_t mask);
#endif

View file

@ -179,4 +179,12 @@ typedef struct Q35PCIHost {
uint64_t mch_mcfg_base(void);
/*
* Arbitary but unique BNF number for IOAPIC device.
*
* TODO: make sure there would have no conflict with real PCI bus
*/
#define Q35_PSEUDO_BUS_PLATFORM (0xff)
#define Q35_PSEUDO_DEVFN_IOAPIC (0x00)
#endif /* HW_Q35_H */

View file

@ -805,4 +805,6 @@ extern const VMStateDescription vmstate_pci_device;
.offset = vmstate_offset_pointer(_state, _field, PCIDevice), \
}
MSIMessage pci_get_msi_message(PCIDevice *dev, int vector);
#endif

View file

@ -118,6 +118,8 @@ typedef struct VirtIOGPU {
uint32_t req_3d;
uint32_t bytes_3d;
} stats;
Error *migration_blocker;
} VirtIOGPU;
extern const GraphicHwOps virtio_gpu_ops;

View file

@ -121,11 +121,9 @@ typedef struct VirtIOSCSIReq {
} req;
} VirtIOSCSIReq;
typedef void (*HandleOutput)(VirtIODevice *, VirtQueue *);
void virtio_scsi_common_realize(DeviceState *dev, Error **errp,
HandleOutput ctrl, HandleOutput evt,
HandleOutput cmd);
VirtIOHandleOutput ctrl, VirtIOHandleOutput evt,
VirtIOHandleOutput cmd);
void virtio_scsi_common_unrealize(DeviceState *dev, Error **errp);
void virtio_scsi_handle_event_vq(VirtIOSCSI *s, VirtQueue *vq);

View file

@ -138,9 +138,13 @@ void virtio_cleanup(VirtIODevice *vdev);
/* Set the child bus name. */
void virtio_device_set_child_bus_name(VirtIODevice *vdev, char *bus_name);
typedef void (*VirtIOHandleOutput)(VirtIODevice *, VirtQueue *);
VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size,
void (*handle_output)(VirtIODevice *,
VirtQueue *));
VirtIOHandleOutput handle_output);
VirtQueue *virtio_add_queue_aio(VirtIODevice *vdev, int queue_size,
VirtIOHandleOutput handle_output);
void virtio_del_queue(VirtIODevice *vdev, int n);
@ -167,6 +171,26 @@ bool virtio_should_notify(VirtIODevice *vdev, VirtQueue *vq);
void virtio_notify(VirtIODevice *vdev, VirtQueue *vq);
void virtio_save(VirtIODevice *vdev, QEMUFile *f);
void virtio_vmstate_save(QEMUFile *f, void *opaque, size_t size);
#define VMSTATE_VIRTIO_DEVICE(devname, v, getf, putf) \
static const VMStateDescription vmstate_virtio_ ## devname = { \
.name = "virtio-" #devname , \
.minimum_version_id = v, \
.version_id = v, \
.fields = (VMStateField[]) { \
{ \
.name = "virtio", \
.info = &(const VMStateInfo) {\
.name = "virtio", \
.get = getf, \
.put = putf, \
}, \
.flags = VMS_SINGLE, \
}, \
VMSTATE_END_OF_LIST() \
} \
}
int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id);

View file

@ -359,13 +359,18 @@ void kvm_arch_init_irq_routing(KVMState *s);
int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route,
uint64_t address, uint32_t data, PCIDevice *dev);
/* Notify arch about newly added MSI routes */
int kvm_arch_add_msi_route_post(struct kvm_irq_routing_entry *route,
int vector, PCIDevice *dev);
/* Notify arch about released MSI routes */
int kvm_arch_release_virq_post(int virq);
int kvm_arch_msi_data_to_gsi(uint32_t data);
int kvm_set_irq(KVMState *s, int irq, int level);
int kvm_irqchip_send_msi(KVMState *s, MSIMessage msg);
void kvm_irqchip_add_irq_route(KVMState *s, int gsi, int irqchip, int pin);
void kvm_irqchip_commit_routes(KVMState *s);
void kvm_put_apic_state(DeviceState *d, struct kvm_lapic_state *kapic);
void kvm_get_apic_state(DeviceState *d, struct kvm_lapic_state *kapic);
@ -474,9 +479,21 @@ static inline void cpu_synchronize_post_init(CPUState *cpu)
}
}
int kvm_irqchip_add_msi_route(KVMState *s, MSIMessage msg, PCIDevice *dev);
/**
* kvm_irqchip_add_msi_route - Add MSI route for specific vector
* @s: KVM state
* @vector: which vector to add. This can be either MSI/MSIX
* vector. The function will automatically detect whether
* MSI/MSIX is enabled, and fetch corresponding MSI
* message.
* @dev: Owner PCI device to add the route. If @dev is specified
* as @NULL, an empty MSI message will be inited.
* @return: virq (>=0) when success, errno (<0) when failed.
*/
int kvm_irqchip_add_msi_route(KVMState *s, int vector, PCIDevice *dev);
int kvm_irqchip_update_msi_route(KVMState *s, int virq, MSIMessage msg,
PCIDevice *dev);
void kvm_irqchip_commit_routes(KVMState *s);
void kvm_irqchip_release_virq(KVMState *s, int virq);
int kvm_irqchip_add_adapter_route(KVMState *s, AdapterInfo *adapter);