mirror of https://gitee.com/openkylin/qemu.git
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:
commit
15763776bf
|
@ -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/*
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.");
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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. "
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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()
|
||||
};
|
||||
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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.
|
||||
|
|
159
hw/pci/pcie.c
159
hw/pci/pcie.c
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/smbios/ipmi.h"
|
||||
#include "smbios_build.h"
|
||||
|
||||
void smbios_build_type_38_table(void)
|
||||
{
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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) \
|
||||
|
|
|
@ -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), \
|
||||
|
|
|
@ -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 */
|
|
@ -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:
|
||||
#
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
|
@ -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 ");
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
|
|
Loading…
Reference in New Issue