@@ -11,7 +11,7 @@ pci_ss.add(files(
# The functions in these modules can be used by devices too. Since we
# allow plugging PCIe devices into PCI buses, include them even if
# CONFIG_PCI_EXPRESS=n.
-pci_ss.add(files('pcie.c', 'pcie_aer.c'))
+pci_ss.add(files('pcie.c', 'pcie_aer.c', 'pcie_rcec.c'))
softmmu_ss.add(when: 'CONFIG_PCI_EXPRESS', if_true: files('pcie_port.c', 'pcie_host.c'))
softmmu_ss.add_all(when: 'CONFIG_PCI', if_true: pci_ss)
@@ -747,6 +747,24 @@ void pcie_cap_slot_push_attention_button(PCIDevice *dev)
pcie_cap_slot_event(dev, PCI_EXP_HP_EV_ABP);
}
+void pcie_rcec_ep_map(PCIDevice *dev)
+{
+ int devnum = PCI_SLOT(dev->devfn);
+ uint32_t ep_bitmap;
+ PCIDevice *rcec;
+ uint16_t cap;
+
+ /* RCEC is always expected to be at 00:01.0 */
+ rcec = pci_find_device(pci_get_bus(dev), 0, PCI_DEVFN(1,0));
+ if (!rcec)
+ return;
+
+ pcie_cap_deverr_init(dev);
+ cap = pcie_find_capability(rcec, PCI_EXT_CAP_ID_RCEC);
+ ep_bitmap = pci_get_long(rcec->config + cap + 0x4);
+ pci_set_long(rcec->config + cap + 0x4, ep_bitmap | 1 << devnum);
+}
+
/* root control/capabilities/status. PME isn't emulated for now */
void pcie_cap_root_init(PCIDevice *dev)
{
@@ -166,6 +166,15 @@ int pcie_aer_init(PCIDevice *dev, uint8_t cap_ver, uint16_t offset,
/* nothing */
break;
}
+
+ /*
+ * If this is a RCiEP, map it into the RCEC's endpoint association bitmap
+ * capability
+ */
+ if (pci_bus_is_express(pci_get_bus(dev))
+ && pci_bus_is_root(pci_get_bus(dev)))
+ pcie_rcec_ep_map(dev);
+
return 0;
}
new file mode 100644
@@ -0,0 +1,119 @@
+/*
+ * pcie_rcec.c
+ * PCIe Root Complex Event Collector emulation
+ *
+ * Copyright (c) 2021 Mayuresh Chitale <mchitale@ventanamicro.com>
+ *
+ * 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 "qemu/osdep.h"
+#include "qemu/units.h"
+#include "qemu/module.h"
+#include "qemu/range.h"
+#include "sysemu/sysemu.h"
+#include "hw/hw.h"
+#include "hw/pci/pci.h"
+#include "hw/qdev-properties.h"
+#include "migration/vmstate.h"
+
+#define TYPE_RCEC_DEVICE "pcie-rcec"
+#define PCIE_RCEC_EXP_CAP_OFF 0x40
+#define PCIE_RCEC_EP_ECAP_OFF 0x100
+#define PCIE_RCEC_AER_ECAP_OFF 0x120
+
+struct RcecState {
+ /*< private >*/
+ PCIDevice parent_obj;
+ /*< public >*/
+};
+
+
+static int pcie_rcec_cap_init(PCIDevice *dev, uint8_t offset)
+{
+ int rc;
+
+ dev->config[PCI_INTERRUPT_PIN] = 1;
+ rc = pcie_endpoint_cap_common_init(dev, offset,
+ PCI_EXP_VER2_SIZEOF, PCI_EXP_TYPE_RC_EC);
+ pcie_cap_root_init(dev);
+ pcie_cap_deverr_init(dev);
+
+ return rc;
+}
+
+static void pcie_rcec_ep_cap_init(PCIDevice *dev, uint8_t cap_ver, uint16_t offset,
+ uint16_t size, Error **errp)
+{
+ pcie_add_capability(dev, PCI_EXT_CAP_ID_RCEC, cap_ver, offset, size);
+ /* Map device (bit) 1 which is RCEC by default */
+ pci_set_long(dev->config + offset + 0x4, 0x2);
+}
+
+static void pcie_rcec_realize(PCIDevice *pci_dev, Error **errp)
+{
+ if (pcie_rcec_cap_init(pci_dev, PCIE_RCEC_EXP_CAP_OFF) < 0)
+ hw_error("Failed to initialize RCEC express capability");
+
+ pcie_rcec_ep_cap_init(pci_dev, PCI_RCEC_EP_VER, PCIE_RCEC_EP_ECAP_OFF,
+ PCI_RCEC_EP_SIZEOF, errp);
+
+ if (pcie_aer_init(pci_dev, PCI_ERR_VER, PCIE_RCEC_AER_ECAP_OFF,
+ PCI_ERR_SIZEOF, errp) < 0)
+ hw_error("Failed to initialize RCEC AER capability");
+}
+
+static const VMStateDescription vmstate_rcec = {
+ .name = "rcec",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_PCI_DEVICE(parent_obj, struct RcecState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void rcec_class_init(ObjectClass *klass, void *data)
+{
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
+ dc->desc = "QEMU generic RCEC";
+ dc->vmsd = &vmstate_rcec;
+ k->vendor_id = PCI_VENDOR_ID_REDHAT;
+ k->device_id = PCI_DEVICE_ID_REDHAT_RCEC;
+ k->revision = 0;
+ k->class_id = PCI_CLASS_SYSTEM_RCEC;
+ k->realize = pcie_rcec_realize;
+}
+
+static const TypeInfo pcie_rcec_info = {
+ .name = TYPE_RCEC_DEVICE,
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(struct RcecState),
+ .class_init = rcec_class_init,
+ .interfaces = (InterfaceInfo[]) {
+ { INTERFACE_PCIE_DEVICE },
+ { },
+ },
+};
+
+
+static void pcie_rcec_register_types(void)
+{
+ type_register_static(&pcie_rcec_info);
+}
+
+type_init(pcie_rcec_register_types)
@@ -109,6 +109,7 @@ extern bool pci_available;
#define PCI_DEVICE_ID_REDHAT_NVME 0x0010
#define PCI_DEVICE_ID_REDHAT_PVPANIC 0x0011
#define PCI_DEVICE_ID_REDHAT_QXL 0x0100
+#define PCI_DEVICE_ID_REDHAT_RCEC 0x0101
#define FMT_PCIBUS PRIx64
@@ -88,6 +88,7 @@
#define PCI_CLASS_SYSTEM_RTC 0x0803
#define PCI_CLASS_SYSTEM_PCI_HOTPLUG 0x0804
#define PCI_CLASS_SYSTEM_SDHCI 0x0805
+#define PCI_CLASS_SYSTEM_RCEC 0x0807
#define PCI_CLASS_SYSTEM_OTHER 0x0880
#define PCI_BASE_CLASS_INPUT 0x09
@@ -149,4 +149,5 @@ void pcie_cap_slot_unplug_request_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp);
int pcie_endpoint_cap_common_init(PCIDevice *dev, uint8_t offset,
uint8_t cap_size, uint8_t type);
+void pcie_rcec_ep_map(PCIDevice *dev);
#endif /* QEMU_PCIE_H */
@@ -179,4 +179,7 @@ typedef enum PCIExpLinkWidth {
#define PCI_ACS_VER 0x1
#define PCI_ACS_SIZEOF 8
+#define PCI_RCEC_EP_VER 1
+#define PCI_RCEC_EP_SIZEOF 0x8
+
#endif /* QEMU_PCIE_REGS_H */
This patch adds support for PCIe Root Complex Event Collector (RCEC) emulation. Further, if a RCiEP supports AER capability then a mapping is created for that RCiEP in the RCEC's endpoint association capability. Signed-off-by: Mayuresh Chitale <mchitale@ventanamicro.com> --- hw/pci/meson.build | 2 +- hw/pci/pcie.c | 18 ++++++ hw/pci/pcie_aer.c | 9 +++ hw/pci/pcie_rcec.c | 119 +++++++++++++++++++++++++++++++++++++ include/hw/pci/pci.h | 1 + include/hw/pci/pci_ids.h | 1 + include/hw/pci/pcie.h | 1 + include/hw/pci/pcie_regs.h | 3 + 8 files changed, 153 insertions(+), 1 deletion(-) create mode 100644 hw/pci/pcie_rcec.c