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>
S: Supported
F: include/hw/acpi/*
F: include/hw/smbios/*
F: include/hw/firmware/smbios.h
F: hw/mem/*
F: hw/acpi/*
F: hw/smbios/*

View File

@ -1589,6 +1589,74 @@ void acpi_build_tables_cleanup(AcpiBuildTables *tables, bool 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 */
void
build_rsdt(GArray *table_data, BIOSLinker *linker, GArray *table_offsets,

View File

@ -30,6 +30,7 @@
#include "hw/hw.h"
#include "hw/i386/pc.h"
#include "hw/pci/pci.h"
#include "hw/pci/pci_bridge.h"
#include "hw/acpi/acpi.h"
#include "sysemu/sysemu.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)
{
HotplugHandler *hotplug_ctrl;
BusChild *kid, *next;
int slot = ctz32(slots);
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);
if (PCI_SLOT(dev->devfn) == slot) {
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);
}
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,
DeviceState *dev, Error **errp)
{
PCIDevice *pdev = PCI_DEVICE(dev);
int slot = PCI_SLOT(pdev->devfn);
int bsel = acpi_pcihp_get_bsel(pci_get_bus(pdev));
if (bsel < 0) {
error_setg(errp, "Unsupported bus. Bus doesn't have property '"
ACPI_PCIHP_PROP_BSEL "' set");
return;
}
int bsel;
/* 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
* event when the device is disabled later. */
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;
}
bsel = acpi_pcihp_get_bsel(pci_get_bus(pdev));
g_assert(bsel >= 0);
s->acpi_pcihp_pci_status[bsel].up |= (1U << slot);
acpi_send_event(DEVICE(hotplug_dev), ACPI_PCI_HOTPLUG_STATUS);
}
void acpi_pcihp_device_unplug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s,
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);
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;
pm_io_space_update(s);
smbus_io_space_update(s);
return 0;
}
@ -370,6 +371,18 @@ static void piix4_pm_powerdown_req(Notifier *n, void *opaque)
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,
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);
}
} else {
error_setg(errp, "acpi: device plug request for not supported device"
" type: %s", object_get_typename(OBJECT(dev)));
g_assert_not_reached();
}
}
@ -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,
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);
acpi_pcihp_device_unplug_request_cb(hotplug_dev, &s->acpi_pci_hotplug,
dev, errp);
} else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU) &&
!s->cpu_hotplug_legacy) {
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 &&
object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
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) &&
!s->cpu_hotplug_legacy) {
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)
{
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[0x67] = (memory_region_present(io_as, 0x3f8) ? 0x08 : 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)
@ -536,6 +536,7 @@ static void piix4_pm_realize(PCIDevice *dev, Error **errp)
piix4_acpi_system_hot_add_init(pci_address_space_io(dev),
pci_get_bus(dev), s);
qbus_set_hotplug_handler(BUS(pci_get_bus(dev)), DEVICE(s), &error_abort);
piix4_pm_add_propeties(s);
}
@ -702,6 +703,7 @@ static void piix4_pm_class_init(ObjectClass *klass, void *data)
*/
dc->user_creatable = false;
dc->hotpluggable = false;
hc->pre_plug = piix4_device_pre_plug_cb;
hc->plug = piix4_device_plug_cb;
hc->unplug_request = piix4_device_unplug_request_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);
}
/* 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
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);
/* 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. */
g_array_free(table_offsets, true);

View File

@ -55,7 +55,7 @@
#include "hw/intc/arm_gic.h"
#include "hw/intc/arm_gicv3_common.h"
#include "kvm_arm.h"
#include "hw/smbios/smbios.h"
#include "hw/firmware/smbios.h"
#include "qapi/visitor.h"
#include "standard-headers/linux/input.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)
{
MachineState *ms = MACHINE(obj);
MachineClass *mc = MACHINE_GET_CLASS(obj);
ms->kernel_irqchip_allowed = true;
ms->kernel_irqchip_split = mc->default_kernel_irqchip_split;
ms->kvm_shadow_mem = -1;
ms->dump_guest_core = true;
ms->mem_merge = true;

View File

@ -1297,3 +1297,179 @@ const PropertyInfo qdev_prop_off_auto_pcibar = {
.set = set_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);
}
static const TypeInfo virtio_gpu_pci_info = {
.name = TYPE_VIRTIO_GPU_PCI,
.parent = TYPE_VIRTIO_PCI,
static const VirtioPCIDeviceTypeInfo virtio_gpu_pci_info = {
.generic_name = TYPE_VIRTIO_GPU_PCI,
.instance_size = sizeof(VirtIOGPUPCI),
.instance_init = virtio_gpu_initfn,
.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)
{
type_register_static(&virtio_gpu_pci_info);
virtio_pci_types_register(&virtio_gpu_pci_info);
}
type_init(virtio_gpu_pci_register_types)

View File

@ -207,9 +207,8 @@ static void virtio_vga_inst_initfn(Object *obj)
TYPE_VIRTIO_GPU);
}
static TypeInfo virtio_vga_info = {
.name = TYPE_VIRTIO_VGA,
.parent = TYPE_VIRTIO_PCI,
static VirtioPCIDeviceTypeInfo virtio_vga_info = {
.generic_name = TYPE_VIRTIO_VGA,
.instance_size = sizeof(struct VirtIOVGA),
.instance_init = virtio_vga_inst_initfn,
.class_init = virtio_vga_class_init,
@ -217,7 +216,7 @@ static TypeInfo virtio_vga_info = {
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)

View File

@ -2426,7 +2426,7 @@ build_dmar_q35(GArray *table_data, BIOSLinker *linker)
IntelIOMMUState *intel_iommu = INTEL_IOMMU_DEVICE(iommu);
assert(iommu);
if (iommu->intr_supported) {
if (x86_iommu_ir_supported(iommu)) {
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
* 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 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).
* 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,
(0x1ull << 56) | /* type IOAPIC */
(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);
}
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
struct AcpiBuildState {
/* 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);
/* 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
* 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 */
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 "
"not in the host. Use intremap=on to enable interrupt "
"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);
if (dma_memory_read(&address_space_memory, addr, re, sizeof(*re))) {
trace_vtd_re_invalid(re->rsvd, re->val);
re->val = 0;
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 */
addr = (root->val & VTD_ROOT_ENTRY_CTP) + index * 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;
}
ce->lo = le64_to_cpu(ce->lo);
@ -630,16 +628,20 @@ static inline bool vtd_ce_type_check(X86IOMMUState *x86_iommu,
break;
case VTD_CONTEXT_TT_DEV_IOTLB:
if (!x86_iommu->dt_supported) {
error_report_once("%s: DT specified but not supported", __func__);
return false;
}
break;
case VTD_CONTEXT_TT_PASS_THROUGH:
if (!x86_iommu->pt_supported) {
error_report_once("%s: PT specified but not supported", __func__);
return false;
}
break;
default:
/* Unknwon type */
error_report_once("%s: unknown ce type: %"PRIu32, __func__,
vtd_ce_get_type(ce));
return false;
}
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))) {
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;
}
@ -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) ||
(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;
}
/* Check if the programming of context-entry is valid */
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;
}
/* Do translation type check */
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;
}
@ -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) ||
(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;
}
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 */
vtd_generate_completion_event(s);
} 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 true;
@ -1913,7 +1925,9 @@ static bool vtd_process_context_cache_desc(IntelIOMMUState *s,
uint16_t sid, fmask;
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;
}
switch (inv_desc->lo & VTD_INV_DESC_CC_G) {
@ -1932,7 +1946,9 @@ static bool vtd_process_context_cache_desc(IntelIOMMUState *s,
break;
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 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) ||
(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;
}
@ -1965,14 +1983,20 @@ static bool vtd_process_iotlb_desc(IntelIOMMUState *s, VTDInvDesc *inv_desc)
addr = VTD_INV_DESC_IOTLB_ADDR(inv_desc->hi);
am = VTD_INV_DESC_IOTLB_AM(inv_desc->hi);
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;
}
vtd_iotlb_page_invalidate(s, domain_id, addr, am);
break;
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 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) ||
(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;
}
@ -2103,7 +2129,9 @@ static bool vtd_process_inv_desc(IntelIOMMUState *s)
break;
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;
}
s->iq_head++;
@ -2540,7 +2568,7 @@ static IOMMUTLBEntry vtd_iommu_translate(IOMMUMemoryRegion *iommu, hwaddr addr,
__func__, pci_bus_num(vtd_as->bus),
VTD_PCI_SLOT(vtd_as->devfn),
VTD_PCI_FUNC(vtd_as->devfn),
iotlb.iova);
addr);
}
return iotlb;
@ -2628,9 +2656,10 @@ static Property vtd_properties[] = {
DEFINE_PROP_ON_OFF_AUTO("eim", IntelIOMMUState, intr_eim,
ON_OFF_AUTO_AUTO),
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),
DEFINE_PROP_BOOL("caching-mode", IntelIOMMUState, caching_mode, FALSE),
DEFINE_PROP_BOOL("dma-drain", IntelIOMMUState, dma_drain, true),
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 |
VTD_CAP_MAMV | VTD_CAP_PSI | VTD_CAP_SLLPS |
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) {
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[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;
if (s->intr_eim == ON_OFF_AUTO_ON) {
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);
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");
return false;
}
if (s->intr_eim == ON_OFF_AUTO_AUTO) {
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;
}
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_PSI (1ULL << 39)
#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)
/* Supported Adjusted Guest Address Widths */

View File

@ -37,7 +37,7 @@
#include "hw/pci/pci_bus.h"
#include "hw/nvram/fw_cfg.h"
#include "hw/timer/hpet.h"
#include "hw/smbios/smbios.h"
#include "hw/firmware/smbios.h"
#include "hw/loader.h"
#include "elf.h"
#include "multiboot.h"
@ -1244,7 +1244,7 @@ void pc_machine_done(Notifier *notifier, void *data)
if (pcms->apic_id_limit > 255 && !xen_enabled()) {
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) {
error_report("current -smp configuration requires "
"Extended Interrupt Mode enabled. "

View File

@ -30,7 +30,7 @@
#include "hw/i386/pc.h"
#include "hw/i386/apic.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_ids.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);
}
/* 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)
{
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);
m->hw_version = "0.15";
m->deprecation_reason = "use a newer machine type instead";
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,
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 {
uint16_t gpu_device_id;
uint16_t pch_device_id;

View File

@ -47,7 +47,7 @@
#include "hw/i386/amd_iommu.h"
#include "hw/i386/intel_iommu.h"
#include "hw/display/ramfb.h"
#include "hw/smbios/smbios.h"
#include "hw/firmware/smbios.h"
#include "hw/ide/pci.h"
#include "hw/ide/ahci.h"
#include "hw/usb.h"
@ -304,6 +304,7 @@ static void pc_q35_machine_options(MachineClass *m)
m->units_per_default_bus = 1;
m->default_machine_opts = "firmware=bios-256k.bin";
m->default_display = "std";
m->default_kernel_irqchip_split = true;
m->no_floppy = 1;
machine_class_allow_dynamic_sysbus_dev(m, TYPE_AMD_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)
{
pc_q35_4_0_machine_options(m);
m->default_kernel_irqchip_split = false;
m->alias = NULL;
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
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_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_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_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_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_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_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"
@ -27,9 +23,7 @@ vtd_inv_qi_tail(uint16_t head) "write tail %d"
vtd_inv_qi_fetch(void) ""
vtd_context_cache_reset(void) ""
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_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_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

View File

@ -112,6 +112,7 @@ static void x86_iommu_realize(DeviceState *dev, Error **errp)
PCMachineState *pcms =
PC_MACHINE(object_dynamic_cast(OBJECT(ms), TYPE_PC_MACHINE));
QLIST_INIT(&x86_iommu->iec_notifiers);
bool irq_all_kernel = kvm_irqchip_in_kernel() && !kvm_irqchip_is_split();
if (!pcms || !pcms->bus) {
error_setg(errp, "Machine-type '%s' not supported by IOMMU",
@ -119,9 +120,14 @@ static void x86_iommu_realize(DeviceState *dev, Error **errp)
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}" */
if (x86_iommu->intr_supported && kvm_irqchip_in_kernel() &&
!kvm_irqchip_is_split()) {
if (x86_iommu_ir_supported(x86_iommu) && irq_all_kernel) {
error_setg(errp, "Interrupt Remapping cannot work with "
"kernel-irqchip=on, please use 'split|off'.");
return;
@ -135,7 +141,8 @@ static void x86_iommu_realize(DeviceState *dev, Error **errp)
}
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("pt", X86IOMMUState, pt_supported, true),
DEFINE_PROP_END_OF_LIST(),
@ -148,6 +155,11 @@ static void x86_iommu_class_init(ObjectClass *klass, void *data)
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 = {
.name = TYPE_X86_IOMMU_DEVICE,
.parent = TYPE_SYS_BUS_DEVICE,

View File

@ -124,6 +124,10 @@ static Property gen_rp_props[] = {
res_reserve.mem_pref_32, -1),
DEFINE_PROP_SIZE("pref64-reserve", GenPCIERootPort,
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()
};

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)
{
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);
"this %s", object_get_typename(OBJECT(hotplug_dev)));
return;
}
shpc_device_hotplug_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);
shpc_device_unplug_request_cb(hotplug_dev, dev, errp);
}
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->vmsd = &pci_bridge_dev_vmstate;
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
hc->plug = pci_bridge_dev_hotplug_cb;
hc->unplug_request = pci_bridge_dev_hot_unplug_request_cb;
hc->plug = pci_bridge_dev_plug_cb;
hc->unplug = pci_bridge_dev_unplug_cb;
hc->unplug_request = pci_bridge_dev_unplug_request_cb;
}
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)
{
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->reset = &pcie_pci_bridge_reset;
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
hc->plug = pcie_pci_bridge_hotplug_cb;
hc->unplug_request = pcie_pci_bridge_hot_unplug_request_cb;
hc->plug = pci_bridge_dev_plug_cb;
hc->unplug = pci_bridge_dev_unplug_cb;
hc->unplug_request = pci_bridge_dev_unplug_request_cb;
}
static const TypeInfo pcie_pci_bridge_info = {

View File

@ -140,6 +140,19 @@ static Property rp_props[] = {
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)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@ -157,6 +170,7 @@ static void rp_class_init(ObjectClass *klass, void *data)
static const TypeInfo rp_info = {
.name = TYPE_PCIE_ROOT_PORT,
.parent = TYPE_PCIE_SLOT,
.instance_post_init = rp_instance_post_init,
.class_init = rp_class_init,
.abstract = true,
.class_size = sizeof(PCIERootPortClass),

View File

@ -1353,6 +1353,10 @@ uint32_t pci_default_read_config(PCIDevice *d,
{
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);
return le32_to_cpu(val);
}

View File

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

View File

@ -20,6 +20,7 @@
#include "qemu/osdep.h"
#include "hw/pci/pci.h"
#include "hw/pci/pci_bridge.h"
#include "hw/pci/pci_host.h"
#include "hw/pci/pci_bus.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);
}
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,
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);
/* non-zero functions are only exposed when function 0 is present,
* 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;
pci_adjust_config_limit(pci_get_bus(pci_dev), &limit);
if (limit <= addr) {
return ~0x0;
}
assert(len <= 4);
/* non-zero functions are only exposed when function 0 is present,
* allowing direct removal of unexposed functions.

View File

@ -27,6 +27,7 @@
#include "hw/pci/msi.h"
#include "hw/pci/pci_bus.h"
#include "hw/pci/pcie_regs.h"
#include "hw/pci/pcie_port.h"
#include "qemu/range.h"
//#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,
(port << PCI_EXP_LNKCAP_PN_SHIFT) |
PCI_EXP_LNKCAP_ASPMS_0S |
PCI_EXP_LNK_MLW_1 |
PCI_EXP_LNK_LS_25);
QEMU_PCI_EXP_LNKCAP_MLW(QEMU_PCI_EXP_LNK_X1) |
QEMU_PCI_EXP_LNKCAP_MLS(QEMU_PCI_EXP_LNK_2_5GT));
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) {
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);
}
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,
uint8_t type, uint8_t port,
Error **errp)
@ -107,6 +179,9 @@ int pcie_cap_init(PCIDevice *dev, uint8_t offset,
/* Filling values common with v1 */
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 */
pci_set_long(exp_cap + PCI_EXP_DEVCAP2,
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);
}
static void pcie_cap_slot_hotplug_common(PCIDevice *hotplug_dev,
DeviceState *dev,
uint8_t **exp_cap, Error **errp)
static void pcie_cap_slot_plug_common(PCIDevice *hotplug_dev, DeviceState *dev,
uint8_t **exp_cap, Error **errp)
{
*exp_cap = hotplug_dev->config + hotplug_dev->exp.exp_cap;
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,
Error **errp)
void pcie_cap_slot_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp)
{
uint8_t *exp_cap;
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:
* 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) {
pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA,
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;
}
@ -355,24 +433,36 @@ void pcie_cap_slot_hotplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
if (pci_get_function_0(pci_dev)) {
pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA,
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),
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));
}
void pcie_cap_slot_hot_unplug_request_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
static void pcie_unplug_device(PCIBus *bus, PCIDevice *dev, void *opaque)
{
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;
PCIDevice *pci_dev = PCI_DEVICE(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,
* 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_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_EXP_SLTSTA_PDC);
}
@ -728,6 +822,45 @@ void pcie_add_capability(PCIDevice *dev,
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
*/

View File

@ -154,8 +154,9 @@ static void pcie_slot_class_init(ObjectClass *oc, void *data)
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
dc->props = pcie_slot_props;
hc->plug = pcie_cap_slot_hotplug_cb;
hc->unplug_request = pcie_cap_slot_hot_unplug_request_cb;
hc->plug = pcie_cap_slot_plug_cb;
hc->unplug = pcie_cap_slot_unplug_cb;
hc->unplug_request = pcie_cap_slot_unplug_request_cb;
}
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)
{
HotplugHandler *hotplug_ctrl;
int devfn;
int pci_slot = SHPC_IDX_TO_PCI(slot);
for (devfn = PCI_DEVFN(pci_slot, 0);
@ -245,7 +246,9 @@ static void shpc_free_devices_in_slot(SHPCDevice *shpc, int slot)
++devfn) {
PCIDevice *affected_dev = shpc->sec_bus->devices[devfn];
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,
},
};
static void shpc_device_hotplug_common(PCIDevice *affected_dev, int *slot,
SHPCDevice *shpc, Error **errp)
static void shpc_device_plug_common(PCIDevice *affected_dev, int *slot,
SHPCDevice *shpc, Error **errp)
{
int pci_slot = PCI_SLOT(affected_dev->devfn);
*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 *local_err = NULL;
@ -505,7 +508,7 @@ void shpc_device_hotplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
SHPCDevice *shpc = pci_hotplug_dev->shpc;
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) {
error_propagate(errp, local_err);
return;
@ -540,8 +543,14 @@ void shpc_device_hotplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
shpc_interrupt_update(pci_hotplug_dev);
}
void shpc_device_hot_unplug_request_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
void shpc_device_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp)
{
object_unparent(OBJECT(dev));
}
void shpc_device_unplug_request_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
Error *local_err = NULL;
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;
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) {
error_propagate(errp, local_err);
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. */
void spapr_phb_remove_pci_device_cb(DeviceState *dev)
{
/* 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(dev));
object_unparent(OBJECT(dev));
HotplugHandler *hotplug_ctrl = qdev_get_hotplug_handler(dev);
hotplug_handler_unplug(hotplug_ctrl, dev, &error_abort);
}
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,
DeviceState *plugged_dev, Error **errp)
{
@ -1965,6 +1973,7 @@ static void spapr_phb_class_init(ObjectClass *klass, void *data)
dc->user_creatable = true;
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
hp->plug = spapr_pci_plug;
hp->unplug = spapr_pci_unplug;
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;
}
static void s390_pcihost_hot_plug(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
static void s390_pcihost_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp)
{
PCIDevice *pdev = NULL;
S390PCIBusDevice *pbdev = NULL;
@ -932,8 +932,8 @@ static void s390_pcihost_timer_cb(void *opaque)
qdev_unplug(DEVICE(pbdev), NULL);
}
static void s390_pcihost_hot_unplug(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
static void s390_pcihost_unplug(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp)
{
PCIDevice *pci_dev = NULL;
PCIBus *bus;
@ -1041,8 +1041,8 @@ static void s390_pcihost_class_init(ObjectClass *klass, void *data)
dc->reset = s390_pcihost_reset;
dc->realize = s390_pcihost_realize;
hc->plug = s390_pcihost_hot_plug;
hc->unplug = s390_pcihost_hot_unplug;
hc->plug = s390_pcihost_plug;
hc->unplug = s390_pcihost_unplug;
msi_nonbroken = true;
}

View File

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

View File

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

View File

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

View File

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

View File

@ -9,8 +9,7 @@
#include "qemu/osdep.h"
#include "hw/ipmi/ipmi.h"
#include "hw/smbios/ipmi.h"
#include "hw/smbios/smbios.h"
#include "hw/firmware/smbios.h"
#include "qemu/error-report.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_FLAGS_TYPE);
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);
}
/* 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);
}
static const TypeInfo virtio_crypto_pci_info = {
.name = TYPE_VIRTIO_CRYPTO_PCI,
.parent = TYPE_VIRTIO_PCI,
static const VirtioPCIDeviceTypeInfo virtio_crypto_pci_info = {
.generic_name = TYPE_VIRTIO_CRYPTO_PCI,
.instance_size = sizeof(VirtIOCryptoPCI),
.instance_init = virtio_crypto_initfn,
.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)
{
type_register_static(&virtio_crypto_pci_info);
virtio_pci_types_register(&virtio_crypto_pci_info);
}
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);
}
static const TypeInfo virtio_9p_pci_info = {
.name = TYPE_VIRTIO_9P_PCI,
.parent = TYPE_VIRTIO_PCI,
static const VirtioPCIDeviceTypeInfo virtio_9p_pci_info = {
.base_name = TYPE_VIRTIO_9P_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_init = virtio_9p_pci_instance_init,
.class_init = virtio_9p_pci_class_init,
@ -1877,9 +1879,6 @@ static void virtio_pci_reset(DeviceState *qdev)
static Property virtio_pci_properties[] = {
DEFINE_PROP_BIT("virtio-pci-bus-master-bug-migration", VirtIOPCIProxy, flags,
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,
VIRTIO_PCI_FLAG_MIGRATE_EXTRA_BIT, true),
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_size = sizeof(VirtioPCIClass),
.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 */
static Property virtio_blk_pci_properties[] = {
@ -1995,9 +2104,11 @@ static void virtio_blk_pci_instance_init(Object *obj)
"bootindex", &error_abort);
}
static const TypeInfo virtio_blk_pci_info = {
.name = TYPE_VIRTIO_BLK_PCI,
.parent = TYPE_VIRTIO_PCI,
static const VirtioPCIDeviceTypeInfo virtio_blk_pci_info = {
.base_name = TYPE_VIRTIO_BLK_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_init = virtio_blk_pci_instance_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);
}
static const TypeInfo vhost_user_blk_pci_info = {
.name = TYPE_VHOST_USER_BLK_PCI,
.parent = TYPE_VIRTIO_PCI,
static const VirtioPCIDeviceTypeInfo vhost_user_blk_pci_info = {
.base_name = TYPE_VHOST_USER_BLK_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_init = vhost_user_blk_pci_instance_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);
}
static const TypeInfo virtio_scsi_pci_info = {
.name = TYPE_VIRTIO_SCSI_PCI,
.parent = TYPE_VIRTIO_PCI,
static const VirtioPCIDeviceTypeInfo virtio_scsi_pci_info = {
.base_name = TYPE_VIRTIO_SCSI_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_init = virtio_scsi_pci_instance_init,
.class_init = virtio_scsi_pci_class_init,
@ -2174,9 +2289,11 @@ static void vhost_scsi_pci_instance_init(Object *obj)
"bootindex", &error_abort);
}
static const TypeInfo vhost_scsi_pci_info = {
.name = TYPE_VHOST_SCSI_PCI,
.parent = TYPE_VIRTIO_PCI,
static const VirtioPCIDeviceTypeInfo vhost_scsi_pci_info = {
.base_name = TYPE_VHOST_SCSI_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_init = vhost_scsi_pci_instance_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);
}
static const TypeInfo vhost_user_scsi_pci_info = {
.name = TYPE_VHOST_USER_SCSI_PCI,
.parent = TYPE_VIRTIO_PCI,
static const VirtioPCIDeviceTypeInfo vhost_user_scsi_pci_info = {
.base_name = TYPE_VHOST_USER_SCSI_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_init = vhost_user_scsi_pci_instance_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);
}
static const TypeInfo vhost_vsock_pci_info = {
.name = TYPE_VHOST_VSOCK_PCI,
.parent = TYPE_VIRTIO_PCI,
static const VirtioPCIDeviceTypeInfo vhost_vsock_pci_info = {
.base_name = TYPE_VHOST_VSOCK_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_init = vhost_vsock_pci_instance_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);
}
static const TypeInfo virtio_balloon_pci_info = {
.name = TYPE_VIRTIO_BALLOON_PCI,
.parent = TYPE_VIRTIO_PCI,
static const VirtioPCIDeviceTypeInfo virtio_balloon_pci_info = {
.base_name = TYPE_VIRTIO_BALLOON_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_init = virtio_balloon_pci_instance_init,
.class_init = virtio_balloon_pci_class_init,
@ -2407,9 +2530,11 @@ static void virtio_serial_pci_instance_init(Object *obj)
TYPE_VIRTIO_SERIAL);
}
static const TypeInfo virtio_serial_pci_info = {
.name = TYPE_VIRTIO_SERIAL_PCI,
.parent = TYPE_VIRTIO_PCI,
static const VirtioPCIDeviceTypeInfo virtio_serial_pci_info = {
.base_name = TYPE_VIRTIO_SERIAL_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_init = virtio_serial_pci_instance_init,
.class_init = virtio_serial_pci_class_init,
@ -2462,9 +2587,11 @@ static void virtio_net_pci_instance_init(Object *obj)
"bootindex", &error_abort);
}
static const TypeInfo virtio_net_pci_info = {
.name = TYPE_VIRTIO_NET_PCI,
.parent = TYPE_VIRTIO_PCI,
static const VirtioPCIDeviceTypeInfo virtio_net_pci_info = {
.base_name = TYPE_VIRTIO_NET_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_init = virtio_net_pci_instance_init,
.class_init = virtio_net_pci_class_init,
@ -2513,9 +2640,11 @@ static void virtio_rng_initfn(Object *obj)
TYPE_VIRTIO_RNG);
}
static const TypeInfo virtio_rng_pci_info = {
.name = TYPE_VIRTIO_RNG_PCI,
.parent = TYPE_VIRTIO_PCI,
static const VirtioPCIDeviceTypeInfo virtio_rng_pci_info = {
.base_name = TYPE_VIRTIO_RNG_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_init = virtio_rng_initfn,
.class_init = virtio_rng_pci_class_init,
@ -2605,24 +2734,24 @@ static const TypeInfo virtio_input_hid_pci_info = {
.abstract = true,
};
static const TypeInfo virtio_keyboard_pci_info = {
.name = TYPE_VIRTIO_KEYBOARD_PCI,
static const VirtioPCIDeviceTypeInfo virtio_keyboard_pci_info = {
.generic_name = TYPE_VIRTIO_KEYBOARD_PCI,
.parent = TYPE_VIRTIO_INPUT_HID_PCI,
.class_init = virtio_input_hid_kbd_pci_class_init,
.instance_size = sizeof(VirtIOInputHIDPCI),
.instance_init = virtio_keyboard_initfn,
};
static const TypeInfo virtio_mouse_pci_info = {
.name = TYPE_VIRTIO_MOUSE_PCI,
static const VirtioPCIDeviceTypeInfo virtio_mouse_pci_info = {
.generic_name = TYPE_VIRTIO_MOUSE_PCI,
.parent = TYPE_VIRTIO_INPUT_HID_PCI,
.class_init = virtio_input_hid_mouse_pci_class_init,
.instance_size = sizeof(VirtIOInputHIDPCI),
.instance_init = virtio_mouse_initfn,
};
static const TypeInfo virtio_tablet_pci_info = {
.name = TYPE_VIRTIO_TABLET_PCI,
static const VirtioPCIDeviceTypeInfo virtio_tablet_pci_info = {
.generic_name = TYPE_VIRTIO_TABLET_PCI,
.parent = TYPE_VIRTIO_INPUT_HID_PCI,
.instance_size = sizeof(VirtIOInputHIDPCI),
.instance_init = virtio_tablet_initfn,
@ -2637,8 +2766,11 @@ static void virtio_host_initfn(Object *obj)
TYPE_VIRTIO_INPUT_HOST);
}
static const TypeInfo virtio_host_pci_info = {
.name = TYPE_VIRTIO_INPUT_HOST_PCI,
static const VirtioPCIDeviceTypeInfo virtio_host_pci_info = {
.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,
.instance_size = sizeof(VirtIOInputHostPCI),
.instance_init = virtio_host_initfn,
@ -2692,36 +2824,39 @@ static const TypeInfo virtio_pci_bus_info = {
static void virtio_pci_register_types(void)
{
type_register_static(&virtio_rng_pci_info);
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
/* Base types: */
type_register_static(&virtio_pci_bus_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
type_register_static(&virtio_9p_pci_info);
virtio_pci_types_register(&virtio_9p_pci_info);
#endif
type_register_static(&virtio_blk_pci_info);
virtio_pci_types_register(&virtio_blk_pci_info);
#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
type_register_static(&virtio_scsi_pci_info);
type_register_static(&virtio_balloon_pci_info);
type_register_static(&virtio_serial_pci_info);
type_register_static(&virtio_net_pci_info);
virtio_pci_types_register(&virtio_scsi_pci_info);
virtio_pci_types_register(&virtio_balloon_pci_info);
virtio_pci_types_register(&virtio_serial_pci_info);
virtio_pci_types_register(&virtio_net_pci_info);
#ifdef CONFIG_VHOST_SCSI
type_register_static(&vhost_scsi_pci_info);
virtio_pci_types_register(&vhost_scsi_pci_info);
#endif
#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
#ifdef CONFIG_VHOST_VSOCK
type_register_static(&vhost_vsock_pci_info);
virtio_pci_types_register(&vhost_vsock_pci_info);
#endif
}

View File

@ -216,7 +216,7 @@ static inline void virtio_pci_disable_modern(VirtIOPCIProxy *proxy)
/*
* 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) \
OBJECT_CHECK(VirtIOSCSIPCI, (obj), TYPE_VIRTIO_SCSI_PCI)
@ -229,7 +229,7 @@ struct VirtIOSCSIPCI {
/*
* 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) \
OBJECT_CHECK(VHostSCSIPCI, (obj), TYPE_VHOST_SCSI_PCI)
@ -239,7 +239,7 @@ struct VHostSCSIPCI {
};
#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) \
OBJECT_CHECK(VHostUserSCSIPCI, (obj), TYPE_VHOST_USER_SCSI_PCI)
@ -252,7 +252,7 @@ struct VHostUserSCSIPCI {
/*
* 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) \
OBJECT_CHECK(VHostUserBlkPCI, (obj), TYPE_VHOST_USER_BLK_PCI)
@ -265,7 +265,7 @@ struct VHostUserBlkPCI {
/*
* 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) \
OBJECT_CHECK(VirtIOBlkPCI, (obj), TYPE_VIRTIO_BLK_PCI)
@ -277,7 +277,7 @@ struct VirtIOBlkPCI {
/*
* 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) \
OBJECT_CHECK(VirtIOBalloonPCI, (obj), TYPE_VIRTIO_BALLOON_PCI)
@ -289,7 +289,7 @@ struct VirtIOBalloonPCI {
/*
* 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) \
OBJECT_CHECK(VirtIOSerialPCI, (obj), TYPE_VIRTIO_SERIAL_PCI)
@ -301,7 +301,7 @@ struct VirtIOSerialPCI {
/*
* 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) \
OBJECT_CHECK(VirtIONetPCI, (obj), TYPE_VIRTIO_NET_PCI)
@ -316,7 +316,7 @@ struct VirtIONetPCI {
#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) \
OBJECT_CHECK(V9fsPCIState, (obj), TYPE_VIRTIO_9P_PCI)
@ -330,7 +330,7 @@ typedef struct V9fsPCIState {
/*
* 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) \
OBJECT_CHECK(VirtIORngPCI, (obj), TYPE_VIRTIO_RNG_PCI)
@ -365,7 +365,7 @@ struct VirtIOInputHIDPCI {
#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) \
OBJECT_CHECK(VirtIOInputHostPCI, (obj), TYPE_VIRTIO_INPUT_HOST_PCI)
@ -392,7 +392,7 @@ struct VirtIOGPUPCI {
/*
* 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) \
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. */
#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

View File

@ -40,18 +40,13 @@ enum {
ACPI_FADT_F_LOW_POWER_S0_IDLE_CAPABLE,
};
struct AcpiRsdpDescriptor { /* Root System Descriptor Pointer */
uint64_t signature; /* ACPI signature, contains "RSD PTR " */
uint8_t checksum; /* To make sum of struct == 0 */
uint8_t oem_id [6]; /* OEM identification */
uint8_t revision; /* Must be 0 for 1.0, 2 for 2.0 */
uint32_t rsdt_physical_address; /* 32-bit physical address of RSDT */
uint32_t length; /* XSDT Length in bytes including hdr */
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;
typedef struct AcpiRsdpData {
uint8_t oem_id[6]; /* OEM identification */
uint8_t revision; /* Must be 0 for 1.0, 2 for 2.0 */
unsigned *rsdt_tbl_offset;
unsigned *xsdt_tbl_offset;
} AcpiRsdpData;
/* Table structure from Linux kernel (the ACPI tables are under the
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_cleanup(AcpiBuildTables *tables, bool mfre);
void
build_rsdp(GArray *tbl, BIOSLinker *linker, AcpiRsdpData *rsdp_data);
void
build_rsdt(GArray *table_data, BIOSLinker *linker, GArray *table_offsets,
const char *oem_id, const char *oem_table_id);
void

View File

@ -56,10 +56,15 @@ typedef struct AcpiPciHpState {
void acpi_pcihp_init(Object *owner, AcpiPciHpState *, PCIBus *root,
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,
DeviceState *dev, Error **errp);
void acpi_pcihp_device_unplug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s,
DeviceState *dev, Error **errp);
void acpi_pcihp_device_unplug_request_cb(HotplugHandler *hotplug_dev,
AcpiPciHpState *s, DeviceState *dev,
Error **errp);
/* Called on reset */
void acpi_pcihp_reset(AcpiPciHpState *s);

View File

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

View File

@ -2,7 +2,15 @@
#define HW_COMPAT_H
#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 \
/* empty */

View File

@ -245,6 +245,7 @@ struct IntelIOMMUState {
OnOffAuto intr_eim; /* Toggle for EIM cabability */
bool buggy_eim; /* Force buggy EIM unless eim=off */
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

View File

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

View File

@ -74,13 +74,15 @@ typedef struct IEC_Notifier IEC_Notifier;
struct X86IOMMUState {
SysBusDevice busdev;
bool intr_supported; /* Whether vIOMMU supports IR */
OnOffAuto intr_supported; /* Whether vIOMMU supports IR */
bool dt_supported; /* Whether vIOMMU supports DT */
bool pt_supported; /* Whether vIOMMU supports pass-through */
IommuType type; /* IOMMU type - AMD/Intel */
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 */
struct X86IOMMUIrq {
/* 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;
}
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)
{
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_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

View File

@ -126,13 +126,16 @@ uint16_t pcie_find_capability(PCIDevice *dev, uint16_t cap_id);
void pcie_add_capability(PCIDevice *dev,
uint16_t cap_id, uint8_t cap_ver,
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_dev_ser_num_init(PCIDevice *dev, uint16_t offset, uint64_t ser_num);
void pcie_ats_init(PCIDevice *dev, uint16_t offset);
void pcie_cap_slot_hotplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp);
void pcie_cap_slot_hot_unplug_request_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp);
void pcie_cap_slot_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp);
void pcie_cap_slot_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp);
void pcie_cap_slot_unplug_request_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp);
#endif /* QEMU_PCIE_H */

View File

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

View File

@ -34,10 +34,29 @@
/* PCI_EXP_LINK{CAP, STA} */
/* 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_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 */
#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_device_hotplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp);
void shpc_device_hot_unplug_request_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp);
void shpc_device_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp);
void shpc_device_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp);
void shpc_device_unplug_request_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp);
extern VMStateInfo shpc_vmstate_info;
#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_link;
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) { \
.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_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_off_auto_pcibar, \
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) { \
.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',
'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:
#

View File

@ -134,7 +134,7 @@ their usecases.
@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
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 <glib/gstdio.h>
#include "qemu-common.h"
#include "hw/smbios/smbios.h"
#include "qemu/bitmap.h"
#include "acpi-utils.h"
#include "boot-sector.h"
@ -52,15 +51,44 @@ uint32_t acpi_find_rsdp_address(QTestState *qts)
return off;
}
void acpi_parse_rsdp_table(QTestState *qts, uint32_t addr,
AcpiRsdpDescriptor *rsdp_table)
uint32_t acpi_get_rsdt_address(uint8_t *rsdp_table)
{
ACPI_READ_FIELD(qts, rsdp_table->signature, addr);
ACPI_ASSERT_CMP64(rsdp_table->signature, "RSD PTR ");
uint32_t rsdt_physical_address;
ACPI_READ_FIELD(qts, rsdp_table->checksum, addr);
ACPI_READ_ARRAY(qts, rsdp_table->oem_id, addr);
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);
memcpy(&rsdt_physical_address, &rsdp_table[16 /* RsdtAddress offset */], 4);
return le32_to_cpu(rsdt_physical_address);
}
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);
uint32_t acpi_find_rsdp_address(QTestState *qts);
void acpi_parse_rsdp_table(QTestState *qts, uint32_t addr,
AcpiRsdpDescriptor *rsdp_table);
uint32_t acpi_get_rsdt_address(uint8_t *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 */

View File

@ -13,7 +13,7 @@
#include "qemu/osdep.h"
#include <glib/gstdio.h>
#include "qemu-common.h"
#include "hw/smbios/smbios.h"
#include "hw/firmware/smbios.h"
#include "qemu/bitmap.h"
#include "acpi-utils.h"
#include "boot-sector.h"
@ -27,7 +27,7 @@ typedef struct {
const char *machine;
const char *variant;
uint32_t rsdp_addr;
AcpiRsdpDescriptor rsdp_table;
uint8_t rsdp_table[36 /* ACPI 2.0+ RSDP size */];
AcpiRsdtDescriptorRev1 rsdt_table;
uint32_t dsdt_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)
{
AcpiRsdpDescriptor *rsdp_table = &data->rsdp_table;
uint8_t *rsdp_table = data->rsdp_table, revision;
uint32_t addr = data->rsdp_addr;
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 */
g_assert(!acpi_calc_checksum((uint8_t *)rsdp_table, 20));
switch (revision) {
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)
{
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;
int tables_nr;
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.14") == 0) ||
(strcmp(mname, "pc-0.13") == 0) ||
(strcmp(mname, "pc-0.12") == 0) ||
(strcmp(mname, "pc-0.11") == 0) ||
(strcmp(mname, "pc-0.10") == 0)) {
(strcmp(mname, "pc-0.12") == 0)) {
path = g_strdup_printf("cpu-plug/%s/init/%ux%ux%u&maxcpus=%u",
mname, data->sockets, data->cores,
data->threads, data->maxcpus);

View File

@ -35,7 +35,7 @@ static uint32_t acpi_find_vgia(QTestState *qts)
{
uint32_t rsdp_offset;
uint32_t guid_offset = 0;
AcpiRsdpDescriptor rsdp_table;
uint8_t rsdp_table[36 /* ACPI 2.0+ RSDP size */];
uint32_t rsdt, rsdt_table_length;
AcpiRsdtDescriptorRev1 rsdt_table;
size_t tables_nr;
@ -52,9 +52,11 @@ static uint32_t acpi_find_vgia(QTestState *qts)
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 */
ACPI_READ_TABLE_HEADER(qts, &rsdt_table, 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/bt.h"
#include "sysemu/watchdog.h"
#include "hw/smbios/smbios.h"
#include "hw/firmware/smbios.h"
#include "hw/acpi/acpi.h"
#include "hw/xen/xen.h"
#include "hw/qdev.h"