From 50e4c7d12fce46ce16f46057322d0b1ab9958622 Mon Sep 17 00:00:00 2001 From: Kuppuswamy Sathyanarayanan Date: Mon, 23 Mar 2020 17:26:04 -0700 Subject: [PATCH 2234/2944] PCI/DPC: Cache DPC capabilities in pci_init_capabilities() task #31407665 commit 27005618178ef9e9bf9c42fd91101771c92e9308 upstream Since Error Disconnect Recover needs to use DPC error handling routines even if the OS doesn't have control of DPC, move the initalization and caching of DPC capabilities from the DPC driver to pci_init_capabilities(). Signed-off-by: Zelin Deng Conflicts: drivers/pci/probe.c Link: https://lore.kernel.org/r/5888380657c8b9551675b5dbd48e370e4fd2703d.1585000084.git.sathyanarayanan.kuppuswamy@linux.intel.com Signed-off-by: Kuppuswamy Sathyanarayanan Signed-off-by: Bjorn Helgaas Signed-off-by: Zelin Deng Reviewed-by: Artie Ding --- drivers/pci/pci.h | 2 ++ drivers/pci/pcie/dpc.c | 33 +++++++++++++++++++++------------ drivers/pci/probe.c | 3 +++ 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 5570f02..19de4da 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -411,9 +411,11 @@ struct aer_err_info { #ifdef CONFIG_PCIE_DPC void pci_save_dpc_state(struct pci_dev *dev); void pci_restore_dpc_state(struct pci_dev *dev); +void pci_dpc_init(struct pci_dev *pdev); #else static inline void pci_save_dpc_state(struct pci_dev *dev) {} static inline void pci_restore_dpc_state(struct pci_dev *dev) {} +static inline void pci_dpc_init(struct pci_dev *pdev) {} #endif #ifdef CONFIG_PCI_ATS diff --git a/drivers/pci/pcie/dpc.c b/drivers/pci/pcie/dpc.c index 1ae5d94..a1c9d45 100644 --- a/drivers/pci/pcie/dpc.c +++ b/drivers/pci/pcie/dpc.c @@ -249,6 +249,27 @@ static irqreturn_t dpc_irq(int irq, void *context) return IRQ_HANDLED; } +void pci_dpc_init(struct pci_dev *pdev) +{ + u16 cap; + + pdev->dpc_cap = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_DPC); + if (!pdev->dpc_cap) + return; + + pci_read_config_word(pdev, pdev->dpc_cap + PCI_EXP_DPC_CAP, &cap); + if (!(cap & PCI_EXP_DPC_CAP_RP_EXT)) + return; + + pdev->dpc_rp_extensions = true; + pdev->dpc_rp_log_size = (cap & PCI_EXP_DPC_RP_PIO_LOG_SIZE) >> 8; + if (pdev->dpc_rp_log_size < 4 || pdev->dpc_rp_log_size > 9) { + pci_err(pdev, "RP PIO log size %u is invalid\n", + pdev->dpc_rp_log_size); + pdev->dpc_rp_log_size = 0; + } +} + #define FLAG(x, y) (((x) & (y)) ? '+' : '-') static int dpc_probe(struct pcie_device *dev) { @@ -260,8 +281,6 @@ static int dpc_probe(struct pcie_device *dev) if (pcie_aer_get_firmware_first(pdev) && !pcie_ports_dpc_native) return -ENOTSUPP; - pdev->dpc_cap = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_DPC); - status = devm_request_threaded_irq(device, dev->irq, dpc_irq, dpc_handler, IRQF_SHARED, "pcie-dpc", pdev); @@ -274,16 +293,6 @@ static int dpc_probe(struct pcie_device *dev) pci_read_config_word(pdev, pdev->dpc_cap + PCI_EXP_DPC_CAP, &cap); pci_read_config_word(pdev, pdev->dpc_cap + PCI_EXP_DPC_CTL, &ctl); - pdev->dpc_rp_extensions = (cap & PCI_EXP_DPC_CAP_RP_EXT) ? 1 : 0; - if (pdev->dpc_rp_extensions) { - pdev->dpc_rp_log_size = (cap & PCI_EXP_DPC_RP_PIO_LOG_SIZE) >> 8; - if (pdev->dpc_rp_log_size < 4 || pdev->dpc_rp_log_size > 9) { - pci_err(pdev, "RP PIO log size %u is invalid\n", - pdev->dpc_rp_log_size); - pdev->dpc_rp_log_size = 0; - } - } - ctl = (ctl & 0xfff4) | PCI_EXP_DPC_CTL_EN_FATAL | PCI_EXP_DPC_CTL_INT_EN; pci_write_config_word(pdev, pdev->dpc_cap + PCI_EXP_DPC_CTL, ctl); diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 2d7ff74..50fc1dd 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -2423,6 +2423,9 @@ static void pci_init_capabilities(struct pci_dev *dev) /* Advanced Error Reporting */ pci_aer_init(dev); + /* Downstream Port Containment */ + pci_dpc_init(dev); + pcie_report_downtraining(dev); if (pci_probe_reset_function(dev) == 0) -- 1.8.3.1