Skip to content

Commit b34d605

Browse files
bjorn-helgaaswilldeacon
authored andcommitted
perf/dwc_pcie: Qualify RAS DES VSEC Capability by Vendor, Revision
PCI Vendor-Specific (VSEC) Capabilities are defined by each vendor. Devices from different vendors may advertise a VSEC Capability with the DWC RAS DES functionality, but the vendors may assign different VSEC IDs. Search for the DWC RAS DES Capability using the VSEC ID and VSEC Rev chosen by the vendor. This does not fix a current problem because Alibaba, Ampere, and Qualcomm all assigned the same VSEC ID and VSEC Rev for the DWC RAS DES Capability. The potential issue is that we may add support for a device from another vendor, where the vendor has already assigned DWC_PCIE_VSEC_RAS_DES_ID (0x02) for an unrelated VSEC. In that event, dwc_pcie_des_cap() would find the unrelated VSEC and mistakenly assume it was a DWC RAS DES Capability. Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Reviewed-and-tested-by: Ilkka Koskinen <ilkka@os.amperecomputing.com> Reviewed-and-tested-by: Shuai Xue <xueshuai@linux.alibaba.com> Link: https://lore.kernel.org/r/20241209222938.3219364-1-helgaas@kernel.org Signed-off-by: Will Deacon <will@kernel.org>
1 parent f03241f commit b34d605

File tree

1 file changed

+37
-31
lines changed

1 file changed

+37
-31
lines changed

drivers/perf/dwc_pcie_pmu.c

Lines changed: 37 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
#include <linux/sysfs.h>
2121
#include <linux/types.h>
2222

23-
#define DWC_PCIE_VSEC_RAS_DES_ID 0x02
2423
#define DWC_PCIE_EVENT_CNT_CTL 0x8
2524

2625
/*
@@ -100,14 +99,23 @@ struct dwc_pcie_dev_info {
10099
struct list_head dev_node;
101100
};
102101

103-
struct dwc_pcie_vendor_id {
104-
int vendor_id;
102+
struct dwc_pcie_pmu_vsec_id {
103+
u16 vendor_id;
104+
u16 vsec_id;
105+
u8 vsec_rev;
105106
};
106107

107-
static const struct dwc_pcie_vendor_id dwc_pcie_vendor_ids[] = {
108-
{.vendor_id = PCI_VENDOR_ID_ALIBABA },
109-
{.vendor_id = PCI_VENDOR_ID_AMPERE },
110-
{.vendor_id = PCI_VENDOR_ID_QCOM },
108+
/*
109+
* VSEC IDs are allocated by the vendor, so a given ID may mean different
110+
* things to different vendors. See PCIe r6.0, sec 7.9.5.2.
111+
*/
112+
static const struct dwc_pcie_pmu_vsec_id dwc_pcie_pmu_vsec_ids[] = {
113+
{ .vendor_id = PCI_VENDOR_ID_ALIBABA,
114+
.vsec_id = 0x02, .vsec_rev = 0x4 },
115+
{ .vendor_id = PCI_VENDOR_ID_AMPERE,
116+
.vsec_id = 0x02, .vsec_rev = 0x4 },
117+
{ .vendor_id = PCI_VENDOR_ID_QCOM,
118+
.vsec_id = 0x02, .vsec_rev = 0x4 },
111119
{} /* terminator */
112120
};
113121

@@ -519,31 +527,28 @@ static void dwc_pcie_unregister_pmu(void *data)
519527
perf_pmu_unregister(&pcie_pmu->pmu);
520528
}
521529

522-
static bool dwc_pcie_match_des_cap(struct pci_dev *pdev)
530+
static u16 dwc_pcie_des_cap(struct pci_dev *pdev)
523531
{
524-
const struct dwc_pcie_vendor_id *vid;
525-
u16 vsec = 0;
532+
const struct dwc_pcie_pmu_vsec_id *vid;
533+
u16 vsec;
526534
u32 val;
527535

528536
if (!pci_is_pcie(pdev) || !(pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT))
529-
return false;
537+
return 0;
530538

531-
for (vid = dwc_pcie_vendor_ids; vid->vendor_id; vid++) {
539+
for (vid = dwc_pcie_pmu_vsec_ids; vid->vendor_id; vid++) {
532540
vsec = pci_find_vsec_capability(pdev, vid->vendor_id,
533-
DWC_PCIE_VSEC_RAS_DES_ID);
534-
if (vsec)
535-
break;
541+
vid->vsec_id);
542+
if (vsec) {
543+
pci_read_config_dword(pdev, vsec + PCI_VNDR_HEADER,
544+
&val);
545+
if (PCI_VNDR_HEADER_REV(val) == vid->vsec_rev) {
546+
pci_dbg(pdev, "Detected PCIe Vendor-Specific Extended Capability RAS DES\n");
547+
return vsec;
548+
}
549+
}
536550
}
537-
if (!vsec)
538-
return false;
539-
540-
pci_read_config_dword(pdev, vsec + PCI_VNDR_HEADER, &val);
541-
if (PCI_VNDR_HEADER_REV(val) != 0x04)
542-
return false;
543-
544-
pci_dbg(pdev,
545-
"Detected PCIe Vendor-Specific Extended Capability RAS DES\n");
546-
return true;
551+
return 0;
547552
}
548553

549554
static void dwc_pcie_unregister_dev(struct dwc_pcie_dev_info *dev_info)
@@ -587,7 +592,7 @@ static int dwc_pcie_pmu_notifier(struct notifier_block *nb,
587592

588593
switch (action) {
589594
case BUS_NOTIFY_ADD_DEVICE:
590-
if (!dwc_pcie_match_des_cap(pdev))
595+
if (!dwc_pcie_des_cap(pdev))
591596
return NOTIFY_DONE;
592597
if (dwc_pcie_register_dev(pdev))
593598
return NOTIFY_BAD;
@@ -612,13 +617,14 @@ static int dwc_pcie_pmu_probe(struct platform_device *plat_dev)
612617
struct pci_dev *pdev = plat_dev->dev.platform_data;
613618
struct dwc_pcie_pmu *pcie_pmu;
614619
char *name;
615-
u32 sbdf, val;
620+
u32 sbdf;
616621
u16 vsec;
617622
int ret;
618623

619-
vsec = pci_find_vsec_capability(pdev, pdev->vendor,
620-
DWC_PCIE_VSEC_RAS_DES_ID);
621-
pci_read_config_dword(pdev, vsec + PCI_VNDR_HEADER, &val);
624+
vsec = dwc_pcie_des_cap(pdev);
625+
if (!vsec)
626+
return -ENODEV;
627+
622628
sbdf = plat_dev->id;
623629
name = devm_kasprintf(&plat_dev->dev, GFP_KERNEL, "dwc_rootport_%x", sbdf);
624630
if (!name)
@@ -730,7 +736,7 @@ static int __init dwc_pcie_pmu_init(void)
730736
int ret;
731737

732738
for_each_pci_dev(pdev) {
733-
if (!dwc_pcie_match_des_cap(pdev))
739+
if (!dwc_pcie_des_cap(pdev))
734740
continue;
735741

736742
ret = dwc_pcie_register_dev(pdev);

0 commit comments

Comments
 (0)