summaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/core/qdev-properties.c2
-rw-r--r--hw/core/sysbus.c11
-rw-r--r--hw/i386/Makefile.objs3
-rw-r--r--hw/i386/acpi-build.c40
-rw-r--r--hw/i386/ssdt-tpm-common.dsl36
-rw-r--r--hw/i386/ssdt-tpm.dsl29
-rw-r--r--hw/i386/ssdt-tpm.hex.generated109
-rw-r--r--hw/i386/ssdt-tpm2.dsl29
-rw-r--r--hw/i386/ssdt-tpm2.hex.generated109
-rw-r--r--hw/pci-bridge/pci_bridge_dev.c117
-rw-r--r--hw/pci-bridge/pci_expander_bridge.c57
-rw-r--r--hw/virtio/vhost.c8
-rw-r--r--hw/virtio/virtio-balloon.c4
-rw-r--r--hw/virtio/virtio-pci.c4
14 files changed, 192 insertions, 366 deletions
diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c
index 47c1e8f3c5..e9e686f260 100644
--- a/hw/core/qdev-properties.c
+++ b/hw/core/qdev-properties.c
@@ -131,7 +131,7 @@ PropertyInfo qdev_prop_bit = {
static uint64_t qdev_get_prop_mask64(Property *prop)
{
assert(prop->info == &qdev_prop_bit);
- return 0x1 << prop->bitnr;
+ return 0x1ull << prop->bitnr;
}
static void bit64_prop_set(DeviceState *dev, Property *props, bool val)
diff --git a/hw/core/sysbus.c b/hw/core/sysbus.c
index 92eced9424..278a2d1bdd 100644
--- a/hw/core/sysbus.c
+++ b/hw/core/sysbus.c
@@ -281,6 +281,9 @@ static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent)
static char *sysbus_get_fw_dev_path(DeviceState *dev)
{
SysBusDevice *s = SYS_BUS_DEVICE(dev);
+ SysBusDeviceClass *sbc = SYS_BUS_DEVICE_GET_CLASS(s);
+ /* for the explicit unit address fallback case: */
+ char *addr, *fw_dev_path;
if (s->num_mmio) {
return g_strdup_printf("%s@" TARGET_FMT_plx, qdev_fw_name(dev),
@@ -289,6 +292,14 @@ static char *sysbus_get_fw_dev_path(DeviceState *dev)
if (s->num_pio) {
return g_strdup_printf("%s@i%04x", qdev_fw_name(dev), s->pio[0]);
}
+ if (sbc->explicit_ofw_unit_address) {
+ addr = sbc->explicit_ofw_unit_address(s);
+ if (addr) {
+ fw_dev_path = g_strdup_printf("%s@%s", qdev_fw_name(dev), addr);
+ g_free(addr);
+ return fw_dev_path;
+ }
+ }
return g_strdup(qdev_fw_name(dev));
}
diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs
index 0be5d97c59..bd4f147f9d 100644
--- a/hw/i386/Makefile.objs
+++ b/hw/i386/Makefile.objs
@@ -8,8 +8,7 @@ obj-$(CONFIG_XEN) += ../xenpv/ xen/
obj-y += kvmvapic.o
obj-y += acpi-build.o
hw/i386/acpi-build.o: hw/i386/acpi-build.c \
- hw/i386/acpi-dsdt.hex hw/i386/q35-acpi-dsdt.hex \
- hw/i386/ssdt-tpm.hex hw/i386/ssdt-tpm2.hex
+ hw/i386/acpi-dsdt.hex hw/i386/q35-acpi-dsdt.hex
iasl-option=$(shell if test -z "`$(1) $(2) 2>&1 > /dev/null`" \
; then echo "$(2)"; else echo "$(3)"; fi ;)
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index b71e942567..00818b925b 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -433,9 +433,6 @@ build_madt(GArray *table_data, GArray *linker, AcpiCpuInfo *cpu,
table_data->len - madt_start, 1);
}
-#include "hw/i386/ssdt-tpm.hex"
-#include "hw/i386/ssdt-tpm2.hex"
-
/* Assign BSEL property to all buses. In the future, this can be changed
* to only assign to buses that support hotplug.
*/
@@ -1328,6 +1325,19 @@ build_ssdt(GArray *table_data, GArray *linker,
Aml *scope = aml_scope("PCI0");
/* Scan all PCI buses. Generate tables to support hotplug. */
build_append_pci_bus_devices(scope, bus, pm->pcihp_bridge_en);
+
+ if (misc->tpm_version != TPM_VERSION_UNSPEC) {
+ dev = aml_device("ISA.TPM");
+ aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C31")));
+ aml_append(dev, aml_name_decl("_STA", aml_int(0xF)));
+ crs = aml_resource_template();
+ aml_append(crs, aml_memory32_fixed(TPM_TIS_ADDR_BASE,
+ TPM_TIS_ADDR_SIZE, AML_READ_WRITE));
+ aml_append(crs, aml_irq_no_flags(TPM_TIS_IRQ));
+ aml_append(dev, aml_name_decl("_CRS", crs));
+ aml_append(scope, dev);
+ }
+
aml_append(sb_scope, scope);
}
}
@@ -1383,22 +1393,9 @@ build_tpm_tcpa(GArray *table_data, GArray *linker, GArray *tcpalog)
}
static void
-build_tpm_ssdt(GArray *table_data, GArray *linker)
-{
- void *tpm_ptr;
-
- tpm_ptr = acpi_data_push(table_data, sizeof(ssdt_tpm_aml));
- memcpy(tpm_ptr, ssdt_tpm_aml, sizeof(ssdt_tpm_aml));
-}
-
-static void
build_tpm2(GArray *table_data, GArray *linker)
{
Acpi20TPM2 *tpm2_ptr;
- void *tpm_ptr;
-
- tpm_ptr = acpi_data_push(table_data, sizeof(ssdt_tpm2_aml));
- memcpy(tpm_ptr, ssdt_tpm2_aml, sizeof(ssdt_tpm2_aml));
tpm2_ptr = acpi_data_push(table_data, sizeof *tpm2_ptr);
@@ -1726,16 +1723,9 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables)
acpi_add_table(table_offsets, tables_blob);
build_tpm_tcpa(tables_blob, tables->linker, tables->tcpalog);
- acpi_add_table(table_offsets, tables_blob);
- switch (misc.tpm_version) {
- case TPM_VERSION_1_2:
- build_tpm_ssdt(tables_blob, tables->linker);
- break;
- case TPM_VERSION_2_0:
+ if (misc.tpm_version == TPM_VERSION_2_0) {
+ acpi_add_table(table_offsets, tables_blob);
build_tpm2(tables_blob, tables->linker);
- break;
- default:
- assert(false);
}
}
if (guest_info->numa_nodes) {
diff --git a/hw/i386/ssdt-tpm-common.dsl b/hw/i386/ssdt-tpm-common.dsl
deleted file mode 100644
index 9da49700d1..0000000000
--- a/hw/i386/ssdt-tpm-common.dsl
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * Common parts for TPM 1.2 and TPM 2 (with slight differences for PPI)
- * to be #included
- */
-
-
- External(\_SB.PCI0.ISA, DeviceObj)
- Scope(\_SB.PCI0.ISA) {
- /* TPM with emulated TPM TIS interface */
- Device (TPM) {
- Name (_HID, EisaID ("PNP0C31"))
- Name (_CRS, ResourceTemplate ()
- {
- Memory32Fixed (ReadWrite, TPM_TIS_ADDR_BASE, TPM_TIS_ADDR_SIZE)
- IRQNoFlags () {TPM_TIS_IRQ}
- })
- Method (_STA, 0, NotSerialized) {
- Return (0x0F)
- }
- }
- }
diff --git a/hw/i386/ssdt-tpm.dsl b/hw/i386/ssdt-tpm.dsl
deleted file mode 100644
index d81478c1b5..0000000000
--- a/hw/i386/ssdt-tpm.dsl
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-#include "hw/acpi/tpm.h"
-
-ACPI_EXTRACT_ALL_CODE ssdt_tpm_aml
-
-DefinitionBlock (
- "ssdt-tpm.aml", // Output Filename
- "SSDT", // Signature
- 0x01, // SSDT Compliance Revision
- "BXPC", // OEMID
- "BXSSDT", // TABLE ID
- 0x1 // OEM Revision
- )
-{
-#include "ssdt-tpm-common.dsl"
-}
diff --git a/hw/i386/ssdt-tpm.hex.generated b/hw/i386/ssdt-tpm.hex.generated
deleted file mode 100644
index 874418c946..0000000000
--- a/hw/i386/ssdt-tpm.hex.generated
+++ /dev/null
@@ -1,109 +0,0 @@
-static unsigned char ssdt_tpm_aml[] = {
-0x53,
-0x53,
-0x44,
-0x54,
-0x6b,
-0x0,
-0x0,
-0x0,
-0x1,
-0x37,
-0x42,
-0x58,
-0x50,
-0x43,
-0x0,
-0x0,
-0x42,
-0x58,
-0x53,
-0x53,
-0x44,
-0x54,
-0x0,
-0x0,
-0x1,
-0x0,
-0x0,
-0x0,
-0x49,
-0x4e,
-0x54,
-0x4c,
-0x7,
-0x11,
-0x14,
-0x20,
-0x10,
-0x46,
-0x4,
-0x5c,
-0x2f,
-0x3,
-0x5f,
-0x53,
-0x42,
-0x5f,
-0x50,
-0x43,
-0x49,
-0x30,
-0x49,
-0x53,
-0x41,
-0x5f,
-0x5b,
-0x82,
-0x33,
-0x54,
-0x50,
-0x4d,
-0x5f,
-0x8,
-0x5f,
-0x48,
-0x49,
-0x44,
-0xc,
-0x41,
-0xd0,
-0xc,
-0x31,
-0x8,
-0x5f,
-0x43,
-0x52,
-0x53,
-0x11,
-0x14,
-0xa,
-0x11,
-0x86,
-0x9,
-0x0,
-0x1,
-0x0,
-0x0,
-0xd4,
-0xfe,
-0x0,
-0x50,
-0x0,
-0x0,
-0x22,
-0x20,
-0x0,
-0x79,
-0x0,
-0x14,
-0x9,
-0x5f,
-0x53,
-0x54,
-0x41,
-0x0,
-0xa4,
-0xa,
-0xf
-};
diff --git a/hw/i386/ssdt-tpm2.dsl b/hw/i386/ssdt-tpm2.dsl
deleted file mode 100644
index 58bbbf806d..0000000000
--- a/hw/i386/ssdt-tpm2.dsl
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-#include "hw/acpi/tpm.h"
-
-ACPI_EXTRACT_ALL_CODE ssdt_tpm2_aml
-
-DefinitionBlock (
- "ssdt-tpm2.aml", // Output Filename
- "SSDT", // Signature
- 0x01, // SSDT Compliance Revision
- "BXPC", // OEMID
- "BXSSDT", // TABLE ID
- 0x1 // OEM Revision
- )
-{
-#include "ssdt-tpm-common.dsl"
-}
diff --git a/hw/i386/ssdt-tpm2.hex.generated b/hw/i386/ssdt-tpm2.hex.generated
deleted file mode 100644
index 9ea827151a..0000000000
--- a/hw/i386/ssdt-tpm2.hex.generated
+++ /dev/null
@@ -1,109 +0,0 @@
-static unsigned char ssdt_tpm2_aml[] = {
-0x53,
-0x53,
-0x44,
-0x54,
-0x6b,
-0x0,
-0x0,
-0x0,
-0x1,
-0x37,
-0x42,
-0x58,
-0x50,
-0x43,
-0x0,
-0x0,
-0x42,
-0x58,
-0x53,
-0x53,
-0x44,
-0x54,
-0x0,
-0x0,
-0x1,
-0x0,
-0x0,
-0x0,
-0x49,
-0x4e,
-0x54,
-0x4c,
-0x7,
-0x11,
-0x14,
-0x20,
-0x10,
-0x46,
-0x4,
-0x5c,
-0x2f,
-0x3,
-0x5f,
-0x53,
-0x42,
-0x5f,
-0x50,
-0x43,
-0x49,
-0x30,
-0x49,
-0x53,
-0x41,
-0x5f,
-0x5b,
-0x82,
-0x33,
-0x54,
-0x50,
-0x4d,
-0x5f,
-0x8,
-0x5f,
-0x48,
-0x49,
-0x44,
-0xc,
-0x41,
-0xd0,
-0xc,
-0x31,
-0x8,
-0x5f,
-0x43,
-0x52,
-0x53,
-0x11,
-0x14,
-0xa,
-0x11,
-0x86,
-0x9,
-0x0,
-0x1,
-0x0,
-0x0,
-0xd4,
-0xfe,
-0x0,
-0x50,
-0x0,
-0x0,
-0x22,
-0x20,
-0x0,
-0x79,
-0x0,
-0x14,
-0x9,
-0x5f,
-0x53,
-0x54,
-0x41,
-0x0,
-0xa4,
-0xa,
-0xf
-};
diff --git a/hw/pci-bridge/pci_bridge_dev.c b/hw/pci-bridge/pci_bridge_dev.c
index 36f73e1f8b..26aded9f00 100644
--- a/hw/pci-bridge/pci_bridge_dev.c
+++ b/hw/pci-bridge/pci_bridge_dev.c
@@ -28,7 +28,8 @@
#include "hw/pci/pci_bus.h"
#include "hw/hotplug.h"
-#define TYPE_PCI_BRIDGE_DEV "pci-bridge"
+#define TYPE_PCI_BRIDGE_DEV "pci-bridge"
+#define TYPE_PCI_BRIDGE_SEAT_DEV "pci-bridge-seat"
#define PCI_BRIDGE_DEV(obj) \
OBJECT_CHECK(PCIBridgeDev, (obj), TYPE_PCI_BRIDGE_DEV)
@@ -40,6 +41,7 @@ struct PCIBridgeDev {
MemoryRegion bar;
uint8_t chassis_nr;
#define PCI_BRIDGE_DEV_F_MSI_REQ 0
+#define PCI_BRIDGE_DEV_F_SHPC_REQ 1
uint32_t flags;
};
typedef struct PCIBridgeDev PCIBridgeDev;
@@ -54,11 +56,17 @@ static int pci_bridge_dev_initfn(PCIDevice *dev)
if (err) {
goto bridge_error;
}
- dev->config[PCI_INTERRUPT_PIN] = 0x1;
- memory_region_init(&bridge_dev->bar, OBJECT(dev), "shpc-bar", shpc_bar_size(dev));
- err = shpc_init(dev, &br->sec_bus, &bridge_dev->bar, 0);
- if (err) {
- goto shpc_error;
+ if (bridge_dev->flags & (1 << PCI_BRIDGE_DEV_F_SHPC_REQ)) {
+ dev->config[PCI_INTERRUPT_PIN] = 0x1;
+ memory_region_init(&bridge_dev->bar, OBJECT(dev), "shpc-bar",
+ shpc_bar_size(dev));
+ err = shpc_init(dev, &br->sec_bus, &bridge_dev->bar, 0);
+ if (err) {
+ goto shpc_error;
+ }
+ } else {
+ /* MSI is not applicable without SHPC */
+ bridge_dev->flags &= ~(1 << PCI_BRIDGE_DEV_F_MSI_REQ);
}
err = slotid_cap_init(dev, 0, bridge_dev->chassis_nr, 0);
if (err) {
@@ -71,15 +79,19 @@ static int pci_bridge_dev_initfn(PCIDevice *dev)
goto msi_error;
}
}
- /* TODO: spec recommends using 64 bit prefetcheable BAR.
- * Check whether that works well. */
- pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY |
- PCI_BASE_ADDRESS_MEM_TYPE_64, &bridge_dev->bar);
+ if (shpc_present(dev)) {
+ /* TODO: spec recommends using 64 bit prefetcheable BAR.
+ * Check whether that works well. */
+ pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY |
+ PCI_BASE_ADDRESS_MEM_TYPE_64, &bridge_dev->bar);
+ }
return 0;
msi_error:
slotid_cap_cleanup(dev);
slotid_error:
- shpc_cleanup(dev, &bridge_dev->bar);
+ if (shpc_present(dev)) {
+ shpc_cleanup(dev, &bridge_dev->bar);
+ }
shpc_error:
pci_bridge_exitfn(dev);
bridge_error:
@@ -93,12 +105,15 @@ static void pci_bridge_dev_exitfn(PCIDevice *dev)
msi_uninit(dev);
}
slotid_cap_cleanup(dev);
- shpc_cleanup(dev, &bridge_dev->bar);
+ if (shpc_present(dev)) {
+ shpc_cleanup(dev, &bridge_dev->bar);
+ }
pci_bridge_exitfn(dev);
}
static void pci_bridge_dev_instance_finalize(Object *obj)
{
+ /* this function is idempotent and handles (PCIDevice.shpc == NULL) */
shpc_free(PCI_DEVICE(obj));
}
@@ -109,7 +124,9 @@ static void pci_bridge_dev_write_config(PCIDevice *d,
if (msi_present(d)) {
msi_write_config(d, address, val, len);
}
- shpc_cap_write_config(d, address, val, len);
+ if (shpc_present(d)) {
+ shpc_cap_write_config(d, address, val, len);
+ }
}
static void qdev_pci_bridge_dev_reset(DeviceState *qdev)
@@ -117,25 +134,65 @@ static void qdev_pci_bridge_dev_reset(DeviceState *qdev)
PCIDevice *dev = PCI_DEVICE(qdev);
pci_bridge_reset(qdev);
- shpc_reset(dev);
+ if (shpc_present(dev)) {
+ shpc_reset(dev);
+ }
}
static Property pci_bridge_dev_properties[] = {
/* Note: 0 is not a legal chassis number. */
- DEFINE_PROP_UINT8("chassis_nr", PCIBridgeDev, chassis_nr, 0),
- DEFINE_PROP_BIT("msi", PCIBridgeDev, flags, PCI_BRIDGE_DEV_F_MSI_REQ, true),
+ DEFINE_PROP_UINT8(PCI_BRIDGE_DEV_PROP_CHASSIS_NR, PCIBridgeDev, chassis_nr,
+ 0),
+ DEFINE_PROP_BIT(PCI_BRIDGE_DEV_PROP_MSI, PCIBridgeDev, flags,
+ PCI_BRIDGE_DEV_F_MSI_REQ, true),
+ DEFINE_PROP_BIT(PCI_BRIDGE_DEV_PROP_SHPC, PCIBridgeDev, flags,
+ PCI_BRIDGE_DEV_F_SHPC_REQ, true),
DEFINE_PROP_END_OF_LIST(),
};
+static bool pci_device_shpc_present(void *opaque, int version_id)
+{
+ PCIDevice *dev = opaque;
+
+ return shpc_present(dev);
+}
+
static const VMStateDescription pci_bridge_dev_vmstate = {
.name = "pci_bridge",
.fields = (VMStateField[]) {
VMSTATE_PCI_DEVICE(parent_obj, PCIBridge),
- SHPC_VMSTATE(shpc, PCIDevice),
+ SHPC_VMSTATE(shpc, PCIDevice, pci_device_shpc_present),
VMSTATE_END_OF_LIST()
}
};
+static void pci_bridge_dev_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_PCI_BRIDGE_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);
+}
+
static void pci_bridge_dev_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -154,8 +211,8 @@ 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 = shpc_device_hotplug_cb;
- hc->unplug_request = shpc_device_hot_unplug_request_cb;
+ hc->plug = pci_bridge_dev_hotplug_cb;
+ hc->unplug_request = pci_bridge_dev_hot_unplug_request_cb;
}
static const TypeInfo pci_bridge_dev_info = {
@@ -170,9 +227,31 @@ static const TypeInfo pci_bridge_dev_info = {
}
};
+/*
+ * Multiseat bridge. Same as the standard pci bridge, only with a
+ * different pci id, so we can match it easily in the guest for
+ * automagic multiseat configuration. See docs/multiseat.txt for more.
+ */
+static void pci_bridge_dev_seat_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->device_id = PCI_DEVICE_ID_REDHAT_BRIDGE_SEAT;
+ dc->desc = "Standard PCI Bridge (multiseat)";
+}
+
+static const TypeInfo pci_bridge_dev_seat_info = {
+ .name = TYPE_PCI_BRIDGE_SEAT_DEV,
+ .parent = TYPE_PCI_BRIDGE_DEV,
+ .instance_size = sizeof(PCIBridgeDev),
+ .class_init = pci_bridge_dev_seat_class_init,
+};
+
static void pci_bridge_dev_register(void)
{
type_register_static(&pci_bridge_dev_info);
+ type_register_static(&pci_bridge_dev_seat_info);
}
type_init(pci_bridge_dev_register);
diff --git a/hw/pci-bridge/pci_expander_bridge.c b/hw/pci-bridge/pci_expander_bridge.c
index ec2bb458f7..57f8a3762b 100644
--- a/hw/pci-bridge/pci_expander_bridge.c
+++ b/hw/pci-bridge/pci_expander_bridge.c
@@ -14,6 +14,7 @@
#include "hw/pci/pci_bus.h"
#include "hw/pci/pci_host.h"
#include "hw/pci/pci_bus.h"
+#include "hw/pci/pci_bridge.h"
#include "hw/i386/pc.h"
#include "qemu/range.h"
#include "qemu/error-report.h"
@@ -42,6 +43,8 @@ typedef struct PXBDev {
uint16_t numa_node;
} PXBDev;
+static GList *pxb_dev_list;
+
#define TYPE_PXB_HOST "pxb-host"
static int pxb_bus_num(PCIBus *bus)
@@ -88,12 +91,45 @@ static const char *pxb_host_root_bus_path(PCIHostState *host_bridge,
return bus->bus_path;
}
+static char *pxb_host_ofw_unit_address(const SysBusDevice *dev)
+{
+ const PCIHostState *pxb_host;
+ const PCIBus *pxb_bus;
+ const PXBDev *pxb_dev;
+ int position;
+ const DeviceState *pxb_dev_base;
+ const PCIHostState *main_host;
+ const SysBusDevice *main_host_sbd;
+
+ pxb_host = PCI_HOST_BRIDGE(dev);
+ pxb_bus = pxb_host->bus;
+ pxb_dev = PXB_DEV(pxb_bus->parent_dev);
+ position = g_list_index(pxb_dev_list, pxb_dev);
+ assert(position >= 0);
+
+ pxb_dev_base = DEVICE(pxb_dev);
+ main_host = PCI_HOST_BRIDGE(pxb_dev_base->parent_bus->parent);
+ main_host_sbd = SYS_BUS_DEVICE(main_host);
+
+ if (main_host_sbd->num_mmio > 0) {
+ return g_strdup_printf(TARGET_FMT_plx ",%x",
+ main_host_sbd->mmio[0].addr, position + 1);
+ }
+ if (main_host_sbd->num_pio > 0) {
+ return g_strdup_printf("i%04x,%x",
+ main_host_sbd->pio[0], position + 1);
+ }
+ return NULL;
+}
+
static void pxb_host_class_init(ObjectClass *class, void *data)
{
DeviceClass *dc = DEVICE_CLASS(class);
+ SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(class);
PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(class);
dc->fw_name = "pci";
+ sbc->explicit_ofw_unit_address = pxb_host_ofw_unit_address;
hc->root_bus_path = pxb_host_root_bus_path;
}
@@ -148,6 +184,15 @@ static int pxb_map_irq_fn(PCIDevice *pci_dev, int pin)
return pin - PCI_SLOT(pxb->devfn);
}
+static gint pxb_compare(gconstpointer a, gconstpointer b)
+{
+ const PXBDev *pxb_a = a, *pxb_b = b;
+
+ return pxb_a->bus_nr < pxb_b->bus_nr ? -1 :
+ pxb_a->bus_nr > pxb_b->bus_nr ? 1 :
+ 0;
+}
+
static int pxb_dev_initfn(PCIDevice *dev)
{
PXBDev *pxb = PXB_DEV(dev);
@@ -175,7 +220,8 @@ static int pxb_dev_initfn(PCIDevice *dev)
bds = qdev_create(BUS(bus), "pci-bridge");
bds->id = dev_name;
- qdev_prop_set_uint8(bds, "chassis_nr", pxb->bus_nr);
+ qdev_prop_set_uint8(bds, PCI_BRIDGE_DEV_PROP_CHASSIS_NR, pxb->bus_nr);
+ qdev_prop_set_bit(bds, PCI_BRIDGE_DEV_PROP_SHPC, false);
PCI_HOST_BRIDGE(ds)->bus = bus;
@@ -190,9 +236,17 @@ static int pxb_dev_initfn(PCIDevice *dev)
PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK);
pci_config_set_class(dev->config, PCI_CLASS_BRIDGE_HOST);
+ pxb_dev_list = g_list_insert_sorted(pxb_dev_list, pxb, pxb_compare);
return 0;
}
+static void pxb_dev_exitfn(PCIDevice *pci_dev)
+{
+ PXBDev *pxb = PXB_DEV(pci_dev);
+
+ pxb_dev_list = g_list_remove(pxb_dev_list, pxb);
+}
+
static Property pxb_dev_properties[] = {
/* Note: 0 is not a legal a PXB bus number. */
DEFINE_PROP_UINT8("bus_nr", PXBDev, bus_nr, 0),
@@ -206,6 +260,7 @@ static void pxb_dev_class_init(ObjectClass *klass, void *data)
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
k->init = pxb_dev_initfn;
+ k->exit = pxb_dev_exitfn;
k->vendor_id = PCI_VENDOR_ID_REDHAT;
k->device_id = PCI_DEVICE_ID_REDHAT_PXB;
k->class_id = PCI_CLASS_BRIDGE_HOST;
diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index a6dcc79399..2712c6fc0a 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -999,7 +999,7 @@ int vhost_dev_enable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev)
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
VirtioBusState *vbus = VIRTIO_BUS(qbus);
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus);
- int i, r;
+ int i, r, e;
if (!k->set_host_notifier) {
fprintf(stderr, "binding does not support host notifiers\n");
r = -ENOSYS;
@@ -1017,12 +1017,12 @@ int vhost_dev_enable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev)
return 0;
fail_vq:
while (--i >= 0) {
- r = k->set_host_notifier(qbus->parent, hdev->vq_index + i, false);
- if (r < 0) {
+ e = k->set_host_notifier(qbus->parent, hdev->vq_index + i, false);
+ if (e < 0) {
fprintf(stderr, "vhost VQ %d notifier cleanup error: %d\n", i, -r);
fflush(stderr);
}
- assert (r >= 0);
+ assert (e >= 0);
}
fail:
return r;
diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c
index 78bc14fc85..2990f8de5d 100644
--- a/hw/virtio/virtio-balloon.c
+++ b/hw/virtio/virtio-balloon.c
@@ -312,6 +312,8 @@ static void virtio_balloon_set_config(VirtIODevice *vdev,
static uint64_t virtio_balloon_get_features(VirtIODevice *vdev, uint64_t f)
{
+ VirtIOBalloon *dev = VIRTIO_BALLOON(vdev);
+ f |= dev->host_features;
virtio_add_feature(&f, VIRTIO_BALLOON_F_STATS_VQ);
return f;
}
@@ -423,6 +425,8 @@ static void virtio_balloon_instance_init(Object *obj)
}
static Property virtio_balloon_properties[] = {
+ DEFINE_PROP_BIT("deflate-on-oom", VirtIOBalloon, host_features,
+ VIRTIO_BALLOON_F_DEFLATE_ON_OOM, false),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index 70bc6d801e..6a0174e9cc 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -977,7 +977,7 @@ static uint64_t virtio_pci_common_read(void *opaque, hwaddr addr,
val = proxy->gfselect;
break;
case VIRTIO_PCI_COMMON_GF:
- if (proxy->gfselect <= ARRAY_SIZE(proxy->guest_features)) {
+ if (proxy->gfselect < ARRAY_SIZE(proxy->guest_features)) {
val = proxy->guest_features[proxy->gfselect];
}
break;
@@ -1052,7 +1052,7 @@ static void virtio_pci_common_write(void *opaque, hwaddr addr,
proxy->gfselect = val;
break;
case VIRTIO_PCI_COMMON_GF:
- if (proxy->gfselect <= ARRAY_SIZE(proxy->guest_features)) {
+ if (proxy->gfselect < ARRAY_SIZE(proxy->guest_features)) {
proxy->guest_features[proxy->gfselect] = val;
virtio_set_features(vdev,
(((uint64_t)proxy->guest_features[1]) << 32) |