aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/pci/pci.h17
-rw-r--r--drivers/pci/pcie/Makefile2
-rw-r--r--drivers/pci/pcie/rcec.c59
-rw-r--r--drivers/pci/probe.c2
-rw-r--r--include/linux/pci.h4
5 files changed, 83 insertions, 1 deletions
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index f86cae9aa1f4..12dcad8f3635 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -448,6 +448,15 @@ int aer_get_device_error_info(struct pci_dev *dev, struct aer_err_info *info);
void aer_print_error(struct pci_dev *dev, struct aer_err_info *info);
#endif /* CONFIG_PCIEAER */
+#ifdef CONFIG_PCIEPORTBUS
+/* Cached RCEC Endpoint Association */
+struct rcec_ea {
+ u8 nextbusn;
+ u8 lastbusn;
+ u32 bitmap;
+};
+#endif
+
#ifdef CONFIG_PCIE_DPC
void pci_save_dpc_state(struct pci_dev *dev);
void pci_restore_dpc_state(struct pci_dev *dev);
@@ -460,6 +469,14 @@ static inline void pci_restore_dpc_state(struct pci_dev *dev) {}
static inline void pci_dpc_init(struct pci_dev *pdev) {}
#endif
+#ifdef CONFIG_PCIEPORTBUS
+void pci_rcec_init(struct pci_dev *dev);
+void pci_rcec_exit(struct pci_dev *dev);
+#else
+static inline void pci_rcec_init(struct pci_dev *dev) {}
+static inline void pci_rcec_exit(struct pci_dev *dev) {}
+#endif
+
#ifdef CONFIG_PCI_ATS
/* Address Translation Service */
void pci_ats_init(struct pci_dev *dev);
diff --git a/drivers/pci/pcie/Makefile b/drivers/pci/pcie/Makefile
index 68da9280ff11..d9697892fa3e 100644
--- a/drivers/pci/pcie/Makefile
+++ b/drivers/pci/pcie/Makefile
@@ -2,7 +2,7 @@
#
# Makefile for PCI Express features and port driver
-pcieportdrv-y := portdrv_core.o portdrv_pci.o err.o
+pcieportdrv-y := portdrv_core.o portdrv_pci.o err.o rcec.o
obj-$(CONFIG_PCIEPORTBUS) += pcieportdrv.o
diff --git a/drivers/pci/pcie/rcec.c b/drivers/pci/pcie/rcec.c
new file mode 100644
index 000000000000..038e9d706d5f
--- /dev/null
+++ b/drivers/pci/pcie/rcec.c
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Root Complex Event Collector Support
+ *
+ * Authors:
+ * Sean V Kelley <sean.v.kelley@intel.com>
+ * Qiuxu Zhuo <qiuxu.zhuo@intel.com>
+ *
+ * Copyright (C) 2020 Intel Corp.
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/pci_regs.h>
+
+#include "../pci.h"
+
+void pci_rcec_init(struct pci_dev *dev)
+{
+ struct rcec_ea *rcec_ea;
+ u32 rcec, hdr, busn;
+ u8 ver;
+
+ /* Only for Root Complex Event Collectors */
+ if (pci_pcie_type(dev) != PCI_EXP_TYPE_RC_EC)
+ return;
+
+ rcec = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_RCEC);
+ if (!rcec)
+ return;
+
+ rcec_ea = kzalloc(sizeof(*rcec_ea), GFP_KERNEL);
+ if (!rcec_ea)
+ return;
+
+ pci_read_config_dword(dev, rcec + PCI_RCEC_RCIEP_BITMAP,
+ &rcec_ea->bitmap);
+
+ /* Check whether RCEC BUSN register is present */
+ pci_read_config_dword(dev, rcec, &hdr);
+ ver = PCI_EXT_CAP_VER(hdr);
+ if (ver >= PCI_RCEC_BUSN_REG_VER) {
+ pci_read_config_dword(dev, rcec + PCI_RCEC_BUSN, &busn);
+ rcec_ea->nextbusn = PCI_RCEC_BUSN_NEXT(busn);
+ rcec_ea->lastbusn = PCI_RCEC_BUSN_LAST(busn);
+ } else {
+ /* Avoid later ver check by setting nextbusn */
+ rcec_ea->nextbusn = 0xff;
+ rcec_ea->lastbusn = 0x00;
+ }
+
+ dev->rcec_ea = rcec_ea;
+}
+
+void pci_rcec_exit(struct pci_dev *dev)
+{
+ kfree(dev->rcec_ea);
+ dev->rcec_ea = NULL;
+}
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 4289030b0fff..f22e1451d65d 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -2216,6 +2216,7 @@ static void pci_configure_device(struct pci_dev *dev)
static void pci_release_capabilities(struct pci_dev *dev)
{
pci_aer_exit(dev);
+ pci_rcec_exit(dev);
pci_vpd_release(dev);
pci_iov_release(dev);
pci_free_cap_save_buffers(dev);
@@ -2415,6 +2416,7 @@ static void pci_init_capabilities(struct pci_dev *dev)
pci_ptm_init(dev); /* Precision Time Measurement */
pci_aer_init(dev); /* Advanced Error Reporting */
pci_dpc_init(dev); /* Downstream Port Containment */
+ pci_rcec_init(dev); /* Root Complex Event Collector */
pcie_report_downtraining(dev);
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 22207a79762c..f8c927fd0602 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -304,6 +304,7 @@ struct pcie_link_state;
struct pci_vpd;
struct pci_sriov;
struct pci_p2pdma;
+struct rcec_ea;
/* The pci_dev structure describes PCI devices */
struct pci_dev {
@@ -327,6 +328,9 @@ struct pci_dev {
u16 aer_cap; /* AER capability offset */
struct aer_stats *aer_stats; /* AER stats for this device */
#endif
+#ifdef CONFIG_PCIEPORTBUS
+ struct rcec_ea *rcec_ea; /* RCEC cached endpoint association */
+#endif
u8 pcie_cap; /* PCIe capability offset */
u8 msi_cap; /* MSI capability offset */
u8 msix_cap; /* MSI-X capability offset */