pci, pc, virtio: fixes, features

VTD fixes
 IR and split irqchip are now the default for Q35
 ACPI refactoring
 hotplug refactoring
 new names for virtio devices
 multiple pcie link width/speeds
 PCI fixes
 
 Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
 -----BEGIN PGP SIGNATURE-----
 
 iQEcBAABAgAGBQJcG967AAoJECgfDbjSjVRpUlMH/1wy8WW7Br/4JxlWUPsfZTqZ
 0Lg2n59wuFzRVS+gLotp6bUaJGR9xn9fKjI1wfD59oVrDTKyauuw82v0OityEs33
 ZquFecuJvP6k5N40DkqA9YJjKSw7nUmLrsyrD0t2H43npikP2aD9f6yootrr3oVV
 nPwBvyT9ykIBQc7IzsHDiLw3EPdIf+9IR7+l+PLptzV0zK43Jfwi/nzHIQq00UMz
 eLM/ejQLIx4BZJnYGS0Cy6v3K7cS3k45LHDY0cGc0id2jHFN2vdQyHCF9I1ps72q
 pSlhMaLEwvQSYyre6iFTG5uuvyIPWv3LOkaBEwMSA5B/HXuEb2RKHThYzS9dc68=
 =OwW7
 -----END PGP SIGNATURE-----

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

pci, pc, virtio: fixes, features

VTD fixes
IR and split irqchip are now the default for Q35
ACPI refactoring
hotplug refactoring
new names for virtio devices
multiple pcie link width/speeds
PCI fixes

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

# gpg: Signature made Thu 20 Dec 2018 18:26:03 GMT
# gpg:                using RSA key 281F0DB8D28D5469
# 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: (44 commits)
  x86-iommu: turn on IR by default if proper
  x86-iommu: switch intr_supported to OnOffAuto type
  q35: set split kernel irqchip as default
  pci: Adjust PCI config limit based on bus topology
  spapr_pci: perform unplug via the hotplug handler
  pci/shpc: perform unplug via the hotplug handler
  pci: Reuse pci-bridge hotplug handler handlers for pcie-pci-bridge
  pci/pcie: perform unplug via the hotplug handler
  pci/pcihp: perform unplug via the hotplug handler
  pci/pcihp: overwrite hotplug handler recursively from the start
  pci/pcihp: perform check for bus capability in pre_plug handler
  s390x/pci: rename hotplug handler callbacks
  pci/shpc: rename hotplug handler callbacks
  pci/pcie: rename hotplug handler callbacks
  hw/i386: Remove deprecated machines pc-0.10 and pc-0.11
  hw: acpi: Remove AcpiRsdpDescriptor and fix tests
  hw: acpi: Export and share the ARM RSDP build
  hw: arm: Support both legacy and current RSDP build
  hw: arm: Convert the RSDP build to the buid_append_foo() API
  hw: arm: Carry RSDP specific data through AcpiRsdpData
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2018-12-21 14:06:01 +00:00
commit 15763776bf
66 changed files with 1363 additions and 451 deletions

View File

@ -1262,7 +1262,7 @@ M: Michael S. Tsirkin <mst@redhat.com>
M: Igor Mammedov <imammedo@redhat.com> M: Igor Mammedov <imammedo@redhat.com>
S: Supported S: Supported
F: include/hw/acpi/* F: include/hw/acpi/*
F: include/hw/smbios/* F: include/hw/firmware/smbios.h
F: hw/mem/* F: hw/mem/*
F: hw/acpi/* F: hw/acpi/*
F: hw/smbios/* F: hw/smbios/*

View File

@ -1589,6 +1589,74 @@ void acpi_build_tables_cleanup(AcpiBuildTables *tables, bool mfre)
g_array_free(tables->vmgenid, mfre); g_array_free(tables->vmgenid, mfre);
} }
/*
* ACPI spec 5.2.5.3 Root System Description Pointer (RSDP).
* (Revision 1.0 or later)
*/
void
build_rsdp(GArray *tbl, BIOSLinker *linker, AcpiRsdpData *rsdp_data)
{
int tbl_off = tbl->len; /* Table offset in the RSDP file */
switch (rsdp_data->revision) {
case 0:
/* With ACPI 1.0, we must have an RSDT pointer */
g_assert(rsdp_data->rsdt_tbl_offset);
break;
case 2:
/* With ACPI 2.0+, we must have an XSDT pointer */
g_assert(rsdp_data->xsdt_tbl_offset);
break;
default:
/* Only revisions 0 (ACPI 1.0) and 2 (ACPI 2.0+) are valid for RSDP */
g_assert_not_reached();
}
bios_linker_loader_alloc(linker, ACPI_BUILD_RSDP_FILE, tbl, 16,
true /* fseg memory */);
g_array_append_vals(tbl, "RSD PTR ", 8); /* Signature */
build_append_int_noprefix(tbl, 0, 1); /* Checksum */
g_array_append_vals(tbl, rsdp_data->oem_id, 6); /* OEMID */
build_append_int_noprefix(tbl, rsdp_data->revision, 1); /* Revision */
build_append_int_noprefix(tbl, 0, 4); /* RsdtAddress */
if (rsdp_data->rsdt_tbl_offset) {
/* RSDT address to be filled by guest linker */
bios_linker_loader_add_pointer(linker, ACPI_BUILD_RSDP_FILE,
tbl_off + 16, 4,
ACPI_BUILD_TABLE_FILE,
*rsdp_data->rsdt_tbl_offset);
}
/* Checksum to be filled by guest linker */
bios_linker_loader_add_checksum(linker, ACPI_BUILD_RSDP_FILE,
tbl_off, 20, /* ACPI rev 1.0 RSDP size */
8);
if (rsdp_data->revision == 0) {
/* ACPI 1.0 RSDP, we're done */
return;
}
build_append_int_noprefix(tbl, 36, 4); /* Length */
/* XSDT address to be filled by guest linker */
build_append_int_noprefix(tbl, 0, 8); /* XsdtAddress */
/* We already validated our xsdt pointer */
bios_linker_loader_add_pointer(linker, ACPI_BUILD_RSDP_FILE,
tbl_off + 24, 8,
ACPI_BUILD_TABLE_FILE,
*rsdp_data->xsdt_tbl_offset);
build_append_int_noprefix(tbl, 0, 1); /* Extended Checksum */
build_append_int_noprefix(tbl, 0, 3); /* Reserved */
/* Extended checksum to be filled by Guest linker */
bios_linker_loader_add_checksum(linker, ACPI_BUILD_RSDP_FILE,
tbl_off, 36, /* ACPI rev 2.0 RSDP size */
32);
}
/* Build rsdt table */ /* Build rsdt table */
void void
build_rsdt(GArray *table_data, BIOSLinker *linker, GArray *table_offsets, build_rsdt(GArray *table_data, BIOSLinker *linker, GArray *table_offsets,

View File

@ -30,6 +30,7 @@
#include "hw/hw.h" #include "hw/hw.h"
#include "hw/i386/pc.h" #include "hw/i386/pc.h"
#include "hw/pci/pci.h" #include "hw/pci/pci.h"
#include "hw/pci/pci_bridge.h"
#include "hw/acpi/acpi.h" #include "hw/acpi/acpi.h"
#include "sysemu/sysemu.h" #include "sysemu/sysemu.h"
#include "exec/address-spaces.h" #include "exec/address-spaces.h"
@ -153,6 +154,7 @@ static bool acpi_pcihp_pc_no_hotplug(AcpiPciHpState *s, PCIDevice *dev)
static void acpi_pcihp_eject_slot(AcpiPciHpState *s, unsigned bsel, unsigned slots) static void acpi_pcihp_eject_slot(AcpiPciHpState *s, unsigned bsel, unsigned slots)
{ {
HotplugHandler *hotplug_ctrl;
BusChild *kid, *next; BusChild *kid, *next;
int slot = ctz32(slots); int slot = ctz32(slots);
PCIBus *bus = acpi_pcihp_find_hotplug_bus(s, bsel); PCIBus *bus = acpi_pcihp_find_hotplug_bus(s, bsel);
@ -170,7 +172,8 @@ static void acpi_pcihp_eject_slot(AcpiPciHpState *s, unsigned bsel, unsigned slo
PCIDevice *dev = PCI_DEVICE(qdev); PCIDevice *dev = PCI_DEVICE(qdev);
if (PCI_SLOT(dev->devfn) == slot) { if (PCI_SLOT(dev->devfn) == slot) {
if (!acpi_pcihp_pc_no_hotplug(s, dev)) { if (!acpi_pcihp_pc_no_hotplug(s, dev)) {
object_unparent(OBJECT(qdev)); hotplug_ctrl = qdev_get_hotplug_handler(qdev);
hotplug_handler_unplug(hotplug_ctrl, qdev, &error_abort);
} }
} }
} }
@ -217,31 +220,61 @@ void acpi_pcihp_reset(AcpiPciHpState *s)
acpi_pcihp_update(s); acpi_pcihp_update(s);
} }
void acpi_pcihp_device_pre_plug_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
/* Only hotplugged devices need the hotplug capability. */
if (dev->hotplugged &&
acpi_pcihp_get_bsel(pci_get_bus(PCI_DEVICE(dev))) < 0) {
error_setg(errp, "Unsupported bus. Bus doesn't have property '"
ACPI_PCIHP_PROP_BSEL "' set");
return;
}
}
void acpi_pcihp_device_plug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s, void acpi_pcihp_device_plug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s,
DeviceState *dev, Error **errp) DeviceState *dev, Error **errp)
{ {
PCIDevice *pdev = PCI_DEVICE(dev); PCIDevice *pdev = PCI_DEVICE(dev);
int slot = PCI_SLOT(pdev->devfn); int slot = PCI_SLOT(pdev->devfn);
int bsel = acpi_pcihp_get_bsel(pci_get_bus(pdev)); int bsel;
if (bsel < 0) {
error_setg(errp, "Unsupported bus. Bus doesn't have property '"
ACPI_PCIHP_PROP_BSEL "' set");
return;
}
/* Don't send event when device is enabled during qemu machine creation: /* Don't send event when device is enabled during qemu machine creation:
* it is present on boot, no hotplug event is necessary. We do send an * it is present on boot, no hotplug event is necessary. We do send an
* event when the device is disabled later. */ * event when the device is disabled later. */
if (!dev->hotplugged) { if (!dev->hotplugged) {
/*
* Overwrite the default hotplug handler with the ACPI PCI one
* for cold plugged bridges only.
*/
if (!s->legacy_piix &&
object_dynamic_cast(OBJECT(dev), TYPE_PCI_BRIDGE)) {
PCIBus *sec = pci_bridge_get_sec_bus(PCI_BRIDGE(pdev));
qbus_set_hotplug_handler(BUS(sec), DEVICE(hotplug_dev),
&error_abort);
/* We don't have to overwrite any other hotplug handler yet */
assert(QLIST_EMPTY(&sec->child));
}
return; return;
} }
bsel = acpi_pcihp_get_bsel(pci_get_bus(pdev));
g_assert(bsel >= 0);
s->acpi_pcihp_pci_status[bsel].up |= (1U << slot); s->acpi_pcihp_pci_status[bsel].up |= (1U << slot);
acpi_send_event(DEVICE(hotplug_dev), ACPI_PCI_HOTPLUG_STATUS); acpi_send_event(DEVICE(hotplug_dev), ACPI_PCI_HOTPLUG_STATUS);
} }
void acpi_pcihp_device_unplug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s, void acpi_pcihp_device_unplug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s,
DeviceState *dev, Error **errp) DeviceState *dev, Error **errp)
{
object_unparent(OBJECT(dev));
}
void acpi_pcihp_device_unplug_request_cb(HotplugHandler *hotplug_dev,
AcpiPciHpState *s, DeviceState *dev,
Error **errp)
{ {
PCIDevice *pdev = PCI_DEVICE(dev); PCIDevice *pdev = PCI_DEVICE(dev);
int slot = PCI_SLOT(pdev->devfn); int slot = PCI_SLOT(pdev->devfn);

View File

@ -173,6 +173,7 @@ static int vmstate_acpi_post_load(void *opaque, int version_id)
PIIX4PMState *s = opaque; PIIX4PMState *s = opaque;
pm_io_space_update(s); pm_io_space_update(s);
smbus_io_space_update(s);
return 0; return 0;
} }
@ -370,6 +371,18 @@ static void piix4_pm_powerdown_req(Notifier *n, void *opaque)
acpi_pm1_evt_power_down(&s->ar); acpi_pm1_evt_power_down(&s->ar);
} }
static void piix4_device_pre_plug_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
acpi_pcihp_device_pre_plug_cb(hotplug_dev, dev, errp);
} else if (!object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) &&
!object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
error_setg(errp, "acpi: device pre plug request for not supported"
" device type: %s", object_get_typename(OBJECT(dev)));
}
}
static void piix4_device_plug_cb(HotplugHandler *hotplug_dev, static void piix4_device_plug_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp) DeviceState *dev, Error **errp)
{ {
@ -392,8 +405,7 @@ static void piix4_device_plug_cb(HotplugHandler *hotplug_dev,
acpi_cpu_plug_cb(hotplug_dev, &s->cpuhp_state, dev, errp); acpi_cpu_plug_cb(hotplug_dev, &s->cpuhp_state, dev, errp);
} }
} else { } else {
error_setg(errp, "acpi: device plug request for not supported device" g_assert_not_reached();
" type: %s", object_get_typename(OBJECT(dev)));
} }
} }
@ -407,8 +419,8 @@ static void piix4_device_unplug_request_cb(HotplugHandler *hotplug_dev,
acpi_memory_unplug_request_cb(hotplug_dev, &s->acpi_memory_hotplug, acpi_memory_unplug_request_cb(hotplug_dev, &s->acpi_memory_hotplug,
dev, errp); dev, errp);
} else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) { } else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
acpi_pcihp_device_unplug_cb(hotplug_dev, &s->acpi_pci_hotplug, dev, acpi_pcihp_device_unplug_request_cb(hotplug_dev, &s->acpi_pci_hotplug,
errp); dev, errp);
} else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU) && } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU) &&
!s->cpu_hotplug_legacy) { !s->cpu_hotplug_legacy) {
acpi_cpu_unplug_request_cb(hotplug_dev, &s->cpuhp_state, dev, errp); acpi_cpu_unplug_request_cb(hotplug_dev, &s->cpuhp_state, dev, errp);
@ -426,6 +438,9 @@ static void piix4_device_unplug_cb(HotplugHandler *hotplug_dev,
if (s->acpi_memory_hotplug.is_enabled && if (s->acpi_memory_hotplug.is_enabled &&
object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
acpi_memory_unplug_cb(&s->acpi_memory_hotplug, dev, errp); acpi_memory_unplug_cb(&s->acpi_memory_hotplug, dev, errp);
} else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
acpi_pcihp_device_unplug_cb(hotplug_dev, &s->acpi_pci_hotplug, dev,
errp);
} else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU) && } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU) &&
!s->cpu_hotplug_legacy) { !s->cpu_hotplug_legacy) {
acpi_cpu_unplug_cb(&s->cpuhp_state, dev, errp); acpi_cpu_unplug_cb(&s->cpuhp_state, dev, errp);
@ -435,15 +450,6 @@ static void piix4_device_unplug_cb(HotplugHandler *hotplug_dev,
} }
} }
static void piix4_update_bus_hotplug(PCIBus *pci_bus, void *opaque)
{
PIIX4PMState *s = opaque;
/* pci_bus cannot outlive PIIX4PMState, because /machine keeps it alive
* and it's not hot-unpluggable */
qbus_set_hotplug_handler(BUS(pci_bus), DEVICE(s), &error_abort);
}
static void piix4_pm_machine_ready(Notifier *n, void *opaque) static void piix4_pm_machine_ready(Notifier *n, void *opaque)
{ {
PIIX4PMState *s = container_of(n, PIIX4PMState, machine_ready); PIIX4PMState *s = container_of(n, PIIX4PMState, machine_ready);
@ -457,12 +463,6 @@ static void piix4_pm_machine_ready(Notifier *n, void *opaque)
pci_conf[0x63] = 0x60; pci_conf[0x63] = 0x60;
pci_conf[0x67] = (memory_region_present(io_as, 0x3f8) ? 0x08 : 0) | pci_conf[0x67] = (memory_region_present(io_as, 0x3f8) ? 0x08 : 0) |
(memory_region_present(io_as, 0x2f8) ? 0x90 : 0); (memory_region_present(io_as, 0x2f8) ? 0x90 : 0);
if (s->use_acpi_pci_hotplug) {
pci_for_each_bus(pci_get_bus(d), piix4_update_bus_hotplug, s);
} else {
piix4_update_bus_hotplug(pci_get_bus(d), s);
}
} }
static void piix4_pm_add_propeties(PIIX4PMState *s) static void piix4_pm_add_propeties(PIIX4PMState *s)
@ -536,6 +536,7 @@ static void piix4_pm_realize(PCIDevice *dev, Error **errp)
piix4_acpi_system_hot_add_init(pci_address_space_io(dev), piix4_acpi_system_hot_add_init(pci_address_space_io(dev),
pci_get_bus(dev), s); pci_get_bus(dev), s);
qbus_set_hotplug_handler(BUS(pci_get_bus(dev)), DEVICE(s), &error_abort);
piix4_pm_add_propeties(s); piix4_pm_add_propeties(s);
} }
@ -702,6 +703,7 @@ static void piix4_pm_class_init(ObjectClass *klass, void *data)
*/ */
dc->user_creatable = false; dc->user_creatable = false;
dc->hotpluggable = false; dc->hotpluggable = false;
hc->pre_plug = piix4_device_pre_plug_cb;
hc->plug = piix4_device_plug_cb; hc->plug = piix4_device_plug_cb;
hc->unplug_request = piix4_device_unplug_request_cb; hc->unplug_request = piix4_device_unplug_request_cb;
hc->unplug = piix4_device_unplug_cb; hc->unplug = piix4_device_unplug_cb;

View File

@ -366,36 +366,6 @@ static void acpi_dsdt_add_power_button(Aml *scope)
aml_append(scope, dev); aml_append(scope, dev);
} }
/* RSDP */
static GArray *
build_rsdp(GArray *rsdp_table, BIOSLinker *linker, unsigned xsdt_tbl_offset)
{
AcpiRsdpDescriptor *rsdp = acpi_data_push(rsdp_table, sizeof *rsdp);
unsigned xsdt_pa_size = sizeof(rsdp->xsdt_physical_address);
unsigned xsdt_pa_offset =
(char *)&rsdp->xsdt_physical_address - rsdp_table->data;
bios_linker_loader_alloc(linker, ACPI_BUILD_RSDP_FILE, rsdp_table, 16,
true /* fseg memory */);
memcpy(&rsdp->signature, "RSD PTR ", sizeof(rsdp->signature));
memcpy(rsdp->oem_id, ACPI_BUILD_APPNAME6, sizeof(rsdp->oem_id));
rsdp->length = cpu_to_le32(sizeof(*rsdp));
rsdp->revision = 0x02;
/* Address to be filled by Guest linker */
bios_linker_loader_add_pointer(linker,
ACPI_BUILD_RSDP_FILE, xsdt_pa_offset, xsdt_pa_size,
ACPI_BUILD_TABLE_FILE, xsdt_tbl_offset);
/* Checksum to be filled by Guest linker */
bios_linker_loader_add_checksum(linker, ACPI_BUILD_RSDP_FILE,
(char *)rsdp - rsdp_table->data, sizeof *rsdp,
(char *)&rsdp->checksum - rsdp_table->data);
return rsdp_table;
}
static void static void
build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
{ {
@ -854,7 +824,15 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables)
build_xsdt(tables_blob, tables->linker, table_offsets, NULL, NULL); build_xsdt(tables_blob, tables->linker, table_offsets, NULL, NULL);
/* RSDP is in FSEG memory, so allocate it separately */ /* RSDP is in FSEG memory, so allocate it separately */
build_rsdp(tables->rsdp, tables->linker, xsdt); {
AcpiRsdpData rsdp_data = {
.revision = 2,
.oem_id = ACPI_BUILD_APPNAME6,
.xsdt_tbl_offset = &xsdt,
.rsdt_tbl_offset = NULL,
};
build_rsdp(tables->rsdp, tables->linker, &rsdp_data);
}
/* Cleanup memory that's no longer used. */ /* Cleanup memory that's no longer used. */
g_array_free(table_offsets, true); g_array_free(table_offsets, true);

View File

@ -55,7 +55,7 @@
#include "hw/intc/arm_gic.h" #include "hw/intc/arm_gic.h"
#include "hw/intc/arm_gicv3_common.h" #include "hw/intc/arm_gicv3_common.h"
#include "kvm_arm.h" #include "kvm_arm.h"
#include "hw/smbios/smbios.h" #include "hw/firmware/smbios.h"
#include "qapi/visitor.h" #include "qapi/visitor.h"
#include "standard-headers/linux/input.h" #include "standard-headers/linux/input.h"
#include "hw/arm/smmuv3.h" #include "hw/arm/smmuv3.h"

View File

@ -653,8 +653,10 @@ static void machine_class_base_init(ObjectClass *oc, void *data)
static void machine_initfn(Object *obj) static void machine_initfn(Object *obj)
{ {
MachineState *ms = MACHINE(obj); MachineState *ms = MACHINE(obj);
MachineClass *mc = MACHINE_GET_CLASS(obj);
ms->kernel_irqchip_allowed = true; ms->kernel_irqchip_allowed = true;
ms->kernel_irqchip_split = mc->default_kernel_irqchip_split;
ms->kvm_shadow_mem = -1; ms->kvm_shadow_mem = -1;
ms->dump_guest_core = true; ms->dump_guest_core = true;
ms->mem_merge = true; ms->mem_merge = true;

View File

@ -1297,3 +1297,179 @@ const PropertyInfo qdev_prop_off_auto_pcibar = {
.set = set_enum, .set = set_enum,
.set_default_value = set_default_value_enum, .set_default_value = set_default_value_enum,
}; };
/* --- PCIELinkSpeed 2_5/5/8/16 -- */
static void get_prop_pcielinkspeed(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
PCIExpLinkSpeed *p = qdev_get_prop_ptr(dev, prop);
int speed;
switch (*p) {
case QEMU_PCI_EXP_LNK_2_5GT:
speed = PCIE_LINK_SPEED_2_5;
break;
case QEMU_PCI_EXP_LNK_5GT:
speed = PCIE_LINK_SPEED_5;
break;
case QEMU_PCI_EXP_LNK_8GT:
speed = PCIE_LINK_SPEED_8;
break;
case QEMU_PCI_EXP_LNK_16GT:
speed = PCIE_LINK_SPEED_16;
break;
default:
/* Unreachable */
abort();
}
visit_type_enum(v, prop->name, &speed, prop->info->enum_table, errp);
}
static void set_prop_pcielinkspeed(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
PCIExpLinkSpeed *p = qdev_get_prop_ptr(dev, prop);
int speed;
Error *local_err = NULL;
if (dev->realized) {
qdev_prop_set_after_realize(dev, name, errp);
return;
}
visit_type_enum(v, prop->name, &speed, prop->info->enum_table, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
switch (speed) {
case PCIE_LINK_SPEED_2_5:
*p = QEMU_PCI_EXP_LNK_2_5GT;
break;
case PCIE_LINK_SPEED_5:
*p = QEMU_PCI_EXP_LNK_5GT;
break;
case PCIE_LINK_SPEED_8:
*p = QEMU_PCI_EXP_LNK_8GT;
break;
case PCIE_LINK_SPEED_16:
*p = QEMU_PCI_EXP_LNK_16GT;
break;
default:
/* Unreachable */
abort();
}
}
const PropertyInfo qdev_prop_pcie_link_speed = {
.name = "PCIELinkSpeed",
.description = "2_5/5/8/16",
.enum_table = &PCIELinkSpeed_lookup,
.get = get_prop_pcielinkspeed,
.set = set_prop_pcielinkspeed,
.set_default_value = set_default_value_enum,
};
/* --- PCIELinkWidth 1/2/4/8/12/16/32 -- */
static void get_prop_pcielinkwidth(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
PCIExpLinkWidth *p = qdev_get_prop_ptr(dev, prop);
int width;
switch (*p) {
case QEMU_PCI_EXP_LNK_X1:
width = PCIE_LINK_WIDTH_1;
break;
case QEMU_PCI_EXP_LNK_X2:
width = PCIE_LINK_WIDTH_2;
break;
case QEMU_PCI_EXP_LNK_X4:
width = PCIE_LINK_WIDTH_4;
break;
case QEMU_PCI_EXP_LNK_X8:
width = PCIE_LINK_WIDTH_8;
break;
case QEMU_PCI_EXP_LNK_X12:
width = PCIE_LINK_WIDTH_12;
break;
case QEMU_PCI_EXP_LNK_X16:
width = PCIE_LINK_WIDTH_16;
break;
case QEMU_PCI_EXP_LNK_X32:
width = PCIE_LINK_WIDTH_32;
break;
default:
/* Unreachable */
abort();
}
visit_type_enum(v, prop->name, &width, prop->info->enum_table, errp);
}
static void set_prop_pcielinkwidth(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
PCIExpLinkWidth *p = qdev_get_prop_ptr(dev, prop);
int width;
Error *local_err = NULL;
if (dev->realized) {
qdev_prop_set_after_realize(dev, name, errp);
return;
}
visit_type_enum(v, prop->name, &width, prop->info->enum_table, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
switch (width) {
case PCIE_LINK_WIDTH_1:
*p = QEMU_PCI_EXP_LNK_X1;
break;
case PCIE_LINK_WIDTH_2:
*p = QEMU_PCI_EXP_LNK_X2;
break;
case PCIE_LINK_WIDTH_4:
*p = QEMU_PCI_EXP_LNK_X4;
break;
case PCIE_LINK_WIDTH_8:
*p = QEMU_PCI_EXP_LNK_X8;
break;
case PCIE_LINK_WIDTH_12:
*p = QEMU_PCI_EXP_LNK_X12;
break;
case PCIE_LINK_WIDTH_16:
*p = QEMU_PCI_EXP_LNK_X16;
break;
case PCIE_LINK_WIDTH_32:
*p = QEMU_PCI_EXP_LNK_X32;
break;
default:
/* Unreachable */
abort();
}
}
const PropertyInfo qdev_prop_pcie_link_width = {
.name = "PCIELinkWidth",
.description = "1/2/4/8/12/16/32",
.enum_table = &PCIELinkWidth_lookup,
.get = get_prop_pcielinkwidth,
.set = set_prop_pcielinkwidth,
.set_default_value = set_default_value_enum,
};

View File

@ -69,9 +69,8 @@ static void virtio_gpu_initfn(Object *obj)
TYPE_VIRTIO_GPU); TYPE_VIRTIO_GPU);
} }
static const TypeInfo virtio_gpu_pci_info = { static const VirtioPCIDeviceTypeInfo virtio_gpu_pci_info = {
.name = TYPE_VIRTIO_GPU_PCI, .generic_name = TYPE_VIRTIO_GPU_PCI,
.parent = TYPE_VIRTIO_PCI,
.instance_size = sizeof(VirtIOGPUPCI), .instance_size = sizeof(VirtIOGPUPCI),
.instance_init = virtio_gpu_initfn, .instance_init = virtio_gpu_initfn,
.class_init = virtio_gpu_pci_class_init, .class_init = virtio_gpu_pci_class_init,
@ -79,6 +78,6 @@ static const TypeInfo virtio_gpu_pci_info = {
static void virtio_gpu_pci_register_types(void) static void virtio_gpu_pci_register_types(void)
{ {
type_register_static(&virtio_gpu_pci_info); virtio_pci_types_register(&virtio_gpu_pci_info);
} }
type_init(virtio_gpu_pci_register_types) type_init(virtio_gpu_pci_register_types)

View File

@ -207,9 +207,8 @@ static void virtio_vga_inst_initfn(Object *obj)
TYPE_VIRTIO_GPU); TYPE_VIRTIO_GPU);
} }
static TypeInfo virtio_vga_info = { static VirtioPCIDeviceTypeInfo virtio_vga_info = {
.name = TYPE_VIRTIO_VGA, .generic_name = TYPE_VIRTIO_VGA,
.parent = TYPE_VIRTIO_PCI,
.instance_size = sizeof(struct VirtIOVGA), .instance_size = sizeof(struct VirtIOVGA),
.instance_init = virtio_vga_inst_initfn, .instance_init = virtio_vga_inst_initfn,
.class_init = virtio_vga_class_init, .class_init = virtio_vga_class_init,
@ -217,7 +216,7 @@ static TypeInfo virtio_vga_info = {
static void virtio_vga_register_types(void) static void virtio_vga_register_types(void)
{ {
type_register_static(&virtio_vga_info); virtio_pci_types_register(&virtio_vga_info);
} }
type_init(virtio_vga_register_types) type_init(virtio_vga_register_types)

View File

@ -2426,7 +2426,7 @@ build_dmar_q35(GArray *table_data, BIOSLinker *linker)
IntelIOMMUState *intel_iommu = INTEL_IOMMU_DEVICE(iommu); IntelIOMMUState *intel_iommu = INTEL_IOMMU_DEVICE(iommu);
assert(iommu); assert(iommu);
if (iommu->intr_supported) { if (x86_iommu_ir_supported(iommu)) {
dmar_flags |= 0x1; /* Flags: 0x1: INT_REMAP */ dmar_flags |= 0x1; /* Flags: 0x1: INT_REMAP */
} }
@ -2499,7 +2499,7 @@ build_amd_iommu(GArray *table_data, BIOSLinker *linker)
* When interrupt remapping is supported, we add a special IVHD device * When interrupt remapping is supported, we add a special IVHD device
* for type IO-APIC. * for type IO-APIC.
*/ */
if (x86_iommu_get_default()->intr_supported) { if (x86_iommu_ir_supported(x86_iommu_get_default())) {
ivhd_table_len += 8; ivhd_table_len += 8;
} }
/* IVHD length */ /* IVHD length */
@ -2535,7 +2535,7 @@ build_amd_iommu(GArray *table_data, BIOSLinker *linker)
* Linux IOMMU driver checks for the special IVHD device (type IO-APIC). * Linux IOMMU driver checks for the special IVHD device (type IO-APIC).
* See Linux kernel commit 'c2ff5cf5294bcbd7fa50f7d860e90a66db7e5059' * See Linux kernel commit 'c2ff5cf5294bcbd7fa50f7d860e90a66db7e5059'
*/ */
if (x86_iommu_get_default()->intr_supported) { if (x86_iommu_ir_supported(x86_iommu_get_default())) {
build_append_int_noprefix(table_data, build_append_int_noprefix(table_data,
(0x1ull << 56) | /* type IOAPIC */ (0x1ull << 56) | /* type IOAPIC */
(IOAPIC_SB_DEVID << 40) | /* IOAPIC devid */ (IOAPIC_SB_DEVID << 40) | /* IOAPIC devid */
@ -2547,32 +2547,6 @@ build_amd_iommu(GArray *table_data, BIOSLinker *linker)
"IVRS", table_data->len - iommu_start, 1, NULL, NULL); "IVRS", table_data->len - iommu_start, 1, NULL, NULL);
} }
static GArray *
build_rsdp(GArray *rsdp_table, BIOSLinker *linker, unsigned rsdt_tbl_offset)
{
AcpiRsdpDescriptor *rsdp = acpi_data_push(rsdp_table, sizeof *rsdp);
unsigned rsdt_pa_size = sizeof(rsdp->rsdt_physical_address);
unsigned rsdt_pa_offset =
(char *)&rsdp->rsdt_physical_address - rsdp_table->data;
bios_linker_loader_alloc(linker, ACPI_BUILD_RSDP_FILE, rsdp_table, 16,
true /* fseg memory */);
memcpy(&rsdp->signature, "RSD PTR ", 8);
memcpy(rsdp->oem_id, ACPI_BUILD_APPNAME6, 6);
/* Address to be filled by Guest linker */
bios_linker_loader_add_pointer(linker,
ACPI_BUILD_RSDP_FILE, rsdt_pa_offset, rsdt_pa_size,
ACPI_BUILD_TABLE_FILE, rsdt_tbl_offset);
/* Checksum to be filled by Guest linker */
bios_linker_loader_add_checksum(linker, ACPI_BUILD_RSDP_FILE,
(char *)rsdp - rsdp_table->data, sizeof *rsdp,
(char *)&rsdp->checksum - rsdp_table->data);
return rsdp_table;
}
typedef typedef
struct AcpiBuildState { struct AcpiBuildState {
/* Copy of table in RAM (for patching). */ /* Copy of table in RAM (for patching). */
@ -2729,7 +2703,25 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine)
slic_oem.id, slic_oem.table_id); slic_oem.id, slic_oem.table_id);
/* RSDP is in FSEG memory, so allocate it separately */ /* RSDP is in FSEG memory, so allocate it separately */
build_rsdp(tables->rsdp, tables->linker, rsdt); {
AcpiRsdpData rsdp_data = {
.revision = 0,
.oem_id = ACPI_BUILD_APPNAME6,
.xsdt_tbl_offset = NULL,
.rsdt_tbl_offset = &rsdt,
};
build_rsdp(tables->rsdp, tables->linker, &rsdp_data);
if (!pcmc->rsdp_in_ram) {
/* We used to allocate some extra space for RSDP revision 2 but
* only used the RSDP revision 0 space. The extra bytes were
* zeroed out and not used.
* Here we continue wasting those extra 16 bytes to make sure we
* don't break migration for machine types 2.2 and older due to
* RSDP blob size mismatch.
*/
build_append_int_noprefix(tables->rsdp, 0, 16);
}
}
/* We'll expose it all to Guest so we want to reduce /* We'll expose it all to Guest so we want to reduce
* chance of size changes. * chance of size changes.

View File

@ -1233,7 +1233,7 @@ static int amdvi_int_remap_msi(AMDVIState *iommu,
} }
/* validate that we are configure with intremap=on */ /* validate that we are configure with intremap=on */
if (!X86_IOMMU_DEVICE(iommu)->intr_supported) { if (!x86_iommu_ir_supported(X86_IOMMU_DEVICE(iommu))) {
trace_amdvi_err("Interrupt remapping is enabled in the guest but " trace_amdvi_err("Interrupt remapping is enabled in the guest but "
"not in the host. Use intremap=on to enable interrupt " "not in the host. Use intremap=on to enable interrupt "
"remapping in amd-iommu."); "remapping in amd-iommu.");

View File

@ -524,7 +524,6 @@ static int vtd_get_root_entry(IntelIOMMUState *s, uint8_t index,
addr = s->root + index * sizeof(*re); addr = s->root + index * sizeof(*re);
if (dma_memory_read(&address_space_memory, addr, re, sizeof(*re))) { if (dma_memory_read(&address_space_memory, addr, re, sizeof(*re))) {
trace_vtd_re_invalid(re->rsvd, re->val);
re->val = 0; re->val = 0;
return -VTD_FR_ROOT_TABLE_INV; return -VTD_FR_ROOT_TABLE_INV;
} }
@ -545,7 +544,6 @@ static int vtd_get_context_entry_from_root(VTDRootEntry *root, uint8_t index,
/* we have checked that root entry is present */ /* we have checked that root entry is present */
addr = (root->val & VTD_ROOT_ENTRY_CTP) + index * sizeof(*ce); addr = (root->val & VTD_ROOT_ENTRY_CTP) + index * sizeof(*ce);
if (dma_memory_read(&address_space_memory, addr, ce, sizeof(*ce))) { if (dma_memory_read(&address_space_memory, addr, ce, sizeof(*ce))) {
trace_vtd_re_invalid(root->rsvd, root->val);
return -VTD_FR_CONTEXT_TABLE_INV; return -VTD_FR_CONTEXT_TABLE_INV;
} }
ce->lo = le64_to_cpu(ce->lo); ce->lo = le64_to_cpu(ce->lo);
@ -630,16 +628,20 @@ static inline bool vtd_ce_type_check(X86IOMMUState *x86_iommu,
break; break;
case VTD_CONTEXT_TT_DEV_IOTLB: case VTD_CONTEXT_TT_DEV_IOTLB:
if (!x86_iommu->dt_supported) { if (!x86_iommu->dt_supported) {
error_report_once("%s: DT specified but not supported", __func__);
return false; return false;
} }
break; break;
case VTD_CONTEXT_TT_PASS_THROUGH: case VTD_CONTEXT_TT_PASS_THROUGH:
if (!x86_iommu->pt_supported) { if (!x86_iommu->pt_supported) {
error_report_once("%s: PT specified but not supported", __func__);
return false; return false;
} }
break; break;
default: default:
/* Unknwon type */ /* Unknwon type */
error_report_once("%s: unknown ce type: %"PRIu32, __func__,
vtd_ce_get_type(ce));
return false; return false;
} }
return true; return true;
@ -1003,7 +1005,9 @@ static int vtd_dev_to_context_entry(IntelIOMMUState *s, uint8_t bus_num,
} }
if (re.rsvd || (re.val & VTD_ROOT_ENTRY_RSVD(s->aw_bits))) { if (re.rsvd || (re.val & VTD_ROOT_ENTRY_RSVD(s->aw_bits))) {
trace_vtd_re_invalid(re.rsvd, re.val); error_report_once("%s: invalid root entry: rsvd=0x%"PRIx64
", val=0x%"PRIx64" (reserved nonzero)",
__func__, re.rsvd, re.val);
return -VTD_FR_ROOT_ENTRY_RSVD; return -VTD_FR_ROOT_ENTRY_RSVD;
} }
@ -1020,19 +1024,23 @@ static int vtd_dev_to_context_entry(IntelIOMMUState *s, uint8_t bus_num,
if ((ce->hi & VTD_CONTEXT_ENTRY_RSVD_HI) || if ((ce->hi & VTD_CONTEXT_ENTRY_RSVD_HI) ||
(ce->lo & VTD_CONTEXT_ENTRY_RSVD_LO(s->aw_bits))) { (ce->lo & VTD_CONTEXT_ENTRY_RSVD_LO(s->aw_bits))) {
trace_vtd_ce_invalid(ce->hi, ce->lo); error_report_once("%s: invalid context entry: hi=%"PRIx64
", lo=%"PRIx64" (reserved nonzero)",
__func__, ce->hi, ce->lo);
return -VTD_FR_CONTEXT_ENTRY_RSVD; return -VTD_FR_CONTEXT_ENTRY_RSVD;
} }
/* Check if the programming of context-entry is valid */ /* Check if the programming of context-entry is valid */
if (!vtd_is_level_supported(s, vtd_ce_get_level(ce))) { if (!vtd_is_level_supported(s, vtd_ce_get_level(ce))) {
trace_vtd_ce_invalid(ce->hi, ce->lo); error_report_once("%s: invalid context entry: hi=%"PRIx64
", lo=%"PRIx64" (level %d not supported)",
__func__, ce->hi, ce->lo, vtd_ce_get_level(ce));
return -VTD_FR_CONTEXT_ENTRY_INV; return -VTD_FR_CONTEXT_ENTRY_INV;
} }
/* Do translation type check */ /* Do translation type check */
if (!vtd_ce_type_check(x86_iommu, ce)) { if (!vtd_ce_type_check(x86_iommu, ce)) {
trace_vtd_ce_invalid(ce->hi, ce->lo); /* Errors dumped in vtd_ce_type_check() */
return -VTD_FR_CONTEXT_ENTRY_INV; return -VTD_FR_CONTEXT_ENTRY_INV;
} }
@ -1878,7 +1886,9 @@ static bool vtd_process_wait_desc(IntelIOMMUState *s, VTDInvDesc *inv_desc)
{ {
if ((inv_desc->hi & VTD_INV_DESC_WAIT_RSVD_HI) || if ((inv_desc->hi & VTD_INV_DESC_WAIT_RSVD_HI) ||
(inv_desc->lo & VTD_INV_DESC_WAIT_RSVD_LO)) { (inv_desc->lo & VTD_INV_DESC_WAIT_RSVD_LO)) {
trace_vtd_inv_desc_wait_invalid(inv_desc->hi, inv_desc->lo); error_report_once("%s: invalid wait desc: hi=%"PRIx64", lo=%"PRIx64
" (reserved nonzero)", __func__, inv_desc->hi,
inv_desc->lo);
return false; return false;
} }
if (inv_desc->lo & VTD_INV_DESC_WAIT_SW) { if (inv_desc->lo & VTD_INV_DESC_WAIT_SW) {
@ -1901,7 +1911,9 @@ static bool vtd_process_wait_desc(IntelIOMMUState *s, VTDInvDesc *inv_desc)
/* Interrupt flag */ /* Interrupt flag */
vtd_generate_completion_event(s); vtd_generate_completion_event(s);
} else { } else {
trace_vtd_inv_desc_wait_invalid(inv_desc->hi, inv_desc->lo); error_report_once("%s: invalid wait desc: hi=%"PRIx64", lo=%"PRIx64
" (unknown type)", __func__, inv_desc->hi,
inv_desc->lo);
return false; return false;
} }
return true; return true;
@ -1913,7 +1925,9 @@ static bool vtd_process_context_cache_desc(IntelIOMMUState *s,
uint16_t sid, fmask; uint16_t sid, fmask;
if ((inv_desc->lo & VTD_INV_DESC_CC_RSVD) || inv_desc->hi) { if ((inv_desc->lo & VTD_INV_DESC_CC_RSVD) || inv_desc->hi) {
trace_vtd_inv_desc_cc_invalid(inv_desc->hi, inv_desc->lo); error_report_once("%s: invalid cc inv desc: hi=%"PRIx64", lo=%"PRIx64
" (reserved nonzero)", __func__, inv_desc->hi,
inv_desc->lo);
return false; return false;
} }
switch (inv_desc->lo & VTD_INV_DESC_CC_G) { switch (inv_desc->lo & VTD_INV_DESC_CC_G) {
@ -1932,7 +1946,9 @@ static bool vtd_process_context_cache_desc(IntelIOMMUState *s,
break; break;
default: default:
trace_vtd_inv_desc_cc_invalid(inv_desc->hi, inv_desc->lo); error_report_once("%s: invalid cc inv desc: hi=%"PRIx64", lo=%"PRIx64
" (invalid type)", __func__, inv_desc->hi,
inv_desc->lo);
return false; return false;
} }
return true; return true;
@ -1946,7 +1962,9 @@ static bool vtd_process_iotlb_desc(IntelIOMMUState *s, VTDInvDesc *inv_desc)
if ((inv_desc->lo & VTD_INV_DESC_IOTLB_RSVD_LO) || if ((inv_desc->lo & VTD_INV_DESC_IOTLB_RSVD_LO) ||
(inv_desc->hi & VTD_INV_DESC_IOTLB_RSVD_HI)) { (inv_desc->hi & VTD_INV_DESC_IOTLB_RSVD_HI)) {
trace_vtd_inv_desc_iotlb_invalid(inv_desc->hi, inv_desc->lo); error_report_once("%s: invalid iotlb inv desc: hi=0x%"PRIx64
", lo=0x%"PRIx64" (reserved bits unzero)\n",
__func__, inv_desc->hi, inv_desc->lo);
return false; return false;
} }
@ -1965,14 +1983,20 @@ static bool vtd_process_iotlb_desc(IntelIOMMUState *s, VTDInvDesc *inv_desc)
addr = VTD_INV_DESC_IOTLB_ADDR(inv_desc->hi); addr = VTD_INV_DESC_IOTLB_ADDR(inv_desc->hi);
am = VTD_INV_DESC_IOTLB_AM(inv_desc->hi); am = VTD_INV_DESC_IOTLB_AM(inv_desc->hi);
if (am > VTD_MAMV) { if (am > VTD_MAMV) {
trace_vtd_inv_desc_iotlb_invalid(inv_desc->hi, inv_desc->lo); error_report_once("%s: invalid iotlb inv desc: hi=0x%"PRIx64
", lo=0x%"PRIx64" (am=%u > VTD_MAMV=%u)\n",
__func__, inv_desc->hi, inv_desc->lo,
am, (unsigned)VTD_MAMV);
return false; return false;
} }
vtd_iotlb_page_invalidate(s, domain_id, addr, am); vtd_iotlb_page_invalidate(s, domain_id, addr, am);
break; break;
default: default:
trace_vtd_inv_desc_iotlb_invalid(inv_desc->hi, inv_desc->lo); error_report_once("%s: invalid iotlb inv desc: hi=0x%"PRIx64
", lo=0x%"PRIx64" (type mismatch: 0x%llx)\n",
__func__, inv_desc->hi, inv_desc->lo,
inv_desc->lo & VTD_INV_DESC_IOTLB_G);
return false; return false;
} }
return true; return true;
@ -2012,7 +2036,9 @@ static bool vtd_process_device_iotlb_desc(IntelIOMMUState *s,
if ((inv_desc->lo & VTD_INV_DESC_DEVICE_IOTLB_RSVD_LO) || if ((inv_desc->lo & VTD_INV_DESC_DEVICE_IOTLB_RSVD_LO) ||
(inv_desc->hi & VTD_INV_DESC_DEVICE_IOTLB_RSVD_HI)) { (inv_desc->hi & VTD_INV_DESC_DEVICE_IOTLB_RSVD_HI)) {
trace_vtd_inv_desc_iotlb_invalid(inv_desc->hi, inv_desc->lo); error_report_once("%s: invalid dev-iotlb inv desc: hi=%"PRIx64
", lo=%"PRIx64" (reserved nonzero)", __func__,
inv_desc->hi, inv_desc->lo);
return false; return false;
} }
@ -2103,7 +2129,9 @@ static bool vtd_process_inv_desc(IntelIOMMUState *s)
break; break;
default: default:
trace_vtd_inv_desc_invalid(inv_desc.hi, inv_desc.lo); error_report_once("%s: invalid inv desc: hi=%"PRIx64", lo=%"PRIx64
" (unknown type)", __func__, inv_desc.hi,
inv_desc.lo);
return false; return false;
} }
s->iq_head++; s->iq_head++;
@ -2540,7 +2568,7 @@ static IOMMUTLBEntry vtd_iommu_translate(IOMMUMemoryRegion *iommu, hwaddr addr,
__func__, pci_bus_num(vtd_as->bus), __func__, pci_bus_num(vtd_as->bus),
VTD_PCI_SLOT(vtd_as->devfn), VTD_PCI_SLOT(vtd_as->devfn),
VTD_PCI_FUNC(vtd_as->devfn), VTD_PCI_FUNC(vtd_as->devfn),
iotlb.iova); addr);
} }
return iotlb; return iotlb;
@ -2628,9 +2656,10 @@ static Property vtd_properties[] = {
DEFINE_PROP_ON_OFF_AUTO("eim", IntelIOMMUState, intr_eim, DEFINE_PROP_ON_OFF_AUTO("eim", IntelIOMMUState, intr_eim,
ON_OFF_AUTO_AUTO), ON_OFF_AUTO_AUTO),
DEFINE_PROP_BOOL("x-buggy-eim", IntelIOMMUState, buggy_eim, false), DEFINE_PROP_BOOL("x-buggy-eim", IntelIOMMUState, buggy_eim, false),
DEFINE_PROP_UINT8("x-aw-bits", IntelIOMMUState, aw_bits, DEFINE_PROP_UINT8("aw-bits", IntelIOMMUState, aw_bits,
VTD_HOST_ADDRESS_WIDTH), VTD_HOST_ADDRESS_WIDTH),
DEFINE_PROP_BOOL("caching-mode", IntelIOMMUState, caching_mode, FALSE), DEFINE_PROP_BOOL("caching-mode", IntelIOMMUState, caching_mode, FALSE),
DEFINE_PROP_BOOL("dma-drain", IntelIOMMUState, dma_drain, true),
DEFINE_PROP_END_OF_LIST(), DEFINE_PROP_END_OF_LIST(),
}; };
@ -3119,6 +3148,9 @@ static void vtd_init(IntelIOMMUState *s)
s->cap = VTD_CAP_FRO | VTD_CAP_NFR | VTD_CAP_ND | s->cap = VTD_CAP_FRO | VTD_CAP_NFR | VTD_CAP_ND |
VTD_CAP_MAMV | VTD_CAP_PSI | VTD_CAP_SLLPS | VTD_CAP_MAMV | VTD_CAP_PSI | VTD_CAP_SLLPS |
VTD_CAP_SAGAW_39bit | VTD_CAP_MGAW(s->aw_bits); VTD_CAP_SAGAW_39bit | VTD_CAP_MGAW(s->aw_bits);
if (s->dma_drain) {
s->cap |= VTD_CAP_DRAIN;
}
if (s->aw_bits == VTD_HOST_AW_48BIT) { if (s->aw_bits == VTD_HOST_AW_48BIT) {
s->cap |= VTD_CAP_SAGAW_48bit; s->cap |= VTD_CAP_SAGAW_48bit;
} }
@ -3137,7 +3169,7 @@ static void vtd_init(IntelIOMMUState *s)
vtd_paging_entry_rsvd_field[7] = VTD_SPTE_LPAGE_L3_RSVD_MASK(s->aw_bits); vtd_paging_entry_rsvd_field[7] = VTD_SPTE_LPAGE_L3_RSVD_MASK(s->aw_bits);
vtd_paging_entry_rsvd_field[8] = VTD_SPTE_LPAGE_L4_RSVD_MASK(s->aw_bits); vtd_paging_entry_rsvd_field[8] = VTD_SPTE_LPAGE_L4_RSVD_MASK(s->aw_bits);
if (x86_iommu->intr_supported) { if (x86_iommu_ir_supported(x86_iommu)) {
s->ecap |= VTD_ECAP_IR | VTD_ECAP_MHMV; s->ecap |= VTD_ECAP_IR | VTD_ECAP_MHMV;
if (s->intr_eim == ON_OFF_AUTO_ON) { if (s->intr_eim == ON_OFF_AUTO_ON) {
s->ecap |= VTD_ECAP_EIM; s->ecap |= VTD_ECAP_EIM;
@ -3238,14 +3270,14 @@ static bool vtd_decide_config(IntelIOMMUState *s, Error **errp)
{ {
X86IOMMUState *x86_iommu = X86_IOMMU_DEVICE(s); X86IOMMUState *x86_iommu = X86_IOMMU_DEVICE(s);
if (s->intr_eim == ON_OFF_AUTO_ON && !x86_iommu->intr_supported) { if (s->intr_eim == ON_OFF_AUTO_ON && !x86_iommu_ir_supported(x86_iommu)) {
error_setg(errp, "eim=on cannot be selected without intremap=on"); error_setg(errp, "eim=on cannot be selected without intremap=on");
return false; return false;
} }
if (s->intr_eim == ON_OFF_AUTO_AUTO) { if (s->intr_eim == ON_OFF_AUTO_AUTO) {
s->intr_eim = (kvm_irqchip_in_kernel() || s->buggy_eim) s->intr_eim = (kvm_irqchip_in_kernel() || s->buggy_eim)
&& x86_iommu->intr_supported ? && x86_iommu_ir_supported(x86_iommu) ?
ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF; ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF;
} }
if (s->intr_eim == ON_OFF_AUTO_ON && !s->buggy_eim) { if (s->intr_eim == ON_OFF_AUTO_ON && !s->buggy_eim) {

View File

@ -203,6 +203,9 @@
#define VTD_CAP_MAMV (VTD_MAMV << 48) #define VTD_CAP_MAMV (VTD_MAMV << 48)
#define VTD_CAP_PSI (1ULL << 39) #define VTD_CAP_PSI (1ULL << 39)
#define VTD_CAP_SLLPS ((1ULL << 34) | (1ULL << 35)) #define VTD_CAP_SLLPS ((1ULL << 34) | (1ULL << 35))
#define VTD_CAP_DRAIN_WRITE (1ULL << 54)
#define VTD_CAP_DRAIN_READ (1ULL << 55)
#define VTD_CAP_DRAIN (VTD_CAP_DRAIN_READ | VTD_CAP_DRAIN_WRITE)
#define VTD_CAP_CM (1ULL << 7) #define VTD_CAP_CM (1ULL << 7)
/* Supported Adjusted Guest Address Widths */ /* Supported Adjusted Guest Address Widths */

View File

@ -37,7 +37,7 @@
#include "hw/pci/pci_bus.h" #include "hw/pci/pci_bus.h"
#include "hw/nvram/fw_cfg.h" #include "hw/nvram/fw_cfg.h"
#include "hw/timer/hpet.h" #include "hw/timer/hpet.h"
#include "hw/smbios/smbios.h" #include "hw/firmware/smbios.h"
#include "hw/loader.h" #include "hw/loader.h"
#include "elf.h" #include "elf.h"
#include "multiboot.h" #include "multiboot.h"
@ -1244,7 +1244,7 @@ void pc_machine_done(Notifier *notifier, void *data)
if (pcms->apic_id_limit > 255 && !xen_enabled()) { if (pcms->apic_id_limit > 255 && !xen_enabled()) {
IntelIOMMUState *iommu = INTEL_IOMMU_DEVICE(x86_iommu_get_default()); IntelIOMMUState *iommu = INTEL_IOMMU_DEVICE(x86_iommu_get_default());
if (!iommu || !iommu->x86_iommu.intr_supported || if (!iommu || !x86_iommu_ir_supported(X86_IOMMU_DEVICE(iommu)) ||
iommu->intr_eim != ON_OFF_AUTO_ON) { iommu->intr_eim != ON_OFF_AUTO_ON) {
error_report("current -smp configuration requires " error_report("current -smp configuration requires "
"Extended Interrupt Mode enabled. " "Extended Interrupt Mode enabled. "

View File

@ -30,7 +30,7 @@
#include "hw/i386/pc.h" #include "hw/i386/pc.h"
#include "hw/i386/apic.h" #include "hw/i386/apic.h"
#include "hw/display/ramfb.h" #include "hw/display/ramfb.h"
#include "hw/smbios/smbios.h" #include "hw/firmware/smbios.h"
#include "hw/pci/pci.h" #include "hw/pci/pci.h"
#include "hw/pci/pci_ids.h" #include "hw/pci/pci_ids.h"
#include "hw/usb.h" #include "hw/usb.h"
@ -368,7 +368,7 @@ static void pc_compat_1_2(MachineState *machine)
x86_cpu_change_kvm_default("kvm-pv-eoi", NULL); x86_cpu_change_kvm_default("kvm-pv-eoi", NULL);
} }
/* PC compat function for pc-0.10 to pc-0.13 */ /* PC compat function for pc-0.12 and pc-0.13 */
static void pc_compat_0_13(MachineState *machine) static void pc_compat_0_13(MachineState *machine)
{ {
pc_compat_1_2(machine); pc_compat_1_2(machine);
@ -834,6 +834,7 @@ static void pc_i440fx_0_15_machine_options(MachineClass *m)
{ {
pc_i440fx_1_0_machine_options(m); pc_i440fx_1_0_machine_options(m);
m->hw_version = "0.15"; m->hw_version = "0.15";
m->deprecation_reason = "use a newer machine type instead";
SET_MACHINE_COMPAT(m, PC_COMPAT_0_15); SET_MACHINE_COMPAT(m, PC_COMPAT_0_15);
} }
@ -951,73 +952,6 @@ static void pc_i440fx_0_12_machine_options(MachineClass *m)
DEFINE_I440FX_MACHINE(v0_12, "pc-0.12", pc_compat_0_13, DEFINE_I440FX_MACHINE(v0_12, "pc-0.12", pc_compat_0_13,
pc_i440fx_0_12_machine_options); pc_i440fx_0_12_machine_options);
#define PC_COMPAT_0_11 \
PC_CPU_MODEL_IDS("0.11") \
{\
.driver = "virtio-blk-pci",\
.property = "vectors",\
.value = stringify(0),\
},{\
.driver = TYPE_PCI_DEVICE,\
.property = "rombar",\
.value = stringify(0),\
},{\
.driver = "ide-drive",\
.property = "ver",\
.value = "0.11",\
},{\
.driver = "scsi-disk",\
.property = "ver",\
.value = "0.11",\
},
static void pc_i440fx_0_11_machine_options(MachineClass *m)
{
pc_i440fx_0_12_machine_options(m);
m->hw_version = "0.11";
m->deprecation_reason = "use a newer machine type instead";
SET_MACHINE_COMPAT(m, PC_COMPAT_0_11);
}
DEFINE_I440FX_MACHINE(v0_11, "pc-0.11", pc_compat_0_13,
pc_i440fx_0_11_machine_options);
#define PC_COMPAT_0_10 \
PC_CPU_MODEL_IDS("0.10") \
{\
.driver = "virtio-blk-pci",\
.property = "class",\
.value = stringify(PCI_CLASS_STORAGE_OTHER),\
},{\
.driver = "virtio-serial-pci",\
.property = "class",\
.value = stringify(PCI_CLASS_DISPLAY_OTHER),\
},{\
.driver = "virtio-net-pci",\
.property = "vectors",\
.value = stringify(0),\
},{\
.driver = "ide-drive",\
.property = "ver",\
.value = "0.10",\
},{\
.driver = "scsi-disk",\
.property = "ver",\
.value = "0.10",\
},
static void pc_i440fx_0_10_machine_options(MachineClass *m)
{
pc_i440fx_0_11_machine_options(m);
m->hw_version = "0.10";
SET_MACHINE_COMPAT(m, PC_COMPAT_0_10);
}
DEFINE_I440FX_MACHINE(v0_10, "pc-0.10", pc_compat_0_13,
pc_i440fx_0_10_machine_options);
typedef struct { typedef struct {
uint16_t gpu_device_id; uint16_t gpu_device_id;
uint16_t pch_device_id; uint16_t pch_device_id;

View File

@ -47,7 +47,7 @@
#include "hw/i386/amd_iommu.h" #include "hw/i386/amd_iommu.h"
#include "hw/i386/intel_iommu.h" #include "hw/i386/intel_iommu.h"
#include "hw/display/ramfb.h" #include "hw/display/ramfb.h"
#include "hw/smbios/smbios.h" #include "hw/firmware/smbios.h"
#include "hw/ide/pci.h" #include "hw/ide/pci.h"
#include "hw/ide/ahci.h" #include "hw/ide/ahci.h"
#include "hw/usb.h" #include "hw/usb.h"
@ -304,6 +304,7 @@ static void pc_q35_machine_options(MachineClass *m)
m->units_per_default_bus = 1; m->units_per_default_bus = 1;
m->default_machine_opts = "firmware=bios-256k.bin"; m->default_machine_opts = "firmware=bios-256k.bin";
m->default_display = "std"; m->default_display = "std";
m->default_kernel_irqchip_split = true;
m->no_floppy = 1; m->no_floppy = 1;
machine_class_allow_dynamic_sysbus_dev(m, TYPE_AMD_IOMMU_DEVICE); machine_class_allow_dynamic_sysbus_dev(m, TYPE_AMD_IOMMU_DEVICE);
machine_class_allow_dynamic_sysbus_dev(m, TYPE_INTEL_IOMMU_DEVICE); machine_class_allow_dynamic_sysbus_dev(m, TYPE_INTEL_IOMMU_DEVICE);
@ -323,6 +324,7 @@ DEFINE_Q35_MACHINE(v4_0, "pc-q35-4.0", NULL,
static void pc_q35_3_1_machine_options(MachineClass *m) static void pc_q35_3_1_machine_options(MachineClass *m)
{ {
pc_q35_4_0_machine_options(m); pc_q35_4_0_machine_options(m);
m->default_kernel_irqchip_split = false;
m->alias = NULL; m->alias = NULL;
SET_MACHINE_COMPAT(m, PC_COMPAT_3_1); SET_MACHINE_COMPAT(m, PC_COMPAT_3_1);
} }

View File

@ -5,19 +5,15 @@ x86_iommu_iec_notify(bool global, uint32_t index, uint32_t mask) "Notify IEC inv
# hw/i386/intel_iommu.c # hw/i386/intel_iommu.c
vtd_inv_desc(const char *type, uint64_t hi, uint64_t lo) "invalidate desc type %s high 0x%"PRIx64" low 0x%"PRIx64 vtd_inv_desc(const char *type, uint64_t hi, uint64_t lo) "invalidate desc type %s high 0x%"PRIx64" low 0x%"PRIx64
vtd_inv_desc_invalid(uint64_t hi, uint64_t lo) "invalid inv desc hi 0x%"PRIx64" lo 0x%"PRIx64
vtd_inv_desc_cc_domain(uint16_t domain) "context invalidate domain 0x%"PRIx16 vtd_inv_desc_cc_domain(uint16_t domain) "context invalidate domain 0x%"PRIx16
vtd_inv_desc_cc_global(void) "context invalidate globally" vtd_inv_desc_cc_global(void) "context invalidate globally"
vtd_inv_desc_cc_device(uint8_t bus, uint8_t dev, uint8_t fn) "context invalidate device %02"PRIx8":%02"PRIx8".%02"PRIx8 vtd_inv_desc_cc_device(uint8_t bus, uint8_t dev, uint8_t fn) "context invalidate device %02"PRIx8":%02"PRIx8".%02"PRIx8
vtd_inv_desc_cc_devices(uint16_t sid, uint16_t fmask) "context invalidate devices sid 0x%"PRIx16" fmask 0x%"PRIx16 vtd_inv_desc_cc_devices(uint16_t sid, uint16_t fmask) "context invalidate devices sid 0x%"PRIx16" fmask 0x%"PRIx16
vtd_inv_desc_cc_invalid(uint64_t hi, uint64_t lo) "invalid context-cache desc hi 0x%"PRIx64" lo 0x%"PRIx64
vtd_inv_desc_iotlb_global(void) "iotlb invalidate global" vtd_inv_desc_iotlb_global(void) "iotlb invalidate global"
vtd_inv_desc_iotlb_domain(uint16_t domain) "iotlb invalidate whole domain 0x%"PRIx16 vtd_inv_desc_iotlb_domain(uint16_t domain) "iotlb invalidate whole domain 0x%"PRIx16
vtd_inv_desc_iotlb_pages(uint16_t domain, uint64_t addr, uint8_t mask) "iotlb invalidate domain 0x%"PRIx16" addr 0x%"PRIx64" mask 0x%"PRIx8 vtd_inv_desc_iotlb_pages(uint16_t domain, uint64_t addr, uint8_t mask) "iotlb invalidate domain 0x%"PRIx16" addr 0x%"PRIx64" mask 0x%"PRIx8
vtd_inv_desc_iotlb_invalid(uint64_t hi, uint64_t lo) "invalid iotlb desc hi 0x%"PRIx64" lo 0x%"PRIx64
vtd_inv_desc_wait_sw(uint64_t addr, uint32_t data) "wait invalidate status write addr 0x%"PRIx64" data 0x%"PRIx32 vtd_inv_desc_wait_sw(uint64_t addr, uint32_t data) "wait invalidate status write addr 0x%"PRIx64" data 0x%"PRIx32
vtd_inv_desc_wait_irq(const char *msg) "%s" vtd_inv_desc_wait_irq(const char *msg) "%s"
vtd_inv_desc_wait_invalid(uint64_t hi, uint64_t lo) "invalid wait desc hi 0x%"PRIx64" lo 0x%"PRIx64
vtd_inv_desc_wait_write_fail(uint64_t hi, uint64_t lo) "write fail for wait desc hi 0x%"PRIx64" lo 0x%"PRIx64 vtd_inv_desc_wait_write_fail(uint64_t hi, uint64_t lo) "write fail for wait desc hi 0x%"PRIx64" lo 0x%"PRIx64
vtd_inv_desc_iec(uint32_t granularity, uint32_t index, uint32_t mask) "granularity 0x%"PRIx32" index 0x%"PRIx32" mask 0x%"PRIx32 vtd_inv_desc_iec(uint32_t granularity, uint32_t index, uint32_t mask) "granularity 0x%"PRIx32" index 0x%"PRIx32" mask 0x%"PRIx32
vtd_inv_qi_enable(bool enable) "enabled %d" vtd_inv_qi_enable(bool enable) "enabled %d"
@ -27,9 +23,7 @@ vtd_inv_qi_tail(uint16_t head) "write tail %d"
vtd_inv_qi_fetch(void) "" vtd_inv_qi_fetch(void) ""
vtd_context_cache_reset(void) "" vtd_context_cache_reset(void) ""
vtd_re_not_present(uint8_t bus) "Root entry bus %"PRIu8" not present" vtd_re_not_present(uint8_t bus) "Root entry bus %"PRIu8" not present"
vtd_re_invalid(uint64_t hi, uint64_t lo) "invalid root entry hi 0x%"PRIx64" lo 0x%"PRIx64
vtd_ce_not_present(uint8_t bus, uint8_t devfn) "Context entry bus %"PRIu8" devfn %"PRIu8" not present" vtd_ce_not_present(uint8_t bus, uint8_t devfn) "Context entry bus %"PRIu8" devfn %"PRIu8" not present"
vtd_ce_invalid(uint64_t hi, uint64_t lo) "invalid context entry hi 0x%"PRIx64" lo 0x%"PRIx64
vtd_iotlb_page_hit(uint16_t sid, uint64_t addr, uint64_t slpte, uint16_t domain) "IOTLB page hit sid 0x%"PRIx16" iova 0x%"PRIx64" slpte 0x%"PRIx64" domain 0x%"PRIx16 vtd_iotlb_page_hit(uint16_t sid, uint64_t addr, uint64_t slpte, uint16_t domain) "IOTLB page hit sid 0x%"PRIx16" iova 0x%"PRIx64" slpte 0x%"PRIx64" domain 0x%"PRIx16
vtd_iotlb_page_update(uint16_t sid, uint64_t addr, uint64_t slpte, uint16_t domain) "IOTLB page update sid 0x%"PRIx16" iova 0x%"PRIx64" slpte 0x%"PRIx64" domain 0x%"PRIx16 vtd_iotlb_page_update(uint16_t sid, uint64_t addr, uint64_t slpte, uint16_t domain) "IOTLB page update sid 0x%"PRIx16" iova 0x%"PRIx64" slpte 0x%"PRIx64" domain 0x%"PRIx16
vtd_iotlb_cc_hit(uint8_t bus, uint8_t devfn, uint64_t high, uint64_t low, uint32_t gen) "IOTLB context hit bus 0x%"PRIx8" devfn 0x%"PRIx8" high 0x%"PRIx64" low 0x%"PRIx64" gen %"PRIu32 vtd_iotlb_cc_hit(uint8_t bus, uint8_t devfn, uint64_t high, uint64_t low, uint32_t gen) "IOTLB context hit bus 0x%"PRIx8" devfn 0x%"PRIx8" high 0x%"PRIx64" low 0x%"PRIx64" gen %"PRIu32

View File

@ -112,6 +112,7 @@ static void x86_iommu_realize(DeviceState *dev, Error **errp)
PCMachineState *pcms = PCMachineState *pcms =
PC_MACHINE(object_dynamic_cast(OBJECT(ms), TYPE_PC_MACHINE)); PC_MACHINE(object_dynamic_cast(OBJECT(ms), TYPE_PC_MACHINE));
QLIST_INIT(&x86_iommu->iec_notifiers); QLIST_INIT(&x86_iommu->iec_notifiers);
bool irq_all_kernel = kvm_irqchip_in_kernel() && !kvm_irqchip_is_split();
if (!pcms || !pcms->bus) { if (!pcms || !pcms->bus) {
error_setg(errp, "Machine-type '%s' not supported by IOMMU", error_setg(errp, "Machine-type '%s' not supported by IOMMU",
@ -119,9 +120,14 @@ static void x86_iommu_realize(DeviceState *dev, Error **errp)
return; return;
} }
/* If the user didn't specify IR, choose a default value for it */
if (x86_iommu->intr_supported == ON_OFF_AUTO_AUTO) {
x86_iommu->intr_supported = irq_all_kernel ?
ON_OFF_AUTO_OFF : ON_OFF_AUTO_ON;
}
/* Both Intel and AMD IOMMU IR only support "kernel-irqchip={off|split}" */ /* Both Intel and AMD IOMMU IR only support "kernel-irqchip={off|split}" */
if (x86_iommu->intr_supported && kvm_irqchip_in_kernel() && if (x86_iommu_ir_supported(x86_iommu) && irq_all_kernel) {
!kvm_irqchip_is_split()) {
error_setg(errp, "Interrupt Remapping cannot work with " error_setg(errp, "Interrupt Remapping cannot work with "
"kernel-irqchip=on, please use 'split|off'."); "kernel-irqchip=on, please use 'split|off'.");
return; return;
@ -135,7 +141,8 @@ static void x86_iommu_realize(DeviceState *dev, Error **errp)
} }
static Property x86_iommu_properties[] = { static Property x86_iommu_properties[] = {
DEFINE_PROP_BOOL("intremap", X86IOMMUState, intr_supported, false), DEFINE_PROP_ON_OFF_AUTO("intremap", X86IOMMUState,
intr_supported, ON_OFF_AUTO_AUTO),
DEFINE_PROP_BOOL("device-iotlb", X86IOMMUState, dt_supported, false), DEFINE_PROP_BOOL("device-iotlb", X86IOMMUState, dt_supported, false),
DEFINE_PROP_BOOL("pt", X86IOMMUState, pt_supported, true), DEFINE_PROP_BOOL("pt", X86IOMMUState, pt_supported, true),
DEFINE_PROP_END_OF_LIST(), DEFINE_PROP_END_OF_LIST(),
@ -148,6 +155,11 @@ static void x86_iommu_class_init(ObjectClass *klass, void *data)
dc->props = x86_iommu_properties; dc->props = x86_iommu_properties;
} }
bool x86_iommu_ir_supported(X86IOMMUState *s)
{
return s->intr_supported == ON_OFF_AUTO_ON;
}
static const TypeInfo x86_iommu_info = { static const TypeInfo x86_iommu_info = {
.name = TYPE_X86_IOMMU_DEVICE, .name = TYPE_X86_IOMMU_DEVICE,
.parent = TYPE_SYS_BUS_DEVICE, .parent = TYPE_SYS_BUS_DEVICE,

View File

@ -124,6 +124,10 @@ static Property gen_rp_props[] = {
res_reserve.mem_pref_32, -1), res_reserve.mem_pref_32, -1),
DEFINE_PROP_SIZE("pref64-reserve", GenPCIERootPort, DEFINE_PROP_SIZE("pref64-reserve", GenPCIERootPort,
res_reserve.mem_pref_64, -1), res_reserve.mem_pref_64, -1),
DEFINE_PROP_PCIE_LINK_SPEED("x-speed", PCIESlot,
speed, PCIE_LINK_SPEED_16),
DEFINE_PROP_PCIE_LINK_WIDTH("x-width", PCIESlot,
width, PCIE_LINK_WIDTH_32),
DEFINE_PROP_END_OF_LIST() DEFINE_PROP_END_OF_LIST()
}; };

View File

@ -206,31 +206,39 @@ static const VMStateDescription pci_bridge_dev_vmstate = {
} }
}; };
static void pci_bridge_dev_hotplug_cb(HotplugHandler *hotplug_dev, void pci_bridge_dev_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp)
{
PCIDevice *pci_hotplug_dev = PCI_DEVICE(hotplug_dev);
if (!shpc_present(pci_hotplug_dev)) {
error_setg(errp, "standard hotplug controller has been disabled for "
"this %s", object_get_typename(OBJECT(hotplug_dev)));
return;
}
shpc_device_plug_cb(hotplug_dev, dev, errp);
}
void pci_bridge_dev_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp)
{
PCIDevice *pci_hotplug_dev = PCI_DEVICE(hotplug_dev);
g_assert(shpc_present(pci_hotplug_dev));
shpc_device_unplug_cb(hotplug_dev, dev, errp);
}
void pci_bridge_dev_unplug_request_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp) DeviceState *dev, Error **errp)
{ {
PCIDevice *pci_hotplug_dev = PCI_DEVICE(hotplug_dev); PCIDevice *pci_hotplug_dev = PCI_DEVICE(hotplug_dev);
if (!shpc_present(pci_hotplug_dev)) { if (!shpc_present(pci_hotplug_dev)) {
error_setg(errp, "standard hotplug controller has been disabled for " error_setg(errp, "standard hotplug controller has been disabled for "
"this %s", TYPE_PCI_BRIDGE_DEV); "this %s", object_get_typename(OBJECT(hotplug_dev)));
return; return;
} }
shpc_device_hotplug_cb(hotplug_dev, dev, errp); shpc_device_unplug_request_cb(hotplug_dev, dev, errp);
}
static void pci_bridge_dev_hot_unplug_request_cb(HotplugHandler *hotplug_dev,
DeviceState *dev,
Error **errp)
{
PCIDevice *pci_hotplug_dev = PCI_DEVICE(hotplug_dev);
if (!shpc_present(pci_hotplug_dev)) {
error_setg(errp, "standard hotplug controller has been disabled for "
"this %s", TYPE_PCI_BRIDGE_DEV);
return;
}
shpc_device_hot_unplug_request_cb(hotplug_dev, dev, errp);
} }
static void pci_bridge_dev_class_init(ObjectClass *klass, void *data) static void pci_bridge_dev_class_init(ObjectClass *klass, void *data)
@ -251,8 +259,9 @@ static void pci_bridge_dev_class_init(ObjectClass *klass, void *data)
dc->props = pci_bridge_dev_properties; dc->props = pci_bridge_dev_properties;
dc->vmsd = &pci_bridge_dev_vmstate; dc->vmsd = &pci_bridge_dev_vmstate;
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
hc->plug = pci_bridge_dev_hotplug_cb; hc->plug = pci_bridge_dev_plug_cb;
hc->unplug_request = pci_bridge_dev_hot_unplug_request_cb; hc->unplug = pci_bridge_dev_unplug_cb;
hc->unplug_request = pci_bridge_dev_unplug_request_cb;
} }
static const TypeInfo pci_bridge_dev_info = { static const TypeInfo pci_bridge_dev_info = {

View File

@ -137,33 +137,6 @@ static const VMStateDescription pcie_pci_bridge_dev_vmstate = {
} }
}; };
static void pcie_pci_bridge_hotplug_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
PCIDevice *pci_hotplug_dev = PCI_DEVICE(hotplug_dev);
if (!shpc_present(pci_hotplug_dev)) {
error_setg(errp, "standard hotplug controller has been disabled for "
"this %s", TYPE_PCIE_PCI_BRIDGE_DEV);
return;
}
shpc_device_hotplug_cb(hotplug_dev, dev, errp);
}
static void pcie_pci_bridge_hot_unplug_request_cb(HotplugHandler *hotplug_dev,
DeviceState *dev,
Error **errp)
{
PCIDevice *pci_hotplug_dev = PCI_DEVICE(hotplug_dev);
if (!shpc_present(pci_hotplug_dev)) {
error_setg(errp, "standard hotplug controller has been disabled for "
"this %s", TYPE_PCIE_PCI_BRIDGE_DEV);
return;
}
shpc_device_hot_unplug_request_cb(hotplug_dev, dev, errp);
}
static void pcie_pci_bridge_class_init(ObjectClass *klass, void *data) static void pcie_pci_bridge_class_init(ObjectClass *klass, void *data)
{ {
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@ -180,8 +153,9 @@ static void pcie_pci_bridge_class_init(ObjectClass *klass, void *data)
dc->props = pcie_pci_bridge_dev_properties; dc->props = pcie_pci_bridge_dev_properties;
dc->reset = &pcie_pci_bridge_reset; dc->reset = &pcie_pci_bridge_reset;
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
hc->plug = pcie_pci_bridge_hotplug_cb; hc->plug = pci_bridge_dev_plug_cb;
hc->unplug_request = pcie_pci_bridge_hot_unplug_request_cb; hc->unplug = pci_bridge_dev_unplug_cb;
hc->unplug_request = pci_bridge_dev_unplug_request_cb;
} }
static const TypeInfo pcie_pci_bridge_info = { static const TypeInfo pcie_pci_bridge_info = {

View File

@ -140,6 +140,19 @@ static Property rp_props[] = {
DEFINE_PROP_END_OF_LIST() DEFINE_PROP_END_OF_LIST()
}; };
static void rp_instance_post_init(Object *obj)
{
PCIESlot *s = PCIE_SLOT(obj);
if (!s->speed) {
s->speed = QEMU_PCI_EXP_LNK_2_5GT;
}
if (!s->width) {
s->width = QEMU_PCI_EXP_LNK_X1;
}
}
static void rp_class_init(ObjectClass *klass, void *data) static void rp_class_init(ObjectClass *klass, void *data)
{ {
DeviceClass *dc = DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass);
@ -157,6 +170,7 @@ static void rp_class_init(ObjectClass *klass, void *data)
static const TypeInfo rp_info = { static const TypeInfo rp_info = {
.name = TYPE_PCIE_ROOT_PORT, .name = TYPE_PCIE_ROOT_PORT,
.parent = TYPE_PCIE_SLOT, .parent = TYPE_PCIE_SLOT,
.instance_post_init = rp_instance_post_init,
.class_init = rp_class_init, .class_init = rp_class_init,
.abstract = true, .abstract = true,
.class_size = sizeof(PCIERootPortClass), .class_size = sizeof(PCIERootPortClass),

View File

@ -1353,6 +1353,10 @@ uint32_t pci_default_read_config(PCIDevice *d,
{ {
uint32_t val = 0; uint32_t val = 0;
if (pci_is_express_downstream_port(d) &&
ranges_overlap(address, len, d->exp.exp_cap + PCI_EXP_LNKSTA, 2)) {
pcie_sync_bridge_lnk(d);
}
memcpy(&val, d->config + address, len); memcpy(&val, d->config + address, len);
return le32_to_cpu(val); return le32_to_cpu(val);
} }

View File

@ -241,9 +241,9 @@ void pci_bridge_update_mappings(PCIBridge *br)
* while another accesses an unaffected region. */ * while another accesses an unaffected region. */
memory_region_transaction_begin(); memory_region_transaction_begin();
pci_bridge_region_del(br, br->windows); pci_bridge_region_del(br, br->windows);
pci_bridge_region_cleanup(br, w);
br->windows = pci_bridge_region_init(br); br->windows = pci_bridge_region_init(br);
memory_region_transaction_commit(); memory_region_transaction_commit();
pci_bridge_region_cleanup(br, w);
} }
/* default write_config function for PCI-to-PCI bridge */ /* default write_config function for PCI-to-PCI bridge */

View File

@ -20,6 +20,7 @@
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "hw/pci/pci.h" #include "hw/pci/pci.h"
#include "hw/pci/pci_bridge.h"
#include "hw/pci/pci_host.h" #include "hw/pci/pci_host.h"
#include "hw/pci/pci_bus.h" #include "hw/pci/pci_bus.h"
#include "trace.h" #include "trace.h"
@ -50,9 +51,29 @@ static inline PCIDevice *pci_dev_find_by_addr(PCIBus *bus, uint32_t addr)
return pci_find_device(bus, bus_num, devfn); return pci_find_device(bus, bus_num, devfn);
} }
static void pci_adjust_config_limit(PCIBus *bus, uint32_t *limit)
{
if (*limit > PCI_CONFIG_SPACE_SIZE) {
if (!pci_bus_is_express(bus)) {
*limit = PCI_CONFIG_SPACE_SIZE;
return;
}
if (!pci_bus_is_root(bus)) {
PCIDevice *bridge = pci_bridge_get_device(bus);
pci_adjust_config_limit(pci_get_bus(bridge), limit);
}
}
}
void pci_host_config_write_common(PCIDevice *pci_dev, uint32_t addr, void pci_host_config_write_common(PCIDevice *pci_dev, uint32_t addr,
uint32_t limit, uint32_t val, uint32_t len) uint32_t limit, uint32_t val, uint32_t len)
{ {
pci_adjust_config_limit(pci_get_bus(pci_dev), &limit);
if (limit <= addr) {
return;
}
assert(len <= 4); assert(len <= 4);
/* non-zero functions are only exposed when function 0 is present, /* non-zero functions are only exposed when function 0 is present,
* allowing direct removal of unexposed functions. * allowing direct removal of unexposed functions.
@ -71,6 +92,11 @@ uint32_t pci_host_config_read_common(PCIDevice *pci_dev, uint32_t addr,
{ {
uint32_t ret; uint32_t ret;
pci_adjust_config_limit(pci_get_bus(pci_dev), &limit);
if (limit <= addr) {
return ~0x0;
}
assert(len <= 4); assert(len <= 4);
/* non-zero functions are only exposed when function 0 is present, /* non-zero functions are only exposed when function 0 is present,
* allowing direct removal of unexposed functions. * allowing direct removal of unexposed functions.

View File

@ -27,6 +27,7 @@
#include "hw/pci/msi.h" #include "hw/pci/msi.h"
#include "hw/pci/pci_bus.h" #include "hw/pci/pci_bus.h"
#include "hw/pci/pcie_regs.h" #include "hw/pci/pcie_regs.h"
#include "hw/pci/pcie_port.h"
#include "qemu/range.h" #include "qemu/range.h"
//#define DEBUG_PCIE //#define DEBUG_PCIE
@ -68,11 +69,12 @@ pcie_cap_v1_fill(PCIDevice *dev, uint8_t port, uint8_t type, uint8_t version)
pci_set_long(exp_cap + PCI_EXP_LNKCAP, pci_set_long(exp_cap + PCI_EXP_LNKCAP,
(port << PCI_EXP_LNKCAP_PN_SHIFT) | (port << PCI_EXP_LNKCAP_PN_SHIFT) |
PCI_EXP_LNKCAP_ASPMS_0S | PCI_EXP_LNKCAP_ASPMS_0S |
PCI_EXP_LNK_MLW_1 | QEMU_PCI_EXP_LNKCAP_MLW(QEMU_PCI_EXP_LNK_X1) |
PCI_EXP_LNK_LS_25); QEMU_PCI_EXP_LNKCAP_MLS(QEMU_PCI_EXP_LNK_2_5GT));
pci_set_word(exp_cap + PCI_EXP_LNKSTA, pci_set_word(exp_cap + PCI_EXP_LNKSTA,
PCI_EXP_LNK_MLW_1 | PCI_EXP_LNK_LS_25); QEMU_PCI_EXP_LNKSTA_NLW(QEMU_PCI_EXP_LNK_X1) |
QEMU_PCI_EXP_LNKSTA_CLS(QEMU_PCI_EXP_LNK_2_5GT));
if (dev->cap_present & QEMU_PCIE_LNKSTA_DLLLA) { if (dev->cap_present & QEMU_PCIE_LNKSTA_DLLLA) {
pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA, pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA,
@ -86,6 +88,76 @@ pcie_cap_v1_fill(PCIDevice *dev, uint8_t port, uint8_t type, uint8_t version)
pci_set_word(cmask + PCI_EXP_LNKSTA, 0); pci_set_word(cmask + PCI_EXP_LNKSTA, 0);
} }
static void pcie_cap_fill_slot_lnk(PCIDevice *dev)
{
PCIESlot *s = (PCIESlot *)object_dynamic_cast(OBJECT(dev), TYPE_PCIE_SLOT);
uint8_t *exp_cap = dev->config + dev->exp.exp_cap;
/* Skip anything that isn't a PCIESlot */
if (!s) {
return;
}
/* Clear and fill LNKCAP from what was configured above */
pci_long_test_and_clear_mask(exp_cap + PCI_EXP_LNKCAP,
PCI_EXP_LNKCAP_MLW | PCI_EXP_LNKCAP_SLS);
pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP,
QEMU_PCI_EXP_LNKCAP_MLW(s->width) |
QEMU_PCI_EXP_LNKCAP_MLS(s->speed));
/*
* Link bandwidth notification is required for all root ports and
* downstream ports supporting links wider than x1 or multiple link
* speeds.
*/
if (s->width > QEMU_PCI_EXP_LNK_X1 ||
s->speed > QEMU_PCI_EXP_LNK_2_5GT) {
pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP,
PCI_EXP_LNKCAP_LBNC);
}
if (s->speed > QEMU_PCI_EXP_LNK_2_5GT) {
/*
* Hot-plug capable downstream ports and downstream ports supporting
* link speeds greater than 5GT/s must hardwire PCI_EXP_LNKCAP_DLLLARC
* to 1b. PCI_EXP_LNKCAP_DLLLARC implies PCI_EXP_LNKSTA_DLLLA, which
* we also hardwire to 1b here. 2.5GT/s hot-plug slots should also
* technically implement this, but it's not done here for compatibility.
*/
pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP,
PCI_EXP_LNKCAP_DLLLARC);
pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA,
PCI_EXP_LNKSTA_DLLLA);
/*
* Target Link Speed defaults to the highest link speed supported by
* the component. 2.5GT/s devices are permitted to hardwire to zero.
*/
pci_word_test_and_clear_mask(exp_cap + PCI_EXP_LNKCTL2,
PCI_EXP_LNKCTL2_TLS);
pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKCTL2,
QEMU_PCI_EXP_LNKCAP_MLS(s->speed) &
PCI_EXP_LNKCTL2_TLS);
}
/*
* 2.5 & 5.0GT/s can be fully described by LNKCAP, but 8.0GT/s is
* actually a reference to the highest bit supported in this register.
* We assume the device supports all link speeds.
*/
if (s->speed > QEMU_PCI_EXP_LNK_5GT) {
pci_long_test_and_clear_mask(exp_cap + PCI_EXP_LNKCAP2, ~0U);
pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP2,
PCI_EXP_LNKCAP2_SLS_2_5GB |
PCI_EXP_LNKCAP2_SLS_5_0GB |
PCI_EXP_LNKCAP2_SLS_8_0GB);
if (s->speed > QEMU_PCI_EXP_LNK_8GT) {
pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP2,
PCI_EXP_LNKCAP2_SLS_16_0GB);
}
}
}
int pcie_cap_init(PCIDevice *dev, uint8_t offset, int pcie_cap_init(PCIDevice *dev, uint8_t offset,
uint8_t type, uint8_t port, uint8_t type, uint8_t port,
Error **errp) Error **errp)
@ -107,6 +179,9 @@ int pcie_cap_init(PCIDevice *dev, uint8_t offset,
/* Filling values common with v1 */ /* Filling values common with v1 */
pcie_cap_v1_fill(dev, port, type, PCI_EXP_FLAGS_VER2); pcie_cap_v1_fill(dev, port, type, PCI_EXP_FLAGS_VER2);
/* Fill link speed and width options */
pcie_cap_fill_slot_lnk(dev);
/* Filling v2 specific values */ /* Filling v2 specific values */
pci_set_long(exp_cap + PCI_EXP_DEVCAP2, pci_set_long(exp_cap + PCI_EXP_DEVCAP2,
PCI_EXP_DEVCAP2_EFF | PCI_EXP_DEVCAP2_EETLPP); PCI_EXP_DEVCAP2_EFF | PCI_EXP_DEVCAP2_EETLPP);
@ -315,9 +390,8 @@ static void pcie_cap_slot_event(PCIDevice *dev, PCIExpressHotPlugEvent event)
hotplug_event_notify(dev); hotplug_event_notify(dev);
} }
static void pcie_cap_slot_hotplug_common(PCIDevice *hotplug_dev, static void pcie_cap_slot_plug_common(PCIDevice *hotplug_dev, DeviceState *dev,
DeviceState *dev, uint8_t **exp_cap, Error **errp)
uint8_t **exp_cap, Error **errp)
{ {
*exp_cap = hotplug_dev->config + hotplug_dev->exp.exp_cap; *exp_cap = hotplug_dev->config + hotplug_dev->exp.exp_cap;
uint16_t sltsta = pci_get_word(*exp_cap + PCI_EXP_SLTSTA); uint16_t sltsta = pci_get_word(*exp_cap + PCI_EXP_SLTSTA);
@ -331,13 +405,13 @@ static void pcie_cap_slot_hotplug_common(PCIDevice *hotplug_dev,
} }
} }
void pcie_cap_slot_hotplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, void pcie_cap_slot_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp) Error **errp)
{ {
uint8_t *exp_cap; uint8_t *exp_cap;
PCIDevice *pci_dev = PCI_DEVICE(dev); PCIDevice *pci_dev = PCI_DEVICE(dev);
pcie_cap_slot_hotplug_common(PCI_DEVICE(hotplug_dev), dev, &exp_cap, errp); pcie_cap_slot_plug_common(PCI_DEVICE(hotplug_dev), dev, &exp_cap, errp);
/* Don't send event when device is enabled during qemu machine creation: /* Don't send event when device is enabled during qemu machine creation:
* it is present on boot, no hotplug event is necessary. We do send an * it is present on boot, no hotplug event is necessary. We do send an
@ -345,6 +419,10 @@ void pcie_cap_slot_hotplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
if (!dev->hotplugged) { if (!dev->hotplugged) {
pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA, pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA,
PCI_EXP_SLTSTA_PDS); PCI_EXP_SLTSTA_PDS);
if (pci_dev->cap_present & QEMU_PCIE_LNKSTA_DLLLA) {
pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA,
PCI_EXP_LNKSTA_DLLLA);
}
return; return;
} }
@ -355,24 +433,36 @@ void pcie_cap_slot_hotplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
if (pci_get_function_0(pci_dev)) { if (pci_get_function_0(pci_dev)) {
pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA, pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA,
PCI_EXP_SLTSTA_PDS); PCI_EXP_SLTSTA_PDS);
if (pci_dev->cap_present & QEMU_PCIE_LNKSTA_DLLLA) {
pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA,
PCI_EXP_LNKSTA_DLLLA);
}
pcie_cap_slot_event(PCI_DEVICE(hotplug_dev), pcie_cap_slot_event(PCI_DEVICE(hotplug_dev),
PCI_EXP_HP_EV_PDC | PCI_EXP_HP_EV_ABP); PCI_EXP_HP_EV_PDC | PCI_EXP_HP_EV_ABP);
} }
} }
static void pcie_unplug_device(PCIBus *bus, PCIDevice *dev, void *opaque) void pcie_cap_slot_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp)
{ {
object_unparent(OBJECT(dev)); object_unparent(OBJECT(dev));
} }
void pcie_cap_slot_hot_unplug_request_cb(HotplugHandler *hotplug_dev, static void pcie_unplug_device(PCIBus *bus, PCIDevice *dev, void *opaque)
DeviceState *dev, Error **errp) {
HotplugHandler *hotplug_ctrl = qdev_get_hotplug_handler(DEVICE(dev));
hotplug_handler_unplug(hotplug_ctrl, DEVICE(dev), &error_abort);
}
void pcie_cap_slot_unplug_request_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{ {
uint8_t *exp_cap; uint8_t *exp_cap;
PCIDevice *pci_dev = PCI_DEVICE(dev); PCIDevice *pci_dev = PCI_DEVICE(dev);
PCIBus *bus = pci_get_bus(pci_dev); PCIBus *bus = pci_get_bus(pci_dev);
pcie_cap_slot_hotplug_common(PCI_DEVICE(hotplug_dev), dev, &exp_cap, errp); pcie_cap_slot_plug_common(PCI_DEVICE(hotplug_dev), dev, &exp_cap, errp);
/* In case user cancel the operation of multi-function hot-add, /* In case user cancel the operation of multi-function hot-add,
* remove the function that is unexposed to guest individually, * remove the function that is unexposed to guest individually,
@ -531,6 +621,10 @@ void pcie_cap_slot_write_config(PCIDevice *dev,
pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTSTA, pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTSTA,
PCI_EXP_SLTSTA_PDS); PCI_EXP_SLTSTA_PDS);
if (dev->cap_present & QEMU_PCIE_LNKSTA_DLLLA) {
pci_word_test_and_clear_mask(exp_cap + PCI_EXP_LNKSTA,
PCI_EXP_LNKSTA_DLLLA);
}
pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA, pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA,
PCI_EXP_SLTSTA_PDC); PCI_EXP_SLTSTA_PDC);
} }
@ -728,6 +822,45 @@ void pcie_add_capability(PCIDevice *dev,
memset(dev->cmask + offset, 0xFF, size); memset(dev->cmask + offset, 0xFF, size);
} }
/*
* Sync the PCIe Link Status negotiated speed and width of a bridge with the
* downstream device. If downstream device is not present, re-write with the
* Link Capability fields. Limit width and speed to bridge capabilities for
* compatibility. Use config_read to access the downstream device since it
* could be an assigned device with volatile link information.
*/
void pcie_sync_bridge_lnk(PCIDevice *bridge_dev)
{
PCIBridge *br = PCI_BRIDGE(bridge_dev);
PCIBus *bus = pci_bridge_get_sec_bus(br);
PCIDevice *target = bus->devices[0];
uint8_t *exp_cap = bridge_dev->config + bridge_dev->exp.exp_cap;
uint16_t lnksta, lnkcap = pci_get_word(exp_cap + PCI_EXP_LNKCAP);
if (!target || !target->exp.exp_cap) {
lnksta = lnkcap;
} else {
lnksta = target->config_read(target,
target->exp.exp_cap + PCI_EXP_LNKSTA,
sizeof(lnksta));
if ((lnksta & PCI_EXP_LNKSTA_NLW) > (lnkcap & PCI_EXP_LNKCAP_MLW)) {
lnksta &= ~PCI_EXP_LNKSTA_NLW;
lnksta |= lnkcap & PCI_EXP_LNKCAP_MLW;
}
if ((lnksta & PCI_EXP_LNKSTA_CLS) > (lnkcap & PCI_EXP_LNKCAP_SLS)) {
lnksta &= ~PCI_EXP_LNKSTA_CLS;
lnksta |= lnkcap & PCI_EXP_LNKCAP_SLS;
}
}
pci_word_test_and_clear_mask(exp_cap + PCI_EXP_LNKSTA,
PCI_EXP_LNKSTA_CLS | PCI_EXP_LNKSTA_NLW);
pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA, lnksta &
(PCI_EXP_LNKSTA_CLS | PCI_EXP_LNKSTA_NLW));
}
/************************************************************************** /**************************************************************************
* pci express extended capability helper functions * pci express extended capability helper functions
*/ */

View File

@ -154,8 +154,9 @@ static void pcie_slot_class_init(ObjectClass *oc, void *data)
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc); HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
dc->props = pcie_slot_props; dc->props = pcie_slot_props;
hc->plug = pcie_cap_slot_hotplug_cb; hc->plug = pcie_cap_slot_plug_cb;
hc->unplug_request = pcie_cap_slot_hot_unplug_request_cb; hc->unplug = pcie_cap_slot_unplug_cb;
hc->unplug_request = pcie_cap_slot_unplug_request_cb;
} }
static const TypeInfo pcie_slot_type_info = { static const TypeInfo pcie_slot_type_info = {

View File

@ -238,6 +238,7 @@ static void shpc_invalid_command(SHPCDevice *shpc)
static void shpc_free_devices_in_slot(SHPCDevice *shpc, int slot) static void shpc_free_devices_in_slot(SHPCDevice *shpc, int slot)
{ {
HotplugHandler *hotplug_ctrl;
int devfn; int devfn;
int pci_slot = SHPC_IDX_TO_PCI(slot); int pci_slot = SHPC_IDX_TO_PCI(slot);
for (devfn = PCI_DEVFN(pci_slot, 0); for (devfn = PCI_DEVFN(pci_slot, 0);
@ -245,7 +246,9 @@ static void shpc_free_devices_in_slot(SHPCDevice *shpc, int slot)
++devfn) { ++devfn) {
PCIDevice *affected_dev = shpc->sec_bus->devices[devfn]; PCIDevice *affected_dev = shpc->sec_bus->devices[devfn];
if (affected_dev) { if (affected_dev) {
object_unparent(OBJECT(affected_dev)); hotplug_ctrl = qdev_get_hotplug_handler(DEVICE(affected_dev));
hotplug_handler_unplug(hotplug_ctrl, DEVICE(affected_dev),
&error_abort);
} }
} }
} }
@ -482,8 +485,8 @@ static const MemoryRegionOps shpc_mmio_ops = {
.max_access_size = 4, .max_access_size = 4,
}, },
}; };
static void shpc_device_hotplug_common(PCIDevice *affected_dev, int *slot, static void shpc_device_plug_common(PCIDevice *affected_dev, int *slot,
SHPCDevice *shpc, Error **errp) SHPCDevice *shpc, Error **errp)
{ {
int pci_slot = PCI_SLOT(affected_dev->devfn); int pci_slot = PCI_SLOT(affected_dev->devfn);
*slot = SHPC_PCI_TO_IDX(pci_slot); *slot = SHPC_PCI_TO_IDX(pci_slot);
@ -497,7 +500,7 @@ static void shpc_device_hotplug_common(PCIDevice *affected_dev, int *slot,
} }
} }
void shpc_device_hotplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, void shpc_device_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp) Error **errp)
{ {
Error *local_err = NULL; Error *local_err = NULL;
@ -505,7 +508,7 @@ void shpc_device_hotplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
SHPCDevice *shpc = pci_hotplug_dev->shpc; SHPCDevice *shpc = pci_hotplug_dev->shpc;
int slot; int slot;
shpc_device_hotplug_common(PCI_DEVICE(dev), &slot, shpc, &local_err); shpc_device_plug_common(PCI_DEVICE(dev), &slot, shpc, &local_err);
if (local_err) { if (local_err) {
error_propagate(errp, local_err); error_propagate(errp, local_err);
return; return;
@ -540,8 +543,14 @@ void shpc_device_hotplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
shpc_interrupt_update(pci_hotplug_dev); shpc_interrupt_update(pci_hotplug_dev);
} }
void shpc_device_hot_unplug_request_cb(HotplugHandler *hotplug_dev, void shpc_device_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
DeviceState *dev, Error **errp) Error **errp)
{
object_unparent(OBJECT(dev));
}
void shpc_device_unplug_request_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{ {
Error *local_err = NULL; Error *local_err = NULL;
PCIDevice *pci_hotplug_dev = PCI_DEVICE(hotplug_dev); PCIDevice *pci_hotplug_dev = PCI_DEVICE(hotplug_dev);
@ -550,7 +559,7 @@ void shpc_device_hot_unplug_request_cb(HotplugHandler *hotplug_dev,
uint8_t led; uint8_t led;
int slot; int slot;
shpc_device_hotplug_common(PCI_DEVICE(dev), &slot, shpc, &local_err); shpc_device_plug_common(PCI_DEVICE(dev), &slot, shpc, &local_err);
if (local_err) { if (local_err) {
error_propagate(errp, local_err); error_propagate(errp, local_err);
return; return;

View File

@ -1370,18 +1370,9 @@ static int spapr_create_pci_child_dt(sPAPRPHBState *phb, PCIDevice *dev,
/* Callback to be called during DRC release. */ /* Callback to be called during DRC release. */
void spapr_phb_remove_pci_device_cb(DeviceState *dev) void spapr_phb_remove_pci_device_cb(DeviceState *dev)
{ {
/* some version guests do not wait for completion of a device HotplugHandler *hotplug_ctrl = qdev_get_hotplug_handler(dev);
* cleanup (generally done asynchronously by the kernel) before
* signaling to QEMU that the device is safe, but instead sleep hotplug_handler_unplug(hotplug_ctrl, dev, &error_abort);
* for some 'safe' period of time. unfortunately on a busy host
* this sleep isn't guaranteed to be long enough, resulting in
* bad things like IRQ lines being left asserted during final
* device removal. to deal with this we call reset just prior
* to finalizing the device, which will put the device back into
* an 'idle' state, as the device cleanup code expects.
*/
pci_device_reset(PCI_DEVICE(dev));
object_unparent(OBJECT(dev));
} }
static sPAPRDRConnector *spapr_phb_get_pci_func_drc(sPAPRPHBState *phb, static sPAPRDRConnector *spapr_phb_get_pci_func_drc(sPAPRPHBState *phb,
@ -1490,6 +1481,23 @@ out:
} }
} }
static void spapr_pci_unplug(HotplugHandler *plug_handler,
DeviceState *plugged_dev, Error **errp)
{
/* some version guests do not wait for completion of a device
* cleanup (generally done asynchronously by the kernel) before
* signaling to QEMU that the device is safe, but instead sleep
* for some 'safe' period of time. unfortunately on a busy host
* this sleep isn't guaranteed to be long enough, resulting in
* bad things like IRQ lines being left asserted during final
* device removal. to deal with this we call reset just prior
* to finalizing the device, which will put the device back into
* an 'idle' state, as the device cleanup code expects.
*/
pci_device_reset(PCI_DEVICE(plugged_dev));
object_unparent(OBJECT(plugged_dev));
}
static void spapr_pci_unplug_request(HotplugHandler *plug_handler, static void spapr_pci_unplug_request(HotplugHandler *plug_handler,
DeviceState *plugged_dev, Error **errp) DeviceState *plugged_dev, Error **errp)
{ {
@ -1965,6 +1973,7 @@ static void spapr_phb_class_init(ObjectClass *klass, void *data)
dc->user_creatable = true; dc->user_creatable = true;
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
hp->plug = spapr_pci_plug; hp->plug = spapr_pci_plug;
hp->unplug = spapr_pci_unplug;
hp->unplug_request = spapr_pci_unplug_request; hp->unplug_request = spapr_pci_unplug_request;
} }

View File

@ -823,8 +823,8 @@ static bool s390_pci_alloc_idx(S390pciState *s, S390PCIBusDevice *pbdev)
return true; return true;
} }
static void s390_pcihost_hot_plug(HotplugHandler *hotplug_dev, static void s390_pcihost_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
DeviceState *dev, Error **errp) Error **errp)
{ {
PCIDevice *pdev = NULL; PCIDevice *pdev = NULL;
S390PCIBusDevice *pbdev = NULL; S390PCIBusDevice *pbdev = NULL;
@ -932,8 +932,8 @@ static void s390_pcihost_timer_cb(void *opaque)
qdev_unplug(DEVICE(pbdev), NULL); qdev_unplug(DEVICE(pbdev), NULL);
} }
static void s390_pcihost_hot_unplug(HotplugHandler *hotplug_dev, static void s390_pcihost_unplug(HotplugHandler *hotplug_dev, DeviceState *dev,
DeviceState *dev, Error **errp) Error **errp)
{ {
PCIDevice *pci_dev = NULL; PCIDevice *pci_dev = NULL;
PCIBus *bus; PCIBus *bus;
@ -1041,8 +1041,8 @@ static void s390_pcihost_class_init(ObjectClass *klass, void *data)
dc->reset = s390_pcihost_reset; dc->reset = s390_pcihost_reset;
dc->realize = s390_pcihost_realize; dc->realize = s390_pcihost_realize;
hc->plug = s390_pcihost_hot_plug; hc->plug = s390_pcihost_plug;
hc->unplug = s390_pcihost_hot_unplug; hc->unplug = s390_pcihost_unplug;
msi_nonbroken = true; msi_nonbroken = true;
} }

View File

@ -23,7 +23,7 @@
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "qapi/error.h" #include "qapi/error.h"
#include "qapi/qmp/qerror.h" #include "qapi/qmp/qerror.h"
#include "hw/smbios/smbios.h" #include "hw/firmware/smbios.h"
void smbios_entry_add(QemuOpts *opts, Error **errp) void smbios_entry_add(QemuOpts *opts, Error **errp)
{ {

View File

@ -24,11 +24,10 @@
#include "sysemu/sysemu.h" #include "sysemu/sysemu.h"
#include "qemu/uuid.h" #include "qemu/uuid.h"
#include "sysemu/cpus.h" #include "sysemu/cpus.h"
#include "hw/smbios/smbios.h" #include "hw/firmware/smbios.h"
#include "hw/loader.h" #include "hw/loader.h"
#include "exec/cpu-common.h" #include "exec/cpu-common.h"
#include "smbios_build.h" #include "smbios_build.h"
#include "hw/smbios/ipmi.h"
/* legacy structures and constants for <= 2.0 machines */ /* legacy structures and constants for <= 2.0 machines */
struct smbios_header { struct smbios_header {

View File

@ -3,6 +3,7 @@
* *
* Copyright (C) 2009 Hewlett-Packard Development Company, L.P. * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
* Copyright (C) 2013 Red Hat, Inc. * Copyright (C) 2013 Red Hat, Inc.
* Copyright (c) 2015,2016 Corey Minyard, MontaVista Software, LLC
* *
* Authors: * Authors:
* Alex Williamson <alex.williamson@hp.com> * Alex Williamson <alex.williamson@hp.com>
@ -96,4 +97,7 @@ extern unsigned smbios_table_cnt;
smbios_table_cnt++; \ smbios_table_cnt++; \
} while (0) } while (0)
/* IPMI SMBIOS firmware handling */
void smbios_build_type_38_table(void);
#endif /* QEMU_SMBIOS_BUILD_H */ #endif /* QEMU_SMBIOS_BUILD_H */

View File

@ -8,7 +8,7 @@
*/ */
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "hw/smbios/ipmi.h" #include "smbios_build.h"
void smbios_build_type_38_table(void) void smbios_build_type_38_table(void)
{ {

View File

@ -9,8 +9,7 @@
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "hw/ipmi/ipmi.h" #include "hw/ipmi/ipmi.h"
#include "hw/smbios/ipmi.h" #include "hw/firmware/smbios.h"
#include "hw/smbios/smbios.h"
#include "qemu/error-report.h" #include "qemu/error-report.h"
#include "smbios_build.h" #include "smbios_build.h"

View File

@ -1897,15 +1897,10 @@ static int vfio_setup_pcie_cap(VFIOPCIDevice *vdev, int pos, uint8_t size,
PCI_EXP_TYPE_ENDPOINT << 4, PCI_EXP_TYPE_ENDPOINT << 4,
PCI_EXP_FLAGS_TYPE); PCI_EXP_FLAGS_TYPE);
vfio_add_emulated_long(vdev, pos + PCI_EXP_LNKCAP, vfio_add_emulated_long(vdev, pos + PCI_EXP_LNKCAP,
PCI_EXP_LNK_MLW_1 | PCI_EXP_LNK_LS_25, ~0); QEMU_PCI_EXP_LNKCAP_MLW(QEMU_PCI_EXP_LNK_X1) |
QEMU_PCI_EXP_LNKCAP_MLS(QEMU_PCI_EXP_LNK_2_5GT), ~0);
vfio_add_emulated_word(vdev, pos + PCI_EXP_LNKCTL, 0, ~0); vfio_add_emulated_word(vdev, pos + PCI_EXP_LNKCTL, 0, ~0);
} }
/* Mark the Link Status bits as emulated to allow virtual negotiation */
vfio_add_emulated_word(vdev, pos + PCI_EXP_LNKSTA,
pci_get_word(vdev->pdev.config + pos +
PCI_EXP_LNKSTA),
PCI_EXP_LNKCAP_MLW | PCI_EXP_LNKCAP_SLS);
} }
/* /*

View File

@ -64,9 +64,8 @@ static void virtio_crypto_initfn(Object *obj)
TYPE_VIRTIO_CRYPTO); TYPE_VIRTIO_CRYPTO);
} }
static const TypeInfo virtio_crypto_pci_info = { static const VirtioPCIDeviceTypeInfo virtio_crypto_pci_info = {
.name = TYPE_VIRTIO_CRYPTO_PCI, .generic_name = TYPE_VIRTIO_CRYPTO_PCI,
.parent = TYPE_VIRTIO_PCI,
.instance_size = sizeof(VirtIOCryptoPCI), .instance_size = sizeof(VirtIOCryptoPCI),
.instance_init = virtio_crypto_initfn, .instance_init = virtio_crypto_initfn,
.class_init = virtio_crypto_pci_class_init, .class_init = virtio_crypto_pci_class_init,
@ -74,6 +73,6 @@ static const TypeInfo virtio_crypto_pci_info = {
static void virtio_crypto_pci_register_types(void) static void virtio_crypto_pci_register_types(void)
{ {
type_register_static(&virtio_crypto_pci_info); virtio_pci_types_register(&virtio_crypto_pci_info);
} }
type_init(virtio_crypto_pci_register_types) type_init(virtio_crypto_pci_register_types)

View File

@ -1119,9 +1119,11 @@ static void virtio_9p_pci_instance_init(Object *obj)
TYPE_VIRTIO_9P); TYPE_VIRTIO_9P);
} }
static const TypeInfo virtio_9p_pci_info = { static const VirtioPCIDeviceTypeInfo virtio_9p_pci_info = {
.name = TYPE_VIRTIO_9P_PCI, .base_name = TYPE_VIRTIO_9P_PCI,
.parent = TYPE_VIRTIO_PCI, .generic_name = "virtio-9p-pci",
.transitional_name = "virtio-9p-pci-transitional",
.non_transitional_name = "virtio-9p-pci-non-transitional",
.instance_size = sizeof(V9fsPCIState), .instance_size = sizeof(V9fsPCIState),
.instance_init = virtio_9p_pci_instance_init, .instance_init = virtio_9p_pci_instance_init,
.class_init = virtio_9p_pci_class_init, .class_init = virtio_9p_pci_class_init,
@ -1877,9 +1879,6 @@ static void virtio_pci_reset(DeviceState *qdev)
static Property virtio_pci_properties[] = { static Property virtio_pci_properties[] = {
DEFINE_PROP_BIT("virtio-pci-bus-master-bug-migration", VirtIOPCIProxy, flags, DEFINE_PROP_BIT("virtio-pci-bus-master-bug-migration", VirtIOPCIProxy, flags,
VIRTIO_PCI_FLAG_BUS_MASTER_BUG_MIGRATION_BIT, false), VIRTIO_PCI_FLAG_BUS_MASTER_BUG_MIGRATION_BIT, false),
DEFINE_PROP_ON_OFF_AUTO("disable-legacy", VirtIOPCIProxy, disable_legacy,
ON_OFF_AUTO_AUTO),
DEFINE_PROP_BOOL("disable-modern", VirtIOPCIProxy, disable_modern, false),
DEFINE_PROP_BIT("migrate-extra", VirtIOPCIProxy, flags, DEFINE_PROP_BIT("migrate-extra", VirtIOPCIProxy, flags,
VIRTIO_PCI_FLAG_MIGRATE_EXTRA_BIT, true), VIRTIO_PCI_FLAG_MIGRATE_EXTRA_BIT, true),
DEFINE_PROP_BIT("modern-pio-notify", VirtIOPCIProxy, flags, DEFINE_PROP_BIT("modern-pio-notify", VirtIOPCIProxy, flags,
@ -1939,13 +1938,123 @@ static const TypeInfo virtio_pci_info = {
.class_init = virtio_pci_class_init, .class_init = virtio_pci_class_init,
.class_size = sizeof(VirtioPCIClass), .class_size = sizeof(VirtioPCIClass),
.abstract = true, .abstract = true,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_PCIE_DEVICE },
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ }
},
}; };
static Property virtio_pci_generic_properties[] = {
DEFINE_PROP_ON_OFF_AUTO("disable-legacy", VirtIOPCIProxy, disable_legacy,
ON_OFF_AUTO_AUTO),
DEFINE_PROP_BOOL("disable-modern", VirtIOPCIProxy, disable_modern, false),
DEFINE_PROP_END_OF_LIST(),
};
static void virtio_pci_base_class_init(ObjectClass *klass, void *data)
{
const VirtioPCIDeviceTypeInfo *t = data;
if (t->class_init) {
t->class_init(klass, NULL);
}
}
static void virtio_pci_generic_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->props = virtio_pci_generic_properties;
}
/* Used when the generic type and the base type is the same */
static void virtio_pci_generic_base_class_init(ObjectClass *klass, void *data)
{
virtio_pci_base_class_init(klass, data);
virtio_pci_generic_class_init(klass, NULL);
}
static void virtio_pci_transitional_instance_init(Object *obj)
{
VirtIOPCIProxy *proxy = VIRTIO_PCI(obj);
proxy->disable_legacy = ON_OFF_AUTO_OFF;
proxy->disable_modern = false;
}
static void virtio_pci_non_transitional_instance_init(Object *obj)
{
VirtIOPCIProxy *proxy = VIRTIO_PCI(obj);
proxy->disable_legacy = ON_OFF_AUTO_ON;
proxy->disable_modern = false;
}
void virtio_pci_types_register(const VirtioPCIDeviceTypeInfo *t)
{
TypeInfo base_type_info = {
.name = t->base_name,
.parent = t->parent ? t->parent : TYPE_VIRTIO_PCI,
.instance_size = t->instance_size,
.instance_init = t->instance_init,
.class_init = virtio_pci_base_class_init,
.class_data = (void *)t,
.abstract = true,
};
TypeInfo generic_type_info = {
.name = t->generic_name,
.parent = base_type_info.name,
.class_init = virtio_pci_generic_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_PCIE_DEVICE },
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ }
},
};
if (!base_type_info.name) {
/* No base type -> register a single generic device type */
base_type_info.name = t->generic_name;
base_type_info.class_init = virtio_pci_generic_base_class_init;
base_type_info.interfaces = generic_type_info.interfaces;
base_type_info.abstract = false;
generic_type_info.name = NULL;
assert(!t->non_transitional_name);
assert(!t->transitional_name);
}
type_register(&base_type_info);
if (generic_type_info.name) {
type_register(&generic_type_info);
}
if (t->non_transitional_name) {
const TypeInfo non_transitional_type_info = {
.name = t->non_transitional_name,
.parent = base_type_info.name,
.instance_init = virtio_pci_non_transitional_instance_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_PCIE_DEVICE },
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ }
},
};
type_register(&non_transitional_type_info);
}
if (t->transitional_name) {
const TypeInfo transitional_type_info = {
.name = t->transitional_name,
.parent = base_type_info.name,
.instance_init = virtio_pci_transitional_instance_init,
.interfaces = (InterfaceInfo[]) {
/*
* Transitional virtio devices work only as Conventional PCI
* devices because they require PIO ports.
*/
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ }
},
};
type_register(&transitional_type_info);
}
}
/* virtio-blk-pci */ /* virtio-blk-pci */
static Property virtio_blk_pci_properties[] = { static Property virtio_blk_pci_properties[] = {
@ -1995,9 +2104,11 @@ static void virtio_blk_pci_instance_init(Object *obj)
"bootindex", &error_abort); "bootindex", &error_abort);
} }
static const TypeInfo virtio_blk_pci_info = { static const VirtioPCIDeviceTypeInfo virtio_blk_pci_info = {
.name = TYPE_VIRTIO_BLK_PCI, .base_name = TYPE_VIRTIO_BLK_PCI,
.parent = TYPE_VIRTIO_PCI, .generic_name = "virtio-blk-pci",
.transitional_name = "virtio-blk-pci-transitional",
.non_transitional_name = "virtio-blk-pci-non-transitional",
.instance_size = sizeof(VirtIOBlkPCI), .instance_size = sizeof(VirtIOBlkPCI),
.instance_init = virtio_blk_pci_instance_init, .instance_init = virtio_blk_pci_instance_init,
.class_init = virtio_blk_pci_class_init, .class_init = virtio_blk_pci_class_init,
@ -2051,9 +2162,11 @@ static void vhost_user_blk_pci_instance_init(Object *obj)
"bootindex", &error_abort); "bootindex", &error_abort);
} }
static const TypeInfo vhost_user_blk_pci_info = { static const VirtioPCIDeviceTypeInfo vhost_user_blk_pci_info = {
.name = TYPE_VHOST_USER_BLK_PCI, .base_name = TYPE_VHOST_USER_BLK_PCI,
.parent = TYPE_VIRTIO_PCI, .generic_name = "vhost-user-blk-pci",
.transitional_name = "vhost-user-blk-pci-transitional",
.non_transitional_name = "vhost-user-blk-pci-non-transitional",
.instance_size = sizeof(VHostUserBlkPCI), .instance_size = sizeof(VHostUserBlkPCI),
.instance_init = vhost_user_blk_pci_instance_init, .instance_init = vhost_user_blk_pci_instance_init,
.class_init = vhost_user_blk_pci_class_init, .class_init = vhost_user_blk_pci_class_init,
@ -2119,9 +2232,11 @@ static void virtio_scsi_pci_instance_init(Object *obj)
TYPE_VIRTIO_SCSI); TYPE_VIRTIO_SCSI);
} }
static const TypeInfo virtio_scsi_pci_info = { static const VirtioPCIDeviceTypeInfo virtio_scsi_pci_info = {
.name = TYPE_VIRTIO_SCSI_PCI, .base_name = TYPE_VIRTIO_SCSI_PCI,
.parent = TYPE_VIRTIO_PCI, .generic_name = "virtio-scsi-pci",
.transitional_name = "virtio-scsi-pci-transitional",
.non_transitional_name = "virtio-scsi-pci-non-transitional",
.instance_size = sizeof(VirtIOSCSIPCI), .instance_size = sizeof(VirtIOSCSIPCI),
.instance_init = virtio_scsi_pci_instance_init, .instance_init = virtio_scsi_pci_instance_init,
.class_init = virtio_scsi_pci_class_init, .class_init = virtio_scsi_pci_class_init,
@ -2174,9 +2289,11 @@ static void vhost_scsi_pci_instance_init(Object *obj)
"bootindex", &error_abort); "bootindex", &error_abort);
} }
static const TypeInfo vhost_scsi_pci_info = { static const VirtioPCIDeviceTypeInfo vhost_scsi_pci_info = {
.name = TYPE_VHOST_SCSI_PCI, .base_name = TYPE_VHOST_SCSI_PCI,
.parent = TYPE_VIRTIO_PCI, .generic_name = "vhost-scsi-pci",
.transitional_name = "vhost-scsi-pci-transitional",
.non_transitional_name = "vhost-scsi-pci-non-transitional",
.instance_size = sizeof(VHostSCSIPCI), .instance_size = sizeof(VHostSCSIPCI),
.instance_init = vhost_scsi_pci_instance_init, .instance_init = vhost_scsi_pci_instance_init,
.class_init = vhost_scsi_pci_class_init, .class_init = vhost_scsi_pci_class_init,
@ -2229,9 +2346,11 @@ static void vhost_user_scsi_pci_instance_init(Object *obj)
"bootindex", &error_abort); "bootindex", &error_abort);
} }
static const TypeInfo vhost_user_scsi_pci_info = { static const VirtioPCIDeviceTypeInfo vhost_user_scsi_pci_info = {
.name = TYPE_VHOST_USER_SCSI_PCI, .base_name = TYPE_VHOST_USER_SCSI_PCI,
.parent = TYPE_VIRTIO_PCI, .generic_name = "vhost-user-scsi-pci",
.transitional_name = "vhost-user-scsi-pci-transitional",
.non_transitional_name = "vhost-user-scsi-pci-non-transitional",
.instance_size = sizeof(VHostUserSCSIPCI), .instance_size = sizeof(VHostUserSCSIPCI),
.instance_init = vhost_user_scsi_pci_instance_init, .instance_init = vhost_user_scsi_pci_instance_init,
.class_init = vhost_user_scsi_pci_class_init, .class_init = vhost_user_scsi_pci_class_init,
@ -2277,9 +2396,11 @@ static void vhost_vsock_pci_instance_init(Object *obj)
TYPE_VHOST_VSOCK); TYPE_VHOST_VSOCK);
} }
static const TypeInfo vhost_vsock_pci_info = { static const VirtioPCIDeviceTypeInfo vhost_vsock_pci_info = {
.name = TYPE_VHOST_VSOCK_PCI, .base_name = TYPE_VHOST_VSOCK_PCI,
.parent = TYPE_VIRTIO_PCI, .generic_name = "vhost-vsock-pci",
.transitional_name = "vhost-vsock-pci-transitional",
.non_transitional_name = "vhost-vsock-pci-non-transitional",
.instance_size = sizeof(VHostVSockPCI), .instance_size = sizeof(VHostVSockPCI),
.instance_init = vhost_vsock_pci_instance_init, .instance_init = vhost_vsock_pci_instance_init,
.class_init = vhost_vsock_pci_class_init, .class_init = vhost_vsock_pci_class_init,
@ -2334,9 +2455,11 @@ static void virtio_balloon_pci_instance_init(Object *obj)
"guest-stats-polling-interval", &error_abort); "guest-stats-polling-interval", &error_abort);
} }
static const TypeInfo virtio_balloon_pci_info = { static const VirtioPCIDeviceTypeInfo virtio_balloon_pci_info = {
.name = TYPE_VIRTIO_BALLOON_PCI, .base_name = TYPE_VIRTIO_BALLOON_PCI,
.parent = TYPE_VIRTIO_PCI, .generic_name = "virtio-balloon-pci",
.transitional_name = "virtio-balloon-pci-transitional",
.non_transitional_name = "virtio-balloon-pci-non-transitional",
.instance_size = sizeof(VirtIOBalloonPCI), .instance_size = sizeof(VirtIOBalloonPCI),
.instance_init = virtio_balloon_pci_instance_init, .instance_init = virtio_balloon_pci_instance_init,
.class_init = virtio_balloon_pci_class_init, .class_init = virtio_balloon_pci_class_init,
@ -2407,9 +2530,11 @@ static void virtio_serial_pci_instance_init(Object *obj)
TYPE_VIRTIO_SERIAL); TYPE_VIRTIO_SERIAL);
} }
static const TypeInfo virtio_serial_pci_info = { static const VirtioPCIDeviceTypeInfo virtio_serial_pci_info = {
.name = TYPE_VIRTIO_SERIAL_PCI, .base_name = TYPE_VIRTIO_SERIAL_PCI,
.parent = TYPE_VIRTIO_PCI, .generic_name = "virtio-serial-pci",
.transitional_name = "virtio-serial-pci-transitional",
.non_transitional_name = "virtio-serial-pci-non-transitional",
.instance_size = sizeof(VirtIOSerialPCI), .instance_size = sizeof(VirtIOSerialPCI),
.instance_init = virtio_serial_pci_instance_init, .instance_init = virtio_serial_pci_instance_init,
.class_init = virtio_serial_pci_class_init, .class_init = virtio_serial_pci_class_init,
@ -2462,9 +2587,11 @@ static void virtio_net_pci_instance_init(Object *obj)
"bootindex", &error_abort); "bootindex", &error_abort);
} }
static const TypeInfo virtio_net_pci_info = { static const VirtioPCIDeviceTypeInfo virtio_net_pci_info = {
.name = TYPE_VIRTIO_NET_PCI, .base_name = TYPE_VIRTIO_NET_PCI,
.parent = TYPE_VIRTIO_PCI, .generic_name = "virtio-net-pci",
.transitional_name = "virtio-net-pci-transitional",
.non_transitional_name = "virtio-net-pci-non-transitional",
.instance_size = sizeof(VirtIONetPCI), .instance_size = sizeof(VirtIONetPCI),
.instance_init = virtio_net_pci_instance_init, .instance_init = virtio_net_pci_instance_init,
.class_init = virtio_net_pci_class_init, .class_init = virtio_net_pci_class_init,
@ -2513,9 +2640,11 @@ static void virtio_rng_initfn(Object *obj)
TYPE_VIRTIO_RNG); TYPE_VIRTIO_RNG);
} }
static const TypeInfo virtio_rng_pci_info = { static const VirtioPCIDeviceTypeInfo virtio_rng_pci_info = {
.name = TYPE_VIRTIO_RNG_PCI, .base_name = TYPE_VIRTIO_RNG_PCI,
.parent = TYPE_VIRTIO_PCI, .generic_name = "virtio-rng-pci",
.transitional_name = "virtio-rng-pci-transitional",
.non_transitional_name = "virtio-rng-pci-non-transitional",
.instance_size = sizeof(VirtIORngPCI), .instance_size = sizeof(VirtIORngPCI),
.instance_init = virtio_rng_initfn, .instance_init = virtio_rng_initfn,
.class_init = virtio_rng_pci_class_init, .class_init = virtio_rng_pci_class_init,
@ -2605,24 +2734,24 @@ static const TypeInfo virtio_input_hid_pci_info = {
.abstract = true, .abstract = true,
}; };
static const TypeInfo virtio_keyboard_pci_info = { static const VirtioPCIDeviceTypeInfo virtio_keyboard_pci_info = {
.name = TYPE_VIRTIO_KEYBOARD_PCI, .generic_name = TYPE_VIRTIO_KEYBOARD_PCI,
.parent = TYPE_VIRTIO_INPUT_HID_PCI, .parent = TYPE_VIRTIO_INPUT_HID_PCI,
.class_init = virtio_input_hid_kbd_pci_class_init, .class_init = virtio_input_hid_kbd_pci_class_init,
.instance_size = sizeof(VirtIOInputHIDPCI), .instance_size = sizeof(VirtIOInputHIDPCI),
.instance_init = virtio_keyboard_initfn, .instance_init = virtio_keyboard_initfn,
}; };
static const TypeInfo virtio_mouse_pci_info = { static const VirtioPCIDeviceTypeInfo virtio_mouse_pci_info = {
.name = TYPE_VIRTIO_MOUSE_PCI, .generic_name = TYPE_VIRTIO_MOUSE_PCI,
.parent = TYPE_VIRTIO_INPUT_HID_PCI, .parent = TYPE_VIRTIO_INPUT_HID_PCI,
.class_init = virtio_input_hid_mouse_pci_class_init, .class_init = virtio_input_hid_mouse_pci_class_init,
.instance_size = sizeof(VirtIOInputHIDPCI), .instance_size = sizeof(VirtIOInputHIDPCI),
.instance_init = virtio_mouse_initfn, .instance_init = virtio_mouse_initfn,
}; };
static const TypeInfo virtio_tablet_pci_info = { static const VirtioPCIDeviceTypeInfo virtio_tablet_pci_info = {
.name = TYPE_VIRTIO_TABLET_PCI, .generic_name = TYPE_VIRTIO_TABLET_PCI,
.parent = TYPE_VIRTIO_INPUT_HID_PCI, .parent = TYPE_VIRTIO_INPUT_HID_PCI,
.instance_size = sizeof(VirtIOInputHIDPCI), .instance_size = sizeof(VirtIOInputHIDPCI),
.instance_init = virtio_tablet_initfn, .instance_init = virtio_tablet_initfn,
@ -2637,8 +2766,11 @@ static void virtio_host_initfn(Object *obj)
TYPE_VIRTIO_INPUT_HOST); TYPE_VIRTIO_INPUT_HOST);
} }
static const TypeInfo virtio_host_pci_info = { static const VirtioPCIDeviceTypeInfo virtio_host_pci_info = {
.name = TYPE_VIRTIO_INPUT_HOST_PCI, .base_name = TYPE_VIRTIO_INPUT_HOST_PCI,
.generic_name = "virtio-input-host-pci",
.transitional_name = "virtio-input-host-pci-transitional",
.non_transitional_name = "virtio-input-host-pci-non-transitional",
.parent = TYPE_VIRTIO_INPUT_PCI, .parent = TYPE_VIRTIO_INPUT_PCI,
.instance_size = sizeof(VirtIOInputHostPCI), .instance_size = sizeof(VirtIOInputHostPCI),
.instance_init = virtio_host_initfn, .instance_init = virtio_host_initfn,
@ -2692,36 +2824,39 @@ static const TypeInfo virtio_pci_bus_info = {
static void virtio_pci_register_types(void) static void virtio_pci_register_types(void)
{ {
type_register_static(&virtio_rng_pci_info); /* Base types: */
type_register_static(&virtio_input_pci_info);
type_register_static(&virtio_input_hid_pci_info);
type_register_static(&virtio_keyboard_pci_info);
type_register_static(&virtio_mouse_pci_info);
type_register_static(&virtio_tablet_pci_info);
#ifdef CONFIG_LINUX
type_register_static(&virtio_host_pci_info);
#endif
type_register_static(&virtio_pci_bus_info); type_register_static(&virtio_pci_bus_info);
type_register_static(&virtio_pci_info); type_register_static(&virtio_pci_info);
type_register_static(&virtio_input_pci_info);
type_register_static(&virtio_input_hid_pci_info);
/* Implementations: */
virtio_pci_types_register(&virtio_rng_pci_info);
virtio_pci_types_register(&virtio_keyboard_pci_info);
virtio_pci_types_register(&virtio_mouse_pci_info);
virtio_pci_types_register(&virtio_tablet_pci_info);
#ifdef CONFIG_LINUX
virtio_pci_types_register(&virtio_host_pci_info);
#endif
#ifdef CONFIG_VIRTFS #ifdef CONFIG_VIRTFS
type_register_static(&virtio_9p_pci_info); virtio_pci_types_register(&virtio_9p_pci_info);
#endif #endif
type_register_static(&virtio_blk_pci_info); virtio_pci_types_register(&virtio_blk_pci_info);
#if defined(CONFIG_VHOST_USER) && defined(CONFIG_LINUX) #if defined(CONFIG_VHOST_USER) && defined(CONFIG_LINUX)
type_register_static(&vhost_user_blk_pci_info); virtio_pci_types_register(&vhost_user_blk_pci_info);
#endif #endif
type_register_static(&virtio_scsi_pci_info); virtio_pci_types_register(&virtio_scsi_pci_info);
type_register_static(&virtio_balloon_pci_info); virtio_pci_types_register(&virtio_balloon_pci_info);
type_register_static(&virtio_serial_pci_info); virtio_pci_types_register(&virtio_serial_pci_info);
type_register_static(&virtio_net_pci_info); virtio_pci_types_register(&virtio_net_pci_info);
#ifdef CONFIG_VHOST_SCSI #ifdef CONFIG_VHOST_SCSI
type_register_static(&vhost_scsi_pci_info); virtio_pci_types_register(&vhost_scsi_pci_info);
#endif #endif
#if defined(CONFIG_VHOST_USER) && defined(CONFIG_LINUX) #if defined(CONFIG_VHOST_USER) && defined(CONFIG_LINUX)
type_register_static(&vhost_user_scsi_pci_info); virtio_pci_types_register(&vhost_user_scsi_pci_info);
#endif #endif
#ifdef CONFIG_VHOST_VSOCK #ifdef CONFIG_VHOST_VSOCK
type_register_static(&vhost_vsock_pci_info); virtio_pci_types_register(&vhost_vsock_pci_info);
#endif #endif
} }

View File

@ -216,7 +216,7 @@ static inline void virtio_pci_disable_modern(VirtIOPCIProxy *proxy)
/* /*
* virtio-scsi-pci: This extends VirtioPCIProxy. * virtio-scsi-pci: This extends VirtioPCIProxy.
*/ */
#define TYPE_VIRTIO_SCSI_PCI "virtio-scsi-pci" #define TYPE_VIRTIO_SCSI_PCI "virtio-scsi-pci-base"
#define VIRTIO_SCSI_PCI(obj) \ #define VIRTIO_SCSI_PCI(obj) \
OBJECT_CHECK(VirtIOSCSIPCI, (obj), TYPE_VIRTIO_SCSI_PCI) OBJECT_CHECK(VirtIOSCSIPCI, (obj), TYPE_VIRTIO_SCSI_PCI)
@ -229,7 +229,7 @@ struct VirtIOSCSIPCI {
/* /*
* vhost-scsi-pci: This extends VirtioPCIProxy. * vhost-scsi-pci: This extends VirtioPCIProxy.
*/ */
#define TYPE_VHOST_SCSI_PCI "vhost-scsi-pci" #define TYPE_VHOST_SCSI_PCI "vhost-scsi-pci-base"
#define VHOST_SCSI_PCI(obj) \ #define VHOST_SCSI_PCI(obj) \
OBJECT_CHECK(VHostSCSIPCI, (obj), TYPE_VHOST_SCSI_PCI) OBJECT_CHECK(VHostSCSIPCI, (obj), TYPE_VHOST_SCSI_PCI)
@ -239,7 +239,7 @@ struct VHostSCSIPCI {
}; };
#endif #endif
#define TYPE_VHOST_USER_SCSI_PCI "vhost-user-scsi-pci" #define TYPE_VHOST_USER_SCSI_PCI "vhost-user-scsi-pci-base"
#define VHOST_USER_SCSI_PCI(obj) \ #define VHOST_USER_SCSI_PCI(obj) \
OBJECT_CHECK(VHostUserSCSIPCI, (obj), TYPE_VHOST_USER_SCSI_PCI) OBJECT_CHECK(VHostUserSCSIPCI, (obj), TYPE_VHOST_USER_SCSI_PCI)
@ -252,7 +252,7 @@ struct VHostUserSCSIPCI {
/* /*
* vhost-user-blk-pci: This extends VirtioPCIProxy. * vhost-user-blk-pci: This extends VirtioPCIProxy.
*/ */
#define TYPE_VHOST_USER_BLK_PCI "vhost-user-blk-pci" #define TYPE_VHOST_USER_BLK_PCI "vhost-user-blk-pci-base"
#define VHOST_USER_BLK_PCI(obj) \ #define VHOST_USER_BLK_PCI(obj) \
OBJECT_CHECK(VHostUserBlkPCI, (obj), TYPE_VHOST_USER_BLK_PCI) OBJECT_CHECK(VHostUserBlkPCI, (obj), TYPE_VHOST_USER_BLK_PCI)
@ -265,7 +265,7 @@ struct VHostUserBlkPCI {
/* /*
* virtio-blk-pci: This extends VirtioPCIProxy. * virtio-blk-pci: This extends VirtioPCIProxy.
*/ */
#define TYPE_VIRTIO_BLK_PCI "virtio-blk-pci" #define TYPE_VIRTIO_BLK_PCI "virtio-blk-pci-base"
#define VIRTIO_BLK_PCI(obj) \ #define VIRTIO_BLK_PCI(obj) \
OBJECT_CHECK(VirtIOBlkPCI, (obj), TYPE_VIRTIO_BLK_PCI) OBJECT_CHECK(VirtIOBlkPCI, (obj), TYPE_VIRTIO_BLK_PCI)
@ -277,7 +277,7 @@ struct VirtIOBlkPCI {
/* /*
* virtio-balloon-pci: This extends VirtioPCIProxy. * virtio-balloon-pci: This extends VirtioPCIProxy.
*/ */
#define TYPE_VIRTIO_BALLOON_PCI "virtio-balloon-pci" #define TYPE_VIRTIO_BALLOON_PCI "virtio-balloon-pci-base"
#define VIRTIO_BALLOON_PCI(obj) \ #define VIRTIO_BALLOON_PCI(obj) \
OBJECT_CHECK(VirtIOBalloonPCI, (obj), TYPE_VIRTIO_BALLOON_PCI) OBJECT_CHECK(VirtIOBalloonPCI, (obj), TYPE_VIRTIO_BALLOON_PCI)
@ -289,7 +289,7 @@ struct VirtIOBalloonPCI {
/* /*
* virtio-serial-pci: This extends VirtioPCIProxy. * virtio-serial-pci: This extends VirtioPCIProxy.
*/ */
#define TYPE_VIRTIO_SERIAL_PCI "virtio-serial-pci" #define TYPE_VIRTIO_SERIAL_PCI "virtio-serial-pci-base"
#define VIRTIO_SERIAL_PCI(obj) \ #define VIRTIO_SERIAL_PCI(obj) \
OBJECT_CHECK(VirtIOSerialPCI, (obj), TYPE_VIRTIO_SERIAL_PCI) OBJECT_CHECK(VirtIOSerialPCI, (obj), TYPE_VIRTIO_SERIAL_PCI)
@ -301,7 +301,7 @@ struct VirtIOSerialPCI {
/* /*
* virtio-net-pci: This extends VirtioPCIProxy. * virtio-net-pci: This extends VirtioPCIProxy.
*/ */
#define TYPE_VIRTIO_NET_PCI "virtio-net-pci" #define TYPE_VIRTIO_NET_PCI "virtio-net-pci-base"
#define VIRTIO_NET_PCI(obj) \ #define VIRTIO_NET_PCI(obj) \
OBJECT_CHECK(VirtIONetPCI, (obj), TYPE_VIRTIO_NET_PCI) OBJECT_CHECK(VirtIONetPCI, (obj), TYPE_VIRTIO_NET_PCI)
@ -316,7 +316,7 @@ struct VirtIONetPCI {
#ifdef CONFIG_VIRTFS #ifdef CONFIG_VIRTFS
#define TYPE_VIRTIO_9P_PCI "virtio-9p-pci" #define TYPE_VIRTIO_9P_PCI "virtio-9p-pci-base"
#define VIRTIO_9P_PCI(obj) \ #define VIRTIO_9P_PCI(obj) \
OBJECT_CHECK(V9fsPCIState, (obj), TYPE_VIRTIO_9P_PCI) OBJECT_CHECK(V9fsPCIState, (obj), TYPE_VIRTIO_9P_PCI)
@ -330,7 +330,7 @@ typedef struct V9fsPCIState {
/* /*
* virtio-rng-pci: This extends VirtioPCIProxy. * virtio-rng-pci: This extends VirtioPCIProxy.
*/ */
#define TYPE_VIRTIO_RNG_PCI "virtio-rng-pci" #define TYPE_VIRTIO_RNG_PCI "virtio-rng-pci-base"
#define VIRTIO_RNG_PCI(obj) \ #define VIRTIO_RNG_PCI(obj) \
OBJECT_CHECK(VirtIORngPCI, (obj), TYPE_VIRTIO_RNG_PCI) OBJECT_CHECK(VirtIORngPCI, (obj), TYPE_VIRTIO_RNG_PCI)
@ -365,7 +365,7 @@ struct VirtIOInputHIDPCI {
#ifdef CONFIG_LINUX #ifdef CONFIG_LINUX
#define TYPE_VIRTIO_INPUT_HOST_PCI "virtio-input-host-pci" #define TYPE_VIRTIO_INPUT_HOST_PCI "virtio-input-host-pci-base"
#define VIRTIO_INPUT_HOST_PCI(obj) \ #define VIRTIO_INPUT_HOST_PCI(obj) \
OBJECT_CHECK(VirtIOInputHostPCI, (obj), TYPE_VIRTIO_INPUT_HOST_PCI) OBJECT_CHECK(VirtIOInputHostPCI, (obj), TYPE_VIRTIO_INPUT_HOST_PCI)
@ -392,7 +392,7 @@ struct VirtIOGPUPCI {
/* /*
* vhost-vsock-pci: This extends VirtioPCIProxy. * vhost-vsock-pci: This extends VirtioPCIProxy.
*/ */
#define TYPE_VHOST_VSOCK_PCI "vhost-vsock-pci" #define TYPE_VHOST_VSOCK_PCI "vhost-vsock-pci-base"
#define VHOST_VSOCK_PCI(obj) \ #define VHOST_VSOCK_PCI(obj) \
OBJECT_CHECK(VHostVSockPCI, (obj), TYPE_VHOST_VSOCK_PCI) OBJECT_CHECK(VHostVSockPCI, (obj), TYPE_VHOST_VSOCK_PCI)
@ -417,4 +417,58 @@ struct VirtIOCryptoPCI {
/* Virtio ABI version, if we increment this, we break the guest driver. */ /* Virtio ABI version, if we increment this, we break the guest driver. */
#define VIRTIO_PCI_ABI_VERSION 0 #define VIRTIO_PCI_ABI_VERSION 0
/* Input for virtio_pci_types_register() */
typedef struct VirtioPCIDeviceTypeInfo {
/*
* Common base class for the subclasses below.
*
* Required only if transitional_name or non_transitional_name is set.
*
* We need a separate base type instead of making all types
* inherit from generic_name for two reasons:
* 1) generic_name implements INTERFACE_PCIE_DEVICE, but
* transitional_name does not.
* 2) generic_name has the "disable-legacy" and "disable-modern"
* properties, transitional_name and non_transitional name don't.
*/
const char *base_name;
/*
* Generic device type. Optional.
*
* Supports both transitional and non-transitional modes,
* using the disable-legacy and disable-modern properties.
* If disable-legacy=auto, (non-)transitional mode is selected
* depending on the bus where the device is plugged.
*
* Implements both INTERFACE_PCIE_DEVICE and INTERFACE_CONVENTIONAL_PCI_DEVICE,
* but PCI Express is supported only in non-transitional mode.
*
* The only type implemented by QEMU 3.1 and older.
*/
const char *generic_name;
/*
* The transitional device type. Optional.
*
* Implements both INTERFACE_PCIE_DEVICE and INTERFACE_CONVENTIONAL_PCI_DEVICE.
*/
const char *transitional_name;
/*
* The non-transitional device type. Optional.
*
* Implements INTERFACE_CONVENTIONAL_PCI_DEVICE only.
*/
const char *non_transitional_name;
/* Parent type. If NULL, TYPE_VIRTIO_PCI is used */
const char *parent;
/* Same as TypeInfo fields: */
size_t instance_size;
void (*instance_init)(Object *obj);
void (*class_init)(ObjectClass *klass, void *data);
} VirtioPCIDeviceTypeInfo;
/* Register virtio-pci type(s). @t must be static. */
void virtio_pci_types_register(const VirtioPCIDeviceTypeInfo *t);
#endif #endif

View File

@ -40,18 +40,13 @@ enum {
ACPI_FADT_F_LOW_POWER_S0_IDLE_CAPABLE, ACPI_FADT_F_LOW_POWER_S0_IDLE_CAPABLE,
}; };
struct AcpiRsdpDescriptor { /* Root System Descriptor Pointer */ typedef struct AcpiRsdpData {
uint64_t signature; /* ACPI signature, contains "RSD PTR " */ uint8_t oem_id[6]; /* OEM identification */
uint8_t checksum; /* To make sum of struct == 0 */ uint8_t revision; /* Must be 0 for 1.0, 2 for 2.0 */
uint8_t oem_id [6]; /* OEM identification */
uint8_t revision; /* Must be 0 for 1.0, 2 for 2.0 */ unsigned *rsdt_tbl_offset;
uint32_t rsdt_physical_address; /* 32-bit physical address of RSDT */ unsigned *xsdt_tbl_offset;
uint32_t length; /* XSDT Length in bytes including hdr */ } AcpiRsdpData;
uint64_t xsdt_physical_address; /* 64-bit physical address of XSDT */
uint8_t extended_checksum; /* Checksum of entire table */
uint8_t reserved [3]; /* Reserved field must be 0 */
} QEMU_PACKED;
typedef struct AcpiRsdpDescriptor AcpiRsdpDescriptor;
/* Table structure from Linux kernel (the ACPI tables are under the /* Table structure from Linux kernel (the ACPI tables are under the
BSD license) */ BSD license) */

View File

@ -388,6 +388,8 @@ void acpi_add_table(GArray *table_offsets, GArray *table_data);
void acpi_build_tables_init(AcpiBuildTables *tables); void acpi_build_tables_init(AcpiBuildTables *tables);
void acpi_build_tables_cleanup(AcpiBuildTables *tables, bool mfre); void acpi_build_tables_cleanup(AcpiBuildTables *tables, bool mfre);
void void
build_rsdp(GArray *tbl, BIOSLinker *linker, AcpiRsdpData *rsdp_data);
void
build_rsdt(GArray *table_data, BIOSLinker *linker, GArray *table_offsets, build_rsdt(GArray *table_data, BIOSLinker *linker, GArray *table_offsets,
const char *oem_id, const char *oem_table_id); const char *oem_id, const char *oem_table_id);
void void

View File

@ -56,10 +56,15 @@ typedef struct AcpiPciHpState {
void acpi_pcihp_init(Object *owner, AcpiPciHpState *, PCIBus *root, void acpi_pcihp_init(Object *owner, AcpiPciHpState *, PCIBus *root,
MemoryRegion *address_space_io, bool bridges_enabled); MemoryRegion *address_space_io, bool bridges_enabled);
void acpi_pcihp_device_pre_plug_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp);
void acpi_pcihp_device_plug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s, void acpi_pcihp_device_plug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s,
DeviceState *dev, Error **errp); DeviceState *dev, Error **errp);
void acpi_pcihp_device_unplug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s, void acpi_pcihp_device_unplug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s,
DeviceState *dev, Error **errp); DeviceState *dev, Error **errp);
void acpi_pcihp_device_unplug_request_cb(HotplugHandler *hotplug_dev,
AcpiPciHpState *s, DeviceState *dev,
Error **errp);
/* Called on reset */ /* Called on reset */
void acpi_pcihp_reset(AcpiPciHpState *s); void acpi_pcihp_reset(AcpiPciHpState *s);

View File

@ -195,6 +195,7 @@ struct MachineClass {
const char *hw_version; const char *hw_version;
ram_addr_t default_ram_size; ram_addr_t default_ram_size;
const char *default_cpu_type; const char *default_cpu_type;
bool default_kernel_irqchip_split;
bool option_rom_has_mr; bool option_rom_has_mr;
bool rom_file_has_mr; bool rom_file_has_mr;
int minimum_page_bits; int minimum_page_bits;

View File

@ -2,7 +2,15 @@
#define HW_COMPAT_H #define HW_COMPAT_H
#define HW_COMPAT_3_1 \ #define HW_COMPAT_3_1 \
/* empty */ {\
.driver = "pcie-root-port",\
.property = "x-speed",\
.value = "2_5",\
},{\
.driver = "pcie-root-port",\
.property = "x-width",\
.value = "1",\
},
#define HW_COMPAT_3_0 \ #define HW_COMPAT_3_0 \
/* empty */ /* empty */

View File

@ -245,6 +245,7 @@ struct IntelIOMMUState {
OnOffAuto intr_eim; /* Toggle for EIM cabability */ OnOffAuto intr_eim; /* Toggle for EIM cabability */
bool buggy_eim; /* Force buggy EIM unless eim=off */ bool buggy_eim; /* Force buggy EIM unless eim=off */
uint8_t aw_bits; /* Host/IOVA address width (in bits) */ uint8_t aw_bits; /* Host/IOVA address width (in bits) */
bool dma_drain; /* Whether DMA r/w draining enabled */
/* /*
* Protects IOMMU states in general. Currently it protects the * Protects IOMMU states in general. Currently it protects the

View File

@ -296,6 +296,11 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
#define PC_COMPAT_3_1 \ #define PC_COMPAT_3_1 \
HW_COMPAT_3_1 \ HW_COMPAT_3_1 \
{\
.driver = "intel-iommu",\
.property = "dma-drain",\
.value = "off",\
},
#define PC_COMPAT_3_0 \ #define PC_COMPAT_3_0 \
HW_COMPAT_3_0 \ HW_COMPAT_3_0 \

View File

@ -74,13 +74,15 @@ typedef struct IEC_Notifier IEC_Notifier;
struct X86IOMMUState { struct X86IOMMUState {
SysBusDevice busdev; SysBusDevice busdev;
bool intr_supported; /* Whether vIOMMU supports IR */ OnOffAuto intr_supported; /* Whether vIOMMU supports IR */
bool dt_supported; /* Whether vIOMMU supports DT */ bool dt_supported; /* Whether vIOMMU supports DT */
bool pt_supported; /* Whether vIOMMU supports pass-through */ bool pt_supported; /* Whether vIOMMU supports pass-through */
IommuType type; /* IOMMU type - AMD/Intel */ IommuType type; /* IOMMU type - AMD/Intel */
QLIST_HEAD(, IEC_Notifier) iec_notifiers; /* IEC notify list */ QLIST_HEAD(, IEC_Notifier) iec_notifiers; /* IEC notify list */
}; };
bool x86_iommu_ir_supported(X86IOMMUState *s);
/* Generic IRQ entry information when interrupt remapping is enabled */ /* Generic IRQ entry information when interrupt remapping is enabled */
struct X86IOMMUIrq { struct X86IOMMUIrq {
/* Used by both IOAPIC/MSI interrupt remapping */ /* Used by both IOAPIC/MSI interrupt remapping */

View File

@ -737,6 +737,19 @@ static inline int pci_is_express(const PCIDevice *d)
return d->cap_present & QEMU_PCI_CAP_EXPRESS; return d->cap_present & QEMU_PCI_CAP_EXPRESS;
} }
static inline int pci_is_express_downstream_port(const PCIDevice *d)
{
uint8_t type;
if (!pci_is_express(d) || !d->exp.exp_cap) {
return 0;
}
type = pcie_cap_get_type(d);
return type == PCI_EXP_TYPE_DOWNSTREAM || type == PCI_EXP_TYPE_ROOT_PORT;
}
static inline uint32_t pci_config_size(const PCIDevice *d) static inline uint32_t pci_config_size(const PCIDevice *d)
{ {
return pci_is_express(d) ? PCIE_CONFIG_SPACE_SIZE : PCI_CONFIG_SPACE_SIZE; return pci_is_express(d) ? PCIE_CONFIG_SPACE_SIZE : PCI_CONFIG_SPACE_SIZE;

View File

@ -99,6 +99,12 @@ void pci_bridge_reset(DeviceState *qdev);
void pci_bridge_initfn(PCIDevice *pci_dev, const char *typename); void pci_bridge_initfn(PCIDevice *pci_dev, const char *typename);
void pci_bridge_exitfn(PCIDevice *pci_dev); void pci_bridge_exitfn(PCIDevice *pci_dev);
void pci_bridge_dev_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp);
void pci_bridge_dev_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp);
void pci_bridge_dev_unplug_request_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp);
/* /*
* before qdev initialization(qdev_init()), this function sets bus_name and * before qdev initialization(qdev_init()), this function sets bus_name and

View File

@ -126,13 +126,16 @@ uint16_t pcie_find_capability(PCIDevice *dev, uint16_t cap_id);
void pcie_add_capability(PCIDevice *dev, void pcie_add_capability(PCIDevice *dev,
uint16_t cap_id, uint8_t cap_ver, uint16_t cap_id, uint8_t cap_ver,
uint16_t offset, uint16_t size); uint16_t offset, uint16_t size);
void pcie_sync_bridge_lnk(PCIDevice *dev);
void pcie_ari_init(PCIDevice *dev, uint16_t offset, uint16_t nextfn); void pcie_ari_init(PCIDevice *dev, uint16_t offset, uint16_t nextfn);
void pcie_dev_ser_num_init(PCIDevice *dev, uint16_t offset, uint64_t ser_num); void pcie_dev_ser_num_init(PCIDevice *dev, uint16_t offset, uint64_t ser_num);
void pcie_ats_init(PCIDevice *dev, uint16_t offset); void pcie_ats_init(PCIDevice *dev, uint16_t offset);
void pcie_cap_slot_hotplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, void pcie_cap_slot_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp); Error **errp);
void pcie_cap_slot_hot_unplug_request_cb(HotplugHandler *hotplug_dev, void pcie_cap_slot_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
DeviceState *dev, Error **errp); Error **errp);
void pcie_cap_slot_unplug_request_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp);
#endif /* QEMU_PCIE_H */ #endif /* QEMU_PCIE_H */

View File

@ -49,6 +49,10 @@ struct PCIESlot {
/* pci express switch port with slot */ /* pci express switch port with slot */
uint8_t chassis; uint8_t chassis;
uint16_t slot; uint16_t slot;
PCIExpLinkSpeed speed;
PCIExpLinkWidth width;
QLIST_ENTRY(PCIESlot) next; QLIST_ENTRY(PCIESlot) next;
}; };

View File

@ -34,10 +34,29 @@
/* PCI_EXP_LINK{CAP, STA} */ /* PCI_EXP_LINK{CAP, STA} */
/* link speed */ /* link speed */
#define PCI_EXP_LNK_LS_25 1 typedef enum PCIExpLinkSpeed {
QEMU_PCI_EXP_LNK_2_5GT = 1,
QEMU_PCI_EXP_LNK_5GT,
QEMU_PCI_EXP_LNK_8GT,
QEMU_PCI_EXP_LNK_16GT,
} PCIExpLinkSpeed;
#define QEMU_PCI_EXP_LNKCAP_MLS(speed) (speed)
#define QEMU_PCI_EXP_LNKSTA_CLS QEMU_PCI_EXP_LNKCAP_MLS
typedef enum PCIExpLinkWidth {
QEMU_PCI_EXP_LNK_X1 = 1,
QEMU_PCI_EXP_LNK_X2 = 2,
QEMU_PCI_EXP_LNK_X4 = 4,
QEMU_PCI_EXP_LNK_X8 = 8,
QEMU_PCI_EXP_LNK_X12 = 12,
QEMU_PCI_EXP_LNK_X16 = 16,
QEMU_PCI_EXP_LNK_X32 = 32,
} PCIExpLinkWidth;
#define PCI_EXP_LNK_MLW_SHIFT ctz32(PCI_EXP_LNKCAP_MLW) #define PCI_EXP_LNK_MLW_SHIFT ctz32(PCI_EXP_LNKCAP_MLW)
#define PCI_EXP_LNK_MLW_1 (1 << PCI_EXP_LNK_MLW_SHIFT) #define QEMU_PCI_EXP_LNKCAP_MLW(width) (width << PCI_EXP_LNK_MLW_SHIFT)
#define QEMU_PCI_EXP_LNKSTA_NLW QEMU_PCI_EXP_LNKCAP_MLW
/* PCI_EXP_LINKCAP */ /* PCI_EXP_LINKCAP */
#define PCI_EXP_LNKCAP_ASPMS_SHIFT ctz32(PCI_EXP_LNKCAP_ASPMS) #define PCI_EXP_LNKCAP_ASPMS_SHIFT ctz32(PCI_EXP_LNKCAP_ASPMS)

View File

@ -45,10 +45,12 @@ void shpc_free(PCIDevice *dev);
void shpc_cap_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int len); void shpc_cap_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int len);
void shpc_device_hotplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, void shpc_device_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp); Error **errp);
void shpc_device_hot_unplug_request_cb(HotplugHandler *hotplug_dev, void shpc_device_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
DeviceState *dev, Error **errp); Error **errp);
void shpc_device_unplug_request_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp);
extern VMStateInfo shpc_vmstate_info; extern VMStateInfo shpc_vmstate_info;
#define SHPC_VMSTATE(_field, _type, _test) \ #define SHPC_VMSTATE(_field, _type, _test) \

View File

@ -36,6 +36,8 @@ extern const PropertyInfo qdev_prop_uuid;
extern const PropertyInfo qdev_prop_arraylen; extern const PropertyInfo qdev_prop_arraylen;
extern const PropertyInfo qdev_prop_link; extern const PropertyInfo qdev_prop_link;
extern const PropertyInfo qdev_prop_off_auto_pcibar; extern const PropertyInfo qdev_prop_off_auto_pcibar;
extern const PropertyInfo qdev_prop_pcie_link_speed;
extern const PropertyInfo qdev_prop_pcie_link_width;
#define DEFINE_PROP(_name, _state, _field, _prop, _type) { \ #define DEFINE_PROP(_name, _state, _field, _prop, _type) { \
.name = (_name), \ .name = (_name), \
@ -217,6 +219,12 @@ extern const PropertyInfo qdev_prop_off_auto_pcibar;
#define DEFINE_PROP_OFF_AUTO_PCIBAR(_n, _s, _f, _d) \ #define DEFINE_PROP_OFF_AUTO_PCIBAR(_n, _s, _f, _d) \
DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_off_auto_pcibar, \ DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_off_auto_pcibar, \
OffAutoPCIBAR) OffAutoPCIBAR)
#define DEFINE_PROP_PCIE_LINK_SPEED(_n, _s, _f, _d) \
DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_pcie_link_speed, \
PCIExpLinkSpeed)
#define DEFINE_PROP_PCIE_LINK_WIDTH(_n, _s, _f, _d) \
DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_pcie_link_width, \
PCIExpLinkWidth)
#define DEFINE_PROP_UUID(_name, _state, _field) { \ #define DEFINE_PROP_UUID(_name, _state, _field) { \
.name = (_name), \ .name = (_name), \

View File

@ -1,15 +0,0 @@
/*
* IPMI SMBIOS firmware handling
*
* Copyright (c) 2015,2016 Corey Minyard, MontaVista Software, LLC
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#ifndef QEMU_SMBIOS_IPMI_H
#define QEMU_SMBIOS_IPMI_H
void smbios_build_type_38_table(void);
#endif /* QEMU_SMBIOS_IPMI_H */

View File

@ -127,6 +127,48 @@
{ 'enum': 'OffAutoPCIBAR', { 'enum': 'OffAutoPCIBAR',
'data': [ 'off', 'auto', 'bar0', 'bar1', 'bar2', 'bar3', 'bar4', 'bar5' ] } 'data': [ 'off', 'auto', 'bar0', 'bar1', 'bar2', 'bar3', 'bar4', 'bar5' ] }
##
# @PCIELinkSpeed:
#
# An enumeration of PCIe link speeds in units of GT/s
#
# @2_5: 2.5GT/s
#
# @5: 5.0GT/s
#
# @8: 8.0GT/s
#
# @16: 16.0GT/s
#
# Since: 4.0
##
{ 'enum': 'PCIELinkSpeed',
'data': [ '2_5', '5', '8', '16' ] }
##
# @PCIELinkWidth:
#
# An enumeration of PCIe link width
#
# @1: x1
#
# @2: x2
#
# @4: x4
#
# @8: x8
#
# @12: x12
#
# @16: x16
#
# @32: x32
#
# Since: 4.0
##
{ 'enum': 'PCIELinkWidth',
'data': [ '1', '2', '4', '8', '12', '16', '32' ] }
## ##
# @SysEmuTarget: # @SysEmuTarget:
# #

View File

@ -134,7 +134,7 @@ their usecases.
@section System emulator machines @section System emulator machines
@subsection pc-0.10 and pc-0.11 (since 3.0) @subsection pc-0.12, pc-0.13, pc-0.14 and pc-0.15 (since 4.0)
These machine types are very old and likely can not be used for live migration These machine types are very old and likely can not be used for live migration
from old QEMU versions anymore. A newer machine type should be used instead. from old QEMU versions anymore. A newer machine type should be used instead.

View File

@ -0,0 +1,176 @@
"""
Check compatibility of virtio device types
"""
# Copyright (c) 2018 Red Hat, Inc.
#
# Author:
# Eduardo Habkost <ehabkost@redhat.com>
#
# This work is licensed under the terms of the GNU GPL, version 2 or
# later. See the COPYING file in the top-level directory.
import sys
import os
sys.path.append(os.path.join(os.path.dirname(__file__), "..", "..", "scripts"))
from qemu import QEMUMachine
from avocado_qemu import Test
# Virtio Device IDs:
VIRTIO_NET = 1
VIRTIO_BLOCK = 2
VIRTIO_CONSOLE = 3
VIRTIO_RNG = 4
VIRTIO_BALLOON = 5
VIRTIO_RPMSG = 7
VIRTIO_SCSI = 8
VIRTIO_9P = 9
VIRTIO_RPROC_SERIAL = 11
VIRTIO_CAIF = 12
VIRTIO_GPU = 16
VIRTIO_INPUT = 18
VIRTIO_VSOCK = 19
VIRTIO_CRYPTO = 20
PCI_VENDOR_ID_REDHAT_QUMRANET = 0x1af4
# Device IDs for legacy/transitional devices:
PCI_LEGACY_DEVICE_IDS = {
VIRTIO_NET: 0x1000,
VIRTIO_BLOCK: 0x1001,
VIRTIO_BALLOON: 0x1002,
VIRTIO_CONSOLE: 0x1003,
VIRTIO_SCSI: 0x1004,
VIRTIO_RNG: 0x1005,
VIRTIO_9P: 0x1009,
VIRTIO_VSOCK: 0x1012,
}
def pci_modern_device_id(virtio_devid):
return virtio_devid + 0x1040
def devtype_implements(vm, devtype, implements):
return devtype in [d['name'] for d in vm.command('qom-list-types', implements=implements)]
def get_pci_interfaces(vm, devtype):
interfaces = ('pci-express-device', 'conventional-pci-device')
return [i for i in interfaces if devtype_implements(vm, devtype, i)]
class VirtioVersionCheck(Test):
"""
Check if virtio-version-specific device types result in the
same device tree created by `disable-modern` and
`disable-legacy`.
:avocado: enable
:avocado: tags=x86_64
"""
# just in case there are failures, show larger diff:
maxDiff = 4096
def run_device(self, devtype, opts=None, machine='pc'):
"""
Run QEMU with `-device DEVTYPE`, return device info from `query-pci`
"""
with QEMUMachine(self.qemu_bin) as vm:
vm.set_machine(machine)
if opts:
devtype += ',' + opts
vm.add_args('-device', '%s,id=devfortest' % (devtype))
vm.add_args('-S')
vm.launch()
pcibuses = vm.command('query-pci')
alldevs = [dev for bus in pcibuses for dev in bus['devices']]
devfortest = [dev for dev in alldevs
if dev['qdev_id'] == 'devfortest']
return devfortest[0], get_pci_interfaces(vm, devtype)
def assert_devids(self, dev, devid, non_transitional=False):
self.assertEqual(dev['id']['vendor'], PCI_VENDOR_ID_REDHAT_QUMRANET)
self.assertEqual(dev['id']['device'], devid)
if non_transitional:
self.assertTrue(0x1040 <= dev['id']['device'] <= 0x107f)
self.assertGreaterEqual(dev['id']['subsystem'], 0x40)
def check_all_variants(self, qemu_devtype, virtio_devid):
"""Check if a virtio device type and its variants behave as expected"""
# Force modern mode:
dev_modern, _ = self.run_device(qemu_devtype,
'disable-modern=off,disable-legacy=on')
self.assert_devids(dev_modern, pci_modern_device_id(virtio_devid),
non_transitional=True)
# <prefix>-non-transitional device types should be 100% equivalent to
# <prefix>,disable-modern=off,disable-legacy=on
dev_1_0, nt_ifaces = self.run_device('%s-non-transitional' % (qemu_devtype))
self.assertEqual(dev_modern, dev_1_0)
# Force transitional mode:
dev_trans, _ = self.run_device(qemu_devtype,
'disable-modern=off,disable-legacy=off')
self.assert_devids(dev_trans, PCI_LEGACY_DEVICE_IDS[virtio_devid])
# Force legacy mode:
dev_legacy, _ = self.run_device(qemu_devtype,
'disable-modern=on,disable-legacy=off')
self.assert_devids(dev_legacy, PCI_LEGACY_DEVICE_IDS[virtio_devid])
# No options: default to transitional on PC machine-type:
no_opts_pc, generic_ifaces = self.run_device(qemu_devtype)
self.assertEqual(dev_trans, no_opts_pc)
#TODO: check if plugging on a PCI Express bus will make the
# device non-transitional
#no_opts_q35 = self.run_device(qemu_devtype, machine='q35')
#self.assertEqual(dev_modern, no_opts_q35)
# <prefix>-transitional device types should be 100% equivalent to
# <prefix>,disable-modern=off,disable-legacy=off
dev_trans, trans_ifaces = self.run_device('%s-transitional' % (qemu_devtype))
self.assertEqual(dev_trans, dev_trans)
# ensure the interface information is correct:
self.assertIn('conventional-pci-device', generic_ifaces)
self.assertIn('pci-express-device', generic_ifaces)
self.assertIn('conventional-pci-device', nt_ifaces)
self.assertIn('pci-express-device', nt_ifaces)
self.assertIn('conventional-pci-device', trans_ifaces)
self.assertNotIn('pci-express-device', trans_ifaces)
def test_conventional_devs(self):
self.check_all_variants('virtio-net-pci', VIRTIO_NET)
# virtio-blk requires 'driver' parameter
#self.check_all_variants('virtio-blk-pci', VIRTIO_BLOCK)
self.check_all_variants('virtio-serial-pci', VIRTIO_CONSOLE)
self.check_all_variants('virtio-rng-pci', VIRTIO_RNG)
self.check_all_variants('virtio-balloon-pci', VIRTIO_BALLOON)
self.check_all_variants('virtio-scsi-pci', VIRTIO_SCSI)
# virtio-9p requires 'fsdev' parameter
#self.check_all_variants('virtio-9p-pci', VIRTIO_9P)
def check_modern_only(self, qemu_devtype, virtio_devid):
"""Check if a modern-only virtio device type behaves as expected"""
# Force modern mode:
dev_modern, _ = self.run_device(qemu_devtype,
'disable-modern=off,disable-legacy=on')
self.assert_devids(dev_modern, pci_modern_device_id(virtio_devid),
non_transitional=True)
# No options: should be modern anyway
dev_no_opts, ifaces = self.run_device(qemu_devtype)
self.assertEqual(dev_modern, dev_no_opts)
self.assertIn('conventional-pci-device', ifaces)
self.assertIn('pci-express-device', ifaces)
def test_modern_only_devs(self):
self.check_modern_only('virtio-vga', VIRTIO_GPU)
self.check_modern_only('virtio-gpu-pci', VIRTIO_GPU)
self.check_modern_only('virtio-mouse-pci', VIRTIO_INPUT)
self.check_modern_only('virtio-tablet-pci', VIRTIO_INPUT)
self.check_modern_only('virtio-keyboard-pci', VIRTIO_INPUT)

View File

@ -15,7 +15,6 @@
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include <glib/gstdio.h> #include <glib/gstdio.h>
#include "qemu-common.h" #include "qemu-common.h"
#include "hw/smbios/smbios.h"
#include "qemu/bitmap.h" #include "qemu/bitmap.h"
#include "acpi-utils.h" #include "acpi-utils.h"
#include "boot-sector.h" #include "boot-sector.h"
@ -52,15 +51,44 @@ uint32_t acpi_find_rsdp_address(QTestState *qts)
return off; return off;
} }
void acpi_parse_rsdp_table(QTestState *qts, uint32_t addr, uint32_t acpi_get_rsdt_address(uint8_t *rsdp_table)
AcpiRsdpDescriptor *rsdp_table)
{ {
ACPI_READ_FIELD(qts, rsdp_table->signature, addr); uint32_t rsdt_physical_address;
ACPI_ASSERT_CMP64(rsdp_table->signature, "RSD PTR ");
ACPI_READ_FIELD(qts, rsdp_table->checksum, addr); memcpy(&rsdt_physical_address, &rsdp_table[16 /* RsdtAddress offset */], 4);
ACPI_READ_ARRAY(qts, rsdp_table->oem_id, addr); return le32_to_cpu(rsdt_physical_address);
ACPI_READ_FIELD(qts, rsdp_table->revision, addr); }
ACPI_READ_FIELD(qts, rsdp_table->rsdt_physical_address, addr);
ACPI_READ_FIELD(qts, rsdp_table->length, addr); uint64_t acpi_get_xsdt_address(uint8_t *rsdp_table)
{
uint64_t xsdt_physical_address;
uint8_t revision = rsdp_table[15 /* Revision offset */];
/* We must have revision 2 if we're looking for an XSDT pointer */
g_assert(revision == 2);
memcpy(&xsdt_physical_address, &rsdp_table[24 /* XsdtAddress offset */], 8);
return le64_to_cpu(xsdt_physical_address);
}
void acpi_parse_rsdp_table(QTestState *qts, uint32_t addr, uint8_t *rsdp_table)
{
uint8_t revision;
/* Read mandatory revision 0 table data (20 bytes) first */
qtest_memread(qts, addr, rsdp_table, 20);
revision = rsdp_table[15 /* Revision offset */];
switch (revision) {
case 0: /* ACPI 1.0 RSDP */
break;
case 2: /* ACPI 2.0+ RSDP */
/* Read the rest of the RSDP table */
qtest_memread(qts, addr + 20, rsdp_table + 20, 16);
break;
default:
g_assert_not_reached();
}
ACPI_ASSERT_CMP64(*((uint64_t *)(rsdp_table)), "RSD PTR ");
} }

View File

@ -74,7 +74,8 @@ typedef struct {
uint8_t acpi_calc_checksum(const uint8_t *data, int len); uint8_t acpi_calc_checksum(const uint8_t *data, int len);
uint32_t acpi_find_rsdp_address(QTestState *qts); uint32_t acpi_find_rsdp_address(QTestState *qts);
void acpi_parse_rsdp_table(QTestState *qts, uint32_t addr, uint32_t acpi_get_rsdt_address(uint8_t *rsdp_table);
AcpiRsdpDescriptor *rsdp_table); uint64_t acpi_get_xsdt_address(uint8_t *rsdp_table);
void acpi_parse_rsdp_table(QTestState *qts, uint32_t addr, uint8_t *rsdp_table);
#endif /* TEST_ACPI_UTILS_H */ #endif /* TEST_ACPI_UTILS_H */

View File

@ -13,7 +13,7 @@
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include <glib/gstdio.h> #include <glib/gstdio.h>
#include "qemu-common.h" #include "qemu-common.h"
#include "hw/smbios/smbios.h" #include "hw/firmware/smbios.h"
#include "qemu/bitmap.h" #include "qemu/bitmap.h"
#include "acpi-utils.h" #include "acpi-utils.h"
#include "boot-sector.h" #include "boot-sector.h"
@ -27,7 +27,7 @@ typedef struct {
const char *machine; const char *machine;
const char *variant; const char *variant;
uint32_t rsdp_addr; uint32_t rsdp_addr;
AcpiRsdpDescriptor rsdp_table; uint8_t rsdp_table[36 /* ACPI 2.0+ RSDP size */];
AcpiRsdtDescriptorRev1 rsdt_table; AcpiRsdtDescriptorRev1 rsdt_table;
uint32_t dsdt_addr; uint32_t dsdt_addr;
uint32_t facs_addr; uint32_t facs_addr;
@ -86,19 +86,31 @@ static void test_acpi_rsdp_address(test_data *data)
static void test_acpi_rsdp_table(test_data *data) static void test_acpi_rsdp_table(test_data *data)
{ {
AcpiRsdpDescriptor *rsdp_table = &data->rsdp_table; uint8_t *rsdp_table = data->rsdp_table, revision;
uint32_t addr = data->rsdp_addr; uint32_t addr = data->rsdp_addr;
acpi_parse_rsdp_table(data->qts, addr, rsdp_table); acpi_parse_rsdp_table(data->qts, addr, rsdp_table);
revision = rsdp_table[15 /* Revision offset */];
/* rsdp checksum is not for the whole table, but for the first 20 bytes */ switch (revision) {
g_assert(!acpi_calc_checksum((uint8_t *)rsdp_table, 20)); case 0: /* ACPI 1.0 RSDP */
/* With rev 1, checksum is only for the first 20 bytes */
g_assert(!acpi_calc_checksum(rsdp_table, 20));
break;
case 2: /* ACPI 2.0+ RSDP */
/* With revision 2, we have 2 checksums */
g_assert(!acpi_calc_checksum(rsdp_table, 20));
g_assert(!acpi_calc_checksum(rsdp_table, 36));
break;
default:
g_assert_not_reached();
}
} }
static void test_acpi_rsdt_table(test_data *data) static void test_acpi_rsdt_table(test_data *data)
{ {
AcpiRsdtDescriptorRev1 *rsdt_table = &data->rsdt_table; AcpiRsdtDescriptorRev1 *rsdt_table = &data->rsdt_table;
uint32_t addr = le32_to_cpu(data->rsdp_table.rsdt_physical_address); uint32_t addr = acpi_get_rsdt_address(data->rsdp_table);
uint32_t *tables; uint32_t *tables;
int tables_nr; int tables_nr;
uint8_t checksum; uint8_t checksum;

View File

@ -157,9 +157,7 @@ static void add_pc_test_case(const char *mname)
(strcmp(mname, "pc-0.15") == 0) || (strcmp(mname, "pc-0.15") == 0) ||
(strcmp(mname, "pc-0.14") == 0) || (strcmp(mname, "pc-0.14") == 0) ||
(strcmp(mname, "pc-0.13") == 0) || (strcmp(mname, "pc-0.13") == 0) ||
(strcmp(mname, "pc-0.12") == 0) || (strcmp(mname, "pc-0.12") == 0)) {
(strcmp(mname, "pc-0.11") == 0) ||
(strcmp(mname, "pc-0.10") == 0)) {
path = g_strdup_printf("cpu-plug/%s/init/%ux%ux%u&maxcpus=%u", path = g_strdup_printf("cpu-plug/%s/init/%ux%ux%u&maxcpus=%u",
mname, data->sockets, data->cores, mname, data->sockets, data->cores,
data->threads, data->maxcpus); data->threads, data->maxcpus);

View File

@ -35,7 +35,7 @@ static uint32_t acpi_find_vgia(QTestState *qts)
{ {
uint32_t rsdp_offset; uint32_t rsdp_offset;
uint32_t guid_offset = 0; uint32_t guid_offset = 0;
AcpiRsdpDescriptor rsdp_table; uint8_t rsdp_table[36 /* ACPI 2.0+ RSDP size */];
uint32_t rsdt, rsdt_table_length; uint32_t rsdt, rsdt_table_length;
AcpiRsdtDescriptorRev1 rsdt_table; AcpiRsdtDescriptorRev1 rsdt_table;
size_t tables_nr; size_t tables_nr;
@ -52,9 +52,11 @@ static uint32_t acpi_find_vgia(QTestState *qts)
g_assert_cmphex(rsdp_offset, <, RSDP_ADDR_INVALID); g_assert_cmphex(rsdp_offset, <, RSDP_ADDR_INVALID);
acpi_parse_rsdp_table(qts, rsdp_offset, &rsdp_table); acpi_parse_rsdp_table(qts, rsdp_offset, rsdp_table);
rsdt = acpi_get_rsdt_address(rsdp_table);
g_assert(rsdt);
rsdt = le32_to_cpu(rsdp_table.rsdt_physical_address);
/* read the header */ /* read the header */
ACPI_READ_TABLE_HEADER(qts, &rsdt_table, rsdt); ACPI_READ_TABLE_HEADER(qts, &rsdt_table, rsdt);
ACPI_ASSERT_CMP(rsdt_table.signature, "RSDT"); ACPI_ASSERT_CMP(rsdt_table.signature, "RSDT");

2
vl.c
View File

@ -61,7 +61,7 @@ int main(int argc, char **argv)
#include "hw/display/vga.h" #include "hw/display/vga.h"
#include "hw/bt.h" #include "hw/bt.h"
#include "sysemu/watchdog.h" #include "sysemu/watchdog.h"
#include "hw/smbios/smbios.h" #include "hw/firmware/smbios.h"
#include "hw/acpi/acpi.h" #include "hw/acpi/acpi.h"
#include "hw/xen/xen.h" #include "hw/xen/xen.h"
#include "hw/qdev.h" #include "hw/qdev.h"