From patchwork Fri Jul 26 21:43:14 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kuppuswamy Sathyanarayanan X-Patchwork-Id: 1137656 X-Patchwork-Delegate: bhelgaas@google.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-pci-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.intel.com Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 45wN2F681Kz9sBF for ; Sat, 27 Jul 2019 07:46:29 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726617AbfGZVqY (ORCPT ); Fri, 26 Jul 2019 17:46:24 -0400 Received: from mga14.intel.com ([192.55.52.115]:28904 "EHLO mga14.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726999AbfGZVpv (ORCPT ); Fri, 26 Jul 2019 17:45:51 -0400 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga005.fm.intel.com ([10.253.24.32]) by fmsmga103.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 26 Jul 2019 14:45:50 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.64,312,1559545200"; d="scan'208";a="369671140" Received: from skuppusw-desk.jf.intel.com ([10.54.74.33]) by fmsmga005.fm.intel.com with ESMTP; 26 Jul 2019 14:45:50 -0700 From: sathyanarayanan.kuppuswamy@linux.intel.com To: bhelgaas@google.com Cc: linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org, ashok.raj@intel.com, keith.busch@intel.com, sathyanarayanan.kuppuswamy@linux.intel.com Subject: [PATCH v6 4/9] PCI/DPC: Allow dpc_probe() even if firmware first mode is enabled Date: Fri, 26 Jul 2019 14:43:14 -0700 Message-Id: <3fbc2b769890718edff2beee1e815bab97156e64.1564177080.git.sathyanarayanan.kuppuswamy@linux.intel.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: References: MIME-Version: 1.0 Sender: linux-pci-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org From: Kuppuswamy Sathyanarayanan As per ACPI specification v6.3, sec 5.6.6, Error Disconnect Recover (EDR) notification used by firmware to let OS know about the DPC event and permit OS to perform error recovery when processing the EDR notification. Also, as per PCI firmware specification r3.2 Downstream Port Containment Related Enhancements ECN, sec 4.5.1, table 4-6, if DPC is controlled by firmware (firmware first mode), it's responsible for initializing Downstream Port Containment Extended Capability Structures per firmware policy. And, OS is permitted to read or write DPC Control and Status registers of a port while processing an Error Disconnect Recover (EDR) notification from firmware on that port. Currently, if firmware controls DPC (firmware first mode), OS will not create/enumerate DPC PCIe port services. But, if OS supports EDR feature, then as mentioned in above spec references, it should permit enumeration of DPC driver and also support handling ACPI EDR notification. So as first step, allow dpc_probe() to continue even if firmware first mode is enabled. Also add appropriate checks to ensure device registers are not modified outside EDR notification window in firmware first mode. This is a preparatory patch for adding EDR support. Signed-off-by: Kuppuswamy Sathyanarayanan --- drivers/pci/pcie/dpc.c | 49 +++++++++++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/drivers/pci/pcie/dpc.c b/drivers/pci/pcie/dpc.c index a32ec3487a8d..9717fda012f8 100644 --- a/drivers/pci/pcie/dpc.c +++ b/drivers/pci/pcie/dpc.c @@ -22,6 +22,8 @@ struct dpc_dev { u16 cap_pos; bool rp_extensions; u8 rp_log_size; + /* Set True if DPC is controlled by firmware */ + bool firmware_dpc; }; static const char * const rp_pio_error_string[] = { @@ -69,6 +71,9 @@ void pci_save_dpc_state(struct pci_dev *dev) if (!dpc) return; + if (dpc->firmware_dpc) + return; + save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_DPC); if (!save_state) return; @@ -90,6 +95,9 @@ void pci_restore_dpc_state(struct pci_dev *dev) if (!dpc) return; + if (dpc->firmware_dpc) + return; + save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_DPC); if (!save_state) return; @@ -291,9 +299,6 @@ static int dpc_probe(struct pcie_device *dev) int status; u16 ctl, cap; - if (pcie_aer_get_firmware_first(pdev)) - return -ENOTSUPP; - dpc = devm_kzalloc(device, sizeof(*dpc), GFP_KERNEL); if (!dpc) return -ENOMEM; @@ -302,13 +307,25 @@ static int dpc_probe(struct pcie_device *dev) dpc->dev = dev; set_service_data(dev, dpc); - status = devm_request_threaded_irq(device, dev->irq, dpc_irq, - dpc_handler, IRQF_SHARED, - "pcie-dpc", dpc); - if (status) { - pci_warn(pdev, "request IRQ%d failed: %d\n", dev->irq, - status); - return status; + if (pcie_aer_get_firmware_first(pdev)) + dpc->firmware_dpc = 1; + + /* + * If DPC is handled in firmware and ACPI support is not enabled + * in OS, skip probe and return error. + */ + if (dpc->firmware_dpc && !IS_ENABLED(CONFIG_ACPI)) + return -ENODEV; + + if (!dpc->firmware_dpc) { + status = devm_request_threaded_irq(device, dev->irq, dpc_irq, + dpc_handler, IRQF_SHARED, + "pcie-dpc", dpc); + if (status) { + pci_warn(pdev, "request IRQ%d failed: %d\n", dev->irq, + status); + return status; + } } pci_read_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_CAP, &cap); @@ -323,9 +340,12 @@ static int dpc_probe(struct pcie_device *dev) 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, dpc->cap_pos + PCI_EXP_DPC_CTL, ctl); + if (!dpc->firmware_dpc) { + ctl = (ctl & 0xfff4) | + (PCI_EXP_DPC_CTL_EN_FATAL | PCI_EXP_DPC_CTL_INT_EN); + pci_write_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_CTL, + ctl); + } pci_info(pdev, "error containment capabilities: Int Msg #%d, RPExt%c PoisonedTLP%c SwTrigger%c RP PIO Log %d, DL_ActiveErr%c\n", cap & PCI_EXP_DPC_IRQ, FLAG(cap, PCI_EXP_DPC_CAP_RP_EXT), @@ -343,6 +363,9 @@ static void dpc_remove(struct pcie_device *dev) struct pci_dev *pdev = dev->port; u16 ctl; + if (dpc->firmware_dpc) + return; + pci_read_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_CTL, &ctl); ctl &= ~(PCI_EXP_DPC_CTL_EN_FATAL | PCI_EXP_DPC_CTL_INT_EN); pci_write_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_CTL, ctl);