Skip to content

Commit

Permalink
PCI/ERR: Cache RCEC EA Capability offset in pci_init_capabilities()
Browse files Browse the repository at this point in the history
Extend support for Root Complex Event Collectors by decoding and caching
the RCEC Endpoint Association Extended Capabilities when enumerating. Use
that cached information for later error source reporting. See PCIe r5.0,
sec 7.9.10.

Co-developed-by: Qiuxu Zhuo <qiuxu.zhuo@intel.com>
Link: https://lore.kernel.org/r/20201121001036.8560-4-sean.v.kelley@intel.com
Tested-by: Jonathan Cameron <Jonathan.Cameron@huawei.com> # non-native/no RCEC
Signed-off-by: Qiuxu Zhuo <qiuxu.zhuo@intel.com>
Signed-off-by: Sean V Kelley <sean.v.kelley@intel.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
  • Loading branch information
seanvk authored and bjorn-helgaas committed Dec 4, 2020
1 parent c9d659b commit 9065563
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 1 deletion.
17 changes: 17 additions & 0 deletions drivers/pci/pci.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion drivers/pci/pcie/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
59 changes: 59 additions & 0 deletions drivers/pci/pcie/rcec.c
Original file line number Diff line number Diff line change
@@ -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;
}
2 changes: 2 additions & 0 deletions drivers/pci/probe.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);

Expand Down
4 changes: 4 additions & 0 deletions include/linux/pci.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -326,6 +327,9 @@ struct pci_dev {
#ifdef CONFIG_PCIEAER
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 */
Expand Down

0 comments on commit 9065563

Please sign in to comment.