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> -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAABAgAGBQJXe4l4AAoJECgfDbjSjVRpIz4IALye7mKG61/POA4Gqmhalc3d HnlNSZ2YcKAuvPg7WWkBuRacrQvVY/MbW1mLloG1lY0tdFgZG8Cy+CY6wJg1NE4c cXd+77vHkIyrnl+Nil+QOgTFiAsMnD+mXHHsnCDw2jGn3JbgVNuCMi7V34fGkQd2 PDkZyYfwTqO3HytuG0/j2Somc9du1gjYdn+9qigfZVgP96jGDojBuJWuuU5flCB3 Kj5xrOuI01XlbdTk71tVjBJBektQurWr6r7GECDqZIpUfc+BI70FU9jPh+OlLTO/ 92yi29ncjyStz4tRnf18xoQ8uBgH/tD1xigEUPRtnm1+0i/tgONBL8cAdBF9FBE= =ABGE -----END PGP SIGNATURE----- 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>
This commit is contained in:
commit
791b7d2340
@ -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(),
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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 = {
|
||||
|
@ -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,
|
||||
|
@ -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 (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);
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
|
||||
pc_cpus_init(pcms);
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
@ -263,32 +262,6 @@ static void e1000e_core_realize(E1000EState *s)
|
||||
s->core.owner_nic = s->nic;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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)) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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(),
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 = {
|
||||
|
@ -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)
|
||||
|
11
hw/pci/msi.c
11
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;
|
||||
}
|
||||
|
74
hw/pci/pci.c
74
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(®ion_range, lob, upb);
|
||||
range_extend(range, ®ion_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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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(),
|
||||
|
@ -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(),
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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 = {
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
virtio_bus_stop_ioeventfd(bus);
|
||||
}
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
return 0;
|
||||
return set_host_notifier_internal(proxy, bus, n, assign, false);
|
||||
}
|
||||
|
||||
static char *virtio_bus_get_dev_path(DeviceState *dev)
|
||||
|
@ -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);
|
||||
|
||||
/*
|
||||
|
@ -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"
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
BIN
tests/acpi-test-data/pc/APIC.cphp
Normal file
BIN
tests/acpi-test-data/pc/APIC.cphp
Normal file
Binary file not shown.
BIN
tests/acpi-test-data/pc/DSDT.cphp
Normal file
BIN
tests/acpi-test-data/pc/DSDT.cphp
Normal file
Binary file not shown.
BIN
tests/acpi-test-data/q35/APIC.cphp
Normal file
BIN
tests/acpi-test-data/q35/APIC.cphp
Normal file
Binary file not shown.
BIN
tests/acpi-test-data/q35/DSDT.cphp
Normal file
BIN
tests/acpi-test-data/q35/DSDT.cphp
Normal file
Binary file not shown.
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
27
util/log.c
27
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:
|
||||
|
19
util/range.c
19
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) {
|
||||
|
5
vl.c
5
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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user