aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2015-06-26 15:57:43 +0100
committerPeter Maydell <peter.maydell@linaro.org>2015-06-26 15:57:43 +0100
commitdc1e1350f8061021df765b396295329797d66933 (patch)
tree3d87edd9fbf9d723f83fad33756cb2a881a73db4
parentd14b9d79be8a424ebc66450d565b81eff2296d55 (diff)
parentd46f7c9e648d8098ac73b36834ac81237b8c2c2d (diff)
Merge remote-tracking branch 'remotes/mst/tags/for_upstream' into staging
virtio, pci fixes, enhancements Almost exclusively bugfixes, though in this case, we are adding functionality to the pxb in order to make OVMF work on it. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> # gpg: Signature made Fri Jun 26 14:43:27 2015 BST using RSA key ID D28D5469 # gpg: Good signature from "Michael S. Tsirkin <mst@kernel.org>" # gpg: aka "Michael S. Tsirkin <mst@redhat.com>" * remotes/mst/tags/for_upstream: Fix glib_subprocess test hw/pci-bridge: format special OFW unit address for PXB host hw/core: explicit OFW unit address callback for SysBusDeviceClass hw/pci-bridge: disable SHPC in PXB hw/pci-bridge: introduce "shpc" property hw/pci: introduce shpc_present() helper function hw/pci-bridge: add macro for "msi" property hw/pci-bridge: add macro for "chassis_nr" property hw/pci-bridge: expose _test parameter in SHPC_VMSTATE() migration: introduce VMSTATE_BUFFER_UNSAFE_INFO_TEST() add pci-bridge-seat pc: cleanup and convert TMP ACPI device description to AML API MAINTAINERS: add ACPI entry vhost: correctly pass error to caller in vhost_dev_enable_notifiers() balloon: add a feature bit to let Guest OS deflate balloon on oom qdev: fix OVERFLOW_BEFORE_WIDEN virito-pci: fix OVERRUN problem Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--MAINTAINERS12
-rwxr-xr-xconfigure2
-rw-r--r--docs/multiseat.txt19
-rw-r--r--docs/specs/pci-ids.txt1
-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
-rw-r--r--include/hw/pci/pci.h1
-rw-r--r--include/hw/pci/pci_bridge.h4
-rw-r--r--include/hw/pci/shpc.h11
-rw-r--r--include/hw/sysbus.h17
-rw-r--r--include/hw/virtio/virtio-balloon.h1
-rw-r--r--include/migration/vmstate.h7
24 files changed, 263 insertions, 370 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 36391730c7..3d48a6bd65 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -644,7 +644,19 @@ M: Michael S. Tsirkin <mst@redhat.com>
S: Supported
F: include/hw/pci/*
F: hw/pci/*
+
+ACPI
+M: Michael S. Tsirkin <mst@redhat.com>
+M: Igor Mammedov <imammedo@redhat.com>
+S: Supported
+F: include/hw/acpi/*
+F: hw/mem/*
F: hw/acpi/*
+F: hw/i386/acpi-build.[hc]
+F: hw/i386/*dsl
+F: hw/arm/virt-acpi-build.c
+F: include/hw/arm/virt-acpi-build.h
+F: scripts/acpi*py
ppc4xx
M: Alexander Graf <agraf@suse.de>
diff --git a/configure b/configure
index f02510bc45..3063739a5e 100755
--- a/configure
+++ b/configure
@@ -4773,7 +4773,7 @@ if test "$bluez" = "yes" ; then
echo "CONFIG_BLUEZ=y" >> $config_host_mak
echo "BLUEZ_CFLAGS=$bluez_cflags" >> $config_host_mak
fi
-if test "glib_subprocess" = "yes" ; then
+if test "$glib_subprocess" = "yes" ; then
echo "CONFIG_HAS_GLIB_SUBPROCESS_TESTS=y" >> $config_host_mak
fi
echo "GLIB_CFLAGS=$glib_cflags" >> $config_host_mak
diff --git a/docs/multiseat.txt b/docs/multiseat.txt
index b963665ef2..814496e94c 100644
--- a/docs/multiseat.txt
+++ b/docs/multiseat.txt
@@ -106,6 +106,25 @@ the devices attached to the seat.
Background info is here:
http://www.freedesktop.org/wiki/Software/systemd/multiseat/
+
+guest side with pci-bridge-seat
+-------------------------------
+
+Qemu version FIXME and newer has a new pci-bridge-seat device which
+can be used instead of pci-bridge. Just swap the device name in the
+qemu command line above. The only difference between the two devices
+is the pci id. We can match the pci id instead of the device path
+with a nice generic rule now, which simplifies the guest
+configuration:
+
+ [root@fedora ~]# cat /etc/udev/rules.d/70-qemu-pci-bridge-seat.rules
+ SUBSYSTEM=="pci", ATTR{vendor}=="0x1b36", ATTR{device}=="0x000a", \
+ TAG+="seat", ENV{ID_AUTOSEAT}="1"
+
+Patch with this rule will be submitted to upstream udev/systemd, so
+long-term, when systemd with this lands in distros, things will work
+just fine without any manual guest configuration.
+
Enjoy!
--
diff --git a/docs/specs/pci-ids.txt b/docs/specs/pci-ids.txt
index e4a44908cb..0adcb89aac 100644
--- a/docs/specs/pci-ids.txt
+++ b/docs/specs/pci-ids.txt
@@ -47,6 +47,7 @@ PCI devices (other than virtio):
1b36:0005 PCI test device (docs/specs/pci-testdev.txt)
1b36:0006 PCI Rocker Ethernet switch device
1b36:0007 PCI SD Card Host Controller Interface (SDHCI)
+1b36:000a PCI-PCI bridge (multiseat)
All these devices are documented in docs/specs.
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) |
diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h
index d44bc84d1e..551cb3d608 100644
--- a/include/hw/pci/pci.h
+++ b/include/hw/pci/pci.h
@@ -92,6 +92,7 @@
#define PCI_DEVICE_ID_REDHAT_SDHCI 0x0007
#define PCI_DEVICE_ID_REDHAT_PCIE_HOST 0x0008
#define PCI_DEVICE_ID_REDHAT_PXB 0x0009
+#define PCI_DEVICE_ID_REDHAT_BRIDGE_SEAT 0x000a
#define PCI_DEVICE_ID_REDHAT_QXL 0x0100
#define FMT_PCIBUS PRIx64
diff --git a/include/hw/pci/pci_bridge.h b/include/hw/pci/pci_bridge.h
index 1d8f9973c7..93b621cef3 100644
--- a/include/hw/pci/pci_bridge.h
+++ b/include/hw/pci/pci_bridge.h
@@ -28,6 +28,10 @@
#include "hw/pci/pci.h"
+#define PCI_BRIDGE_DEV_PROP_CHASSIS_NR "chassis_nr"
+#define PCI_BRIDGE_DEV_PROP_MSI "msi"
+#define PCI_BRIDGE_DEV_PROP_SHPC "shpc"
+
int pci_bridge_ssvid_init(PCIDevice *dev, uint8_t offset,
uint16_t svid, uint16_t ssid);
diff --git a/include/hw/pci/shpc.h b/include/hw/pci/shpc.h
index 9bbea39996..2c871b947b 100644
--- a/include/hw/pci/shpc.h
+++ b/include/hw/pci/shpc.h
@@ -6,6 +6,7 @@
#include "migration/vmstate.h"
#include "qapi/error.h"
#include "hw/hotplug.h"
+#include "hw/pci/pci.h"
struct SHPCDevice {
/* Capability offset in device's config space */
@@ -51,7 +52,13 @@ void shpc_device_hot_unplug_request_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp);
extern VMStateInfo shpc_vmstate_info;
-#define SHPC_VMSTATE(_field, _type) \
- VMSTATE_BUFFER_UNSAFE_INFO(_field, _type, 0, shpc_vmstate_info, 0)
+#define SHPC_VMSTATE(_field, _type, _test) \
+ VMSTATE_BUFFER_UNSAFE_INFO_TEST(_field, _type, _test, 0, \
+ shpc_vmstate_info, 0)
+
+static inline bool shpc_present(const PCIDevice *dev)
+{
+ return dev->cap_present & QEMU_PCI_CAP_SHPC;
+}
#endif
diff --git a/include/hw/sysbus.h b/include/hw/sysbus.h
index d1f3f000f9..34f93c39bf 100644
--- a/include/hw/sysbus.h
+++ b/include/hw/sysbus.h
@@ -41,6 +41,23 @@ typedef struct SysBusDeviceClass {
/*< public >*/
int (*init)(SysBusDevice *dev);
+
+ /*
+ * Let the sysbus device format its own non-PIO, non-MMIO unit address.
+ *
+ * Sometimes a class of SysBusDevices has neither MMIO nor PIO resources,
+ * yet instances of it would like to distinguish themselves, in
+ * OpenFirmware device paths, from other instances of the same class on the
+ * sysbus. For that end we expose this callback.
+ *
+ * The implementation is not supposed to change *@dev, or incur other
+ * observable change.
+ *
+ * The function returns a dynamically allocated string. On error, NULL
+ * should be returned; the unit address portion of the OFW node will be
+ * omitted then. (This is not considered a fatal error.)
+ */
+ char *(*explicit_ofw_unit_address)(const SysBusDevice *dev);
} SysBusDeviceClass;
struct SysBusDevice {
diff --git a/include/hw/virtio/virtio-balloon.h b/include/hw/virtio/virtio-balloon.h
index 346a9fdb7d..09c2ce4dcd 100644
--- a/include/hw/virtio/virtio-balloon.h
+++ b/include/hw/virtio/virtio-balloon.h
@@ -42,6 +42,7 @@ typedef struct VirtIOBalloon {
QEMUTimer *stats_timer;
int64_t stats_last_update;
int64_t stats_poll_interval;
+ uint32_t host_features;
} VirtIOBalloon;
#endif
diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
index 7153b1e145..0695d7c3de 100644
--- a/include/migration/vmstate.h
+++ b/include/migration/vmstate.h
@@ -500,9 +500,10 @@ extern const VMStateInfo vmstate_info_bitmap;
.start = (_start), \
}
-#define VMSTATE_BUFFER_UNSAFE_INFO(_field, _state, _version, _info, _size) { \
+#define VMSTATE_BUFFER_UNSAFE_INFO_TEST(_field, _state, _test, _version, _info, _size) { \
.name = (stringify(_field)), \
.version_id = (_version), \
+ .field_exists = (_test), \
.size = (_size), \
.info = &(_info), \
.flags = VMS_BUFFER, \
@@ -562,6 +563,10 @@ extern const VMStateInfo vmstate_info_bitmap;
VMSTATE_STRUCT_ARRAY_TEST(_field, _state, _num, NULL, _version, \
_vmsd, _type)
+#define VMSTATE_BUFFER_UNSAFE_INFO(_field, _state, _version, _info, _size) \
+ VMSTATE_BUFFER_UNSAFE_INFO_TEST(_field, _state, NULL, _version, _info, \
+ _size)
+
#define VMSTATE_BOOL_V(_f, _s, _v) \
VMSTATE_SINGLE(_f, _s, _v, vmstate_info_bool, bool)