aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2016-07-05 16:48:24 +0100
committerPeter Maydell <peter.maydell@linaro.org>2016-07-05 16:48:24 +0100
commit791b7d2340cfafcac9af7864343cf23504d57804 (patch)
tree5834c152f6881c3e907bfe64dd66bcfa83cf8369
parent60a0f1af07d685c88f4ffa09370da5bd7514823e (diff)
parent269fe4c3ab0cf29329317eb868f8ec90ac761b41 (diff)
downloadqemu-791b7d2340cfafcac9af7864343cf23504d57804.zip
qemu-791b7d2340cfafcac9af7864343cf23504d57804.tar.gz
qemu-791b7d2340cfafcac9af7864343cf23504d57804.tar.bz2
Merge remote-tracking branch 'remotes/mst/tags/for_upstream' into staging
pc, pci, virtio: new features, cleanups, fixes iommus can not be added with -device. cleanups and fixes all over the place Signed-off-by: Michael S. Tsirkin <mst@redhat.com> # gpg: Signature made Tue 05 Jul 2016 11:18:32 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: (30 commits) vmw_pvscsi: remove unnecessary internal msi state flag e1000e: remove unnecessary internal msi state flag vmxnet3: remove unnecessary internal msi state flag mptsas: remove unnecessary internal msi state flag megasas: remove unnecessary megasas_use_msi() pci: Convert msi_init() to Error and fix callers to check it pci bridge dev: change msi property type megasas: change msi/msix property type mptsas: change msi property type intel-hda: change msi property type usb xhci: change msi/msix property type change pvscsi_init_msi() type to void tests: add APIC.cphp and DSDT.cphp blobs tests: acpi: add CPU hotplug testcase log: Permit -dfilter 0..0xffffffffffffffff range: Replace internal representation of Range range: Eliminate direct Range member access log: Clean up misuse of Range for -dfilter pci_register_bar: cleanup Revert "virtio-net: unbreak self announcement and guest offloads after migration" ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--hw/audio/intel-hda.c29
-rw-r--r--hw/core/machine.c20
-rw-r--r--hw/i386/acpi-build.c44
-rw-r--r--hw/i386/intel_iommu.c16
-rw-r--r--hw/i386/pc.c2
-rw-r--r--hw/i386/pc_piix.c50
-rw-r--r--hw/i386/pc_q35.c5
-rw-r--r--hw/ide/ich.c7
-rw-r--r--hw/net/e1000e.c37
-rw-r--r--hw/net/virtio-net.c40
-rw-r--r--hw/net/vmxnet3.c52
-rw-r--r--hw/pci-bridge/ioh3420.c6
-rw-r--r--hw/pci-bridge/pci_bridge_dev.c31
-rw-r--r--hw/pci-bridge/pci_expander_bridge.c2
-rw-r--r--hw/pci-bridge/xio3130_downstream.c6
-rw-r--r--hw/pci-bridge/xio3130_upstream.c6
-rw-r--r--hw/pci-host/piix.c32
-rw-r--r--hw/pci-host/q35.c72
-rw-r--r--hw/pci/msi.c11
-rw-r--r--hw/pci/pci.c74
-rw-r--r--hw/ppc/mac_newworld.c1
-rw-r--r--hw/scsi/megasas.c59
-rw-r--r--hw/scsi/mptsas.c36
-rw-r--r--hw/scsi/mptsas.h5
-rw-r--r--hw/scsi/vmw_pvscsi.c15
-rw-r--r--hw/usb/hcd-xhci.c35
-rw-r--r--hw/vfio/pci.c7
-rw-r--r--hw/virtio/virtio-bus.c26
-rw-r--r--hw/virtio/virtio.c10
-rw-r--r--include/hw/i386/pc.h5
-rw-r--r--include/hw/pci-host/q35.h3
-rw-r--r--include/hw/pci/msi.h3
-rw-r--r--include/hw/pci/pci_bus.h2
-rw-r--r--include/qemu/range.h103
-rw-r--r--include/sysemu/sysemu.h1
-rw-r--r--qapi/string-input-visitor.c20
-rw-r--r--qapi/string-output-visitor.c18
-rw-r--r--qemu-options.hx3
-rw-r--r--tests/acpi-test-data/pc/APIC.cphpbin0 -> 160 bytes
-rw-r--r--tests/acpi-test-data/pc/DSDT.cphpbin0 -> 6435 bytes
-rw-r--r--tests/acpi-test-data/q35/APIC.cphpbin0 -> 160 bytes
-rw-r--r--tests/acpi-test-data/q35/DSDT.cphpbin0 -> 9197 bytes
-rw-r--r--tests/bios-tables-test.c28
-rw-r--r--tests/test-logging.c11
-rw-r--r--util/log.c27
-rw-r--r--util/range.c19
-rw-r--r--vl.c5
-rw-r--r--xen-hvm.c3
48 files changed, 586 insertions, 401 deletions
diff --git a/hw/audio/intel-hda.c b/hw/audio/intel-hda.c
index 098b17d..cd95340 100644
--- a/hw/audio/intel-hda.c
+++ b/hw/audio/intel-hda.c
@@ -191,7 +191,7 @@ struct IntelHDAState {
/* properties */
uint32_t debug;
- uint32_t msi;
+ OnOffAuto msi;
bool old_msi_addr;
};
@@ -256,7 +256,7 @@ static void intel_hda_update_int_sts(IntelHDAState *d)
static void intel_hda_update_irq(IntelHDAState *d)
{
- int msi = d->msi && msi_enabled(&d->pci);
+ bool msi = msi_enabled(&d->pci);
int level;
intel_hda_update_int_sts(d);
@@ -1132,6 +1132,8 @@ static void intel_hda_realize(PCIDevice *pci, Error **errp)
{
IntelHDAState *d = INTEL_HDA(pci);
uint8_t *conf = d->pci.config;
+ Error *err = NULL;
+ int ret;
d->name = object_get_typename(OBJECT(d));
@@ -1140,12 +1142,27 @@ static void intel_hda_realize(PCIDevice *pci, Error **errp)
/* HDCTL off 0x40 bit 0 selects signaling mode (1-HDA, 0 - Ac97) 18.1.19 */
conf[0x40] = 0x01;
+ if (d->msi != ON_OFF_AUTO_OFF) {
+ ret = msi_init(&d->pci, d->old_msi_addr ? 0x50 : 0x60,
+ 1, true, false, &err);
+ /* Any error other than -ENOTSUP(board's MSI support is broken)
+ * is a programming error */
+ assert(!ret || ret == -ENOTSUP);
+ if (ret && d->msi == ON_OFF_AUTO_ON) {
+ /* Can't satisfy user's explicit msi=on request, fail */
+ error_append_hint(&err, "You have to use msi=auto (default) or "
+ "msi=off with this machine type.\n");
+ error_propagate(errp, err);
+ return;
+ }
+ assert(!err || d->msi == ON_OFF_AUTO_AUTO);
+ /* With msi=auto, we fall back to MSI off silently */
+ error_free(err);
+ }
+
memory_region_init_io(&d->mmio, OBJECT(d), &intel_hda_mmio_ops, d,
"intel-hda", 0x4000);
pci_register_bar(&d->pci, 0, 0, &d->mmio);
- if (d->msi) {
- msi_init(&d->pci, d->old_msi_addr ? 0x50 : 0x60, 1, true, false);
- }
hda_codec_bus_init(DEVICE(pci), &d->codecs, sizeof(d->codecs),
intel_hda_response, intel_hda_xfer);
@@ -1235,7 +1252,7 @@ static const VMStateDescription vmstate_intel_hda = {
static Property intel_hda_properties[] = {
DEFINE_PROP_UINT32("debug", IntelHDAState, debug, 0),
- DEFINE_PROP_UINT32("msi", IntelHDAState, msi, 1),
+ DEFINE_PROP_ON_OFF_AUTO("msi", IntelHDAState, msi, ON_OFF_AUTO_AUTO),
DEFINE_PROP_BOOL("old_msi_addr", IntelHDAState, old_msi_addr, false),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/core/machine.c b/hw/core/machine.c
index ccdd5fa..8f94301 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -300,20 +300,6 @@ static void machine_set_firmware(Object *obj, const char *value, Error **errp)
ms->firmware = g_strdup(value);
}
-static bool machine_get_iommu(Object *obj, Error **errp)
-{
- MachineState *ms = MACHINE(obj);
-
- return ms->iommu;
-}
-
-static void machine_set_iommu(Object *obj, bool value, Error **errp)
-{
- MachineState *ms = MACHINE(obj);
-
- ms->iommu = value;
-}
-
static void machine_set_suppress_vmdesc(Object *obj, bool value, Error **errp)
{
MachineState *ms = MACHINE(obj);
@@ -493,12 +479,6 @@ static void machine_initfn(Object *obj)
object_property_set_description(obj, "firmware",
"Firmware image",
NULL);
- object_property_add_bool(obj, "iommu",
- machine_get_iommu,
- machine_set_iommu, NULL);
- object_property_set_description(obj, "iommu",
- "Set on/off to enable/disable Intel IOMMU (VT-d)",
- NULL);
object_property_add_bool(obj, "suppress-vmdesc",
machine_get_suppress_vmdesc,
machine_set_suppress_vmdesc, NULL);
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 5a594be..fbba461 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -229,26 +229,27 @@ static Object *acpi_get_i386_pci_host(void)
return OBJECT(host);
}
-static void acpi_get_pci_info(PcPciInfo *info)
+static void acpi_get_pci_holes(Range *hole, Range *hole64)
{
Object *pci_host;
-
pci_host = acpi_get_i386_pci_host();
g_assert(pci_host);
- info->w32.begin = object_property_get_int(pci_host,
+ range_set_bounds1(hole,
+ object_property_get_int(pci_host,
PCI_HOST_PROP_PCI_HOLE_START,
- NULL);
- info->w32.end = object_property_get_int(pci_host,
- PCI_HOST_PROP_PCI_HOLE_END,
- NULL);
- info->w64.begin = object_property_get_int(pci_host,
+ NULL),
+ object_property_get_int(pci_host,
+ PCI_HOST_PROP_PCI_HOLE_END,
+ NULL));
+ range_set_bounds1(hole64,
+ object_property_get_int(pci_host,
PCI_HOST_PROP_PCI_HOLE64_START,
- NULL);
- info->w64.end = object_property_get_int(pci_host,
- PCI_HOST_PROP_PCI_HOLE64_END,
- NULL);
+ NULL),
+ object_property_get_int(pci_host,
+ PCI_HOST_PROP_PCI_HOLE64_END,
+ NULL));
}
#define ACPI_PORT_SMI_CMD 0x00b2 /* TODO: this is APM_CNT_IOPORT */
@@ -1890,7 +1891,7 @@ static Aml *build_q35_osc_method(void)
static void
build_dsdt(GArray *table_data, BIOSLinker *linker,
AcpiPmInfo *pm, AcpiMiscInfo *misc,
- PcPciInfo *pci, MachineState *machine)
+ Range *pci_hole, Range *pci_hole64, MachineState *machine)
{
CrsRangeEntry *entry;
Aml *dsdt, *sb_scope, *scope, *dev, *method, *field, *pkg, *crs;
@@ -2047,7 +2048,9 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
AML_CACHEABLE, AML_READ_WRITE,
0, 0x000A0000, 0x000BFFFF, 0, 0x00020000));
- crs_replace_with_free_ranges(mem_ranges, pci->w32.begin, pci->w32.end - 1);
+ crs_replace_with_free_ranges(mem_ranges,
+ range_lob(pci_hole),
+ range_upb(pci_hole));
for (i = 0; i < mem_ranges->len; i++) {
entry = g_ptr_array_index(mem_ranges, i);
aml_append(crs,
@@ -2057,12 +2060,12 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
0, entry->limit - entry->base + 1));
}
- if (pci->w64.begin) {
+ if (!range_is_empty(pci_hole64)) {
aml_append(crs,
aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED,
AML_CACHEABLE, AML_READ_WRITE,
- 0, pci->w64.begin, pci->w64.end - 1, 0,
- pci->w64.end - pci->w64.begin));
+ 0, range_lob(pci_hole64), range_upb(pci_hole64), 0,
+ range_upb(pci_hole64) + 1 - range_lob(pci_hole64)));
}
if (misc->tpm_version != TPM_VERSION_UNSPEC) {
@@ -2554,7 +2557,7 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine)
AcpiPmInfo pm;
AcpiMiscInfo misc;
AcpiMcfgInfo mcfg;
- PcPciInfo pci;
+ Range pci_hole, pci_hole64;
uint8_t *u;
size_t aml_len = 0;
GArray *tables_blob = tables->table_data;
@@ -2562,7 +2565,7 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine)
acpi_get_pm_info(&pm);
acpi_get_misc_info(&misc);
- acpi_get_pci_info(&pci);
+ acpi_get_pci_holes(&pci_hole, &pci_hole64);
acpi_get_slic_oem(&slic_oem);
table_offsets = g_array_new(false, true /* clear */,
@@ -2584,7 +2587,8 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine)
/* DSDT is pointed to by FADT */
dsdt = tables_blob->len;
- build_dsdt(tables_blob, tables->linker, &pm, &misc, &pci, machine);
+ build_dsdt(tables_blob, tables->linker, &pm, &misc,
+ &pci_hole, &pci_hole64, machine);
/* Count the size of the DSDT and SSDT, we will need it for legacy
* sizing of ACPI tables.
diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c
index 5eba704..464f2a0 100644
--- a/hw/i386/intel_iommu.c
+++ b/hw/i386/intel_iommu.c
@@ -25,6 +25,7 @@
#include "intel_iommu_internal.h"
#include "hw/pci/pci.h"
#include "hw/pci/pci_bus.h"
+#include "hw/i386/pc.h"
/*#define DEBUG_INTEL_IOMMU*/
#ifdef DEBUG_INTEL_IOMMU
@@ -2026,8 +2027,20 @@ static void vtd_reset(DeviceState *dev)
vtd_init(s);
}
+static AddressSpace *vtd_host_dma_iommu(PCIBus *bus, void *opaque, int devfn)
+{
+ IntelIOMMUState *s = opaque;
+ VTDAddressSpace *vtd_as;
+
+ assert(0 <= devfn && devfn <= VTD_PCI_DEVFN_MAX);
+
+ vtd_as = vtd_find_add_as(s, bus, devfn);
+ return &vtd_as->as;
+}
+
static void vtd_realize(DeviceState *dev, Error **errp)
{
+ PCIBus *bus = PC_MACHINE(qdev_get_machine())->bus;
IntelIOMMUState *s = INTEL_IOMMU_DEVICE(dev);
VTD_DPRINTF(GENERAL, "");
@@ -2041,6 +2054,8 @@ static void vtd_realize(DeviceState *dev, Error **errp)
s->vtd_as_by_busptr = g_hash_table_new_full(vtd_uint64_hash, vtd_uint64_equal,
g_free, g_free);
vtd_init(s);
+ sysbus_mmio_map(SYS_BUS_DEVICE(s), 0, Q35_HOST_BRIDGE_IOMMU_ADDR);
+ pci_setup_iommu(bus, vtd_host_dma_iommu, dev);
}
static void vtd_class_init(ObjectClass *klass, void *data)
@@ -2051,6 +2066,7 @@ static void vtd_class_init(ObjectClass *klass, void *data)
dc->realize = vtd_realize;
dc->vmsd = &vtd_vmstate;
dc->props = vtd_properties;
+ dc->hotpluggable = false;
}
static const TypeInfo vtd_info = {
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 44a8f3b..cd1745e 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -1919,7 +1919,7 @@ static void pc_machine_initfn(Object *obj)
pc_machine_get_hotplug_memory_region_size,
NULL, NULL, NULL, &error_abort);
- pcms->max_ram_below_4g = 0xe0000000; /* 3.5G */
+ pcms->max_ram_below_4g = 0; /* use default */
object_property_add(obj, PC_MACHINE_MAX_RAM_BELOW_4G, "size",
pc_machine_get_max_ram_below_4g,
pc_machine_set_max_ram_below_4g,
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index c7d70af..a07dc81 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -108,37 +108,43 @@ static void pc_init1(MachineState *machine,
* so legacy non-PAE guests can get as much memory as possible in
* the 32bit address space below 4G.
*
+ * - Note that Xen has its own ram setp code in xen_ram_init(),
+ * called via xen_hvm_init().
+ *
* Examples:
* qemu -M pc-1.7 -m 4G (old default) -> 3584M low, 512M high
* qemu -M pc -m 4G (new default) -> 3072M low, 1024M high
* qemu -M pc,max-ram-below-4g=2G -m 4G -> 2048M low, 2048M high
* qemu -M pc,max-ram-below-4g=4G -m 3968M -> 3968M low (=4G-128M)
*/
- lowmem = pcms->max_ram_below_4g;
- if (machine->ram_size >= pcms->max_ram_below_4g) {
- if (pcmc->gigabyte_align) {
- if (lowmem > 0xc0000000) {
- lowmem = 0xc0000000;
- }
- if (lowmem & ((1ULL << 30) - 1)) {
- error_report("Warning: Large machine and max_ram_below_4g "
- "(%" PRIu64 ") not a multiple of 1G; "
- "possible bad performance.",
- pcms->max_ram_below_4g);
+ if (xen_enabled()) {
+ xen_hvm_init(pcms, &ram_memory);
+ } else {
+ if (!pcms->max_ram_below_4g) {
+ pcms->max_ram_below_4g = 0xe0000000; /* default: 3.5G */
+ }
+ lowmem = pcms->max_ram_below_4g;
+ if (machine->ram_size >= pcms->max_ram_below_4g) {
+ if (pcmc->gigabyte_align) {
+ if (lowmem > 0xc0000000) {
+ lowmem = 0xc0000000;
+ }
+ if (lowmem & ((1ULL << 30) - 1)) {
+ error_report("Warning: Large machine and max_ram_below_4g "
+ "(%" PRIu64 ") not a multiple of 1G; "
+ "possible bad performance.",
+ pcms->max_ram_below_4g);
+ }
}
}
- }
- if (machine->ram_size >= lowmem) {
- pcms->above_4g_mem_size = machine->ram_size - lowmem;
- pcms->below_4g_mem_size = lowmem;
- } else {
- pcms->above_4g_mem_size = 0;
- pcms->below_4g_mem_size = machine->ram_size;
- }
-
- if (xen_enabled()) {
- xen_hvm_init(pcms, &ram_memory);
+ if (machine->ram_size >= lowmem) {
+ pcms->above_4g_mem_size = machine->ram_size - lowmem;
+ pcms->below_4g_mem_size = lowmem;
+ } else {
+ pcms->above_4g_mem_size = 0;
+ pcms->below_4g_mem_size = machine->ram_size;
+ }
}
pc_cpus_init(pcms);
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index 04b2684..c0b9961 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -94,6 +94,9 @@ static void pc_q35_init(MachineState *machine)
/* Handle the machine opt max-ram-below-4g. It is basically doing
* min(qemu limit, user limit).
*/
+ if (!pcms->max_ram_below_4g) {
+ pcms->max_ram_below_4g = 1ULL << 32; /* default: 4G */;
+ }
if (lowmem > pcms->max_ram_below_4g) {
lowmem = pcms->max_ram_below_4g;
if (machine->ram_size - lowmem > lowmem &&
@@ -176,7 +179,6 @@ static void pc_q35_init(MachineState *machine)
qdev_init_nofail(DEVICE(q35_host));
phb = PCI_HOST_BRIDGE(q35_host);
host_bus = phb->bus;
- pcms->bus = phb->bus;
/* create ISA bus */
lpc = pci_create_simple_multifunction(host_bus, PCI_DEVFN(ICH9_LPC_DEV,
ICH9_LPC_FUNC), true,
@@ -287,6 +289,7 @@ static void pc_q35_machine_options(MachineClass *m)
m->default_machine_opts = "firmware=bios-256k.bin";
m->default_display = "std";
m->no_floppy = 1;
+ m->has_dynamic_sysbus = true;
}
static void pc_q35_2_7_machine_options(MachineClass *m)
diff --git a/hw/ide/ich.c b/hw/ide/ich.c
index 0a13334..920ec27 100644
--- a/hw/ide/ich.c
+++ b/hw/ide/ich.c
@@ -68,7 +68,6 @@
#include <hw/isa/isa.h>
#include "sysemu/block-backend.h"
#include "sysemu/dma.h"
-
#include <hw/ide/pci.h>
#include <hw/ide/ahci.h>
@@ -111,6 +110,7 @@ static void pci_ich9_ahci_realize(PCIDevice *dev, Error **errp)
int sata_cap_offset;
uint8_t *sata_cap;
d = ICH_AHCI(dev);
+ int ret;
ahci_realize(&d->ahci, DEVICE(dev), pci_get_address_space(dev), 6);
@@ -146,7 +146,10 @@ static void pci_ich9_ahci_realize(PCIDevice *dev, Error **errp)
/* Although the AHCI 1.3 specification states that the first capability
* should be PMCAP, the Intel ICH9 data sheet specifies that the ICH9
* AHCI device puts the MSI capability first, pointing to 0x80. */
- msi_init(dev, ICH9_MSI_CAP_OFFSET, 1, true, false);
+ ret = msi_init(dev, ICH9_MSI_CAP_OFFSET, 1, true, false, NULL);
+ /* Any error other than -ENOTSUP(board's MSI support is broken)
+ * is a programming error. Fall back to INTx silently on -ENOTSUP */
+ assert(!ret || ret == -ENOTSUP);
}
static void pci_ich9_uninit(PCIDevice *dev)
diff --git a/hw/net/e1000e.c b/hw/net/e1000e.c
index 4778744..b4758bc 100644
--- a/hw/net/e1000e.c
+++ b/hw/net/e1000e.c
@@ -89,8 +89,7 @@ typedef struct E1000EState {
#define E1000E_MSIX_TABLE (0x0000)
#define E1000E_MSIX_PBA (0x2000)
-#define E1000E_USE_MSI BIT(0)
-#define E1000E_USE_MSIX BIT(1)
+#define E1000E_USE_MSIX BIT(0)
static uint64_t
e1000e_mmio_read(void *opaque, hwaddr addr, unsigned size)
@@ -264,32 +263,6 @@ static void e1000e_core_realize(E1000EState *s)
}
static void
-e1000e_init_msi(E1000EState *s)
-{
- int res;
-
- res = msi_init(PCI_DEVICE(s),
- 0xD0, /* MSI capability offset */
- 1, /* MAC MSI interrupts */
- true, /* 64-bit message addresses supported */
- false); /* Per vector mask supported */
-
- if (res > 0) {
- s->intr_state |= E1000E_USE_MSI;
- } else {
- trace_e1000e_msi_init_fail(res);
- }
-}
-
-static void
-e1000e_cleanup_msi(E1000EState *s)
-{
- if (s->intr_state & E1000E_USE_MSI) {
- msi_uninit(PCI_DEVICE(s));
- }
-}
-
-static void
e1000e_unuse_msix_vectors(E1000EState *s, int num_vectors)
{
int i;
@@ -444,6 +417,7 @@ static void e1000e_pci_realize(PCIDevice *pci_dev, Error **errp)
static const uint16_t e1000e_dsn_offset = 0x140;
E1000EState *s = E1000E(pci_dev);
uint8_t *macaddr;
+ int ret;
trace_e1000e_cb_pci_realize();
@@ -493,7 +467,10 @@ static void e1000e_pci_realize(PCIDevice *pci_dev, Error **errp)
hw_error("Failed to initialize PCIe capability");
}
- e1000e_init_msi(s);
+ ret = msi_init(PCI_DEVICE(s), 0xD0, 1, true, false, NULL);
+ if (ret) {
+ trace_e1000e_msi_init_fail(ret);
+ }
if (e1000e_add_pm_capability(pci_dev, e1000e_pmrb_offset,
PCI_PM_CAP_DSI) < 0) {
@@ -532,7 +509,7 @@ static void e1000e_pci_uninit(PCIDevice *pci_dev)
qemu_del_nic(s->nic);
e1000e_cleanup_msix(s);
- e1000e_cleanup_msi(s);
+ msi_uninit(pci_dev);
}
static void e1000e_qdev_reset(DeviceState *dev)
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 7e6a60a..9999899 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -1542,33 +1542,11 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id)
{
VirtIONet *n = opaque;
VirtIODevice *vdev = VIRTIO_DEVICE(n);
- int ret;
if (version_id < 2 || version_id > VIRTIO_NET_VM_VERSION)
return -EINVAL;
- ret = virtio_load(vdev, f, version_id);
- if (ret) {
- return ret;
- }
-
- if (virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)) {
- n->curr_guest_offloads = qemu_get_be64(f);
- } else {
- n->curr_guest_offloads = virtio_net_supported_guest_offloads(n);
- }
-
- if (peer_has_vnet_hdr(n)) {
- virtio_net_apply_guest_offloads(n);
- }
-
- if (virtio_vdev_has_feature(vdev, VIRTIO_NET_F_GUEST_ANNOUNCE) &&
- virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ)) {
- n->announce_counter = SELF_ANNOUNCE_ROUNDS;
- timer_mod(n->announce_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL));
- }
-
- return 0;
+ return virtio_load(vdev, f, version_id);
}
static int virtio_net_load_device(VirtIODevice *vdev, QEMUFile *f,
@@ -1665,6 +1643,16 @@ static int virtio_net_load_device(VirtIODevice *vdev, QEMUFile *f,
}
}
+ if (virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)) {
+ n->curr_guest_offloads = qemu_get_be64(f);
+ } else {
+ n->curr_guest_offloads = virtio_net_supported_guest_offloads(n);
+ }
+
+ if (peer_has_vnet_hdr(n)) {
+ virtio_net_apply_guest_offloads(n);
+ }
+
virtio_net_set_queues(n);
/* Find the first multicast entry in the saved MAC filter */
@@ -1682,6 +1670,12 @@ static int virtio_net_load_device(VirtIODevice *vdev, QEMUFile *f,
qemu_get_subqueue(n->nic, i)->link_down = link_down;
}
+ if (virtio_vdev_has_feature(vdev, VIRTIO_NET_F_GUEST_ANNOUNCE) &&
+ virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ)) {
+ n->announce_counter = SELF_ANNOUNCE_ROUNDS;
+ timer_mod(n->announce_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL));
+ }
+
return 0;
}
diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c
index b8e3b25..e767fc6 100644
--- a/hw/net/vmxnet3.c
+++ b/hw/net/vmxnet3.c
@@ -283,8 +283,6 @@ typedef struct {
/* Whether MSI-X support was installed successfully */
bool msix_used;
- /* Whether MSI support was installed successfully */
- bool msi_used;
hwaddr drv_shmem;
hwaddr temp_shared_guest_driver_memory;
@@ -366,7 +364,7 @@ static bool _vmxnet3_assert_interrupt_line(VMXNET3State *s, uint32_t int_idx)
msix_notify(d, int_idx);
return false;
}
- if (s->msi_used && msi_enabled(d)) {
+ if (msi_enabled(d)) {
VMW_IRPRN("Sending MSI notification for vector %u", int_idx);
msi_notify(d, int_idx);
return false;
@@ -390,7 +388,7 @@ static void _vmxnet3_deassert_interrupt_line(VMXNET3State *s, int lidx)
* This function should never be called for MSI(X) interrupts
* because deassertion never required for message interrupts
*/
- assert(!s->msi_used || !msi_enabled(d));
+ assert(!msi_enabled(d));
VMW_IRPRN("Deasserting line for interrupt %u", lidx);
pci_irq_deassert(d);
@@ -427,7 +425,7 @@ static void vmxnet3_trigger_interrupt(VMXNET3State *s, int lidx)
goto do_automask;
}
- if (s->msi_used && msi_enabled(d) && s->auto_int_masking) {
+ if (msi_enabled(d) && s->auto_int_masking) {
goto do_automask;
}
@@ -1425,8 +1423,8 @@ static void vmxnet3_update_features(VMXNET3State *s)
static bool vmxnet3_verify_intx(VMXNET3State *s, int intx)
{
- return s->msix_used || s->msi_used || (intx ==
- (pci_get_byte(s->parent_obj.config + PCI_INTERRUPT_PIN) - 1));
+ return s->msix_used || msi_enabled(PCI_DEVICE(s))
+ || intx == pci_get_byte(s->parent_obj.config + PCI_INTERRUPT_PIN) - 1;
}
static void vmxnet3_validate_interrupt_idx(bool is_msix, int idx)
@@ -2216,35 +2214,12 @@ vmxnet3_cleanup_msix(VMXNET3State *s)
}
}
-#define VMXNET3_USE_64BIT (true)
-#define VMXNET3_PER_VECTOR_MASK (false)
-
-static bool
-vmxnet3_init_msi(VMXNET3State *s)
-{
- PCIDevice *d = PCI_DEVICE(s);
- int res;
-
- res = msi_init(d, VMXNET3_MSI_OFFSET(s), VMXNET3_MAX_NMSIX_INTRS,
- VMXNET3_USE_64BIT, VMXNET3_PER_VECTOR_MASK);
- if (0 > res) {
- VMW_WRPRN("Failed to initialize MSI, error %d", res);
- s->msi_used = false;
- } else {
- s->msi_used = true;
- }
-
- return s->msi_used;
-}
-
static void
vmxnet3_cleanup_msi(VMXNET3State *s)
{
PCIDevice *d = PCI_DEVICE(s);
- if (s->msi_used) {
- msi_uninit(d);
- }
+ msi_uninit(d);
}
static void
@@ -2298,10 +2273,15 @@ static uint64_t vmxnet3_device_serial_num(VMXNET3State *s)
return dsn_payload;
}
+
+#define VMXNET3_USE_64BIT (true)
+#define VMXNET3_PER_VECTOR_MASK (false)
+
static void vmxnet3_pci_realize(PCIDevice *pci_dev, Error **errp)
{
DeviceState *dev = DEVICE(pci_dev);
VMXNET3State *s = VMXNET3(pci_dev);
+ int ret;
VMW_CBPRN("Starting init...");
@@ -2325,14 +2305,16 @@ static void vmxnet3_pci_realize(PCIDevice *pci_dev, Error **errp)
/* Interrupt pin A */
pci_dev->config[PCI_INTERRUPT_PIN] = 0x01;
+ ret = msi_init(pci_dev, VMXNET3_MSI_OFFSET(s), VMXNET3_MAX_NMSIX_INTRS,
+ VMXNET3_USE_64BIT, VMXNET3_PER_VECTOR_MASK, NULL);
+ /* Any error other than -ENOTSUP(board's MSI support is broken)
+ * is a programming error. Fall back to INTx silently on -ENOTSUP */
+ assert(!ret || ret == -ENOTSUP);
+
if (!vmxnet3_init_msix(s)) {
VMW_WRPRN("Failed to initialize MSI-X, configuration is inconsistent.");
}
- if (!vmxnet3_init_msi(s)) {
- VMW_WRPRN("Failed to initialize MSI, configuration is inconsistent.");
- }
-
vmxnet3_net_init(s);
if (pci_is_express(pci_dev)) {
diff --git a/hw/pci-bridge/ioh3420.c b/hw/pci-bridge/ioh3420.c
index b4a7806..93c6f0b 100644
--- a/hw/pci-bridge/ioh3420.c
+++ b/hw/pci-bridge/ioh3420.c
@@ -25,6 +25,7 @@
#include "hw/pci/msi.h"
#include "hw/pci/pcie.h"
#include "ioh3420.h"
+#include "qapi/error.h"
#define PCI_DEVICE_ID_IOH_EPORT 0x3420 /* D0:F0 express mode */
#define PCI_DEVICE_ID_IOH_REV 0x2
@@ -97,6 +98,7 @@ static int ioh3420_initfn(PCIDevice *d)
PCIEPort *p = PCIE_PORT(d);
PCIESlot *s = PCIE_SLOT(d);
int rc;
+ Error *err = NULL;
pci_bridge_initfn(d, TYPE_PCIE_BUS);
pcie_port_init_reg(d);
@@ -109,8 +111,10 @@ static int ioh3420_initfn(PCIDevice *d)
rc = msi_init(d, IOH_EP_MSI_OFFSET, IOH_EP_MSI_NR_VECTOR,
IOH_EP_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT,
- IOH_EP_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT);
+ IOH_EP_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT, &err);
if (rc < 0) {
+ assert(rc == -ENOTSUP);
+ error_report_err(err);
goto err_bridge;
}
diff --git a/hw/pci-bridge/pci_bridge_dev.c b/hw/pci-bridge/pci_bridge_dev.c
index 41ca47b..5dbd933 100644
--- a/hw/pci-bridge/pci_bridge_dev.c
+++ b/hw/pci-bridge/pci_bridge_dev.c
@@ -42,9 +42,10 @@ struct PCIBridgeDev {
MemoryRegion bar;
uint8_t chassis_nr;
-#define PCI_BRIDGE_DEV_F_MSI_REQ 0
-#define PCI_BRIDGE_DEV_F_SHPC_REQ 1
+#define PCI_BRIDGE_DEV_F_SHPC_REQ 0
uint32_t flags;
+
+ OnOffAuto msi;
};
typedef struct PCIBridgeDev PCIBridgeDev;
@@ -53,6 +54,7 @@ static int pci_bridge_dev_initfn(PCIDevice *dev)
PCIBridge *br = PCI_BRIDGE(dev);
PCIBridgeDev *bridge_dev = PCI_BRIDGE_DEV(dev);
int err;
+ Error *local_err = NULL;
pci_bridge_initfn(dev, TYPE_PCI_BUS);
@@ -66,7 +68,7 @@ static int pci_bridge_dev_initfn(PCIDevice *dev)
}
} else {
/* MSI is not applicable without SHPC */
- bridge_dev->flags &= ~(1 << PCI_BRIDGE_DEV_F_MSI_REQ);
+ bridge_dev->msi = ON_OFF_AUTO_OFF;
}
err = slotid_cap_init(dev, 0, bridge_dev->chassis_nr, 0);
@@ -74,12 +76,23 @@ static int pci_bridge_dev_initfn(PCIDevice *dev)
goto slotid_error;
}
- if ((bridge_dev->flags & (1 << PCI_BRIDGE_DEV_F_MSI_REQ)) &&
- msi_nonbroken) {
- err = msi_init(dev, 0, 1, true, true);
- if (err < 0) {
+ if (bridge_dev->msi != ON_OFF_AUTO_OFF) {
+ /* it means SHPC exists, because MSI is needed by SHPC */
+
+ err = msi_init(dev, 0, 1, true, true, &local_err);
+ /* Any error other than -ENOTSUP(board's MSI support is broken)
+ * is a programming error */
+ assert(!err || err == -ENOTSUP);
+ if (err && bridge_dev->msi == ON_OFF_AUTO_ON) {
+ /* Can't satisfy user's explicit msi=on request, fail */
+ error_append_hint(&local_err, "You have to use msi=auto (default) "
+ "or msi=off with this machine type.\n");
+ error_report_err(local_err);
goto msi_error;
}
+ assert(!local_err || bridge_dev->msi == ON_OFF_AUTO_AUTO);
+ /* With msi=auto, we fall back to MSI off silently */
+ error_free(local_err);
}
if (shpc_present(dev)) {
@@ -147,8 +160,8 @@ static Property pci_bridge_dev_properties[] = {
/* Note: 0 is not a legal chassis number. */
DEFINE_PROP_UINT8(PCI_BRIDGE_DEV_PROP_CHASSIS_NR, PCIBridgeDev, chassis_nr,
0),
- DEFINE_PROP_BIT(PCI_BRIDGE_DEV_PROP_MSI, PCIBridgeDev, flags,
- PCI_BRIDGE_DEV_F_MSI_REQ, true),
+ DEFINE_PROP_ON_OFF_AUTO(PCI_BRIDGE_DEV_PROP_MSI, PCIBridgeDev, msi,
+ ON_OFF_AUTO_AUTO),
DEFINE_PROP_BIT(PCI_BRIDGE_DEV_PROP_SHPC, PCIBridgeDev, flags,
PCI_BRIDGE_DEV_F_SHPC_REQ, true),
DEFINE_PROP_END_OF_LIST(),
diff --git a/hw/pci-bridge/pci_expander_bridge.c b/hw/pci-bridge/pci_expander_bridge.c
index ba320bd..ab86121 100644
--- a/hw/pci-bridge/pci_expander_bridge.c
+++ b/hw/pci-bridge/pci_expander_bridge.c
@@ -149,6 +149,8 @@ static void pxb_host_class_init(ObjectClass *class, void *data)
PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(class);
dc->fw_name = "pci";
+ /* Reason: Internal part of the pxb/pxb-pcie device, not usable by itself */
+ dc->cannot_instantiate_with_device_add_yet = true;
sbc->explicit_ofw_unit_address = pxb_host_ofw_unit_address;
hc->root_bus_path = pxb_host_root_bus_path;
}
diff --git a/hw/pci-bridge/xio3130_downstream.c b/hw/pci-bridge/xio3130_downstream.c
index e6d653d..f6149a3 100644
--- a/hw/pci-bridge/xio3130_downstream.c
+++ b/hw/pci-bridge/xio3130_downstream.c
@@ -24,6 +24,7 @@
#include "hw/pci/msi.h"
#include "hw/pci/pcie.h"
#include "xio3130_downstream.h"
+#include "qapi/error.h"
#define PCI_DEVICE_ID_TI_XIO3130D 0x8233 /* downstream port */
#define XIO3130_REVISION 0x1
@@ -60,14 +61,17 @@ static int xio3130_downstream_initfn(PCIDevice *d)
PCIEPort *p = PCIE_PORT(d);
PCIESlot *s = PCIE_SLOT(d);
int rc;
+ Error *err = NULL;
pci_bridge_initfn(d, TYPE_PCIE_BUS);
pcie_port_init_reg(d);
rc = msi_init(d, XIO3130_MSI_OFFSET, XIO3130_MSI_NR_VECTOR,
XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT,
- XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT);
+ XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT, &err);
if (rc < 0) {
+ assert(rc == -ENOTSUP);
+ error_report_err(err);
goto err_bridge;
}
diff --git a/hw/pci-bridge/xio3130_upstream.c b/hw/pci-bridge/xio3130_upstream.c
index d976844..487edac 100644
--- a/hw/pci-bridge/xio3130_upstream.c
+++ b/hw/pci-bridge/xio3130_upstream.c
@@ -24,6 +24,7 @@
#include "hw/pci/msi.h"
#include "hw/pci/pcie.h"
#include "xio3130_upstream.h"
+#include "qapi/error.h"
#define PCI_DEVICE_ID_TI_XIO3130U 0x8232 /* upstream port */
#define XIO3130_REVISION 0x2
@@ -56,14 +57,17 @@ static int xio3130_upstream_initfn(PCIDevice *d)
{
PCIEPort *p = PCIE_PORT(d);
int rc;
+ Error *err = NULL;
pci_bridge_initfn(d, TYPE_PCIE_BUS);
pcie_port_init_reg(d);
rc = msi_init(d, XIO3130_MSI_OFFSET, XIO3130_MSI_NR_VECTOR,
XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT,
- XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT);
+ XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT, &err);
if (rc < 0) {
+ assert(rc == -ENOTSUP);
+ error_report_err(err);
goto err_bridge;
}
diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c
index df2b0e2..f9218aa 100644
--- a/hw/pci-host/piix.c
+++ b/hw/pci-host/piix.c
@@ -48,7 +48,7 @@
typedef struct I440FXState {
PCIHostState parent_obj;
- PcPciInfo pci_info;
+ Range pci_hole;
uint64_t pci_hole64_size;
uint32_t short_root_bus;
} I440FXState;
@@ -221,8 +221,12 @@ static void i440fx_pcihost_get_pci_hole_start(Object *obj, Visitor *v,
Error **errp)
{
I440FXState *s = I440FX_PCI_HOST_BRIDGE(obj);
- uint32_t value = s->pci_info.w32.begin;
+ uint64_t val64;
+ uint32_t value;
+ val64 = range_is_empty(&s->pci_hole) ? 0 : range_lob(&s->pci_hole);
+ value = val64;
+ assert(value == val64);
visit_type_uint32(v, name, &value, errp);
}
@@ -231,8 +235,12 @@ static void i440fx_pcihost_get_pci_hole_end(Object *obj, Visitor *v,
Error **errp)
{
I440FXState *s = I440FX_PCI_HOST_BRIDGE(obj);
- uint32_t value = s->pci_info.w32.end;
+ uint64_t val64;
+ uint32_t value;
+ val64 = range_is_empty(&s->pci_hole) ? 0 : range_upb(&s->pci_hole) + 1;
+ value = val64;
+ assert(value == val64);
visit_type_uint32(v, name, &value, errp);
}
@@ -242,10 +250,11 @@ static void i440fx_pcihost_get_pci_hole64_start(Object *obj, Visitor *v,
{
PCIHostState *h = PCI_HOST_BRIDGE(obj);
Range w64;
+ uint64_t value;
pci_bus_get_w64_range(h->bus, &w64);
-
- visit_type_uint64(v, name, &w64.begin, errp);
+ value = range_is_empty(&w64) ? 0 : range_lob(&w64);
+ visit_type_uint64(v, name, &value, errp);
}
static void i440fx_pcihost_get_pci_hole64_end(Object *obj, Visitor *v,
@@ -254,16 +263,16 @@ static void i440fx_pcihost_get_pci_hole64_end(Object *obj, Visitor *v,
{
PCIHostState *h = PCI_HOST_BRIDGE(obj);
Range w64;
+ uint64_t value;
pci_bus_get_w64_range(h->bus, &w64);
-
- visit_type_uint64(v, name, &w64.end, errp);
+ value = range_is_empty(&w64) ? 0 : range_upb(&w64) + 1;
+ visit_type_uint64(v, name, &value, errp);
}
static void i440fx_pcihost_initfn(Object *obj)
{
PCIHostState *s = PCI_HOST_BRIDGE(obj);
- I440FXState *d = I440FX_PCI_HOST_BRIDGE(obj);
memory_region_init_io(&s->conf_mem, obj, &pci_host_conf_le_ops, s,
"pci-conf-idx", 4);
@@ -285,8 +294,6 @@ static void i440fx_pcihost_initfn(Object *obj)
object_property_add(obj, PCI_HOST_PROP_PCI_HOLE64_END, "int",
i440fx_pcihost_get_pci_hole64_end,
NULL, NULL, NULL, NULL);
-
- d->pci_info.w32.end = IO_APIC_DEFAULT_ADDRESS;
}
static void i440fx_pcihost_realize(DeviceState *dev, Error **errp)
@@ -347,7 +354,8 @@ PCIBus *i440fx_init(const char *host_type, const char *pci_type,
f->ram_memory = ram_memory;
i440fx = I440FX_PCI_HOST_BRIDGE(dev);
- i440fx->pci_info.w32.begin = below_4g_mem_size;
+ range_set_bounds(&i440fx->pci_hole, below_4g_mem_size,
+ IO_APIC_DEFAULT_ADDRESS - 1);
/* setup pci memory mapping */
pc_pci_as_mapping_init(OBJECT(f), f->system_memory,
@@ -865,6 +873,8 @@ static void i440fx_pcihost_class_init(ObjectClass *klass, void *data)
dc->realize = i440fx_pcihost_realize;
dc->fw_name = "pci";
dc->props = i440fx_props;
+ /* Reason: needs to be wired up by pc_init1 */
+ dc->cannot_instantiate_with_device_add_yet = true;
}
static const TypeInfo i440fx_pcihost_info = {
diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c
index 03be05d..344f77b 100644
--- a/hw/pci-host/q35.c
+++ b/hw/pci-host/q35.c
@@ -52,6 +52,7 @@ static void q35_host_realize(DeviceState *dev, Error **errp)
pci->bus = pci_bus_new(DEVICE(s), "pcie.0",
s->mch.pci_address_space, s->mch.address_space_io,
0, TYPE_PCIE_BUS);
+ PC_MACHINE(qdev_get_machine())->bus = pci->bus;
qdev_set_parent_bus(DEVICE(&s->mch), BUS(pci->bus));
qdev_init_nofail(DEVICE(&s->mch));
}
@@ -73,8 +74,13 @@ static void q35_host_get_pci_hole_start(Object *obj, Visitor *v,
Error **errp)
{
Q35PCIHost *s = Q35_HOST_DEVICE(obj);
- uint32_t value = s->mch.pci_info.w32.begin;
+ uint64_t val64;
+ uint32_t value;
+ val64 = range_is_empty(&s->mch.pci_hole)
+ ? 0 : range_lob(&s->mch.pci_hole);
+ value = val64;
+ assert(value == val64);
visit_type_uint32(v, name, &value, errp);
}
@@ -83,8 +89,13 @@ static void q35_host_get_pci_hole_end(Object *obj, Visitor *v,
Error **errp)
{
Q35PCIHost *s = Q35_HOST_DEVICE(obj);
- uint32_t value = s->mch.pci_info.w32.end;
+ uint64_t val64;
+ uint32_t value;
+ val64 = range_is_empty(&s->mch.pci_hole)
+ ? 0 : range_upb(&s->mch.pci_hole) + 1;
+ value = val64;
+ assert(value == val64);
visit_type_uint32(v, name, &value, errp);
}
@@ -94,10 +105,11 @@ static void q35_host_get_pci_hole64_start(Object *obj, Visitor *v,
{
PCIHostState *h = PCI_HOST_BRIDGE(obj);
Range w64;
+ uint64_t value;
pci_bus_get_w64_range(h->bus, &w64);
-
- visit_type_uint64(v, name, &w64.begin, errp);
+ value = range_is_empty(&w64) ? 0 : range_lob(&w64);
+ visit_type_uint64(v, name, &value, errp);
}
static void q35_host_get_pci_hole64_end(Object *obj, Visitor *v,
@@ -106,10 +118,11 @@ static void q35_host_get_pci_hole64_end(Object *obj, Visitor *v,
{
PCIHostState *h = PCI_HOST_BRIDGE(obj);
Range w64;
+ uint64_t value;
pci_bus_get_w64_range(h->bus, &w64);
-
- visit_type_uint64(v, name, &w64.end, errp);
+ value = range_is_empty(&w64) ? 0 : range_upb(&w64) + 1;
+ visit_type_uint64(v, name, &value, errp);
}
static void q35_host_get_mmcfg_size(Object *obj, Visitor *v, const char *name,
@@ -142,6 +155,8 @@ static void q35_host_class_init(ObjectClass *klass, void *data)
hc->root_bus_path = q35_host_root_bus_path;
dc->realize = q35_host_realize;
dc->props = mch_props;
+ /* Reason: needs to be wired up by pc_q35_init */
+ dc->cannot_instantiate_with_device_add_yet = true;
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
dc->fw_name = "pci";
}
@@ -202,9 +217,9 @@ static void q35_host_initfn(Object *obj)
* it's not a power of two, which means an MTRR
* can't cover it exactly.
*/
- s->mch.pci_info.w32.begin = MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT +
- MCH_HOST_BRIDGE_PCIEXBAR_MAX;
- s->mch.pci_info.w32.end = IO_APIC_DEFAULT_ADDRESS;
+ range_set_bounds(&s->mch.pci_hole,
+ MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT + MCH_HOST_BRIDGE_PCIEXBAR_MAX,
+ IO_APIC_DEFAULT_ADDRESS - 1);
}
static const TypeInfo q35_host_info = {
@@ -272,10 +287,7 @@ static void mch_update_pciexbar(MCHPCIState *mch)
break;
case MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_RVD:
default:
- enable = 0;
- length = 0;
abort();
- break;
}
addr = pciexbar & addr_mask;
pcie_host_mmcfg_update(pehb, enable, addr, length);
@@ -285,9 +297,13 @@ static void mch_update_pciexbar(MCHPCIState *mch)
* which means an MTRR can't cover it exactly.
*/
if (enable) {
- mch->pci_info.w32.begin = addr + length;
+ range_set_bounds(&mch->pci_hole,
+ addr + length,
+ IO_APIC_DEFAULT_ADDRESS - 1);
} else {
- mch->pci_info.w32.begin = MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT;
+ range_set_bounds(&mch->pci_hole,
+ MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT,
+ IO_APIC_DEFAULT_ADDRESS - 1);
}
}
@@ -444,30 +460,6 @@ static void mch_reset(DeviceState *qdev)
mch_update(mch);
}
-static AddressSpace *q35_host_dma_iommu(PCIBus *bus, void *opaque, int devfn)
-{
- IntelIOMMUState *s = opaque;
- VTDAddressSpace *vtd_as;
-
- assert(0 <= devfn && devfn <= VTD_PCI_DEVFN_MAX);
-
- vtd_as = vtd_find_add_as(s, bus, devfn);
- return &vtd_as->as;
-}
-
-static void mch_init_dmar(MCHPCIState *mch)
-{
- PCIBus *pci_bus = PCI_BUS(qdev_get_parent_bus(DEVICE(mch)));
-
- mch->iommu = INTEL_IOMMU_DEVICE(qdev_create(NULL, TYPE_INTEL_IOMMU_DEVICE));
- object_property_add_child(OBJECT(mch), "intel-iommu",
- OBJECT(mch->iommu), NULL);
- qdev_init_nofail(DEVICE(mch->iommu));
- sysbus_mmio_map(SYS_BUS_DEVICE(mch->iommu), 0, Q35_HOST_BRIDGE_IOMMU_ADDR);
-
- pci_setup_iommu(pci_bus, q35_host_dma_iommu, mch->iommu);
-}
-
static void mch_realize(PCIDevice *d, Error **errp)
{
int i;
@@ -526,10 +518,6 @@ static void mch_realize(PCIDevice *d, Error **errp)
mch->pci_address_space, &mch->pam_regions[i+1],
PAM_EXPAN_BASE + i * PAM_EXPAN_SIZE, PAM_EXPAN_SIZE);
}
- /* Intel IOMMU (VT-d) */
- if (object_property_get_bool(qdev_get_machine(), "iommu", NULL)) {
- mch_init_dmar(mch);
- }
}
uint64_t mch_mcfg_base(void)
diff --git a/hw/pci/msi.c b/hw/pci/msi.c
index ed79225..a87b227 100644
--- a/hw/pci/msi.c
+++ b/hw/pci/msi.c
@@ -22,6 +22,7 @@
#include "hw/pci/msi.h"
#include "hw/xen/xen.h"
#include "qemu/range.h"
+#include "qapi/error.h"
/* PCI_MSI_ADDRESS_LO */
#define PCI_MSI_ADDRESS_LO_MASK (~0x3)
@@ -173,7 +174,8 @@ bool msi_enabled(const PCIDevice *dev)
* If @msi64bit, make the device capable of sending a 64-bit message
* address.
* If @msi_per_vector_mask, make the device support per-vector masking.
- * Return 0 on success, return -errno on error.
+ * @errp is for returning errors.
+ * Return 0 on success; set @errp and return -errno on error.
*
* -ENOTSUP means lacking msi support for a msi-capable platform.
* -EINVAL means capability overlap, happens when @offset is non-zero,
@@ -181,7 +183,8 @@ bool msi_enabled(const PCIDevice *dev)
* if a real HW is broken.
*/
int msi_init(struct PCIDevice *dev, uint8_t offset,
- unsigned int nr_vectors, bool msi64bit, bool msi_per_vector_mask)
+ unsigned int nr_vectors, bool msi64bit,
+ bool msi_per_vector_mask, Error **errp)
{
unsigned int vectors_order;
uint16_t flags;
@@ -189,6 +192,7 @@ int msi_init(struct PCIDevice *dev, uint8_t offset,
int config_offset;
if (!msi_nonbroken) {
+ error_setg(errp, "MSI is not supported by interrupt controller");
return -ENOTSUP;
}
@@ -212,7 +216,8 @@ int msi_init(struct PCIDevice *dev, uint8_t offset,
}
cap_size = msi_cap_sizeof(flags);
- config_offset = pci_add_capability(dev, PCI_CAP_ID_MSI, offset, cap_size);
+ config_offset = pci_add_capability2(dev, PCI_CAP_ID_MSI, offset,
+ cap_size, errp);
if (config_offset < 0) {
return config_offset;
}
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index 4b585f4..149994b 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -78,10 +78,37 @@ static const VMStateDescription vmstate_pcibus = {
}
};
+static void pci_init_bus_master(PCIDevice *pci_dev)
+{
+ AddressSpace *dma_as = pci_device_iommu_address_space(pci_dev);
+
+ memory_region_init_alias(&pci_dev->bus_master_enable_region,
+ OBJECT(pci_dev), "bus master",
+ dma_as->root, 0, memory_region_size(dma_as->root));
+ memory_region_set_enabled(&pci_dev->bus_master_enable_region, false);
+ address_space_init(&pci_dev->bus_master_as,
+ &pci_dev->bus_master_enable_region, pci_dev->name);
+}
+
+static void pcibus_machine_done(Notifier *notifier, void *data)
+{
+ PCIBus *bus = container_of(notifier, PCIBus, machine_done);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(bus->devices); ++i) {
+ if (bus->devices[i]) {
+ pci_init_bus_master(bus->devices[i]);
+ }
+ }
+}
+
static void pci_bus_realize(BusState *qbus, Error **errp)
{
PCIBus *bus = PCI_BUS(qbus);
+ bus->machine_done.notify = pcibus_machine_done;
+ qemu_add_machine_init_done_notifier(&bus->machine_done);
+
vmstate_register(NULL, -1, &vmstate_pcibus, bus);
}
@@ -89,6 +116,8 @@ static void pci_bus_unrealize(BusState *qbus, Error **errp)
{
PCIBus *bus = PCI_BUS(qbus);
+ qemu_remove_machine_init_done_notifier(&bus->machine_done);
+
vmstate_unregister(NULL, &vmstate_pcibus, bus);
}
@@ -920,7 +949,6 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus,
PCIConfigReadFunc *config_read = pc->config_read;
PCIConfigWriteFunc *config_write = pc->config_write;
Error *local_err = NULL;
- AddressSpace *dma_as;
DeviceState *dev = DEVICE(pci_dev);
pci_dev->bus = bus;
@@ -961,15 +989,10 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus,
pci_dev->devfn = devfn;
pci_dev->requester_id_cache = pci_req_id_cache_get(pci_dev);
- dma_as = pci_device_iommu_address_space(pci_dev);
-
- memory_region_init_alias(&pci_dev->bus_master_enable_region,
- OBJECT(pci_dev), "bus master",
- dma_as->root, 0, memory_region_size(dma_as->root));
- memory_region_set_enabled(&pci_dev->bus_master_enable_region, false);
- address_space_init(&pci_dev->bus_master_as, &pci_dev->bus_master_enable_region,
- name);
+ if (qdev_hotplug) {
+ pci_init_bus_master(pci_dev);
+ }
pstrcpy(pci_dev->name, sizeof(pci_dev->name), name);
pci_dev->irq_state = 0;
pci_config_alloc(pci_dev);
@@ -1051,7 +1074,7 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num,
uint8_t type, MemoryRegion *memory)
{
PCIIORegion *r;
- uint32_t addr;
+ uint32_t addr; /* offset in pci config space */
uint64_t wmask;
pcibus_t size = memory_region_size(memory);
@@ -1067,15 +1090,20 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num,
r->addr = PCI_BAR_UNMAPPED;
r->size = size;
r->type = type;
- r->memory = NULL;
+ r->memory = memory;
+ r->address_space = type & PCI_BASE_ADDRESS_SPACE_IO
+ ? pci_dev->bus->address_space_io
+ : pci_dev->bus->address_space_mem;
wmask = ~(size - 1);
- addr = pci_bar(pci_dev, region_num);
if (region_num == PCI_ROM_SLOT) {
/* ROM enable bit is writable */
wmask |= PCI_ROM_ADDRESS_ENABLE;
}
+
+ addr = pci_bar(pci_dev, region_num);
pci_set_long(pci_dev->config + addr, type);
+
if (!(r->type & PCI_BASE_ADDRESS_SPACE_IO) &&
r->type & PCI_BASE_ADDRESS_MEM_TYPE_64) {
pci_set_quad(pci_dev->wmask + addr, wmask);
@@ -1084,11 +1112,6 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num,
pci_set_long(pci_dev->wmask + addr, wmask & 0xffffffff);
pci_set_long(pci_dev->cmask + addr, 0xffffffff);
}
- pci_dev->io_regions[region_num].memory = memory;
- pci_dev->io_regions[region_num].address_space
- = type & PCI_BASE_ADDRESS_SPACE_IO
- ? pci_dev->bus->address_space_io
- : pci_dev->bus->address_space_mem;
}
static void pci_update_vga(PCIDevice *pci_dev)
@@ -2510,13 +2533,13 @@ static void pci_dev_get_w64(PCIBus *b, PCIDevice *dev, void *opaque)
if (limit >= base) {
Range pref_range;
- pref_range.begin = base;
- pref_range.end = limit + 1;
+ range_set_bounds(&pref_range, base, limit);
range_extend(range, &pref_range);
}
}
for (i = 0; i < PCI_NUM_REGIONS; ++i) {
PCIIORegion *r = &dev->io_regions[i];
+ pcibus_t lob, upb;
Range region_range;
if (!r->size ||
@@ -2524,16 +2547,17 @@ static void pci_dev_get_w64(PCIBus *b, PCIDevice *dev, void *opaque)
!(r->type & PCI_BASE_ADDRESS_MEM_TYPE_64)) {
continue;
}
- region_range.begin = pci_bar_address(dev, i, r->type, r->size);
- region_range.end = region_range.begin + r->size;
- if (region_range.begin == PCI_BAR_UNMAPPED) {
+ lob = pci_bar_address(dev, i, r->type, r->size);
+ upb = lob + r->size - 1;
+ if (lob == PCI_BAR_UNMAPPED) {
continue;
}
- region_range.begin = MAX(region_range.begin, 0x1ULL << 32);
+ lob = MAX(lob, 0x1ULL << 32);
- if (region_range.end - 1 >= region_range.begin) {
+ if (upb >= lob) {
+ range_set_bounds(&region_range, lob, upb);
range_extend(range, &region_range);
}
}
@@ -2541,7 +2565,7 @@ static void pci_dev_get_w64(PCIBus *b, PCIDevice *dev, void *opaque)
void pci_bus_get_w64_range(PCIBus *bus, Range *range)
{
- range->begin = range->end = 0;
+ range_make_empty(range);
pci_for_each_device_under_bus(bus, pci_dev_get_w64, range);
}
diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c
index 32e88b3..7d25106 100644
--- a/hw/ppc/mac_newworld.c
+++ b/hw/ppc/mac_newworld.c
@@ -380,6 +380,7 @@ static void ppc_core99_init(MachineState *machine)
pci_bus = pci_pmac_init(pic, get_system_memory(), get_system_io());
machine_arch = ARCH_MAC99;
}
+ object_property_set_bool(OBJECT(pci_bus), true, "realized", &error_abort);
machine->usb |= defaults_enabled() && !machine->usb_disabled;
diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c
index d177218..52a4123 100644
--- a/hw/scsi/megasas.c
+++ b/hw/scsi/megasas.c
@@ -29,7 +29,7 @@
#include "hw/scsi/scsi.h"
#include "block/scsi.h"
#include "trace.h"
-
+#include "qapi/error.h"
#include "mfi.h"
#define MEGASAS_VERSION_GEN1 "1.70"
@@ -48,11 +48,7 @@
#define MEGASAS_FLAG_USE_JBOD 0
#define MEGASAS_MASK_USE_JBOD (1 << MEGASAS_FLAG_USE_JBOD)
-#define MEGASAS_FLAG_USE_MSI 1
-#define MEGASAS_MASK_USE_MSI (1 << MEGASAS_FLAG_USE_MSI)
-#define MEGASAS_FLAG_USE_MSIX 2
-#define MEGASAS_MASK_USE_MSIX (1 << MEGASAS_FLAG_USE_MSIX)
-#define MEGASAS_FLAG_USE_QUEUE64 3
+#define MEGASAS_FLAG_USE_QUEUE64 1
#define MEGASAS_MASK_USE_QUEUE64 (1 << MEGASAS_FLAG_USE_QUEUE64)
static const char *mfi_frame_desc[] = {
@@ -96,6 +92,8 @@ typedef struct MegasasState {
int busy;
int diag;
int adp_reset;
+ OnOffAuto msi;
+ OnOffAuto msix;
MegasasCmd *event_cmd;
int event_locale;
@@ -157,14 +155,9 @@ static bool megasas_use_queue64(MegasasState *s)
return s->flags & MEGASAS_MASK_USE_QUEUE64;
}
-static bool megasas_use_msi(MegasasState *s)
-{
- return s->flags & MEGASAS_MASK_USE_MSI;
-}
-
static bool megasas_use_msix(MegasasState *s)
{
- return s->flags & MEGASAS_MASK_USE_MSIX;
+ return s->msix != ON_OFF_AUTO_OFF;
}
static bool megasas_is_jbod(MegasasState *s)
@@ -2309,9 +2302,7 @@ static void megasas_scsi_uninit(PCIDevice *d)
if (megasas_use_msix(s)) {
msix_uninit(d, &s->mmio_io, &s->mmio_io);
}
- if (megasas_use_msi(s)) {
- msi_uninit(d);
- }
+ msi_uninit(d);
}
static const struct SCSIBusInfo megasas_scsi_info = {
@@ -2332,6 +2323,8 @@ static void megasas_scsi_realize(PCIDevice *dev, Error **errp)
MegasasBaseClass *b = MEGASAS_DEVICE_GET_CLASS(s);
uint8_t *pci_conf;
int i, bar_type;
+ Error *err = NULL;
+ int ret;
pci_conf = dev->config;
@@ -2340,6 +2333,24 @@ static void megasas_scsi_realize(PCIDevice *dev, Error **errp)
/* Interrupt pin 1 */
pci_conf[PCI_INTERRUPT_PIN] = 0x01;
+ if (s->msi != ON_OFF_AUTO_OFF) {
+ ret = msi_init(dev, 0x50, 1, true, false, &err);
+ /* Any error other than -ENOTSUP(board's MSI support is broken)
+ * is a programming error */
+ assert(!ret || ret == -ENOTSUP);
+ if (ret && s->msi == ON_OFF_AUTO_ON) {
+ /* Can't satisfy user's explicit msi=on request, fail */
+ error_append_hint(&err, "You have to use msi=auto (default) or "
+ "msi=off with this machine type.\n");
+ error_propagate(errp, err);
+ return;
+ } else if (ret) {
+ /* With msi=auto, we fall back to MSI off silently */
+ s->msi = ON_OFF_AUTO_OFF;
+ error_free(err);
+ }
+ }
+
memory_region_init_io(&s->mmio_io, OBJECT(s), &megasas_mmio_ops, s,
"megasas-mmio", 0x4000);
memory_region_init_io(&s->port_io, OBJECT(s), &megasas_port_ops, s,
@@ -2347,14 +2358,10 @@ static void megasas_scsi_realize(PCIDevice *dev, Error **errp)
memory_region_init_io(&s->queue_io, OBJECT(s), &megasas_queue_ops, s,
"megasas-queue", 0x40000);
- if (megasas_use_msi(s) &&
- msi_init(dev, 0x50, 1, true, false)) {
- s->flags &= ~MEGASAS_MASK_USE_MSI;
- }
if (megasas_use_msix(s) &&
msix_init(dev, 15, &s->mmio_io, b->mmio_bar, 0x2000,
&s->mmio_io, b->mmio_bar, 0x3800, 0x68)) {
- s->flags &= ~MEGASAS_MASK_USE_MSIX;
+ s->msix = ON_OFF_AUTO_OFF;
}
if (pci_is_express(dev)) {
pcie_endpoint_cap_init(dev, 0xa0);
@@ -2422,10 +2429,8 @@ static Property megasas_properties_gen1[] = {
MEGASAS_DEFAULT_FRAMES),
DEFINE_PROP_STRING("hba_serial", MegasasState, hba_serial),
DEFINE_PROP_UINT64("sas_address", MegasasState, sas_addr, 0),
- DEFINE_PROP_BIT("use_msi", MegasasState, flags,
- MEGASAS_FLAG_USE_MSI, false),
- DEFINE_PROP_BIT("use_msix", MegasasState, flags,
- MEGASAS_FLAG_USE_MSIX, false),
+ DEFINE_PROP_ON_OFF_AUTO("msi", MegasasState, msi, ON_OFF_AUTO_AUTO),
+ DEFINE_PROP_ON_OFF_AUTO("msix", MegasasState, msix, ON_OFF_AUTO_AUTO),
DEFINE_PROP_BIT("use_jbod", MegasasState, flags,
MEGASAS_FLAG_USE_JBOD, false),
DEFINE_PROP_END_OF_LIST(),
@@ -2438,10 +2443,8 @@ static Property megasas_properties_gen2[] = {
MEGASAS_GEN2_DEFAULT_FRAMES),
DEFINE_PROP_STRING("hba_serial", MegasasState, hba_serial),
DEFINE_PROP_UINT64("sas_address", MegasasState, sas_addr, 0),
- DEFINE_PROP_BIT("use_msi", MegasasState, flags,
- MEGASAS_FLAG_USE_MSI, true),
- DEFINE_PROP_BIT("use_msix", MegasasState, flags,
- MEGASAS_FLAG_USE_MSIX, true),
+ DEFINE_PROP_ON_OFF_AUTO("msi", MegasasState, msi, ON_OFF_AUTO_AUTO),
+ DEFINE_PROP_ON_OFF_AUTO("msix", MegasasState, msix, ON_OFF_AUTO_AUTO),
DEFINE_PROP_BIT("use_jbod", MegasasState, flags,
MEGASAS_FLAG_USE_JBOD, false),
DEFINE_PROP_END_OF_LIST(),
diff --git a/hw/scsi/mptsas.c b/hw/scsi/mptsas.c
index be88e16..1ae32fb 100644
--- a/hw/scsi/mptsas.c
+++ b/hw/scsi/mptsas.c
@@ -32,7 +32,7 @@
#include "hw/scsi/scsi.h"
#include "block/scsi.h"
#include "trace.h"
-
+#include "qapi/error.h"
#include "mptsas.h"
#include "mpi.h"
@@ -63,7 +63,7 @@ static void mptsas_update_interrupt(MPTSASState *s)
PCIDevice *pci = (PCIDevice *) s;
uint32_t state = s->intr_status & ~(s->intr_mask | MPI_HIS_IOP_DOORBELL_STATUS);
- if (s->msi_in_use && msi_enabled(pci)) {
+ if (msi_enabled(pci)) {
if (state) {
trace_mptsas_irq_msi(s);
msi_notify(pci, 0);
@@ -1273,10 +1273,30 @@ static void mptsas_scsi_init(PCIDevice *dev, Error **errp)
{
DeviceState *d = DEVICE(dev);
MPTSASState *s = MPT_SAS(dev);
+ Error *err = NULL;
+ int ret;
dev->config[PCI_LATENCY_TIMER] = 0;
dev->config[PCI_INTERRUPT_PIN] = 0x01;
+ if (s->msi != ON_OFF_AUTO_OFF) {
+ ret = msi_init(dev, 0, 1, true, false, &err);
+ /* Any error other than -ENOTSUP(board's MSI support is broken)
+ * is a programming error */
+ assert(!ret || ret == -ENOTSUP);
+ if (ret && s->msi == ON_OFF_AUTO_ON) {
+ /* Can't satisfy user's explicit msi=on request, fail */
+ error_append_hint(&err, "You have to use msi=auto (default) or "
+ "msi=off with this machine type.\n");
+ error_propagate(errp, err);
+ return;
+ }
+ assert(!err || s->msi == ON_OFF_AUTO_AUTO);
+ /* With msi=auto, we fall back to MSI off silently */
+ error_free(err);
+
+ }
+
memory_region_init_io(&s->mmio_io, OBJECT(s), &mptsas_mmio_ops, s,
"mptsas-mmio", 0x4000);
memory_region_init_io(&s->port_io, OBJECT(s), &mptsas_port_ops, s,
@@ -1284,11 +1304,6 @@ static void mptsas_scsi_init(PCIDevice *dev, Error **errp)
memory_region_init_io(&s->diag_io, OBJECT(s), &mptsas_diag_ops, s,
"mptsas-diag", 0x10000);
- if (s->msi_available &&
- msi_init(dev, 0, 1, true, false) >= 0) {
- s->msi_in_use = true;
- }
-
pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->port_io);
pci_register_bar(dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY |
PCI_BASE_ADDRESS_MEM_TYPE_32, &s->mmio_io);
@@ -1319,9 +1334,7 @@ static void mptsas_scsi_uninit(PCIDevice *dev)
MPTSASState *s = MPT_SAS(dev);
qemu_bh_delete(s->request_bh);
- if (s->msi_in_use) {
- msi_uninit(dev);
- }
+ msi_uninit(dev);
}
static void mptsas_reset(DeviceState *dev)
@@ -1357,7 +1370,6 @@ static const VMStateDescription vmstate_mptsas = {
.post_load = mptsas_post_load,
.fields = (VMStateField[]) {
VMSTATE_PCI_DEVICE(dev, MPTSASState),
- VMSTATE_BOOL(msi_in_use, MPTSASState),
VMSTATE_UINT32(state, MPTSASState),
VMSTATE_UINT8(who_init, MPTSASState),
@@ -1403,7 +1415,7 @@ static const VMStateDescription vmstate_mptsas = {
static Property mptsas_properties[] = {
DEFINE_PROP_UINT64("sas_address", MPTSASState, sas_addr, 0),
/* TODO: test MSI support under Windows */
- DEFINE_PROP_BIT("msi", MPTSASState, msi_available, 0, true),
+ DEFINE_PROP_ON_OFF_AUTO("msi", MPTSASState, msi, ON_OFF_AUTO_AUTO),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/scsi/mptsas.h b/hw/scsi/mptsas.h
index 595f81f..da014a3 100644
--- a/hw/scsi/mptsas.h
+++ b/hw/scsi/mptsas.h
@@ -27,11 +27,10 @@ struct MPTSASState {
MemoryRegion diag_io;
QEMUBH *request_bh;
- uint32_t msi_available;
+ /* properties */
+ OnOffAuto msi;
uint64_t sas_addr;
- bool msi_in_use;
-
/* Doorbell register */
uint32_t state;
uint8_t who_init;
diff --git a/hw/scsi/vmw_pvscsi.c b/hw/scsi/vmw_pvscsi.c
index 2d7528d..da71c8c 100644
--- a/hw/scsi/vmw_pvscsi.c
+++ b/hw/scsi/vmw_pvscsi.c
@@ -121,8 +121,7 @@ typedef struct {
uint8_t msg_ring_info_valid; /* Whether message ring initialized */
uint8_t use_msg; /* Whether to use message ring */
- uint8_t msi_used; /* Whether MSI support was installed successfully */
-
+ uint8_t msi_used; /* For migration compatibility */
PVSCSIRingInfo rings; /* Data transfer rings manager */
uint32_t resetting; /* Reset in progress */
@@ -362,7 +361,7 @@ pvscsi_update_irq_status(PVSCSIState *s)
trace_pvscsi_update_irq_level(should_raise, s->reg_interrupt_enabled,
s->reg_interrupt_status);
- if (s->msi_used && msi_enabled(d)) {
+ if (msi_enabled(d)) {
if (should_raise) {
trace_pvscsi_update_irq_msi();
msi_notify(d, PVSCSI_VECTOR_COMPLETION);
@@ -1056,22 +1055,20 @@ pvscsi_io_read(void *opaque, hwaddr addr, unsigned size)
}
-static bool
+static void
pvscsi_init_msi(PVSCSIState *s)
{
int res;
PCIDevice *d = PCI_DEVICE(s);
res = msi_init(d, PVSCSI_MSI_OFFSET(s), PVSCSI_MSIX_NUM_VECTORS,
- PVSCSI_USE_64BIT, PVSCSI_PER_VECTOR_MASK);
+ PVSCSI_USE_64BIT, PVSCSI_PER_VECTOR_MASK, NULL);
if (res < 0) {
trace_pvscsi_init_msi_fail(res);
s->msi_used = false;
} else {
s->msi_used = true;
}
-
- return s->msi_used;
}
static void
@@ -1079,9 +1076,7 @@ pvscsi_cleanup_msi(PVSCSIState *s)
{
PCIDevice *d = PCI_DEVICE(s);
- if (s->msi_used) {
- msi_uninit(d);
- }
+ msi_uninit(d);
}
static const MemoryRegionOps pvscsi_ops = {
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
index 43ba615..1a3377f 100644
--- a/hw/usb/hcd-xhci.c
+++ b/hw/usb/hcd-xhci.c
@@ -26,6 +26,7 @@
#include "hw/pci/msi.h"
#include "hw/pci/msix.h"
#include "trace.h"
+#include "qapi/error.h"
//#define DEBUG_XHCI
//#define DEBUG_DATA
@@ -461,6 +462,8 @@ struct XHCIState {
uint32_t numslots;
uint32_t flags;
uint32_t max_pstreams_mask;
+ OnOffAuto msi;
+ OnOffAuto msix;
/* Operational Registers */
uint32_t usbcmd;
@@ -498,9 +501,7 @@ typedef struct XHCIEvRingSeg {
} XHCIEvRingSeg;
enum xhci_flags {
- XHCI_FLAG_USE_MSI = 1,
- XHCI_FLAG_USE_MSI_X,
- XHCI_FLAG_SS_FIRST,
+ XHCI_FLAG_SS_FIRST = 1,
XHCI_FLAG_FORCE_PCIE_ENDCAP,
XHCI_FLAG_ENABLE_STREAMS,
};
@@ -3581,6 +3582,7 @@ static void usb_xhci_init(XHCIState *xhci)
static void usb_xhci_realize(struct PCIDevice *dev, Error **errp)
{
int i, ret;
+ Error *err = NULL;
XHCIState *xhci = XHCI(dev);
@@ -3591,6 +3593,23 @@ static void usb_xhci_realize(struct PCIDevice *dev, Error **errp)
usb_xhci_init(xhci);
+ if (xhci->msi != ON_OFF_AUTO_OFF) {
+ ret = msi_init(dev, 0x70, xhci->numintrs, true, false, &err);
+ /* Any error other than -ENOTSUP(board's MSI support is broken)
+ * is a programming error */
+ assert(!ret || ret == -ENOTSUP);
+ if (ret && xhci->msi == ON_OFF_AUTO_ON) {
+ /* Can't satisfy user's explicit msi=on request, fail */
+ error_append_hint(&err, "You have to use msi=auto (default) or "
+ "msi=off with this machine type.\n");
+ error_propagate(errp, err);
+ return;
+ }
+ assert(!err || xhci->msi == ON_OFF_AUTO_AUTO);
+ /* With msi=auto, we fall back to MSI off silently */
+ error_free(err);
+ }
+
if (xhci->numintrs > MAXINTRS) {
xhci->numintrs = MAXINTRS;
}
@@ -3648,10 +3667,8 @@ static void usb_xhci_realize(struct PCIDevice *dev, Error **errp)
assert(ret >= 0);
}
- if (xhci_get_flag(xhci, XHCI_FLAG_USE_MSI)) {
- msi_init(dev, 0x70, xhci->numintrs, true, false);
- }
- if (xhci_get_flag(xhci, XHCI_FLAG_USE_MSI_X)) {
+ if (xhci->msix != ON_OFF_AUTO_OFF) {
+ /* TODO check for errors */
msix_init(dev, xhci->numintrs,
&xhci->mem, 0, OFF_MSIX_TABLE,
&xhci->mem, 0, OFF_MSIX_PBA,
@@ -3872,8 +3889,8 @@ static const VMStateDescription vmstate_xhci = {
};
static Property xhci_properties[] = {
- DEFINE_PROP_BIT("msi", XHCIState, flags, XHCI_FLAG_USE_MSI, true),
- DEFINE_PROP_BIT("msix", XHCIState, flags, XHCI_FLAG_USE_MSI_X, true),
+ DEFINE_PROP_ON_OFF_AUTO("msi", XHCIState, msi, ON_OFF_AUTO_AUTO),
+ DEFINE_PROP_ON_OFF_AUTO("msix", XHCIState, msix, ON_OFF_AUTO_AUTO),
DEFINE_PROP_BIT("superspeed-ports-first",
XHCIState, flags, XHCI_FLAG_SS_FIRST, true),
DEFINE_PROP_BIT("force-pcie-endcap", XHCIState, flags,
diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
index f2c679e..44783c5 100644
--- a/hw/vfio/pci.c
+++ b/hw/vfio/pci.c
@@ -31,6 +31,7 @@
#include "sysemu/sysemu.h"
#include "pci.h"
#include "trace.h"
+#include "qapi/error.h"
#define MSIX_CAP_LENGTH 12
@@ -1170,6 +1171,7 @@ static int vfio_msi_setup(VFIOPCIDevice *vdev, int pos)
uint16_t ctrl;
bool msi_64bit, msi_maskbit;
int ret, entries;
+ Error *err = NULL;
if (pread(vdev->vbasedev.fd, &ctrl, sizeof(ctrl),
vdev->config_offset + pos + PCI_CAP_FLAGS) != sizeof(ctrl)) {
@@ -1183,12 +1185,13 @@ static int vfio_msi_setup(VFIOPCIDevice *vdev, int pos)
trace_vfio_msi_setup(vdev->vbasedev.name, pos);
- ret = msi_init(&vdev->pdev, pos, entries, msi_64bit, msi_maskbit);
+ ret = msi_init(&vdev->pdev, pos, entries, msi_64bit, msi_maskbit, &err);
if (ret < 0) {
if (ret == -ENOTSUP) {
return 0;
}
- error_report("vfio: msi_init failed");
+ error_prepend(&err, "vfio: msi_init failed: ");
+ error_report_err(err);
return ret;
}
vdev->msi_cap_size = 0xa + (msi_maskbit ? 0xa : 0) + (msi_64bit ? 0x4 : 0);
diff --git a/hw/virtio/virtio-bus.c b/hw/virtio/virtio-bus.c
index 1313760..a85b7c8 100644
--- a/hw/virtio/virtio-bus.c
+++ b/hw/virtio/virtio-bus.c
@@ -176,8 +176,8 @@ static int set_host_notifier_internal(DeviceState *proxy, VirtioBusState *bus,
return r;
}
} else {
- virtio_queue_set_host_notifier_fd_handler(vq, false, false);
k->ioeventfd_assign(proxy, notifier, n, assign);
+ virtio_queue_set_host_notifier_fd_handler(vq, false, false);
event_notifier_cleanup(notifier);
}
return r;
@@ -251,31 +251,25 @@ int virtio_bus_set_host_notifier(VirtioBusState *bus, int n, bool assign)
{
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(bus);
DeviceState *proxy = DEVICE(BUS(bus)->parent);
- VirtIODevice *vdev = virtio_bus_get_device(bus);
- VirtQueue *vq = virtio_get_queue(vdev, n);
if (!k->ioeventfd_started) {
return -ENOSYS;
}
+ k->ioeventfd_set_disabled(proxy, assign);
if (assign) {
/*
* Stop using the generic ioeventfd, we are doing eventfd handling
* ourselves below
+ *
+ * FIXME: We should just switch the handler and not deassign the
+ * ioeventfd.
+ * Otherwise, there's a window where we don't have an
+ * ioeventfd and we may end up with a notification where
+ * we don't expect one.
*/
- k->ioeventfd_set_disabled(proxy, true);
- }
- /*
- * Just switch the handler, don't deassign the ioeventfd.
- * Otherwise, there's a window where we don't have an
- * ioeventfd and we may end up with a notification where
- * we don't expect one.
- */
- virtio_queue_set_host_notifier_fd_handler(vq, assign, !assign);
- if (!assign) {
- /* Use generic ioeventfd handler again. */
- k->ioeventfd_set_disabled(proxy, false);
+ virtio_bus_stop_ioeventfd(bus);
}
- return 0;
+ return set_host_notifier_internal(proxy, bus, n, assign, false);
}
static char *virtio_bus_get_dev_path(DeviceState *dev)
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 7ed06ea..18153d5 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -1499,6 +1499,16 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id)
}
qemu_get_be32s(f, &features);
+ /*
+ * Temporarily set guest_features low bits - needed by
+ * virtio net load code testing for VIRTIO_NET_F_CTRL_GUEST_OFFLOADS
+ * VIRTIO_NET_F_GUEST_ANNOUNCE and VIRTIO_NET_F_CTRL_VQ.
+ *
+ * Note: devices should always test host features in future - don't create
+ * new dependencies like this.
+ */
+ vdev->guest_features = features;
+
config_len = qemu_get_be32(f);
/*
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index fe5444d..2123532 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -150,11 +150,6 @@ struct PCMachineClass {
/* PC-style peripherals (also used by other machines). */
-typedef struct PcPciInfo {
- Range w32;
- Range w64;
-} PcPciInfo;
-
#define ACPI_PM_PROP_S3_DISABLED "disable_s3"
#define ACPI_PM_PROP_S4_DISABLED "disable_s4"
#define ACPI_PM_PROP_S4_VAL "s4_val"
diff --git a/include/hw/pci-host/q35.h b/include/hw/pci-host/q35.h
index 1075f3e..0d64032 100644
--- a/include/hw/pci-host/q35.h
+++ b/include/hw/pci-host/q35.h
@@ -55,12 +55,11 @@ typedef struct MCHPCIState {
MemoryRegion smram_region, open_high_smram;
MemoryRegion smram, low_smram, high_smram;
MemoryRegion tseg_blackhole, tseg_window;
- PcPciInfo pci_info;
+ Range pci_hole;
uint64_t below_4g_mem_size;
uint64_t above_4g_mem_size;
uint64_t pci_hole64_size;
uint32_t short_root_bus;
- IntelIOMMUState *iommu;
} MCHPCIState;
typedef struct Q35PCIHost {
diff --git a/include/hw/pci/msi.h b/include/hw/pci/msi.h
index 8124908..4837bcf 100644
--- a/include/hw/pci/msi.h
+++ b/include/hw/pci/msi.h
@@ -35,7 +35,8 @@ void msi_set_message(PCIDevice *dev, MSIMessage msg);
MSIMessage msi_get_message(PCIDevice *dev, unsigned int vector);
bool msi_enabled(const PCIDevice *dev);
int msi_init(struct PCIDevice *dev, uint8_t offset,
- unsigned int nr_vectors, bool msi64bit, bool msi_per_vector_mask);
+ unsigned int nr_vectors, bool msi64bit,
+ bool msi_per_vector_mask, Error **errp);
void msi_uninit(struct PCIDevice *dev);
void msi_reset(PCIDevice *dev);
void msi_notify(PCIDevice *dev, unsigned int vector);
diff --git a/include/hw/pci/pci_bus.h b/include/hw/pci/pci_bus.h
index 403fec6..5484a9b 100644
--- a/include/hw/pci/pci_bus.h
+++ b/include/hw/pci/pci_bus.h
@@ -39,6 +39,8 @@ struct PCIBus {
Keep a count of the number of devices with raised IRQs. */
int nirq;
int *irq_count;
+
+ Notifier machine_done;
};
typedef struct PCIBridgeWindows PCIBridgeWindows;
diff --git a/include/qemu/range.h b/include/qemu/range.h
index 3970f00..f28f0c1 100644
--- a/include/qemu/range.h
+++ b/include/qemu/range.h
@@ -26,32 +26,111 @@
/*
* Operations on 64 bit address ranges.
* Notes:
- * - ranges must not wrap around 0, but can include the last byte ~0x0LL.
- * - this can not represent a full 0 to ~0x0LL range.
+ * - Ranges must not wrap around 0, but can include UINT64_MAX.
*/
-/* A structure representing a range of addresses. */
struct Range {
- uint64_t begin; /* First byte of the range, or 0 if empty. */
- uint64_t end; /* 1 + the last byte. 0 if range empty or ends at ~0x0LL. */
+ /*
+ * Do not access members directly, use the functions!
+ * A non-empty range has @lob <= @upb.
+ * An empty range has @lob == @upb + 1.
+ */
+ uint64_t lob; /* inclusive lower bound */
+ uint64_t upb; /* inclusive upper bound */
};
+static inline void range_invariant(Range *range)
+{
+ assert(range->lob <= range->upb || range->lob == range->upb + 1);
+}
+
+/* Compound literal encoding the empty range */
+#define range_empty ((Range){ .lob = 1, .upb = 0 })
+
+/* Is @range empty? */
+static inline bool range_is_empty(Range *range)
+{
+ range_invariant(range);
+ return range->lob > range->upb;
+}
+
+/* Does @range contain @val? */
+static inline bool range_contains(Range *range, uint64_t val)
+{
+ return val >= range->lob && val <= range->upb;
+}
+
+/* Initialize @range to the empty range */
+static inline void range_make_empty(Range *range)
+{
+ *range = range_empty;
+ assert(range_is_empty(range));
+}
+
+/*
+ * Initialize @range to span the interval [@lob,@upb].
+ * Both bounds are inclusive.
+ * The interval must not be empty, i.e. @lob must be less than or
+ * equal @upb.
+ */
+static inline void range_set_bounds(Range *range, uint64_t lob, uint64_t upb)
+{
+ range->lob = lob;
+ range->upb = upb;
+ assert(!range_is_empty(range));
+}
+
+/*
+ * Initialize @range to span the interval [@lob,@upb_plus1).
+ * The lower bound is inclusive, the upper bound is exclusive.
+ * Zero @upb_plus1 is special: if @lob is also zero, set @range to the
+ * empty range. Else, set @range to [@lob,UINT64_MAX].
+ */
+static inline void range_set_bounds1(Range *range,
+ uint64_t lob, uint64_t upb_plus1)
+{
+ if (!lob && !upb_plus1) {
+ *range = range_empty;
+ } else {
+ range->lob = lob;
+ range->upb = upb_plus1 - 1;
+ }
+ range_invariant(range);
+}
+
+/* Return @range's lower bound. @range must not be empty. */
+static inline uint64_t range_lob(Range *range)
+{
+ assert(!range_is_empty(range));
+ return range->lob;
+}
+
+/* Return @range's upper bound. @range must not be empty. */
+static inline uint64_t range_upb(Range *range)
+{
+ assert(!range_is_empty(range));
+ return range->upb;
+}
+
+/*
+ * Extend @range to the smallest interval that includes @extend_by, too.
+ */
static inline void range_extend(Range *range, Range *extend_by)
{
- if (!extend_by->begin && !extend_by->end) {
+ if (range_is_empty(extend_by)) {
return;
}
- if (!range->begin && !range->end) {
+ if (range_is_empty(range)) {
*range = *extend_by;
return;
}
- if (range->begin > extend_by->begin) {
- range->begin = extend_by->begin;
+ if (range->lob > extend_by->lob) {
+ range->lob = extend_by->lob;
}
- /* Compare last byte in case region ends at ~0x0LL */
- if (range->end - 1 < extend_by->end - 1) {
- range->end = extend_by->end;
+ if (range->upb < extend_by->upb) {
+ range->upb = extend_by->upb;
}
+ range_invariant(range);
}
/* Get last byte of a range from offset + length.
diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
index 7313673..ee7c760 100644
--- a/include/sysemu/sysemu.h
+++ b/include/sysemu/sysemu.h
@@ -75,6 +75,7 @@ void qemu_add_exit_notifier(Notifier *notify);
void qemu_remove_exit_notifier(Notifier *notify);
void qemu_add_machine_init_done_notifier(Notifier *notify);
+void qemu_remove_machine_init_done_notifier(Notifier *notify);
void hmp_savevm(Monitor *mon, const QDict *qdict);
int load_vmstate(const char *name);
diff --git a/qapi/string-input-visitor.c b/qapi/string-input-visitor.c
index b546e5f..0690abb 100644
--- a/qapi/string-input-visitor.c
+++ b/qapi/string-input-visitor.c
@@ -59,8 +59,7 @@ static int parse_str(StringInputVisitor *siv, const char *name, Error **errp)
if (errno == 0 && endptr > str) {
if (*endptr == '\0') {
cur = g_malloc0(sizeof(*cur));
- cur->begin = start;
- cur->end = start + 1;
+ range_set_bounds(cur, start, start);
siv->ranges = range_list_insert(siv->ranges, cur);
cur = NULL;
str = NULL;
@@ -73,16 +72,14 @@ static int parse_str(StringInputVisitor *siv, const char *name, Error **errp)
end < start + 65536)) {
if (*endptr == '\0') {
cur = g_malloc0(sizeof(*cur));
- cur->begin = start;
- cur->end = end + 1;
+ range_set_bounds(cur, start, end);
siv->ranges = range_list_insert(siv->ranges, cur);
cur = NULL;
str = NULL;
} else if (*endptr == ',') {
str = endptr + 1;
cur = g_malloc0(sizeof(*cur));
- cur->begin = start;
- cur->end = end + 1;
+ range_set_bounds(cur, start, end);
siv->ranges = range_list_insert(siv->ranges, cur);
cur = NULL;
} else {
@@ -94,8 +91,7 @@ static int parse_str(StringInputVisitor *siv, const char *name, Error **errp)
} else if (*endptr == ',') {
str = endptr + 1;
cur = g_malloc0(sizeof(*cur));
- cur->begin = start;
- cur->end = start + 1;
+ range_set_bounds(cur, start, start);
siv->ranges = range_list_insert(siv->ranges, cur);
cur = NULL;
} else {
@@ -134,7 +130,7 @@ start_list(Visitor *v, const char *name, GenericList **list, size_t size,
if (siv->cur_range) {
Range *r = siv->cur_range->data;
if (r) {
- siv->cur = r->begin;
+ siv->cur = range_lob(r);
}
*list = g_malloc0(size);
} else {
@@ -156,7 +152,7 @@ static GenericList *next_list(Visitor *v, GenericList *tail, size_t size)
return NULL;
}
- if (siv->cur < r->begin || siv->cur >= r->end) {
+ if (!range_contains(r, siv->cur)) {
siv->cur_range = g_list_next(siv->cur_range);
if (!siv->cur_range) {
return NULL;
@@ -165,7 +161,7 @@ static GenericList *next_list(Visitor *v, GenericList *tail, size_t size)
if (!r) {
return NULL;
}
- siv->cur = r->begin;
+ siv->cur = range_lob(r);
}
tail->next = g_malloc0(size);
@@ -208,7 +204,7 @@ static void parse_type_int64(Visitor *v, const char *name, int64_t *obj,
goto error;
}
- siv->cur = r->begin;
+ siv->cur = range_lob(r);
}
*obj = siv->cur;
diff --git a/qapi/string-output-visitor.c b/qapi/string-output-visitor.c
index 5ea395a..c6f01f9 100644
--- a/qapi/string-output-visitor.c
+++ b/qapi/string-output-visitor.c
@@ -83,8 +83,8 @@ static void string_output_set(StringOutputVisitor *sov, char *string)
static void string_output_append(StringOutputVisitor *sov, int64_t a)
{
Range *r = g_malloc0(sizeof(*r));
- r->begin = a;
- r->end = a + 1;
+
+ range_set_bounds(r, a, a);
sov->ranges = range_list_insert(sov->ranges, r);
}
@@ -92,28 +92,28 @@ static void string_output_append_range(StringOutputVisitor *sov,
int64_t s, int64_t e)
{
Range *r = g_malloc0(sizeof(*r));
- r->begin = s;
- r->end = e + 1;
+
+ range_set_bounds(r, s, e);
sov->ranges = range_list_insert(sov->ranges, r);
}
static void format_string(StringOutputVisitor *sov, Range *r, bool next,
bool human)
{
- if (r->end - r->begin > 1) {
+ if (range_lob(r) != range_upb(r)) {
if (human) {
g_string_append_printf(sov->string, "0x%" PRIx64 "-0x%" PRIx64,
- r->begin, r->end - 1);
+ range_lob(r), range_upb(r));
} else {
g_string_append_printf(sov->string, "%" PRId64 "-%" PRId64,
- r->begin, r->end - 1);
+ range_lob(r), range_upb(r));
}
} else {
if (human) {
- g_string_append_printf(sov->string, "0x%" PRIx64, r->begin);
+ g_string_append_printf(sov->string, "0x%" PRIx64, range_lob(r));
} else {
- g_string_append_printf(sov->string, "%" PRId64, r->begin);
+ g_string_append_printf(sov->string, "%" PRId64, range_lob(r));
}
}
if (next) {
diff --git a/qemu-options.hx b/qemu-options.hx
index a95a936..9692e53 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -38,7 +38,6 @@ DEF("machine", HAS_ARG, QEMU_OPTION_machine, \
" kvm_shadow_mem=size of KVM shadow MMU in bytes\n"
" dump-guest-core=on|off include guest memory in a core dump (default=on)\n"
" mem-merge=on|off controls memory merge support (default: on)\n"
- " iommu=on|off controls emulated Intel IOMMU (VT-d) support (default=off)\n"
" igd-passthru=on|off controls IGD GFX passthrough support (default=off)\n"
" aes-key-wrap=on|off controls support for AES key wrapping (default=on)\n"
" dea-key-wrap=on|off controls support for DEA key wrapping (default=on)\n"
@@ -73,8 +72,6 @@ Include guest memory in a core dump. The default is on.
Enables or disables memory merge support. This feature, when supported by
the host, de-duplicates identical memory pages among VMs instances
(enabled by default).
-@item iommu=on|off
-Enables or disables emulated Intel IOMMU (VT-d) support. The default is off.
@item aes-key-wrap=on|off
Enables or disables AES key wrapping support on s390-ccw hosts. This feature
controls whether AES wrapping keys will be created to allow
diff --git a/tests/acpi-test-data/pc/APIC.cphp b/tests/acpi-test-data/pc/APIC.cphp
new file mode 100644
index 0000000..1bf8a0a
--- /dev/null
+++ b/tests/acpi-test-data/pc/APIC.cphp
Binary files differ
diff --git a/tests/acpi-test-data/pc/DSDT.cphp b/tests/acpi-test-data/pc/DSDT.cphp
new file mode 100644
index 0000000..e8b1462
--- /dev/null
+++ b/tests/acpi-test-data/pc/DSDT.cphp
Binary files differ
diff --git a/tests/acpi-test-data/q35/APIC.cphp b/tests/acpi-test-data/q35/APIC.cphp
new file mode 100644
index 0000000..1bf8a0a
--- /dev/null
+++ b/tests/acpi-test-data/q35/APIC.cphp
Binary files differ
diff --git a/tests/acpi-test-data/q35/DSDT.cphp b/tests/acpi-test-data/q35/DSDT.cphp
new file mode 100644
index 0000000..6cc28c6
--- /dev/null
+++ b/tests/acpi-test-data/q35/DSDT.cphp
Binary files differ
diff --git a/tests/bios-tables-test.c b/tests/bios-tables-test.c
index 92c90dd..de4019e 100644
--- a/tests/bios-tables-test.c
+++ b/tests/bios-tables-test.c
@@ -801,6 +801,32 @@ static void test_acpi_q35_tcg_bridge(void)
free_test_data(&data);
}
+static void test_acpi_piix4_tcg_cphp(void)
+{
+ test_data data;
+
+ memset(&data, 0, sizeof(data));
+ data.machine = MACHINE_PC;
+ data.variant = ".cphp";
+ test_acpi_one("-machine accel=tcg"
+ " -smp 2,cores=3,sockets=2,maxcpus=6",
+ &data);
+ free_test_data(&data);
+}
+
+static void test_acpi_q35_tcg_cphp(void)
+{
+ test_data data;
+
+ memset(&data, 0, sizeof(data));
+ data.machine = MACHINE_Q35;
+ data.variant = ".cphp";
+ test_acpi_one("-machine q35,accel=tcg"
+ " -smp 2,cores=3,sockets=2,maxcpus=6",
+ &data);
+ free_test_data(&data);
+}
+
static uint8_t ipmi_required_struct_types[] = {
0, 1, 3, 4, 16, 17, 19, 32, 38, 127
};
@@ -856,6 +882,8 @@ int main(int argc, char *argv[])
qtest_add_func("acpi/q35/tcg/bridge", test_acpi_q35_tcg_bridge);
qtest_add_func("acpi/piix4/tcg/ipmi", test_acpi_piix4_tcg_ipmi);
qtest_add_func("acpi/q35/tcg/ipmi", test_acpi_q35_tcg_ipmi);
+ qtest_add_func("acpi/piix4/tcg/cpuhp", test_acpi_piix4_tcg_cphp);
+ qtest_add_func("acpi/q35/tcg/cpuhp", test_acpi_q35_tcg_cphp);
}
ret = g_test_run();
boot_sector_cleanup(disk);
diff --git a/tests/test-logging.c b/tests/test-logging.c
index 440e75f..cdf13c6 100644
--- a/tests/test-logging.c
+++ b/tests/test-logging.c
@@ -68,6 +68,17 @@ static void test_parse_range(void)
g_assert(qemu_log_in_addr_range(0x2050));
g_assert(qemu_log_in_addr_range(0x3050));
+ qemu_set_dfilter_ranges("0xffffffffffffffff-1", &error_abort);
+ g_assert(qemu_log_in_addr_range(UINT64_MAX));
+ g_assert_false(qemu_log_in_addr_range(UINT64_MAX - 1));
+
+ qemu_set_dfilter_ranges("0..0xffffffffffffffff", &err);
+ g_assert(qemu_log_in_addr_range(0));
+ g_assert(qemu_log_in_addr_range(UINT64_MAX));
+
+ qemu_set_dfilter_ranges("2..1", &err);
+ error_free_or_abort(&err);
+
qemu_set_dfilter_ranges("0x1000+onehundred", &err);
error_free_or_abort(&err);
diff --git a/util/log.c b/util/log.c
index 32e4160..b6c75b1 100644
--- a/util/log.c
+++ b/util/log.c
@@ -131,8 +131,8 @@ bool qemu_log_in_addr_range(uint64_t addr)
if (debug_regions) {
int i = 0;
for (i = 0; i < debug_regions->len; i++) {
- struct Range *range = &g_array_index(debug_regions, Range, i);
- if (addr >= range->begin && addr <= range->end) {
+ Range *range = &g_array_index(debug_regions, Range, i);
+ if (range_contains(range, addr)) {
return true;
}
}
@@ -158,7 +158,7 @@ void qemu_set_dfilter_ranges(const char *filter_spec, Error **errp)
for (i = 0; ranges[i]; i++) {
const char *r = ranges[i];
const char *range_op, *r2, *e;
- uint64_t r1val, r2val;
+ uint64_t r1val, r2val, lob, upb;
struct Range range;
range_op = strstr(r, "-");
@@ -187,27 +187,28 @@ void qemu_set_dfilter_ranges(const char *filter_spec, Error **errp)
(int)(r2 - range_op), range_op);
goto out;
}
- if (r2val == 0) {
- error_setg(errp, "Invalid range");
- goto out;
- }
switch (*range_op) {
case '+':
- range.begin = r1val;
- range.end = r1val + (r2val - 1);
+ lob = r1val;
+ upb = r1val + r2val - 1;
break;
case '-':
- range.end = r1val;
- range.begin = r1val - (r2val - 1);
+ upb = r1val;
+ lob = r1val - (r2val - 1);
break;
case '.':
- range.begin = r1val;
- range.end = r2val;
+ lob = r1val;
+ upb = r2val;
break;
default:
g_assert_not_reached();
}
+ if (lob > upb) {
+ error_setg(errp, "Invalid range");
+ goto out;
+ }
+ range_set_bounds(&range, lob, upb);
g_array_append_val(debug_regions, range);
}
out:
diff --git a/util/range.c b/util/range.c
index e90c988..416df7c 100644
--- a/util/range.c
+++ b/util/range.c
@@ -22,20 +22,18 @@
#include "qemu/range.h"
/*
- * Operations on 64 bit address ranges.
- * Notes:
- * - ranges must not wrap around 0, but can include the last byte ~0x0LL.
- * - this can not represent a full 0 to ~0x0LL range.
+ * Return -1 if @a < @b, 1 @a > @b, and 0 if they touch or overlap.
+ * Both @a and @b must not be empty.
*/
-
-/* Return -1 if @a < @b, 1 if greater, and 0 if they touch or overlap. */
static inline int range_compare(Range *a, Range *b)
{
- /* Zero a->end is 2**64, and therefore not less than any b->begin */
- if (a->end && a->end < b->begin) {
+ assert(!range_is_empty(a) && !range_is_empty(b));
+
+ /* Careful, avoid wraparound */
+ if (b->lob && b->lob - 1 > a->upb) {
return -1;
}
- if (b->end && a->begin > b->end) {
+ if (a->lob && a->lob - 1 > b->upb) {
return 1;
}
return 0;
@@ -46,8 +44,7 @@ GList *range_list_insert(GList *list, Range *data)
{
GList *l;
- /* Range lists require no empty ranges */
- assert(data->begin < data->end || (data->begin && !data->end));
+ assert(!range_is_empty(data));
/* Skip all list elements strictly less than data */
for (l = list; l && range_compare(l->data, data) < 0; l = l->next) {
diff --git a/vl.c b/vl.c
index 9bb7f4c..5cd0f2a 100644
--- a/vl.c
+++ b/vl.c
@@ -2675,6 +2675,11 @@ void qemu_add_machine_init_done_notifier(Notifier *notify)
}
}
+void qemu_remove_machine_init_done_notifier(Notifier *notify)
+{
+ notifier_remove(notify);
+}
+
static void qemu_run_machine_init_done_notifiers(void)
{
notifier_list_notify(&machine_init_done_notifiers, NULL);
diff --git a/xen-hvm.c b/xen-hvm.c
index 98ea44f..eb57792 100644
--- a/xen-hvm.c
+++ b/xen-hvm.c
@@ -190,6 +190,9 @@ static void xen_ram_init(PCMachineState *pcms,
/* Handle the machine opt max-ram-below-4g. It is basically doing
* min(xen limit, user limit).
*/
+ if (!user_lowmem) {
+ user_lowmem = HVM_BELOW_4G_RAM_END; /* default */
+ }
if (HVM_BELOW_4G_RAM_END <= user_lowmem) {
user_lowmem = HVM_BELOW_4G_RAM_END;
}