*/
#include "qemu/osdep.h"
-#include "hw/hw.h"
+#include "qemu-common.h"
+#include "hw/irq.h"
#include "hw/pci/pci.h"
#include "hw/pci/pci_bridge.h"
#include "hw/pci/pci_bus.h"
#include "hw/pci/pci_host.h"
+#include "hw/qdev-properties.h"
+#include "migration/qemu-file-types.h"
+#include "migration/vmstate.h"
#include "monitor/monitor.h"
#include "net/net.h"
+#include "sysemu/numa.h"
#include "sysemu/sysemu.h"
#include "hw/loader.h"
#include "qemu/error-report.h"
DEFINE_PROP_UINT32("rombar", PCIDevice, rom_bar, 1),
DEFINE_PROP_BIT("multifunction", PCIDevice, cap_present,
QEMU_PCI_CAP_MULTIFUNCTION_BITNR, false),
- DEFINE_PROP_BIT("command_serr_enable", PCIDevice, cap_present,
- QEMU_PCI_CAP_SERR_BITNR, true),
DEFINE_PROP_BIT("x-pcie-lnksta-dllla", PCIDevice, cap_present,
QEMU_PCIE_LNKSTA_DLLLA_BITNR, true),
DEFINE_PROP_BIT("x-pcie-extcap-init", PCIDevice, cap_present,
QEMU_PCIE_EXTCAP_INIT_BITNR, true),
+ DEFINE_PROP_STRING("failover_pair_id", PCIDevice,
+ failover_pair_id),
DEFINE_PROP_END_OF_LIST()
};
pci_set_word(dev->wmask + PCI_COMMAND,
PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
PCI_COMMAND_INTX_DISABLE);
- if (dev->cap_present & QEMU_PCI_CAP_SERR) {
- pci_word_test_and_set_mask(dev->wmask + PCI_COMMAND, PCI_COMMAND_SERR);
- }
+ pci_word_test_and_set_mask(dev->wmask + PCI_COMMAND, PCI_COMMAND_SERR);
memset(dev->wmask + PCI_CONFIG_HEADER_SIZE, 0xff,
config_size - PCI_CONFIG_HEADER_SIZE);
ObjectClass *klass = OBJECT_CLASS(pc);
Error *local_err = NULL;
bool is_default_rom;
+ uint16_t class_id;
/* initialize cap_present for pci_is_express() and pci_config_size(),
* Note that hybrid PCIs are not set automatically and need to manage
}
}
+ if (pci_dev->failover_pair_id) {
+ if (!pci_bus_is_express(pci_get_bus(pci_dev))) {
+ error_setg(errp, "failover primary device must be on "
+ "PCIExpress bus");
+ error_propagate(errp, local_err);
+ pci_qdev_unrealize(DEVICE(pci_dev), NULL);
+ return;
+ }
+ class_id = pci_get_word(pci_dev->config + PCI_CLASS_DEVICE);
+ if (class_id != PCI_CLASS_NETWORK_ETHERNET) {
+ error_setg(errp, "failover primary device is not an "
+ "Ethernet device");
+ error_propagate(errp, local_err);
+ pci_qdev_unrealize(DEVICE(pci_dev), NULL);
+ return;
+ }
+ if (!(pci_dev->cap_present & QEMU_PCI_CAP_MULTIFUNCTION)
+ && (PCI_FUNC(pci_dev->devfn) == 0)) {
+ qdev->allow_unplug_during_migration = true;
+ } else {
+ error_setg(errp, "failover: primary device must be in its own "
+ "PCI slot");
+ error_propagate(errp, local_err);
+ pci_qdev_unrealize(DEVICE(pci_dev), NULL);
+ return;
+ }
+ qdev->allow_unplug_during_migration = true;
+ }
+
/* rom loading */
is_default_rom = false;
if (pci_dev->romfile == NULL && pc->romfile != NULL) {
{
PCIBus *bus = pci_get_bus(dev);
PCIBus *iommu_bus = bus;
+ uint8_t devfn = dev->devfn;
+
+ while (iommu_bus && !iommu_bus->iommu_fn && iommu_bus->parent_dev) {
+ PCIBus *parent_bus = pci_get_bus(iommu_bus->parent_dev);
+
+ /*
+ * The requester ID of the provided device may be aliased, as seen from
+ * the IOMMU, due to topology limitations. The IOMMU relies on a
+ * requester ID to provide a unique AddressSpace for devices, but
+ * conventional PCI buses pre-date such concepts. Instead, the PCIe-
+ * to-PCI bridge creates and accepts transactions on behalf of down-
+ * stream devices. When doing so, all downstream devices are masked
+ * (aliased) behind a single requester ID. The requester ID used
+ * depends on the format of the bridge devices. Proper PCIe-to-PCI
+ * bridges, with a PCIe capability indicating such, follow the
+ * guidelines of chapter 2.3 of the PCIe-to-PCI/X bridge specification,
+ * where the bridge uses the seconary bus as the bridge portion of the
+ * requester ID and devfn of 00.0. For other bridges, typically those
+ * found on the root complex such as the dmi-to-pci-bridge, we follow
+ * the convention of typical bare-metal hardware, which uses the
+ * requester ID of the bridge itself. There are device specific
+ * exceptions to these rules, but these are the defaults that the
+ * Linux kernel uses when determining DMA aliases itself and believed
+ * to be true for the bare metal equivalents of the devices emulated
+ * in QEMU.
+ */
+ if (!pci_bus_is_express(iommu_bus)) {
+ PCIDevice *parent = iommu_bus->parent_dev;
+
+ if (pci_is_express(parent) &&
+ pcie_cap_get_type(parent) == PCI_EXP_TYPE_PCI_BRIDGE) {
+ devfn = PCI_DEVFN(0, 0);
+ bus = iommu_bus;
+ } else {
+ devfn = parent->devfn;
+ bus = parent_bus;
+ }
+ }
- while(iommu_bus && !iommu_bus->iommu_fn && iommu_bus->parent_dev) {
- iommu_bus = pci_get_bus(iommu_bus->parent_dev);
+ iommu_bus = parent_bus;
}
if (iommu_bus && iommu_bus->iommu_fn) {
- return iommu_bus->iommu_fn(bus, iommu_bus->iommu_opaque, dev->devfn);
+ return iommu_bus->iommu_fn(bus, iommu_bus->iommu_opaque, devfn);
}
return &address_space_memory;
}