summaryrefslogtreecommitdiffstats
path: root/hw/pci-bridge/pcie_pci_bridge.c
diff options
context:
space:
mode:
authorPeter Maydell2017-09-08 17:04:42 +0200
committerPeter Maydell2017-09-08 17:04:42 +0200
commitfcea73709b966a7ded9efa7b106ea50c7fe9025c (patch)
tree3a68a579a3831ae4c3e4c9eb486dce709e55d4b3 /hw/pci-bridge/pcie_pci_bridge.c
parentMerge remote-tracking branch 'remotes/dgibson/tags/ppc-for-2.11-20170908' int... (diff)
parentfw_cfg: rename read callback (diff)
downloadqemu-fcea73709b966a7ded9efa7b106ea50c7fe9025c.tar.gz
qemu-fcea73709b966a7ded9efa7b106ea50c7fe9025c.tar.xz
qemu-fcea73709b966a7ded9efa7b106ea50c7fe9025c.zip
Merge remote-tracking branch 'remotes/mst/tags/for_upstream' into staging
pc, pci, virtio: patches queued before 2.10 A bunch of stuff that was posted before the 2.10 timeframe, mostly fixes/cleanups. New PCI bridges. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> # gpg: Signature made Fri 08 Sep 2017 14:15:34 BST # gpg: using RSA key 0x281F0DB8D28D5469 # 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: fw_cfg: rename read callback pci: add reserved slot check to do_pci_register_device() pci: move check for existing devfn into new pci_bus_devfn_available() helper vmgenid: replace x-write-pointer-available hack vhost-user-bridge: fix resume regression (since 2.9) libvhost-user: support resuming vq->last_avail_idx based on used_idx acpi/vmgenid: change device category to misc intel_iommu: fix missing BQL in pt fast path docs: update documentation considering PCIE-PCI bridge hw/pci: add QEMU-specific PCI capability to the Generic PCI Express Root Port hw/pci: introduce bridge-only vendor-specific capability to provide some hints to firmware hw/pci: introduce pcie-pci-bridge device Revert "ACPI: don't call acpi_pcihp_device_plug_cb on xen" hw/acpi: Move acpi_set_pci_info to pcihp hw/acpi: Limit hotplug to root bus on legacy mode pc: add 2.11 machine types vhost: Release memory references on cleanup Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw/pci-bridge/pcie_pci_bridge.c')
-rw-r--r--hw/pci-bridge/pcie_pci_bridge.c192
1 files changed, 192 insertions, 0 deletions
diff --git a/hw/pci-bridge/pcie_pci_bridge.c b/hw/pci-bridge/pcie_pci_bridge.c
new file mode 100644
index 0000000000..9aa5cc3e45
--- /dev/null
+++ b/hw/pci-bridge/pcie_pci_bridge.c
@@ -0,0 +1,192 @@
+/*
+ * QEMU Generic PCIE-PCI Bridge
+ *
+ * Copyright (c) 2017 Aleksandr Bezzubikov
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "hw/pci/pci.h"
+#include "hw/pci/pci_bus.h"
+#include "hw/pci/pci_bridge.h"
+#include "hw/pci/msi.h"
+#include "hw/pci/shpc.h"
+#include "hw/pci/slotid_cap.h"
+
+typedef struct PCIEPCIBridge {
+ /*< private >*/
+ PCIBridge parent_obj;
+
+ OnOffAuto msi;
+ MemoryRegion shpc_bar;
+ /*< public >*/
+} PCIEPCIBridge;
+
+#define TYPE_PCIE_PCI_BRIDGE_DEV "pcie-pci-bridge"
+#define PCIE_PCI_BRIDGE_DEV(obj) \
+ OBJECT_CHECK(PCIEPCIBridge, (obj), TYPE_PCIE_PCI_BRIDGE_DEV)
+
+static void pcie_pci_bridge_realize(PCIDevice *d, Error **errp)
+{
+ PCIBridge *br = PCI_BRIDGE(d);
+ PCIEPCIBridge *pcie_br = PCIE_PCI_BRIDGE_DEV(d);
+ int rc, pos;
+
+ pci_bridge_initfn(d, TYPE_PCI_BUS);
+
+ d->config[PCI_INTERRUPT_PIN] = 0x1;
+ memory_region_init(&pcie_br->shpc_bar, OBJECT(d), "shpc-bar",
+ shpc_bar_size(d));
+ rc = shpc_init(d, &br->sec_bus, &pcie_br->shpc_bar, 0, errp);
+ if (rc) {
+ goto error;
+ }
+
+ rc = pcie_cap_init(d, 0, PCI_EXP_TYPE_PCI_BRIDGE, 0, errp);
+ if (rc < 0) {
+ goto cap_error;
+ }
+
+ pos = pci_add_capability(d, PCI_CAP_ID_PM, 0, PCI_PM_SIZEOF, errp);
+ if (pos < 0) {
+ goto pm_error;
+ }
+ d->exp.pm_cap = pos;
+ pci_set_word(d->config + pos + PCI_PM_PMC, 0x3);
+
+ pcie_cap_arifwd_init(d);
+ pcie_cap_deverr_init(d);
+
+ rc = pcie_aer_init(d, PCI_ERR_VER, 0x100, PCI_ERR_SIZEOF, errp);
+ if (rc < 0) {
+ goto aer_error;
+ }
+
+ if (pcie_br->msi != ON_OFF_AUTO_OFF) {
+ rc = msi_init(d, 0, 1, true, true, errp);
+ if (rc < 0) {
+ goto msi_error;
+ }
+ }
+ pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY |
+ PCI_BASE_ADDRESS_MEM_TYPE_64, &pcie_br->shpc_bar);
+ return;
+
+msi_error:
+ pcie_aer_exit(d);
+aer_error:
+pm_error:
+ pcie_cap_exit(d);
+cap_error:
+ shpc_free(d);
+error:
+ pci_bridge_exitfn(d);
+}
+
+static void pcie_pci_bridge_exit(PCIDevice *d)
+{
+ PCIEPCIBridge *bridge_dev = PCIE_PCI_BRIDGE_DEV(d);
+ pcie_cap_exit(d);
+ shpc_cleanup(d, &bridge_dev->shpc_bar);
+ pci_bridge_exitfn(d);
+}
+
+static void pcie_pci_bridge_reset(DeviceState *qdev)
+{
+ PCIDevice *d = PCI_DEVICE(qdev);
+ pci_bridge_reset(qdev);
+ msi_reset(d);
+ shpc_reset(d);
+}
+
+static void pcie_pci_bridge_write_config(PCIDevice *d,
+ uint32_t address, uint32_t val, int len)
+{
+ pci_bridge_write_config(d, address, val, len);
+ msi_write_config(d, address, val, len);
+ shpc_cap_write_config(d, address, val, len);
+}
+
+static Property pcie_pci_bridge_dev_properties[] = {
+ DEFINE_PROP_ON_OFF_AUTO("msi", PCIEPCIBridge, msi, ON_OFF_AUTO_ON),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static const VMStateDescription pcie_pci_bridge_dev_vmstate = {
+ .name = TYPE_PCIE_PCI_BRIDGE_DEV,
+ .fields = (VMStateField[]) {
+ VMSTATE_PCI_DEVICE(parent_obj, PCIBridge),
+ SHPC_VMSTATE(shpc, PCIDevice, NULL),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+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);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
+
+ k->is_express = 1;
+ k->is_bridge = 1;
+ k->vendor_id = PCI_VENDOR_ID_REDHAT;
+ k->device_id = PCI_DEVICE_ID_REDHAT_PCIE_BRIDGE;
+ k->realize = pcie_pci_bridge_realize;
+ k->exit = pcie_pci_bridge_exit;
+ k->config_write = pcie_pci_bridge_write_config;
+ dc->vmsd = &pcie_pci_bridge_dev_vmstate;
+ dc->props = pcie_pci_bridge_dev_properties;
+ dc->vmsd = &pcie_pci_bridge_dev_vmstate;
+ 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;
+}
+
+static const TypeInfo pcie_pci_bridge_info = {
+ .name = TYPE_PCIE_PCI_BRIDGE_DEV,
+ .parent = TYPE_PCI_BRIDGE,
+ .instance_size = sizeof(PCIEPCIBridge),
+ .class_init = pcie_pci_bridge_class_init,
+ .interfaces = (InterfaceInfo[]) {
+ { TYPE_HOTPLUG_HANDLER },
+ { },
+ }
+};
+
+static void pciepci_register(void)
+{
+ type_register_static(&pcie_pci_bridge_info);
+}
+
+type_init(pciepci_register);