Merge branch 'pci/controller/broadcom'
authorBjorn Helgaas <bhelgaas@google.com>
Tue, 12 Mar 2024 17:14:24 +0000 (12:14 -0500)
committerBjorn Helgaas <bhelgaas@google.com>
Tue, 12 Mar 2024 17:14:24 +0000 (12:14 -0500)
- Fix polling for MDIO write completion, which previously used the wrong
  access width so it always indicated "completed" (Jonathan Bell)

* pci/controller/broadcom:
  PCI: brcmstb: Fix broken brcm_pcie_mdio_write() polling

51 files changed:
Documentation/ABI/testing/sysfs-bus-pci-devices-aer_stats
Documentation/driver-api/device-io.rst
Documentation/driver-api/pci/pci.rst
MAINTAINERS
arch/x86/pci/fixup.c
drivers/acpi/sleep.c
drivers/firmware/efi/cper.c
drivers/ntb/core.c
drivers/pci/Kconfig
drivers/pci/Makefile
drivers/pci/controller/dwc/pci-imx6.c
drivers/pci/controller/dwc/pci-keystone.c
drivers/pci/controller/dwc/pci-layerscape-ep.c
drivers/pci/controller/dwc/pcie-keembay.c
drivers/pci/controller/dwc/pcie-rcar-gen4.c
drivers/pci/controller/dwc/pcie-tegra194.c
drivers/pci/controller/dwc/pcie-uniphier-ep.c
drivers/pci/controller/pcie-rcar-ep.c
drivers/pci/devres.c [new file with mode: 0644]
drivers/pci/endpoint/functions/pci-epf-mhi.c
drivers/pci/endpoint/functions/pci-epf-ntb.c
drivers/pci/endpoint/functions/pci-epf-test.c
drivers/pci/endpoint/functions/pci-epf-vntb.c
drivers/pci/endpoint/pci-epc-core.c
drivers/pci/endpoint/pci-epf-core.c
drivers/pci/iomap.c [moved from lib/pci_iomap.c with 99% similarity]
drivers/pci/irq.c
drivers/pci/mmap.c
drivers/pci/p2pdma.c
drivers/pci/pci-driver.c
drivers/pci/pci-sysfs.c
drivers/pci/pci.c
drivers/pci/pci.h
drivers/pci/pcie/Makefile
drivers/pci/pcie/aer.c
drivers/pci/pcie/aspm.c
drivers/pci/pcie/dpc.c
drivers/pci/pcie/err.c
drivers/pci/pcie/portdrv.h
drivers/pci/probe.c
drivers/pci/quirks.c
drivers/pci/setup-irq.c [deleted file]
drivers/pci/switch/switchtec.c
include/linux/aer.h
include/linux/pci-epc.h
include/linux/pci-epf.h
include/linux/pci.h
include/ras/ras_event.h
lib/Kconfig
lib/Makefile
lib/devres.c

index 860db53037a58fae2faa10fcfc8672c0ed20ace9..d1f67bb81d5d14c28eb518a97ba0ca6413325b3a 100644 (file)
@@ -11,7 +11,7 @@ saw any problems).
 
 What:          /sys/bus/pci/devices/<dev>/aer_dev_correctable
 Date:          July 2018
-KernelVersion: 4.19.0
+KernelVersion: 4.19.0
 Contact:       linux-pci@vger.kernel.org, rajatja@google.com
 Description:   List of correctable errors seen and reported by this
                PCI device using ERR_COR. Note that since multiple errors may
@@ -32,7 +32,7 @@ Description:  List of correctable errors seen and reported by this
 
 What:          /sys/bus/pci/devices/<dev>/aer_dev_fatal
 Date:          July 2018
-KernelVersion: 4.19.0
+KernelVersion: 4.19.0
 Contact:       linux-pci@vger.kernel.org, rajatja@google.com
 Description:   List of uncorrectable fatal errors seen and reported by this
                PCI device using ERR_FATAL. Note that since multiple errors may
@@ -62,7 +62,7 @@ Description:  List of uncorrectable fatal errors seen and reported by this
 
 What:          /sys/bus/pci/devices/<dev>/aer_dev_nonfatal
 Date:          July 2018
-KernelVersion: 4.19.0
+KernelVersion: 4.19.0
 Contact:       linux-pci@vger.kernel.org, rajatja@google.com
 Description:   List of uncorrectable nonfatal errors seen and reported by this
                PCI device using ERR_NONFATAL. Note that since multiple errors
@@ -100,20 +100,20 @@ collectors) that are AER capable. These indicate the number of error messages as
 device, so these counters include them and are thus cumulative of all the error
 messages on the PCI hierarchy originating at that root port.
 
-What:          /sys/bus/pci/devices/<dev>/aer_stats/aer_rootport_total_err_cor
+What:          /sys/bus/pci/devices/<dev>/aer_rootport_total_err_cor
 Date:          July 2018
-KernelVersion: 4.19.0
+KernelVersion: 4.19.0
 Contact:       linux-pci@vger.kernel.org, rajatja@google.com
 Description:   Total number of ERR_COR messages reported to rootport.
 
-What:      /sys/bus/pci/devices/<dev>/aer_stats/aer_rootport_total_err_fatal
+What:          /sys/bus/pci/devices/<dev>/aer_rootport_total_err_fatal
 Date:          July 2018
-KernelVersion: 4.19.0
+KernelVersion: 4.19.0
 Contact:       linux-pci@vger.kernel.org, rajatja@google.com
 Description:   Total number of ERR_FATAL messages reported to rootport.
 
-What:      /sys/bus/pci/devices/<dev>/aer_stats/aer_rootport_total_err_nonfatal
+What:          /sys/bus/pci/devices/<dev>/aer_rootport_total_err_nonfatal
 Date:          July 2018
-KernelVersion: 4.19.0
+KernelVersion: 4.19.0
 Contact:       linux-pci@vger.kernel.org, rajatja@google.com
 Description:   Total number of ERR_NONFATAL messages reported to rootport.
index d55384b106bd4ef7e4c41b77ea58624dbda88688..5c7e8194bef92bcb5c3c807852a3b21b04337728 100644 (file)
@@ -517,6 +517,3 @@ Public Functions Provided
 
 .. kernel-doc:: arch/x86/include/asm/io.h
    :internal:
-
-.. kernel-doc:: lib/pci_iomap.c
-   :export:
index 4843cfad4f60bb43a189fbe0da135b9241c4bff3..aa40b1cc243b84d0485499e977c33dce056053ab 100644 (file)
@@ -4,6 +4,12 @@ PCI Support Library
 .. kernel-doc:: drivers/pci/pci.c
    :export:
 
+.. kernel-doc:: drivers/pci/iomap.c
+   :export:
+
+.. kernel-doc:: drivers/pci/devres.c
+   :export:
+
 .. kernel-doc:: drivers/pci/pci-driver.c
    :export:
 
index 8d1052fa6a6924d17a4d2681fa7907c544e35186..395fcaad63e7e77aa6ffbd52eeb760e39efea1b2 100644 (file)
@@ -16954,7 +16954,6 @@ F:      include/asm-generic/pci*
 F:     include/linux/of_pci.h
 F:     include/linux/pci*
 F:     include/uapi/linux/pci*
-F:     lib/pci*
 
 PCIE DRIVER FOR AMAZON ANNAPURNA LABS
 M:     Jonathan Chocron <jonnyc@amazon.com>
index f347c20247d307752ab8260b94654aa988816de1..b33afb240601b006d5fd27b5245fed16354f3f71 100644 (file)
@@ -907,6 +907,54 @@ static void chromeos_fixup_apl_pci_l1ss_capability(struct pci_dev *dev)
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x5ad6, chromeos_save_apl_pci_l1ss_capability);
 DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, 0x5ad6, chromeos_fixup_apl_pci_l1ss_capability);
 
+/*
+ * Disable D3cold on Asus B1400 PCI-NVMe bridge
+ *
+ * On this platform with VMD off, the NVMe device cannot successfully power
+ * back on from D3cold. This appears to be an untested transition by the
+ * vendor: Windows leaves the NVMe and parent bridge in D0 during suspend.
+ *
+ * We disable D3cold on the parent bridge for simplicity, and the fact that
+ * both parent bridge and NVMe device share the same power resource.
+ *
+ * This is only needed on BIOS versions before 308; the newer versions flip
+ * StorageD3Enable from 1 to 0.
+ */
+static const struct dmi_system_id asus_nvme_broken_d3cold_table[] = {
+       {
+               .matches = {
+                               DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+                               DMI_MATCH(DMI_BIOS_VERSION, "B1400CEAE.304"),
+               },
+       },
+       {
+               .matches = {
+                               DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+                               DMI_MATCH(DMI_BIOS_VERSION, "B1400CEAE.305"),
+               },
+       },
+       {
+               .matches = {
+                               DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+                               DMI_MATCH(DMI_BIOS_VERSION, "B1400CEAE.306"),
+               },
+       },
+       {
+               .matches = {
+                               DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+                               DMI_MATCH(DMI_BIOS_VERSION, "B1400CEAE.307"),
+               },
+       },
+       {}
+};
+
+static void asus_disable_nvme_d3cold(struct pci_dev *pdev)
+{
+       if (dmi_check_system(asus_nvme_broken_d3cold_table) > 0)
+               pci_d3cold_disable(pdev);
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x9a09, asus_disable_nvme_d3cold);
+
 #ifdef CONFIG_SUSPEND
 /*
  * Root Ports on some AMD SoCs advertise PME_Support for D3hot and D3cold, but
index 808484d11209761d93e10a6e4937a3e4a75d34b2..728acfeb774d8327bc24108c2401bc46920c8d0c 100644 (file)
@@ -385,18 +385,6 @@ static const struct dmi_system_id acpisleep_dmi_table[] __initconst = {
                DMI_MATCH(DMI_PRODUCT_NAME, "20GGA00L00"),
                },
        },
-       /*
-        * ASUS B1400CEAE hangs on resume from suspend (see
-        * https://bugzilla.kernel.org/show_bug.cgi?id=215742).
-        */
-       {
-       .callback = init_default_s3,
-       .ident = "ASUS B1400CEAE",
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-               DMI_MATCH(DMI_PRODUCT_NAME, "ASUS EXPERTBOOK B1400CEAE"),
-               },
-       },
        {},
 };
 
index 35c37f667781c7071c714aef274e68dbddca026b..d3f98161171eced48b2e576300dffcd82d3f7d75 100644 (file)
@@ -445,8 +445,8 @@ static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie,
                printk("%saer_uncor_severity: 0x%08x\n",
                       pfx, aer->uncor_severity);
                printk("%sTLP Header: %08x %08x %08x %08x\n", pfx,
-                      aer->header_log.dw0, aer->header_log.dw1,
-                      aer->header_log.dw2, aer->header_log.dw3);
+                      aer->header_log.dw[0], aer->header_log.dw[1],
+                      aer->header_log.dw[2], aer->header_log.dw[3]);
        }
 }
 
index 27dd93deff6e561bea171f4695dbd8b975df6c0c..d702bee7808266e3ee04fd49a2c157a3413bc9b2 100644 (file)
@@ -100,6 +100,8 @@ EXPORT_SYMBOL(ntb_unregister_client);
 
 int ntb_register_device(struct ntb_dev *ntb)
 {
+       int ret;
+
        if (!ntb)
                return -EINVAL;
        if (!ntb->pdev)
@@ -120,7 +122,11 @@ int ntb_register_device(struct ntb_dev *ntb)
        ntb->ctx_ops = NULL;
        spin_lock_init(&ntb->ctx_lock);
 
-       return device_register(&ntb->dev);
+       ret = device_register(&ntb->dev);
+       if (ret)
+               put_device(&ntb->dev);
+
+       return ret;
 }
 EXPORT_SYMBOL(ntb_register_device);
 
index 74147262625bc2f899928feeaf643ea5f9f7fcd7..d35001589d88f85a56541d20b6ba4dd7088d2138 100644 (file)
@@ -13,6 +13,11 @@ config FORCE_PCI
        select HAVE_PCI
        select PCI
 
+# select this to provide a generic PCI iomap,
+# without PCI itself having to be defined
+config GENERIC_PCI_IOMAP
+       bool
+
 menuconfig PCI
        bool "PCI support"
        depends on HAVE_PCI
index cc8b4e01e29de5439c1671896d5dd53f77a3b9c4..1753020368909e1f8e770ef171ff7d7c1bf40437 100644 (file)
@@ -4,16 +4,17 @@
 
 obj-$(CONFIG_PCI)              += access.o bus.o probe.o host-bridge.o \
                                   remove.o pci.o pci-driver.o search.o \
-                                  pci-sysfs.o rom.o setup-res.o irq.o vpd.o \
-                                  setup-bus.o vc.o mmap.o setup-irq.o
+                                  rom.o setup-res.o irq.o vpd.o \
+                                  setup-bus.o vc.o mmap.o devres.o
 
 obj-$(CONFIG_PCI)              += msi/
 obj-$(CONFIG_PCI)              += pcie/
 
 ifdef CONFIG_PCI
 obj-$(CONFIG_PROC_FS)          += proc.o
-obj-$(CONFIG_SYSFS)            += slot.o
+obj-$(CONFIG_SYSFS)            += pci-sysfs.o slot.o
 obj-$(CONFIG_ACPI)             += pci-acpi.o
+obj-$(CONFIG_GENERIC_PCI_IOMAP) += iomap.o
 endif
 
 obj-$(CONFIG_OF)               += of.o
index dc2c036ab28cb64a2174a73b367cfe5016534123..47a9a96484ed2edbeac9b7e6c0218fc5711ddae6 100644 (file)
@@ -1081,7 +1081,8 @@ static const struct pci_epc_features imx8m_pcie_epc_features = {
        .linkup_notifier = false,
        .msi_capable = true,
        .msix_capable = false,
-       .reserved_bar = 1 << BAR_1 | 1 << BAR_3,
+       .bar[BAR_1] = { .type = BAR_RESERVED, },
+       .bar[BAR_3] = { .type = BAR_RESERVED, },
        .align = SZ_64K,
 };
 
index c0c62533a3f17688d4bf0ae34def85f77e19e2ba..844de441872429b230c9c5ccf594c38e684f7147 100644 (file)
@@ -924,12 +924,12 @@ static const struct pci_epc_features ks_pcie_am654_epc_features = {
        .linkup_notifier = false,
        .msi_capable = true,
        .msix_capable = true,
-       .reserved_bar = 1 << BAR_0 | 1 << BAR_1,
-       .bar_fixed_64bit = 1 << BAR_0,
-       .bar_fixed_size[2] = SZ_1M,
-       .bar_fixed_size[3] = SZ_64K,
-       .bar_fixed_size[4] = 256,
-       .bar_fixed_size[5] = SZ_1M,
+       .bar[BAR_0] = { .type = BAR_RESERVED, },
+       .bar[BAR_1] = { .type = BAR_RESERVED, },
+       .bar[BAR_2] = { .type = BAR_FIXED, .fixed_size = SZ_1M, },
+       .bar[BAR_3] = { .type = BAR_FIXED, .fixed_size = SZ_64K, },
+       .bar[BAR_4] = { .type = BAR_FIXED, .fixed_size = 256, },
+       .bar[BAR_5] = { .type = BAR_FIXED, .fixed_size = SZ_1M, },
        .align = SZ_1M,
 };
 
index 2e398494e7c0ca625fee3040b096c73c01c85b57..1f6ee1460ec2a390968140ec8bd0001da171c495 100644 (file)
@@ -250,7 +250,10 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev)
        pci->dev = dev;
        pci->ops = pcie->drvdata->dw_pcie_ops;
 
-       ls_epc->bar_fixed_64bit = (1 << BAR_2) | (1 << BAR_4);
+       ls_epc->bar[BAR_2].only_64bit = true;
+       ls_epc->bar[BAR_3].type = BAR_RESERVED;
+       ls_epc->bar[BAR_4].only_64bit = true;
+       ls_epc->bar[BAR_5].type = BAR_RESERVED;
        ls_epc->linkup_notifier = true;
 
        pcie->pci = pci;
index 208d3b0ba196021aa9e0377c87136f07367594f8..5e8e54f597dd4785dcaf6a1a22ba964c5e03273c 100644 (file)
@@ -312,8 +312,12 @@ static const struct pci_epc_features keembay_pcie_epc_features = {
        .linkup_notifier        = false,
        .msi_capable            = true,
        .msix_capable           = true,
-       .reserved_bar           = BIT(BAR_1) | BIT(BAR_3) | BIT(BAR_5),
-       .bar_fixed_64bit        = BIT(BAR_0) | BIT(BAR_2) | BIT(BAR_4),
+       .bar[BAR_0]             = { .only_64bit = true, },
+       .bar[BAR_1]             = { .type = BAR_RESERVED, },
+       .bar[BAR_2]             = { .only_64bit = true, },
+       .bar[BAR_3]             = { .type = BAR_RESERVED, },
+       .bar[BAR_4]             = { .only_64bit = true, },
+       .bar[BAR_5]             = { .type = BAR_RESERVED, },
        .align                  = SZ_16K,
 };
 
index e9166619b1f9f656a83d60330515e7b20f34d7ca..0be760ed420bdcb6b500acda907e15ae2cefaff3 100644 (file)
@@ -383,7 +383,9 @@ static const struct pci_epc_features rcar_gen4_pcie_epc_features = {
        .linkup_notifier = false,
        .msi_capable = true,
        .msix_capable = false,
-       .reserved_bar = 1 << BAR_1 | 1 << BAR_3 | 1 << BAR_5,
+       .bar[BAR_1] = { .type = BAR_RESERVED, },
+       .bar[BAR_3] = { .type = BAR_RESERVED, },
+       .bar[BAR_5] = { .type = BAR_RESERVED, },
        .align = SZ_1M,
 };
 
index 7afa9e9aabe2165828aff5eaed0dd5033b08fc4c..1f7b662cb8e15b5fecd2b131037274865779ec0f 100644 (file)
@@ -2007,9 +2007,13 @@ static const struct pci_epc_features tegra_pcie_epc_features = {
        .core_init_notifier = true,
        .msi_capable = false,
        .msix_capable = false,
-       .reserved_bar = 1 << BAR_2 | 1 << BAR_3 | 1 << BAR_4 | 1 << BAR_5,
-       .bar_fixed_64bit = 1 << BAR_0,
-       .bar_fixed_size[0] = SZ_1M,
+       .bar[BAR_0] = { .type = BAR_FIXED, .fixed_size = SZ_1M,
+                       .only_64bit = true, },
+       .bar[BAR_1] = { .type = BAR_RESERVED, },
+       .bar[BAR_2] = { .type = BAR_RESERVED, },
+       .bar[BAR_3] = { .type = BAR_RESERVED, },
+       .bar[BAR_4] = { .type = BAR_RESERVED, },
+       .bar[BAR_5] = { .type = BAR_RESERVED, },
 };
 
 static const struct pci_epc_features*
index 3fced0d3e85125067024f948717713278422f6d4..639bc2e12476f5dd92eb60309a2789bfe990b086 100644 (file)
@@ -411,8 +411,12 @@ static const struct uniphier_pcie_ep_soc_data uniphier_pro5_data = {
                .msi_capable = true,
                .msix_capable = false,
                .align = 1 << 16,
-               .bar_fixed_64bit = BIT(BAR_0) | BIT(BAR_2) | BIT(BAR_4),
-               .reserved_bar =  BIT(BAR_4),
+               .bar[BAR_0] = { .only_64bit = true, },
+               .bar[BAR_1] = { .type = BAR_RESERVED, },
+               .bar[BAR_2] = { .only_64bit = true, },
+               .bar[BAR_3] = { .type = BAR_RESERVED, },
+               .bar[BAR_4] = { .type = BAR_RESERVED, },
+               .bar[BAR_5] = { .type = BAR_RESERVED, },
        },
 };
 
@@ -425,7 +429,12 @@ static const struct uniphier_pcie_ep_soc_data uniphier_nx1_data = {
                .msi_capable = true,
                .msix_capable = false,
                .align = 1 << 12,
-               .bar_fixed_64bit = BIT(BAR_0) | BIT(BAR_2) | BIT(BAR_4),
+               .bar[BAR_0] = { .only_64bit = true, },
+               .bar[BAR_1] = { .type = BAR_RESERVED, },
+               .bar[BAR_2] = { .only_64bit = true, },
+               .bar[BAR_3] = { .type = BAR_RESERVED, },
+               .bar[BAR_4] = { .only_64bit = true, },
+               .bar[BAR_5] = { .type = BAR_RESERVED, },
        },
 };
 
index e6909271def798e5332dfa02b47befdcee5f610d..05967c6c0b426ad4c8269000cbe61c47d7228992 100644 (file)
@@ -440,11 +440,15 @@ static const struct pci_epc_features rcar_pcie_epc_features = {
        .msi_capable = true,
        .msix_capable = false,
        /* use 64-bit BARs so mark BAR[1,3,5] as reserved */
-       .reserved_bar = 1 << BAR_1 | 1 << BAR_3 | 1 << BAR_5,
-       .bar_fixed_64bit = 1 << BAR_0 | 1 << BAR_2 | 1 << BAR_4,
-       .bar_fixed_size[0] = 128,
-       .bar_fixed_size[2] = 256,
-       .bar_fixed_size[4] = 256,
+       .bar[BAR_0] = { .type = BAR_FIXED, .fixed_size = 128,
+                       .only_64bit = true, },
+       .bar[BAR_1] = { .type = BAR_RESERVED, },
+       .bar[BAR_2] = { .type = BAR_FIXED, .fixed_size = 256,
+                       .only_64bit = true, },
+       .bar[BAR_3] = { .type = BAR_RESERVED, },
+       .bar[BAR_4] = { .type = BAR_FIXED, .fixed_size = 256,
+                       .only_64bit = true, },
+       .bar[BAR_5] = { .type = BAR_RESERVED, },
 };
 
 static const struct pci_epc_features*
diff --git a/drivers/pci/devres.c b/drivers/pci/devres.c
new file mode 100644 (file)
index 0000000..2c562b9
--- /dev/null
@@ -0,0 +1,448 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/device.h>
+#include <linux/pci.h>
+#include "pci.h"
+
+/*
+ * PCI iomap devres
+ */
+#define PCIM_IOMAP_MAX PCI_STD_NUM_BARS
+
+struct pcim_iomap_devres {
+       void __iomem *table[PCIM_IOMAP_MAX];
+};
+
+
+static void devm_pci_unmap_iospace(struct device *dev, void *ptr)
+{
+       struct resource **res = ptr;
+
+       pci_unmap_iospace(*res);
+}
+
+/**
+ * devm_pci_remap_iospace - Managed pci_remap_iospace()
+ * @dev: Generic device to remap IO address for
+ * @res: Resource describing the I/O space
+ * @phys_addr: physical address of range to be mapped
+ *
+ * Managed pci_remap_iospace().  Map is automatically unmapped on driver
+ * detach.
+ */
+int devm_pci_remap_iospace(struct device *dev, const struct resource *res,
+                          phys_addr_t phys_addr)
+{
+       const struct resource **ptr;
+       int error;
+
+       ptr = devres_alloc(devm_pci_unmap_iospace, sizeof(*ptr), GFP_KERNEL);
+       if (!ptr)
+               return -ENOMEM;
+
+       error = pci_remap_iospace(res, phys_addr);
+       if (error) {
+               devres_free(ptr);
+       } else  {
+               *ptr = res;
+               devres_add(dev, ptr);
+       }
+
+       return error;
+}
+EXPORT_SYMBOL(devm_pci_remap_iospace);
+
+/**
+ * devm_pci_remap_cfgspace - Managed pci_remap_cfgspace()
+ * @dev: Generic device to remap IO address for
+ * @offset: Resource address to map
+ * @size: Size of map
+ *
+ * Managed pci_remap_cfgspace().  Map is automatically unmapped on driver
+ * detach.
+ */
+void __iomem *devm_pci_remap_cfgspace(struct device *dev,
+                                     resource_size_t offset,
+                                     resource_size_t size)
+{
+       void __iomem **ptr, *addr;
+
+       ptr = devres_alloc(devm_ioremap_release, sizeof(*ptr), GFP_KERNEL);
+       if (!ptr)
+               return NULL;
+
+       addr = pci_remap_cfgspace(offset, size);
+       if (addr) {
+               *ptr = addr;
+               devres_add(dev, ptr);
+       } else
+               devres_free(ptr);
+
+       return addr;
+}
+EXPORT_SYMBOL(devm_pci_remap_cfgspace);
+
+/**
+ * devm_pci_remap_cfg_resource - check, request region and ioremap cfg resource
+ * @dev: generic device to handle the resource for
+ * @res: configuration space resource to be handled
+ *
+ * Checks that a resource is a valid memory region, requests the memory
+ * region and ioremaps with pci_remap_cfgspace() API that ensures the
+ * proper PCI configuration space memory attributes are guaranteed.
+ *
+ * All operations are managed and will be undone on driver detach.
+ *
+ * Returns a pointer to the remapped memory or an ERR_PTR() encoded error code
+ * on failure. Usage example::
+ *
+ *     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ *     base = devm_pci_remap_cfg_resource(&pdev->dev, res);
+ *     if (IS_ERR(base))
+ *             return PTR_ERR(base);
+ */
+void __iomem *devm_pci_remap_cfg_resource(struct device *dev,
+                                         struct resource *res)
+{
+       resource_size_t size;
+       const char *name;
+       void __iomem *dest_ptr;
+
+       BUG_ON(!dev);
+
+       if (!res || resource_type(res) != IORESOURCE_MEM) {
+               dev_err(dev, "invalid resource\n");
+               return IOMEM_ERR_PTR(-EINVAL);
+       }
+
+       size = resource_size(res);
+
+       if (res->name)
+               name = devm_kasprintf(dev, GFP_KERNEL, "%s %s", dev_name(dev),
+                                     res->name);
+       else
+               name = devm_kstrdup(dev, dev_name(dev), GFP_KERNEL);
+       if (!name)
+               return IOMEM_ERR_PTR(-ENOMEM);
+
+       if (!devm_request_mem_region(dev, res->start, size, name)) {
+               dev_err(dev, "can't request region for resource %pR\n", res);
+               return IOMEM_ERR_PTR(-EBUSY);
+       }
+
+       dest_ptr = devm_pci_remap_cfgspace(dev, res->start, size);
+       if (!dest_ptr) {
+               dev_err(dev, "ioremap failed for resource %pR\n", res);
+               devm_release_mem_region(dev, res->start, size);
+               dest_ptr = IOMEM_ERR_PTR(-ENOMEM);
+       }
+
+       return dest_ptr;
+}
+EXPORT_SYMBOL(devm_pci_remap_cfg_resource);
+
+/**
+ * pcim_set_mwi - a device-managed pci_set_mwi()
+ * @dev: the PCI device for which MWI is enabled
+ *
+ * Managed pci_set_mwi().
+ *
+ * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
+ */
+int pcim_set_mwi(struct pci_dev *dev)
+{
+       struct pci_devres *dr;
+
+       dr = find_pci_dr(dev);
+       if (!dr)
+               return -ENOMEM;
+
+       dr->mwi = 1;
+       return pci_set_mwi(dev);
+}
+EXPORT_SYMBOL(pcim_set_mwi);
+
+
+static void pcim_release(struct device *gendev, void *res)
+{
+       struct pci_dev *dev = to_pci_dev(gendev);
+       struct pci_devres *this = res;
+       int i;
+
+       for (i = 0; i < DEVICE_COUNT_RESOURCE; i++)
+               if (this->region_mask & (1 << i))
+                       pci_release_region(dev, i);
+
+       if (this->mwi)
+               pci_clear_mwi(dev);
+
+       if (this->restore_intx)
+               pci_intx(dev, this->orig_intx);
+
+       if (this->enabled && !this->pinned)
+               pci_disable_device(dev);
+}
+
+/*
+ * TODO: After the last four callers in pci.c are ported, find_pci_dr()
+ * needs to be made static again.
+ */
+struct pci_devres *find_pci_dr(struct pci_dev *pdev)
+{
+       if (pci_is_managed(pdev))
+               return devres_find(&pdev->dev, pcim_release, NULL, NULL);
+       return NULL;
+}
+
+static struct pci_devres *get_pci_dr(struct pci_dev *pdev)
+{
+       struct pci_devres *dr, *new_dr;
+
+       dr = devres_find(&pdev->dev, pcim_release, NULL, NULL);
+       if (dr)
+               return dr;
+
+       new_dr = devres_alloc(pcim_release, sizeof(*new_dr), GFP_KERNEL);
+       if (!new_dr)
+               return NULL;
+       return devres_get(&pdev->dev, new_dr, NULL, NULL);
+}
+
+/**
+ * pcim_enable_device - Managed pci_enable_device()
+ * @pdev: PCI device to be initialized
+ *
+ * Managed pci_enable_device().
+ */
+int pcim_enable_device(struct pci_dev *pdev)
+{
+       struct pci_devres *dr;
+       int rc;
+
+       dr = get_pci_dr(pdev);
+       if (unlikely(!dr))
+               return -ENOMEM;
+       if (dr->enabled)
+               return 0;
+
+       rc = pci_enable_device(pdev);
+       if (!rc) {
+               pdev->is_managed = 1;
+               dr->enabled = 1;
+       }
+       return rc;
+}
+EXPORT_SYMBOL(pcim_enable_device);
+
+/**
+ * pcim_pin_device - Pin managed PCI device
+ * @pdev: PCI device to pin
+ *
+ * Pin managed PCI device @pdev.  Pinned device won't be disabled on
+ * driver detach.  @pdev must have been enabled with
+ * pcim_enable_device().
+ */
+void pcim_pin_device(struct pci_dev *pdev)
+{
+       struct pci_devres *dr;
+
+       dr = find_pci_dr(pdev);
+       WARN_ON(!dr || !dr->enabled);
+       if (dr)
+               dr->pinned = 1;
+}
+EXPORT_SYMBOL(pcim_pin_device);
+
+static void pcim_iomap_release(struct device *gendev, void *res)
+{
+       struct pci_dev *dev = to_pci_dev(gendev);
+       struct pcim_iomap_devres *this = res;
+       int i;
+
+       for (i = 0; i < PCIM_IOMAP_MAX; i++)
+               if (this->table[i])
+                       pci_iounmap(dev, this->table[i]);
+}
+
+/**
+ * pcim_iomap_table - access iomap allocation table
+ * @pdev: PCI device to access iomap table for
+ *
+ * Access iomap allocation table for @dev.  If iomap table doesn't
+ * exist and @pdev is managed, it will be allocated.  All iomaps
+ * recorded in the iomap table are automatically unmapped on driver
+ * detach.
+ *
+ * This function might sleep when the table is first allocated but can
+ * be safely called without context and guaranteed to succeed once
+ * allocated.
+ */
+void __iomem * const *pcim_iomap_table(struct pci_dev *pdev)
+{
+       struct pcim_iomap_devres *dr, *new_dr;
+
+       dr = devres_find(&pdev->dev, pcim_iomap_release, NULL, NULL);
+       if (dr)
+               return dr->table;
+
+       new_dr = devres_alloc_node(pcim_iomap_release, sizeof(*new_dr), GFP_KERNEL,
+                                  dev_to_node(&pdev->dev));
+       if (!new_dr)
+               return NULL;
+       dr = devres_get(&pdev->dev, new_dr, NULL, NULL);
+       return dr->table;
+}
+EXPORT_SYMBOL(pcim_iomap_table);
+
+/**
+ * pcim_iomap - Managed pcim_iomap()
+ * @pdev: PCI device to iomap for
+ * @bar: BAR to iomap
+ * @maxlen: Maximum length of iomap
+ *
+ * Managed pci_iomap().  Map is automatically unmapped on driver
+ * detach.
+ */
+void __iomem *pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen)
+{
+       void __iomem **tbl;
+
+       BUG_ON(bar >= PCIM_IOMAP_MAX);
+
+       tbl = (void __iomem **)pcim_iomap_table(pdev);
+       if (!tbl || tbl[bar])   /* duplicate mappings not allowed */
+               return NULL;
+
+       tbl[bar] = pci_iomap(pdev, bar, maxlen);
+       return tbl[bar];
+}
+EXPORT_SYMBOL(pcim_iomap);
+
+/**
+ * pcim_iounmap - Managed pci_iounmap()
+ * @pdev: PCI device to iounmap for
+ * @addr: Address to unmap
+ *
+ * Managed pci_iounmap().  @addr must have been mapped using pcim_iomap().
+ */
+void pcim_iounmap(struct pci_dev *pdev, void __iomem *addr)
+{
+       void __iomem **tbl;
+       int i;
+
+       pci_iounmap(pdev, addr);
+
+       tbl = (void __iomem **)pcim_iomap_table(pdev);
+       BUG_ON(!tbl);
+
+       for (i = 0; i < PCIM_IOMAP_MAX; i++)
+               if (tbl[i] == addr) {
+                       tbl[i] = NULL;
+                       return;
+               }
+       WARN_ON(1);
+}
+EXPORT_SYMBOL(pcim_iounmap);
+
+/**
+ * pcim_iomap_regions - Request and iomap PCI BARs
+ * @pdev: PCI device to map IO resources for
+ * @mask: Mask of BARs to request and iomap
+ * @name: Name used when requesting regions
+ *
+ * Request and iomap regions specified by @mask.
+ */
+int pcim_iomap_regions(struct pci_dev *pdev, int mask, const char *name)
+{
+       void __iomem * const *iomap;
+       int i, rc;
+
+       iomap = pcim_iomap_table(pdev);
+       if (!iomap)
+               return -ENOMEM;
+
+       for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+               unsigned long len;
+
+               if (!(mask & (1 << i)))
+                       continue;
+
+               rc = -EINVAL;
+               len = pci_resource_len(pdev, i);
+               if (!len)
+                       goto err_inval;
+
+               rc = pci_request_region(pdev, i, name);
+               if (rc)
+                       goto err_inval;
+
+               rc = -ENOMEM;
+               if (!pcim_iomap(pdev, i, 0))
+                       goto err_region;
+       }
+
+       return 0;
+
+ err_region:
+       pci_release_region(pdev, i);
+ err_inval:
+       while (--i >= 0) {
+               if (!(mask & (1 << i)))
+                       continue;
+               pcim_iounmap(pdev, iomap[i]);
+               pci_release_region(pdev, i);
+       }
+
+       return rc;
+}
+EXPORT_SYMBOL(pcim_iomap_regions);
+
+/**
+ * pcim_iomap_regions_request_all - Request all BARs and iomap specified ones
+ * @pdev: PCI device to map IO resources for
+ * @mask: Mask of BARs to iomap
+ * @name: Name used when requesting regions
+ *
+ * Request all PCI BARs and iomap regions specified by @mask.
+ */
+int pcim_iomap_regions_request_all(struct pci_dev *pdev, int mask,
+                                  const char *name)
+{
+       int request_mask = ((1 << 6) - 1) & ~mask;
+       int rc;
+
+       rc = pci_request_selected_regions(pdev, request_mask, name);
+       if (rc)
+               return rc;
+
+       rc = pcim_iomap_regions(pdev, mask, name);
+       if (rc)
+               pci_release_selected_regions(pdev, request_mask);
+       return rc;
+}
+EXPORT_SYMBOL(pcim_iomap_regions_request_all);
+
+/**
+ * pcim_iounmap_regions - Unmap and release PCI BARs
+ * @pdev: PCI device to map IO resources for
+ * @mask: Mask of BARs to unmap and release
+ *
+ * Unmap and release regions specified by @mask.
+ */
+void pcim_iounmap_regions(struct pci_dev *pdev, int mask)
+{
+       void __iomem * const *iomap;
+       int i;
+
+       iomap = pcim_iomap_table(pdev);
+       if (!iomap)
+               return;
+
+       for (i = 0; i < PCIM_IOMAP_MAX; i++) {
+               if (!(mask & (1 << i)))
+                       continue;
+
+               pcim_iounmap(pdev, iomap[i]);
+               pci_release_region(pdev, i);
+       }
+}
+EXPORT_SYMBOL(pcim_iounmap_regions);
index 1c3e4ea76bd2578e47397d0ddbcfa96a8f705574..2c54d80107cf3cb0c8c6a0de5964ea1e6b6c1b67 100644 (file)
@@ -123,6 +123,22 @@ static const struct pci_epf_mhi_ep_info sm8450_info = {
        .flags = MHI_EPF_USE_DMA,
 };
 
+static struct pci_epf_header sa8775p_header = {
+       .vendorid = PCI_VENDOR_ID_QCOM,
+       .deviceid = 0x0306,               /* FIXME: Update deviceid for sa8775p EP */
+       .baseclass_code = PCI_CLASS_OTHERS,
+       .interrupt_pin = PCI_INTERRUPT_INTA,
+};
+
+static const struct pci_epf_mhi_ep_info sa8775p_info = {
+       .config = &mhi_v1_config,
+       .epf_header = &sa8775p_header,
+       .bar_num = BAR_0,
+       .epf_flags = PCI_BASE_ADDRESS_MEM_TYPE_32,
+       .msi_count = 32,
+       .mru = 0x8000,
+};
+
 struct pci_epf_mhi {
        const struct pci_epc_features *epc_features;
        const struct pci_epf_mhi_ep_info *info;
@@ -913,8 +929,9 @@ static int pci_epf_mhi_probe(struct pci_epf *epf,
 }
 
 static const struct pci_epf_device_id pci_epf_mhi_ids[] = {
-       { .name = "sdx55", .driver_data = (kernel_ulong_t)&sdx55_info },
-       { .name = "sm8450", .driver_data = (kernel_ulong_t)&sm8450_info },
+       { .name = "pci_epf_mhi_sa8775p", .driver_data = (kernel_ulong_t)&sa8775p_info },
+       { .name = "pci_epf_mhi_sdx55", .driver_data = (kernel_ulong_t)&sdx55_info },
+       { .name = "pci_epf_mhi_sm8450", .driver_data = (kernel_ulong_t)&sm8450_info },
        {},
 };
 
index 0553946005c4d92990af6ca8ce6962ea51e74772..e01a98e74d211174db3075c20457a3183f37e0a5 100644 (file)
@@ -1012,13 +1012,13 @@ static int epf_ntb_config_spad_bar_alloc(struct epf_ntb *ntb,
 
        epc_features = ntb_epc->epc_features;
        barno = ntb_epc->epf_ntb_bar[BAR_CONFIG];
-       size = epc_features->bar_fixed_size[barno];
+       size = epc_features->bar[barno].fixed_size;
        align = epc_features->align;
 
        peer_ntb_epc = ntb->epc[!type];
        peer_epc_features = peer_ntb_epc->epc_features;
        peer_barno = ntb_epc->epf_ntb_bar[BAR_PEER_SPAD];
-       peer_size = peer_epc_features->bar_fixed_size[peer_barno];
+       peer_size = peer_epc_features->bar[peer_barno].fixed_size;
 
        /* Check if epc_features is populated incorrectly */
        if ((!IS_ALIGNED(size, align)))
@@ -1067,7 +1067,7 @@ static int epf_ntb_config_spad_bar_alloc(struct epf_ntb *ntb,
        else if (size < ctrl_size + spad_size)
                return -EINVAL;
 
-       base = pci_epf_alloc_space(epf, size, barno, align, type);
+       base = pci_epf_alloc_space(epf, size, barno, epc_features, type);
        if (!base) {
                dev_err(dev, "%s intf: Config/Status/SPAD alloc region fail\n",
                        pci_epc_interface_string(type));
index 18c80002d3bd57c1116e04937371eb7077582835..cd4ffb39dcdc6137a3569ac420c90fc09cce7983 100644 (file)
@@ -729,7 +729,7 @@ static int pci_epf_test_set_bar(struct pci_epf *epf)
                 */
                add = (epf_bar->flags & PCI_BASE_ADDRESS_MEM_TYPE_64) ? 2 : 1;
 
-               if (!!(epc_features->reserved_bar & (1 << bar)))
+               if (epc_features->bar[bar].type == BAR_RESERVED)
                        continue;
 
                ret = pci_epc_set_bar(epc, epf->func_no, epf->vfunc_no,
@@ -841,14 +841,8 @@ static int pci_epf_test_alloc_space(struct pci_epf *epf)
        }
        test_reg_size = test_reg_bar_size + msix_table_size + pba_size;
 
-       if (epc_features->bar_fixed_size[test_reg_bar]) {
-               if (test_reg_size > bar_size[test_reg_bar])
-                       return -ENOMEM;
-               test_reg_size = bar_size[test_reg_bar];
-       }
-
        base = pci_epf_alloc_space(epf, test_reg_size, test_reg_bar,
-                                  epc_features->align, PRIMARY_INTERFACE);
+                                  epc_features, PRIMARY_INTERFACE);
        if (!base) {
                dev_err(dev, "Failed to allocated register space\n");
                return -ENOMEM;
@@ -862,12 +856,11 @@ static int pci_epf_test_alloc_space(struct pci_epf *epf)
                if (bar == test_reg_bar)
                        continue;
 
-               if (!!(epc_features->reserved_bar & (1 << bar)))
+               if (epc_features->bar[bar].type == BAR_RESERVED)
                        continue;
 
                base = pci_epf_alloc_space(epf, bar_size[bar], bar,
-                                          epc_features->align,
-                                          PRIMARY_INTERFACE);
+                                          epc_features, PRIMARY_INTERFACE);
                if (!base)
                        dev_err(dev, "Failed to allocate space for BAR%d\n",
                                bar);
@@ -881,16 +874,12 @@ static void pci_epf_configure_bar(struct pci_epf *epf,
                                  const struct pci_epc_features *epc_features)
 {
        struct pci_epf_bar *epf_bar;
-       bool bar_fixed_64bit;
        int i;
 
        for (i = 0; i < PCI_STD_NUM_BARS; i++) {
                epf_bar = &epf->bar[i];
-               bar_fixed_64bit = !!(epc_features->bar_fixed_64bit & (1 << i));
-               if (bar_fixed_64bit)
+               if (epc_features->bar[i].only_64bit)
                        epf_bar->flags |= PCI_BASE_ADDRESS_MEM_TYPE_64;
-               if (epc_features->bar_fixed_size[i])
-                       bar_size[i] = epc_features->bar_fixed_size[i];
        }
 }
 
index e75a2af77328ea47efb67ea358b4f847d4275687..8e779eecd62d41babe9beca177a01e2fd7ae7f69 100644 (file)
@@ -422,7 +422,7 @@ static int epf_ntb_config_spad_bar_alloc(struct epf_ntb *ntb)
                                                                epf->func_no,
                                                                epf->vfunc_no);
        barno = ntb->epf_ntb_bar[BAR_CONFIG];
-       size = epc_features->bar_fixed_size[barno];
+       size = epc_features->bar[barno].fixed_size;
        align = epc_features->align;
 
        if ((!IS_ALIGNED(size, align)))
@@ -446,7 +446,7 @@ static int epf_ntb_config_spad_bar_alloc(struct epf_ntb *ntb)
        else if (size < ctrl_size + spad_size)
                return -EINVAL;
 
-       base = pci_epf_alloc_space(epf, size, barno, align, 0);
+       base = pci_epf_alloc_space(epf, size, barno, epc_features, 0);
        if (!base) {
                dev_err(dev, "Config/Status/SPAD alloc region fail\n");
                return -ENOMEM;
@@ -527,7 +527,6 @@ static int epf_ntb_configure_interrupt(struct epf_ntb *ntb)
 static int epf_ntb_db_bar_init(struct epf_ntb *ntb)
 {
        const struct pci_epc_features *epc_features;
-       u32 align;
        struct device *dev = &ntb->epf->dev;
        int ret;
        struct pci_epf_bar *epf_bar;
@@ -538,19 +537,9 @@ static int epf_ntb_db_bar_init(struct epf_ntb *ntb)
        epc_features = pci_epc_get_features(ntb->epf->epc,
                                            ntb->epf->func_no,
                                            ntb->epf->vfunc_no);
-       align = epc_features->align;
-
-       if (size < 128)
-               size = 128;
-
-       if (align)
-               size = ALIGN(size, align);
-       else
-               size = roundup_pow_of_two(size);
-
        barno = ntb->epf_ntb_bar[BAR_DB];
 
-       mw_addr = pci_epf_alloc_space(ntb->epf, size, barno, align, 0);
+       mw_addr = pci_epf_alloc_space(ntb->epf, size, barno, epc_features, 0);
        if (!mw_addr) {
                dev_err(dev, "Failed to allocate OB address\n");
                return -ENOMEM;
@@ -1269,21 +1258,17 @@ static int pci_vntb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
        if (ret) {
                dev_err(dev, "Cannot set DMA mask\n");
-               return -EINVAL;
+               return ret;
        }
 
        ret = ntb_register_device(&ndev->ntb);
        if (ret) {
                dev_err(dev, "Failed to register NTB device\n");
-               goto err_register_dev;
+               return ret;
        }
 
        dev_dbg(dev, "PCI Virtual NTB driver loaded\n");
        return 0;
-
-err_register_dev:
-       put_device(&ndev->ntb.dev);
-       return -EINVAL;
 }
 
 static struct pci_device_id pci_vntb_table[] = {
index dcd4e66430c10a9328f05a11f9c28c88b2c5c4bf..da3fc0795b0b620c06c39fe9304eb84857c6c0ca 100644 (file)
@@ -87,7 +87,7 @@ EXPORT_SYMBOL_GPL(pci_epc_get);
  * @epc_features: pci_epc_features structure that holds the reserved bar bitmap
  *
  * Invoke to get the first unreserved BAR that can be used by the endpoint
- * function. For any incorrect value in reserved_bar return '0'.
+ * function.
  */
 enum pci_barno
 pci_epc_get_first_free_bar(const struct pci_epc_features *epc_features)
@@ -102,32 +102,27 @@ EXPORT_SYMBOL_GPL(pci_epc_get_first_free_bar);
  * @bar: the starting BAR number from where unreserved BAR should be searched
  *
  * Invoke to get the next unreserved BAR starting from @bar that can be used
- * for endpoint function. For any incorrect value in reserved_bar return '0'.
+ * for endpoint function.
  */
 enum pci_barno pci_epc_get_next_free_bar(const struct pci_epc_features
                                         *epc_features, enum pci_barno bar)
 {
-       unsigned long free_bar;
+       int i;
 
        if (!epc_features)
                return BAR_0;
 
        /* If 'bar - 1' is a 64-bit BAR, move to the next BAR */
-       if ((epc_features->bar_fixed_64bit << 1) & 1 << bar)
+       if (bar > 0 && epc_features->bar[bar - 1].only_64bit)
                bar++;
 
-       /* Find if the reserved BAR is also a 64-bit BAR */
-       free_bar = epc_features->reserved_bar & epc_features->bar_fixed_64bit;
-
-       /* Set the adjacent bit if the reserved BAR is also a 64-bit BAR */
-       free_bar <<= 1;
-       free_bar |= epc_features->reserved_bar;
-
-       free_bar = find_next_zero_bit(&free_bar, 6, bar);
-       if (free_bar > 5)
-               return NO_BAR;
+       for (i = bar; i < PCI_STD_NUM_BARS; i++) {
+               /* If the BAR is not reserved, return it. */
+               if (epc_features->bar[i].type != BAR_RESERVED)
+                       return i;
+       }
 
-       return free_bar;
+       return NO_BAR;
 }
 EXPORT_SYMBOL_GPL(pci_epc_get_next_free_bar);
 
index 2c32de66793778d3d99932e362339bc1764451ee..0a28a0b0911b1989dc2a265e0115282db00bc8a3 100644 (file)
@@ -17,7 +17,7 @@
 
 static DEFINE_MUTEX(pci_epf_mutex);
 
-static struct bus_type pci_epf_bus_type;
+static const struct bus_type pci_epf_bus_type;
 static const struct device_type pci_epf_type;
 
 /**
@@ -251,14 +251,17 @@ EXPORT_SYMBOL_GPL(pci_epf_free_space);
  * @epf: the EPF device to whom allocate the memory
  * @size: the size of the memory that has to be allocated
  * @bar: the BAR number corresponding to the allocated register space
- * @align: alignment size for the allocation region
+ * @epc_features: the features provided by the EPC specific to this EPF
  * @type: Identifies if the allocation is for primary EPC or secondary EPC
  *
  * Invoke to allocate memory for the PCI EPF register space.
  */
 void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar,
-                         size_t align, enum pci_epc_interface_type type)
+                         const struct pci_epc_features *epc_features,
+                         enum pci_epc_interface_type type)
 {
+       u64 bar_fixed_size = epc_features->bar[bar].fixed_size;
+       size_t align = epc_features->align;
        struct pci_epf_bar *epf_bar;
        dma_addr_t phys_addr;
        struct pci_epc *epc;
@@ -268,6 +271,15 @@ void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar,
        if (size < 128)
                size = 128;
 
+       if (epc_features->bar[bar].type == BAR_FIXED && bar_fixed_size) {
+               if (size > bar_fixed_size) {
+                       dev_err(&epf->dev,
+                               "requested BAR size is larger than fixed size\n");
+                       return NULL;
+               }
+               size = bar_fixed_size;
+       }
+
        if (align)
                size = ALIGN(size, align);
        else
@@ -507,7 +519,7 @@ static void pci_epf_device_remove(struct device *dev)
        epf->driver = NULL;
 }
 
-static struct bus_type pci_epf_bus_type = {
+static const struct bus_type pci_epf_bus_type = {
        .name           = "pci-epf",
        .match          = pci_epf_device_match,
        .probe          = pci_epf_device_probe,
similarity index 99%
rename from lib/pci_iomap.c
rename to drivers/pci/iomap.c
index ce39ce9f3526ea2eee7891b62302369b076e8974..c9725428e3874ffd0a7ee6baac1299ba270f5457 100644 (file)
@@ -9,7 +9,6 @@
 
 #include <linux/export.h>
 
-#ifdef CONFIG_PCI
 /**
  * pci_iomap_range - create a virtual mapping cookie for a PCI BAR
  * @dev: PCI device that owns the BAR
@@ -170,11 +169,9 @@ void pci_iounmap(struct pci_dev *dev, void __iomem *p)
 
        if (addr >= start && addr < start + IO_SPACE_LIMIT)
                return;
-       iounmap(p);
 #endif
+       iounmap(p);
 }
 EXPORT_SYMBOL(pci_iounmap);
 
 #endif /* ARCH_WANTS_GENERIC_PCI_IOUNMAP */
-
-#endif /* CONFIG_PCI */
index 0050e8f6814ed655ee06a87252ed468d22963722..4555630be9ecdf3d46b5ea1ebf90fe6861a00212 100644 (file)
@@ -8,9 +8,13 @@
 
 #include <linux/device.h>
 #include <linux/kernel.h>
+#include <linux/errno.h>
 #include <linux/export.h>
+#include <linux/interrupt.h>
 #include <linux/pci.h>
 
+#include "pci.h"
+
 /**
  * pci_request_irq - allocate an interrupt line for a PCI device
  * @dev:       PCI device to operate on
@@ -74,3 +78,203 @@ void pci_free_irq(struct pci_dev *dev, unsigned int nr, void *dev_id)
        kfree(free_irq(pci_irq_vector(dev, nr), dev_id));
 }
 EXPORT_SYMBOL(pci_free_irq);
+
+/**
+ * pci_swizzle_interrupt_pin - swizzle INTx for device behind bridge
+ * @dev: the PCI device
+ * @pin: the INTx pin (1=INTA, 2=INTB, 3=INTC, 4=INTD)
+ *
+ * Perform INTx swizzling for a device behind one level of bridge.  This is
+ * required by section 9.1 of the PCI-to-PCI bridge specification for devices
+ * behind bridges on add-in cards.  For devices with ARI enabled, the slot
+ * number is always 0 (see the Implementation Note in section 2.2.8.1 of
+ * the PCI Express Base Specification, Revision 2.1)
+ */
+u8 pci_swizzle_interrupt_pin(const struct pci_dev *dev, u8 pin)
+{
+       int slot;
+
+       if (pci_ari_enabled(dev->bus))
+               slot = 0;
+       else
+               slot = PCI_SLOT(dev->devfn);
+
+       return (((pin - 1) + slot) % 4) + 1;
+}
+
+int pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge)
+{
+       u8 pin;
+
+       pin = dev->pin;
+       if (!pin)
+               return -1;
+
+       while (!pci_is_root_bus(dev->bus)) {
+               pin = pci_swizzle_interrupt_pin(dev, pin);
+               dev = dev->bus->self;
+       }
+       *bridge = dev;
+       return pin;
+}
+
+/**
+ * pci_common_swizzle - swizzle INTx all the way to root bridge
+ * @dev: the PCI device
+ * @pinp: pointer to the INTx pin value (1=INTA, 2=INTB, 3=INTD, 4=INTD)
+ *
+ * Perform INTx swizzling for a device.  This traverses through all PCI-to-PCI
+ * bridges all the way up to a PCI root bus.
+ */
+u8 pci_common_swizzle(struct pci_dev *dev, u8 *pinp)
+{
+       u8 pin = *pinp;
+
+       while (!pci_is_root_bus(dev->bus)) {
+               pin = pci_swizzle_interrupt_pin(dev, pin);
+               dev = dev->bus->self;
+       }
+       *pinp = pin;
+       return PCI_SLOT(dev->devfn);
+}
+EXPORT_SYMBOL_GPL(pci_common_swizzle);
+
+void pci_assign_irq(struct pci_dev *dev)
+{
+       u8 pin;
+       u8 slot = -1;
+       int irq = 0;
+       struct pci_host_bridge *hbrg = pci_find_host_bridge(dev->bus);
+
+       if (!(hbrg->map_irq)) {
+               pci_dbg(dev, "runtime IRQ mapping not provided by arch\n");
+               return;
+       }
+
+       /*
+        * If this device is not on the primary bus, we need to figure out
+        * which interrupt pin it will come in on. We know which slot it
+        * will come in on because that slot is where the bridge is. Each
+        * time the interrupt line passes through a PCI-PCI bridge we must
+        * apply the swizzle function.
+        */
+       pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+       /* Cope with illegal. */
+       if (pin > 4)
+               pin = 1;
+
+       if (pin) {
+               /* Follow the chain of bridges, swizzling as we go. */
+               if (hbrg->swizzle_irq)
+                       slot = (*(hbrg->swizzle_irq))(dev, &pin);
+
+               /*
+                * If a swizzling function is not used, map_irq() must
+                * ignore slot.
+                */
+               irq = (*(hbrg->map_irq))(dev, slot, pin);
+               if (irq == -1)
+                       irq = 0;
+       }
+       dev->irq = irq;
+
+       pci_dbg(dev, "assign IRQ: got %d\n", dev->irq);
+
+       /*
+        * Always tell the device, so the driver knows what is the real IRQ
+        * to use; the device does not use it.
+        */
+       pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
+}
+
+static bool pci_check_and_set_intx_mask(struct pci_dev *dev, bool mask)
+{
+       struct pci_bus *bus = dev->bus;
+       bool mask_updated = true;
+       u32 cmd_status_dword;
+       u16 origcmd, newcmd;
+       unsigned long flags;
+       bool irq_pending;
+
+       /*
+        * We do a single dword read to retrieve both command and status.
+        * Document assumptions that make this possible.
+        */
+       BUILD_BUG_ON(PCI_COMMAND % 4);
+       BUILD_BUG_ON(PCI_COMMAND + 2 != PCI_STATUS);
+
+       raw_spin_lock_irqsave(&pci_lock, flags);
+
+       bus->ops->read(bus, dev->devfn, PCI_COMMAND, 4, &cmd_status_dword);
+
+       irq_pending = (cmd_status_dword >> 16) & PCI_STATUS_INTERRUPT;
+
+       /*
+        * Check interrupt status register to see whether our device
+        * triggered the interrupt (when masking) or the next IRQ is
+        * already pending (when unmasking).
+        */
+       if (mask != irq_pending) {
+               mask_updated = false;
+               goto done;
+       }
+
+       origcmd = cmd_status_dword;
+       newcmd = origcmd & ~PCI_COMMAND_INTX_DISABLE;
+       if (mask)
+               newcmd |= PCI_COMMAND_INTX_DISABLE;
+       if (newcmd != origcmd)
+               bus->ops->write(bus, dev->devfn, PCI_COMMAND, 2, newcmd);
+
+done:
+       raw_spin_unlock_irqrestore(&pci_lock, flags);
+
+       return mask_updated;
+}
+
+/**
+ * pci_check_and_mask_intx - mask INTx on pending interrupt
+ * @dev: the PCI device to operate on
+ *
+ * Check if the device dev has its INTx line asserted, mask it and return
+ * true in that case. False is returned if no interrupt was pending.
+ */
+bool pci_check_and_mask_intx(struct pci_dev *dev)
+{
+       return pci_check_and_set_intx_mask(dev, true);
+}
+EXPORT_SYMBOL_GPL(pci_check_and_mask_intx);
+
+/**
+ * pci_check_and_unmask_intx - unmask INTx if no interrupt is pending
+ * @dev: the PCI device to operate on
+ *
+ * Check if the device dev has its INTx line asserted, unmask it if not and
+ * return true. False is returned and the mask remains active if there was
+ * still an interrupt pending.
+ */
+bool pci_check_and_unmask_intx(struct pci_dev *dev)
+{
+       return pci_check_and_set_intx_mask(dev, false);
+}
+EXPORT_SYMBOL_GPL(pci_check_and_unmask_intx);
+
+/**
+ * pcibios_penalize_isa_irq - penalize an ISA IRQ
+ * @irq: ISA IRQ to penalize
+ * @active: IRQ active or not
+ *
+ * Permits the platform to provide architecture-specific functionality when
+ * penalizing ISA IRQs. This is the default implementation. Architecture
+ * implementations can override this.
+ */
+void __weak pcibios_penalize_isa_irq(int irq, int active) {}
+
+int __weak pcibios_alloc_irq(struct pci_dev *dev)
+{
+       return 0;
+}
+
+void __weak pcibios_free_irq(struct pci_dev *dev)
+{
+}
index 4504039056d1b54978bcbbdb8fca0360297a7ca6..8da3347a95c47a655dbf0cba643bd4235cd2ba28 100644 (file)
@@ -11,6 +11,8 @@
 #include <linux/mm.h>
 #include <linux/pci.h>
 
+#include "pci.h"
+
 #ifdef ARCH_GENERIC_PCI_MMAP_RESOURCE
 
 static const struct vm_operations_struct pci_phys_vm_ops = {
@@ -50,3 +52,30 @@ int pci_mmap_resource_range(struct pci_dev *pdev, int bar,
 }
 
 #endif
+
+#if (defined(CONFIG_SYSFS) || defined(CONFIG_PROC_FS)) && \
+    (defined(HAVE_PCI_MMAP) || defined(ARCH_GENERIC_PCI_MMAP_RESOURCE))
+
+int pci_mmap_fits(struct pci_dev *pdev, int resno, struct vm_area_struct *vma,
+                 enum pci_mmap_api mmap_api)
+{
+       resource_size_t pci_start = 0, pci_end;
+       unsigned long nr, start, size;
+
+       if (pci_resource_len(pdev, resno) == 0)
+               return 0;
+       nr = vma_pages(vma);
+       start = vma->vm_pgoff;
+       size = ((pci_resource_len(pdev, resno) - 1) >> PAGE_SHIFT) + 1;
+       if (mmap_api == PCI_MMAP_PROCFS) {
+               pci_resource_to_user(pdev, resno, &pdev->resource[resno],
+                                    &pci_start, &pci_end);
+               pci_start >>= PAGE_SHIFT;
+       }
+       if (start >= pci_start && start < pci_start + size &&
+           start + nr <= pci_start + size)
+               return 1;
+       return 0;
+}
+
+#endif
index 0c361561b855c1bde88c43266baa04afb9554622..4f47a13cb500ff5339cde426b6ccb020fcd74ae7 100644 (file)
@@ -661,7 +661,7 @@ done:
        p2pdma = rcu_dereference(provider->p2pdma);
        if (p2pdma)
                xa_store(&p2pdma->map_types, map_types_idx(client),
-                        xa_mk_value(map_type), GFP_KERNEL);
+                        xa_mk_value(map_type), GFP_ATOMIC);
        rcu_read_unlock();
        return map_type;
 }
index 51ec9e7e784f0e3a82134a05b114abe5be90d07c..af2996d0d17ffc0fa2ae730eb09d58243cf79a5b 100644 (file)
@@ -419,15 +419,6 @@ static int __pci_device_probe(struct pci_driver *drv, struct pci_dev *pci_dev)
        return error;
 }
 
-int __weak pcibios_alloc_irq(struct pci_dev *dev)
-{
-       return 0;
-}
-
-void __weak pcibios_free_irq(struct pci_dev *dev)
-{
-}
-
 #ifdef CONFIG_PCI_IOV
 static inline bool pci_device_can_probe(struct pci_dev *pdev)
 {
@@ -473,6 +464,13 @@ static void pci_device_remove(struct device *dev)
 
        if (drv->remove) {
                pm_runtime_get_sync(dev);
+               /*
+                * If the driver provides a .runtime_idle() callback and it has
+                * started to run already, it may continue to run in parallel
+                * with the code below, so wait until all of the runtime PM
+                * activity has completed.
+                */
+               pm_runtime_barrier(dev);
                drv->remove(pci_dev);
                pm_runtime_put_noidle(dev);
        }
@@ -1382,10 +1380,7 @@ static int pci_pm_runtime_idle(struct device *dev)
        if (!pci_dev->driver)
                return 0;
 
-       if (!pm)
-               return -ENOSYS;
-
-       if (pm->runtime_idle)
+       if (pm && pm->runtime_idle)
                return pm->runtime_idle(dev);
 
        return 0;
@@ -1714,7 +1709,7 @@ static int pcie_port_bus_match(struct device *dev, struct device_driver *drv)
        return 1;
 }
 
-struct bus_type pcie_port_bus_type = {
+const struct bus_type pcie_port_bus_type = {
        .name           = "pci_express",
        .match          = pcie_port_bus_match,
 };
index 2321fdfefd7db2682f230cc6267a7bc9b23f75e3..40cfa716392fbd79e075270ca64185ff4c6022c5 100644 (file)
@@ -1022,29 +1022,6 @@ void pci_remove_legacy_files(struct pci_bus *b)
 #endif /* HAVE_PCI_LEGACY */
 
 #if defined(HAVE_PCI_MMAP) || defined(ARCH_GENERIC_PCI_MMAP_RESOURCE)
-
-int pci_mmap_fits(struct pci_dev *pdev, int resno, struct vm_area_struct *vma,
-                 enum pci_mmap_api mmap_api)
-{
-       unsigned long nr, start, size;
-       resource_size_t pci_start = 0, pci_end;
-
-       if (pci_resource_len(pdev, resno) == 0)
-               return 0;
-       nr = vma_pages(vma);
-       start = vma->vm_pgoff;
-       size = ((pci_resource_len(pdev, resno) - 1) >> PAGE_SHIFT) + 1;
-       if (mmap_api == PCI_MMAP_PROCFS) {
-               pci_resource_to_user(pdev, resno, &pdev->resource[resno],
-                                    &pci_start, &pci_end);
-               pci_start >>= PAGE_SHIFT;
-       }
-       if (start >= pci_start && start < pci_start + size &&
-                       start + nr <= pci_start + size)
-               return 1;
-       return 0;
-}
-
 /**
  * pci_mmap_resource - map a PCI resource into user memory space
  * @kobj: kobject for mapping
@@ -1410,79 +1387,89 @@ static const struct attribute_group pci_dev_reset_attr_group = {
        .is_visible = pci_dev_reset_attr_is_visible,
 };
 
+static ssize_t __resource_resize_show(struct device *dev, int n, char *buf)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       ssize_t ret;
+
+       pci_config_pm_runtime_get(pdev);
+
+       ret = sysfs_emit(buf, "%016llx\n",
+                        (u64)pci_rebar_get_possible_sizes(pdev, n));
+
+       pci_config_pm_runtime_put(pdev);
+
+       return ret;
+}
+
+static ssize_t __resource_resize_store(struct device *dev, int n,
+                                      const char *buf, size_t count)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       unsigned long size, flags;
+       int ret, i;
+       u16 cmd;
+
+       if (kstrtoul(buf, 0, &size) < 0)
+               return -EINVAL;
+
+       device_lock(dev);
+       if (dev->driver) {
+               ret = -EBUSY;
+               goto unlock;
+       }
+
+       pci_config_pm_runtime_get(pdev);
+
+       if ((pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA) {
+               ret = aperture_remove_conflicting_pci_devices(pdev,
+                                               "resourceN_resize");
+               if (ret)
+                       goto pm_put;
+       }
+
+       pci_read_config_word(pdev, PCI_COMMAND, &cmd);
+       pci_write_config_word(pdev, PCI_COMMAND,
+                             cmd & ~PCI_COMMAND_MEMORY);
+
+       flags = pci_resource_flags(pdev, n);
+
+       pci_remove_resource_files(pdev);
+
+       for (i = 0; i < PCI_STD_NUM_BARS; i++) {
+               if (pci_resource_len(pdev, i) &&
+                   pci_resource_flags(pdev, i) == flags)
+                       pci_release_resource(pdev, i);
+       }
+
+       ret = pci_resize_resource(pdev, n, size);
+
+       pci_assign_unassigned_bus_resources(pdev->bus);
+
+       if (pci_create_resource_files(pdev))
+               pci_warn(pdev, "Failed to recreate resource files after BAR resizing\n");
+
+       pci_write_config_word(pdev, PCI_COMMAND, cmd);
+pm_put:
+       pci_config_pm_runtime_put(pdev);
+unlock:
+       device_unlock(dev);
+
+       return ret ? ret : count;
+}
+
 #define pci_dev_resource_resize_attr(n)                                        \
 static ssize_t resource##n##_resize_show(struct device *dev,           \
                                         struct device_attribute *attr, \
-                                        char * buf)                    \
+                                        char *buf)                     \
 {                                                                      \
-       struct pci_dev *pdev = to_pci_dev(dev);                         \
-       ssize_t ret;                                                    \
-                                                                       \
-       pci_config_pm_runtime_get(pdev);                                \
-                                                                       \
-       ret = sysfs_emit(buf, "%016llx\n",                              \
-                        (u64)pci_rebar_get_possible_sizes(pdev, n));   \
-                                                                       \
-       pci_config_pm_runtime_put(pdev);                                \
-                                                                       \
-       return ret;                                                     \
+       return __resource_resize_show(dev, n, buf);                     \
 }                                                                      \
-                                                                       \
 static ssize_t resource##n##_resize_store(struct device *dev,          \
                                          struct device_attribute *attr,\
                                          const char *buf, size_t count)\
 {                                                                      \
-       struct pci_dev *pdev = to_pci_dev(dev);                         \
-       unsigned long size, flags;                                      \
-       int ret, i;                                                     \
-       u16 cmd;                                                        \
-                                                                       \
-       if (kstrtoul(buf, 0, &size) < 0)                                \
-               return -EINVAL;                                         \
-                                                                       \
-       device_lock(dev);                                               \
-       if (dev->driver) {                                              \
-               ret = -EBUSY;                                           \
-               goto unlock;                                            \
-       }                                                               \
-                                                                       \
-       pci_config_pm_runtime_get(pdev);                                \
-                                                                       \
-       if ((pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA) {              \
-               ret = aperture_remove_conflicting_pci_devices(pdev,     \
-                                               "resourceN_resize");    \
-               if (ret)                                                \
-                       goto pm_put;                                    \
-       }                                                               \
-                                                                       \
-       pci_read_config_word(pdev, PCI_COMMAND, &cmd);                  \
-       pci_write_config_word(pdev, PCI_COMMAND,                        \
-                             cmd & ~PCI_COMMAND_MEMORY);               \
-                                                                       \
-       flags = pci_resource_flags(pdev, n);                            \
-                                                                       \
-       pci_remove_resource_files(pdev);                                \
-                                                                       \
-       for (i = 0; i < PCI_STD_NUM_BARS; i++) {                        \
-               if (pci_resource_len(pdev, i) &&                        \
-                   pci_resource_flags(pdev, i) == flags)               \
-                       pci_release_resource(pdev, i);                  \
-       }                                                               \
-                                                                       \
-       ret = pci_resize_resource(pdev, n, size);                       \
-                                                                       \
-       pci_assign_unassigned_bus_resources(pdev->bus);                 \
-                                                                       \
-       if (pci_create_resource_files(pdev))                            \
-               pci_warn(pdev, "Failed to recreate resource files after BAR resizing\n");\
-                                                                       \
-       pci_write_config_word(pdev, PCI_COMMAND, cmd);                  \
-pm_put:                                                                        \
-       pci_config_pm_runtime_put(pdev);                                \
-unlock:                                                                        \
-       device_unlock(dev);                                             \
-                                                                       \
-       return ret ? ret : count;                                       \
+       return __resource_resize_store(dev, n, buf, count);             \
 }                                                                      \
 static DEVICE_ATTR_RW(resource##n##_resize)
 
@@ -1660,7 +1647,7 @@ static const struct attribute_group pcie_dev_attr_group = {
        .is_visible = pcie_dev_attrs_are_visible,
 };
 
-static const struct attribute_group *pci_dev_attr_groups[] = {
+const struct attribute_group *pci_dev_attr_groups[] = {
        &pci_dev_attr_group,
        &pci_dev_hp_attr_group,
 #ifdef CONFIG_PCI_IOV
@@ -1677,7 +1664,3 @@ static const struct attribute_group *pci_dev_attr_groups[] = {
 #endif
        NULL,
 };
-
-const struct device_type pci_dev_type = {
-       .groups = pci_dev_attr_groups,
-};
index d8f11a078924c1336326456b0e3f37f7b0e66df9..da7560b29da977e98becf270542bf505f47131dc 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/log2.h>
 #include <linux/logic_pio.h>
 #include <linux/pm_wakeup.h>
-#include <linux/interrupt.h>
 #include <linux/device.h>
 #include <linux/pm_runtime.h>
 #include <linux/pci_hotplug.h>
@@ -1067,6 +1066,34 @@ disable_acs_redir:
        pci_disable_acs_redir(dev);
 }
 
+/**
+ * pcie_read_tlp_log - read TLP Header Log
+ * @dev: PCIe device
+ * @where: PCI Config offset of TLP Header Log
+ * @tlp_log: TLP Log structure to fill
+ *
+ * Fill @tlp_log from TLP Header Log registers, e.g., AER or DPC.
+ *
+ * Return: 0 on success and filled TLP Log structure, <0 on error.
+ */
+int pcie_read_tlp_log(struct pci_dev *dev, int where,
+                     struct pcie_tlp_log *tlp_log)
+{
+       int i, ret;
+
+       memset(tlp_log, 0, sizeof(*tlp_log));
+
+       for (i = 0; i < 4; i++) {
+               ret = pci_read_config_dword(dev, where + i * 4,
+                                           &tlp_log->dw[i]);
+               if (ret)
+                       return pcibios_err_to_errno(ret);
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(pcie_read_tlp_log);
+
 /**
  * pci_restore_bars - restore a device's BAR values (e.g. after wake-up)
  * @dev: PCI device to have its BARs restored
@@ -1623,25 +1650,10 @@ static int pci_save_pcie_state(struct pci_dev *dev)
        pcie_capability_read_word(dev, PCI_EXP_LNKCTL2, &cap[i++]);
        pcie_capability_read_word(dev, PCI_EXP_SLTCTL2, &cap[i++]);
 
-       return 0;
-}
-
-void pci_bridge_reconfigure_ltr(struct pci_dev *dev)
-{
-#ifdef CONFIG_PCIEASPM
-       struct pci_dev *bridge;
-       u32 ctl;
+       pci_save_aspm_l1ss_state(dev);
+       pci_save_ltr_state(dev);
 
-       bridge = pci_upstream_bridge(dev);
-       if (bridge && bridge->ltr_path) {
-               pcie_capability_read_dword(bridge, PCI_EXP_DEVCTL2, &ctl);
-               if (!(ctl & PCI_EXP_DEVCTL2_LTR_EN)) {
-                       pci_dbg(bridge, "re-enabling LTR\n");
-                       pcie_capability_set_word(bridge, PCI_EXP_DEVCTL2,
-                                                PCI_EXP_DEVCTL2_LTR_EN);
-               }
-       }
-#endif
+       return 0;
 }
 
 static void pci_restore_pcie_state(struct pci_dev *dev)
@@ -1650,6 +1662,13 @@ static void pci_restore_pcie_state(struct pci_dev *dev)
        struct pci_cap_saved_state *save_state;
        u16 *cap;
 
+       /*
+        * Restore max latencies (in the LTR capability) before enabling
+        * LTR itself in PCI_EXP_DEVCTL2.
+        */
+       pci_restore_ltr_state(dev);
+       pci_restore_aspm_l1ss_state(dev);
+
        save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP);
        if (!save_state)
                return;
@@ -1707,46 +1726,6 @@ static void pci_restore_pcix_state(struct pci_dev *dev)
        pci_write_config_word(dev, pos + PCI_X_CMD, cap[i++]);
 }
 
-static void pci_save_ltr_state(struct pci_dev *dev)
-{
-       int ltr;
-       struct pci_cap_saved_state *save_state;
-       u32 *cap;
-
-       if (!pci_is_pcie(dev))
-               return;
-
-       ltr = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_LTR);
-       if (!ltr)
-               return;
-
-       save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_LTR);
-       if (!save_state) {
-               pci_err(dev, "no suspend buffer for LTR; ASPM issues possible after resume\n");
-               return;
-       }
-
-       /* Some broken devices only support dword access to LTR */
-       cap = &save_state->cap.data[0];
-       pci_read_config_dword(dev, ltr + PCI_LTR_MAX_SNOOP_LAT, cap);
-}
-
-static void pci_restore_ltr_state(struct pci_dev *dev)
-{
-       struct pci_cap_saved_state *save_state;
-       int ltr;
-       u32 *cap;
-
-       save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_LTR);
-       ltr = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_LTR);
-       if (!save_state || !ltr)
-               return;
-
-       /* Some broken devices only support dword access to LTR */
-       cap = &save_state->cap.data[0];
-       pci_write_config_dword(dev, ltr + PCI_LTR_MAX_SNOOP_LAT, *cap);
-}
-
 /**
  * pci_save_state - save the PCI configuration space of a device before
  *                 suspending
@@ -1771,7 +1750,6 @@ int pci_save_state(struct pci_dev *dev)
        if (i != 0)
                return i;
 
-       pci_save_ltr_state(dev);
        pci_save_dpc_state(dev);
        pci_save_aer_state(dev);
        pci_save_ptm_state(dev);
@@ -1872,12 +1850,6 @@ void pci_restore_state(struct pci_dev *dev)
        if (!dev->state_saved)
                return;
 
-       /*
-        * Restore max latencies (in the LTR capability) before enabling
-        * LTR itself (in the PCIe capability).
-        */
-       pci_restore_ltr_state(dev);
-
        pci_restore_pcie_state(dev);
        pci_restore_pasid_state(dev);
        pci_restore_pri_state(dev);
@@ -2157,107 +2129,6 @@ int pci_enable_device(struct pci_dev *dev)
 }
 EXPORT_SYMBOL(pci_enable_device);
 
-/*
- * Managed PCI resources.  This manages device on/off, INTx/MSI/MSI-X
- * on/off and BAR regions.  pci_dev itself records MSI/MSI-X status, so
- * there's no need to track it separately.  pci_devres is initialized
- * when a device is enabled using managed PCI device enable interface.
- */
-struct pci_devres {
-       unsigned int enabled:1;
-       unsigned int pinned:1;
-       unsigned int orig_intx:1;
-       unsigned int restore_intx:1;
-       unsigned int mwi:1;
-       u32 region_mask;
-};
-
-static void pcim_release(struct device *gendev, void *res)
-{
-       struct pci_dev *dev = to_pci_dev(gendev);
-       struct pci_devres *this = res;
-       int i;
-
-       for (i = 0; i < DEVICE_COUNT_RESOURCE; i++)
-               if (this->region_mask & (1 << i))
-                       pci_release_region(dev, i);
-
-       if (this->mwi)
-               pci_clear_mwi(dev);
-
-       if (this->restore_intx)
-               pci_intx(dev, this->orig_intx);
-
-       if (this->enabled && !this->pinned)
-               pci_disable_device(dev);
-}
-
-static struct pci_devres *get_pci_dr(struct pci_dev *pdev)
-{
-       struct pci_devres *dr, *new_dr;
-
-       dr = devres_find(&pdev->dev, pcim_release, NULL, NULL);
-       if (dr)
-               return dr;
-
-       new_dr = devres_alloc(pcim_release, sizeof(*new_dr), GFP_KERNEL);
-       if (!new_dr)
-               return NULL;
-       return devres_get(&pdev->dev, new_dr, NULL, NULL);
-}
-
-static struct pci_devres *find_pci_dr(struct pci_dev *pdev)
-{
-       if (pci_is_managed(pdev))
-               return devres_find(&pdev->dev, pcim_release, NULL, NULL);
-       return NULL;
-}
-
-/**
- * pcim_enable_device - Managed pci_enable_device()
- * @pdev: PCI device to be initialized
- *
- * Managed pci_enable_device().
- */
-int pcim_enable_device(struct pci_dev *pdev)
-{
-       struct pci_devres *dr;
-       int rc;
-
-       dr = get_pci_dr(pdev);
-       if (unlikely(!dr))
-               return -ENOMEM;
-       if (dr->enabled)
-               return 0;
-
-       rc = pci_enable_device(pdev);
-       if (!rc) {
-               pdev->is_managed = 1;
-               dr->enabled = 1;
-       }
-       return rc;
-}
-EXPORT_SYMBOL(pcim_enable_device);
-
-/**
- * pcim_pin_device - Pin managed PCI device
- * @pdev: PCI device to pin
- *
- * Pin managed PCI device @pdev.  Pinned device won't be disabled on
- * driver detach.  @pdev must have been enabled with
- * pcim_enable_device().
- */
-void pcim_pin_device(struct pci_dev *pdev)
-{
-       struct pci_devres *dr;
-
-       dr = find_pci_dr(pdev);
-       WARN_ON(!dr || !dr->enabled);
-       if (dr)
-               dr->pinned = 1;
-}
-EXPORT_SYMBOL(pcim_pin_device);
-
 /*
  * pcibios_device_add - provide arch specific hooks when adding device dev
  * @dev: the PCI device being added
@@ -2292,17 +2163,6 @@ void __weak pcibios_release_device(struct pci_dev *dev) {}
  */
 void __weak pcibios_disable_device(struct pci_dev *dev) {}
 
-/**
- * pcibios_penalize_isa_irq - penalize an ISA IRQ
- * @irq: ISA IRQ to penalize
- * @active: IRQ active or not
- *
- * Permits the platform to provide architecture-specific functionality when
- * penalizing ISA IRQs. This is the default implementation. Architecture
- * implementations can override this.
- */
-void __weak pcibios_penalize_isa_irq(int irq, int active) {}
-
 static void do_pci_disable_device(struct pci_dev *dev)
 {
        u16 pci_command;
@@ -3964,66 +3824,6 @@ int pci_enable_atomic_ops_to_root(struct pci_dev *dev, u32 cap_mask)
 }
 EXPORT_SYMBOL(pci_enable_atomic_ops_to_root);
 
-/**
- * pci_swizzle_interrupt_pin - swizzle INTx for device behind bridge
- * @dev: the PCI device
- * @pin: the INTx pin (1=INTA, 2=INTB, 3=INTC, 4=INTD)
- *
- * Perform INTx swizzling for a device behind one level of bridge.  This is
- * required by section 9.1 of the PCI-to-PCI bridge specification for devices
- * behind bridges on add-in cards.  For devices with ARI enabled, the slot
- * number is always 0 (see the Implementation Note in section 2.2.8.1 of
- * the PCI Express Base Specification, Revision 2.1)
- */
-u8 pci_swizzle_interrupt_pin(const struct pci_dev *dev, u8 pin)
-{
-       int slot;
-
-       if (pci_ari_enabled(dev->bus))
-               slot = 0;
-       else
-               slot = PCI_SLOT(dev->devfn);
-
-       return (((pin - 1) + slot) % 4) + 1;
-}
-
-int pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge)
-{
-       u8 pin;
-
-       pin = dev->pin;
-       if (!pin)
-               return -1;
-
-       while (!pci_is_root_bus(dev->bus)) {
-               pin = pci_swizzle_interrupt_pin(dev, pin);
-               dev = dev->bus->self;
-       }
-       *bridge = dev;
-       return pin;
-}
-
-/**
- * pci_common_swizzle - swizzle INTx all the way to root bridge
- * @dev: the PCI device
- * @pinp: pointer to the INTx pin value (1=INTA, 2=INTB, 3=INTD, 4=INTD)
- *
- * Perform INTx swizzling for a device.  This traverses through all PCI-to-PCI
- * bridges all the way up to a PCI root bus.
- */
-u8 pci_common_swizzle(struct pci_dev *dev, u8 *pinp)
-{
-       u8 pin = *pinp;
-
-       while (!pci_is_root_bus(dev->bus)) {
-               pin = pci_swizzle_interrupt_pin(dev, pin);
-               dev = dev->bus->self;
-       }
-       *pinp = pin;
-       return PCI_SLOT(dev->devfn);
-}
-EXPORT_SYMBOL_GPL(pci_common_swizzle);
-
 /**
  * pci_release_region - Release a PCI bar
  * @pdev: PCI device whose resources were previously reserved by
@@ -4352,133 +4152,6 @@ void pci_unmap_iospace(struct resource *res)
 }
 EXPORT_SYMBOL(pci_unmap_iospace);
 
-static void devm_pci_unmap_iospace(struct device *dev, void *ptr)
-{
-       struct resource **res = ptr;
-
-       pci_unmap_iospace(*res);
-}
-
-/**
- * devm_pci_remap_iospace - Managed pci_remap_iospace()
- * @dev: Generic device to remap IO address for
- * @res: Resource describing the I/O space
- * @phys_addr: physical address of range to be mapped
- *
- * Managed pci_remap_iospace().  Map is automatically unmapped on driver
- * detach.
- */
-int devm_pci_remap_iospace(struct device *dev, const struct resource *res,
-                          phys_addr_t phys_addr)
-{
-       const struct resource **ptr;
-       int error;
-
-       ptr = devres_alloc(devm_pci_unmap_iospace, sizeof(*ptr), GFP_KERNEL);
-       if (!ptr)
-               return -ENOMEM;
-
-       error = pci_remap_iospace(res, phys_addr);
-       if (error) {
-               devres_free(ptr);
-       } else  {
-               *ptr = res;
-               devres_add(dev, ptr);
-       }
-
-       return error;
-}
-EXPORT_SYMBOL(devm_pci_remap_iospace);
-
-/**
- * devm_pci_remap_cfgspace - Managed pci_remap_cfgspace()
- * @dev: Generic device to remap IO address for
- * @offset: Resource address to map
- * @size: Size of map
- *
- * Managed pci_remap_cfgspace().  Map is automatically unmapped on driver
- * detach.
- */
-void __iomem *devm_pci_remap_cfgspace(struct device *dev,
-                                     resource_size_t offset,
-                                     resource_size_t size)
-{
-       void __iomem **ptr, *addr;
-
-       ptr = devres_alloc(devm_ioremap_release, sizeof(*ptr), GFP_KERNEL);
-       if (!ptr)
-               return NULL;
-
-       addr = pci_remap_cfgspace(offset, size);
-       if (addr) {
-               *ptr = addr;
-               devres_add(dev, ptr);
-       } else
-               devres_free(ptr);
-
-       return addr;
-}
-EXPORT_SYMBOL(devm_pci_remap_cfgspace);
-
-/**
- * devm_pci_remap_cfg_resource - check, request region and ioremap cfg resource
- * @dev: generic device to handle the resource for
- * @res: configuration space resource to be handled
- *
- * Checks that a resource is a valid memory region, requests the memory
- * region and ioremaps with pci_remap_cfgspace() API that ensures the
- * proper PCI configuration space memory attributes are guaranteed.
- *
- * All operations are managed and will be undone on driver detach.
- *
- * Returns a pointer to the remapped memory or an ERR_PTR() encoded error code
- * on failure. Usage example::
- *
- *     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- *     base = devm_pci_remap_cfg_resource(&pdev->dev, res);
- *     if (IS_ERR(base))
- *             return PTR_ERR(base);
- */
-void __iomem *devm_pci_remap_cfg_resource(struct device *dev,
-                                         struct resource *res)
-{
-       resource_size_t size;
-       const char *name;
-       void __iomem *dest_ptr;
-
-       BUG_ON(!dev);
-
-       if (!res || resource_type(res) != IORESOURCE_MEM) {
-               dev_err(dev, "invalid resource\n");
-               return IOMEM_ERR_PTR(-EINVAL);
-       }
-
-       size = resource_size(res);
-
-       if (res->name)
-               name = devm_kasprintf(dev, GFP_KERNEL, "%s %s", dev_name(dev),
-                                     res->name);
-       else
-               name = devm_kstrdup(dev, dev_name(dev), GFP_KERNEL);
-       if (!name)
-               return IOMEM_ERR_PTR(-ENOMEM);
-
-       if (!devm_request_mem_region(dev, res->start, size, name)) {
-               dev_err(dev, "can't request region for resource %pR\n", res);
-               return IOMEM_ERR_PTR(-EBUSY);
-       }
-
-       dest_ptr = devm_pci_remap_cfgspace(dev, res->start, size);
-       if (!dest_ptr) {
-               dev_err(dev, "ioremap failed for resource %pR\n", res);
-               devm_release_mem_region(dev, res->start, size);
-               dest_ptr = IOMEM_ERR_PTR(-ENOMEM);
-       }
-
-       return dest_ptr;
-}
-EXPORT_SYMBOL(devm_pci_remap_cfg_resource);
-
 static void __pci_set_master(struct pci_dev *dev, bool enable)
 {
        u16 old_cmd, cmd;
@@ -4628,27 +4301,6 @@ int pci_set_mwi(struct pci_dev *dev)
 }
 EXPORT_SYMBOL(pci_set_mwi);
 
-/**
- * pcim_set_mwi - a device-managed pci_set_mwi()
- * @dev: the PCI device for which MWI is enabled
- *
- * Managed pci_set_mwi().
- *
- * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
- */
-int pcim_set_mwi(struct pci_dev *dev)
-{
-       struct pci_devres *dr;
-
-       dr = find_pci_dr(dev);
-       if (!dr)
-               return -ENOMEM;
-
-       dr->mwi = 1;
-       return pci_set_mwi(dev);
-}
-EXPORT_SYMBOL(pcim_set_mwi);
-
 /**
  * pci_try_set_mwi - enables memory-write-invalidate PCI transaction
  * @dev: the PCI device for which MWI is enabled
@@ -4737,78 +4389,6 @@ void pci_intx(struct pci_dev *pdev, int enable)
 }
 EXPORT_SYMBOL_GPL(pci_intx);
 
-static bool pci_check_and_set_intx_mask(struct pci_dev *dev, bool mask)
-{
-       struct pci_bus *bus = dev->bus;
-       bool mask_updated = true;
-       u32 cmd_status_dword;
-       u16 origcmd, newcmd;
-       unsigned long flags;
-       bool irq_pending;
-
-       /*
-        * We do a single dword read to retrieve both command and status.
-        * Document assumptions that make this possible.
-        */
-       BUILD_BUG_ON(PCI_COMMAND % 4);
-       BUILD_BUG_ON(PCI_COMMAND + 2 != PCI_STATUS);
-
-       raw_spin_lock_irqsave(&pci_lock, flags);
-
-       bus->ops->read(bus, dev->devfn, PCI_COMMAND, 4, &cmd_status_dword);
-
-       irq_pending = (cmd_status_dword >> 16) & PCI_STATUS_INTERRUPT;
-
-       /*
-        * Check interrupt status register to see whether our device
-        * triggered the interrupt (when masking) or the next IRQ is
-        * already pending (when unmasking).
-        */
-       if (mask != irq_pending) {
-               mask_updated = false;
-               goto done;
-       }
-
-       origcmd = cmd_status_dword;
-       newcmd = origcmd & ~PCI_COMMAND_INTX_DISABLE;
-       if (mask)
-               newcmd |= PCI_COMMAND_INTX_DISABLE;
-       if (newcmd != origcmd)
-               bus->ops->write(bus, dev->devfn, PCI_COMMAND, 2, newcmd);
-
-done:
-       raw_spin_unlock_irqrestore(&pci_lock, flags);
-
-       return mask_updated;
-}
-
-/**
- * pci_check_and_mask_intx - mask INTx on pending interrupt
- * @dev: the PCI device to operate on
- *
- * Check if the device dev has its INTx line asserted, mask it and return
- * true in that case. False is returned if no interrupt was pending.
- */
-bool pci_check_and_mask_intx(struct pci_dev *dev)
-{
-       return pci_check_and_set_intx_mask(dev, true);
-}
-EXPORT_SYMBOL_GPL(pci_check_and_mask_intx);
-
-/**
- * pci_check_and_unmask_intx - unmask INTx if no interrupt is pending
- * @dev: the PCI device to operate on
- *
- * Check if the device dev has its INTx line asserted, unmask it if not and
- * return true. False is returned and the mask remains active if there was
- * still an interrupt pending.
- */
-bool pci_check_and_unmask_intx(struct pci_dev *dev)
-{
-       return pci_check_and_set_intx_mask(dev, false);
-}
-EXPORT_SYMBOL_GPL(pci_check_and_unmask_intx);
-
 /**
  * pci_wait_for_pending_transaction - wait for pending transaction
  * @dev: the PCI device to operate on
index 2336a8d1edab27646220794a3a4cdd085ba7b3e9..02573b03604061fbf226c0b57dbfd4099de711cb 100644 (file)
@@ -31,9 +31,6 @@ bool pcie_cap_has_rtctl(const struct pci_dev *dev);
 
 /* Functions internal to the PCI core code */
 
-int pci_create_sysfs_dev_files(struct pci_dev *pdev);
-void pci_remove_sysfs_dev_files(struct pci_dev *pdev);
-void pci_cleanup_rom(struct pci_dev *dev);
 #ifdef CONFIG_DMI
 extern const struct attribute_group pci_dev_smbios_attr_group;
 #endif
@@ -97,7 +94,6 @@ void pci_msi_init(struct pci_dev *dev);
 void pci_msix_init(struct pci_dev *dev);
 bool pci_bridge_d3_possible(struct pci_dev *dev);
 void pci_bridge_d3_update(struct pci_dev *dev);
-void pci_bridge_reconfigure_ltr(struct pci_dev *dev);
 int pci_bridge_wait_for_secondary_bus(struct pci_dev *dev, char *reset_type);
 
 static inline void pci_wakeup_event(struct pci_dev *dev)
@@ -152,7 +148,7 @@ static inline int pci_proc_detach_bus(struct pci_bus *bus) { return 0; }
 /* Functions for PCI Hotplug drivers to use */
 int pci_hp_add_bridge(struct pci_dev *dev);
 
-#ifdef HAVE_PCI_LEGACY
+#if defined(CONFIG_SYSFS) && defined(HAVE_PCI_LEGACY)
 void pci_create_legacy_files(struct pci_bus *bus);
 void pci_remove_legacy_files(struct pci_bus *bus);
 #else
@@ -185,10 +181,22 @@ static inline int pci_no_d1d2(struct pci_dev *dev)
        return (dev->no_d1d2 || parent_dstates);
 
 }
+
+#ifdef CONFIG_SYSFS
+int pci_create_sysfs_dev_files(struct pci_dev *pdev);
+void pci_remove_sysfs_dev_files(struct pci_dev *pdev);
 extern const struct attribute_group *pci_dev_groups[];
+extern const struct attribute_group *pci_dev_attr_groups[];
 extern const struct attribute_group *pcibus_groups[];
-extern const struct device_type pci_dev_type;
 extern const struct attribute_group *pci_bus_groups[];
+#else
+static inline int pci_create_sysfs_dev_files(struct pci_dev *pdev) { return 0; }
+static inline void pci_remove_sysfs_dev_files(struct pci_dev *pdev) { }
+#define pci_dev_groups NULL
+#define pci_dev_attr_groups NULL
+#define pcibus_groups NULL
+#define pci_bus_groups NULL
+#endif
 
 extern unsigned long pci_hotplug_io_size;
 extern unsigned long pci_hotplug_mmio_size;
@@ -409,7 +417,7 @@ struct aer_err_info {
 
        unsigned int status;            /* COR/UNCOR Error Status */
        unsigned int mask;              /* COR/UNCOR Error Mask */
-       struct aer_header_log_regs tlp; /* TLP Header */
+       struct pcie_tlp_log tlp;        /* TLP Header */
 };
 
 int aer_get_device_error_info(struct pci_dev *dev, struct aer_err_info *info);
@@ -568,16 +576,28 @@ pci_ers_result_t pcie_do_recovery(struct pci_dev *dev,
 
 bool pcie_wait_for_link(struct pci_dev *pdev, bool active);
 int pcie_retrain_link(struct pci_dev *pdev, bool use_lt);
+
+/* ASPM-related functionality we need even without CONFIG_PCIEASPM */
+void pci_save_ltr_state(struct pci_dev *dev);
+void pci_restore_ltr_state(struct pci_dev *dev);
+void pci_configure_aspm_l1ss(struct pci_dev *dev);
+void pci_save_aspm_l1ss_state(struct pci_dev *dev);
+void pci_restore_aspm_l1ss_state(struct pci_dev *dev);
+
 #ifdef CONFIG_PCIEASPM
 void pcie_aspm_init_link_state(struct pci_dev *pdev);
 void pcie_aspm_exit_link_state(struct pci_dev *pdev);
 void pcie_aspm_pm_state_change(struct pci_dev *pdev);
 void pcie_aspm_powersave_config_link(struct pci_dev *pdev);
+void pci_configure_ltr(struct pci_dev *pdev);
+void pci_bridge_reconfigure_ltr(struct pci_dev *pdev);
 #else
 static inline void pcie_aspm_init_link_state(struct pci_dev *pdev) { }
 static inline void pcie_aspm_exit_link_state(struct pci_dev *pdev) { }
 static inline void pcie_aspm_pm_state_change(struct pci_dev *pdev) { }
 static inline void pcie_aspm_powersave_config_link(struct pci_dev *pdev) { }
+static inline void pci_configure_ltr(struct pci_dev *pdev) { }
+static inline void pci_bridge_reconfigure_ltr(struct pci_dev *pdev) { }
 #endif
 
 #ifdef CONFIG_PCIE_ECRC
@@ -797,6 +817,27 @@ static inline pci_power_t mid_pci_get_power_state(struct pci_dev *pdev)
 }
 #endif
 
+/*
+ * Managed PCI resources.  This manages device on/off, INTx/MSI/MSI-X
+ * on/off and BAR regions.  pci_dev itself records MSI/MSI-X status, so
+ * there's no need to track it separately.  pci_devres is initialized
+ * when a device is enabled using managed PCI device enable interface.
+ *
+ * TODO: Struct pci_devres and find_pci_dr() only need to be here because
+ * they're used in pci.c.  Port or move these functions to devres.c and
+ * then remove them from here.
+ */
+struct pci_devres {
+       unsigned int enabled:1;
+       unsigned int pinned:1;
+       unsigned int orig_intx:1;
+       unsigned int restore_intx:1;
+       unsigned int mwi:1;
+       u32 region_mask;
+};
+
+struct pci_devres *find_pci_dr(struct pci_dev *pdev);
+
 /*
  * Config Address for PCI Configuration Mechanism #1
  *
index 8de4ed5f98f145065b6c2678f7e09dd184d09a24..6461aa93fe76eccd39c4af08e7e1c9c327e7b77d 100644 (file)
@@ -6,7 +6,7 @@ pcieportdrv-y                   := portdrv.o rcec.o
 
 obj-$(CONFIG_PCIEPORTBUS)      += pcieportdrv.o
 
-obj-$(CONFIG_PCIEASPM)         += aspm.o
+obj-y                          += aspm.o
 obj-$(CONFIG_PCIEAER)          += aer.o err.o
 obj-$(CONFIG_PCIEAER_INJECT)   += aer_inject.o
 obj-$(CONFIG_PCIE_PME)         += pme.o
index 05fc30bb5134d9ae31e681375d843b0f49738c30..ac6293c249766460ddf74ea05a1147651faa21c9 100644 (file)
@@ -664,11 +664,10 @@ static void pci_rootport_aer_stats_incr(struct pci_dev *pdev,
        }
 }
 
-static void __print_tlp_header(struct pci_dev *dev,
-                              struct aer_header_log_regs *t)
+static void __print_tlp_header(struct pci_dev *dev, struct pcie_tlp_log *t)
 {
        pci_err(dev, "  TLP Header: %08x %08x %08x %08x\n",
-               t->dw0, t->dw1, t->dw2, t->dw3);
+               t->dw[0], t->dw[1], t->dw[2], t->dw[3]);
 }
 
 static void __aer_print_error(struct pci_dev *dev,
@@ -1210,7 +1209,7 @@ int aer_get_device_error_info(struct pci_dev *dev, struct aer_err_info *info)
 {
        int type = pci_pcie_type(dev);
        int aer = dev->aer_cap;
-       int temp;
+       u32 aercc;
 
        /* Must reset in this function */
        info->status = 0;
@@ -1241,19 +1240,12 @@ int aer_get_device_error_info(struct pci_dev *dev, struct aer_err_info *info)
                        return 0;
 
                /* Get First Error Pointer */
-               pci_read_config_dword(dev, aer + PCI_ERR_CAP, &temp);
-               info->first_error = PCI_ERR_CAP_FEP(temp);
+               pci_read_config_dword(dev, aer + PCI_ERR_CAP, &aercc);
+               info->first_error = PCI_ERR_CAP_FEP(aercc);
 
                if (info->status & AER_LOG_TLP_MASKS) {
                        info->tlp_header_valid = 1;
-                       pci_read_config_dword(dev,
-                               aer + PCI_ERR_HEADER_LOG, &info->tlp.dw0);
-                       pci_read_config_dword(dev,
-                               aer + PCI_ERR_HEADER_LOG + 4, &info->tlp.dw1);
-                       pci_read_config_dword(dev,
-                               aer + PCI_ERR_HEADER_LOG + 8, &info->tlp.dw2);
-                       pci_read_config_dword(dev,
-                               aer + PCI_ERR_HEADER_LOG + 12, &info->tlp.dw3);
+                       pcie_read_tlp_log(dev, aer + PCI_ERR_HEADER_LOG, &info->tlp);
                }
        }
 
index 5a0066ecc3c5adcc97e14f08f166c783f254f6e9..10160d82c10a6d7036c68f73f95e24e141c98e84 100644 (file)
 
 #include "../pci.h"
 
+void pci_save_ltr_state(struct pci_dev *dev)
+{
+       int ltr;
+       struct pci_cap_saved_state *save_state;
+       u32 *cap;
+
+       if (!pci_is_pcie(dev))
+               return;
+
+       ltr = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_LTR);
+       if (!ltr)
+               return;
+
+       save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_LTR);
+       if (!save_state) {
+               pci_err(dev, "no suspend buffer for LTR; ASPM issues possible after resume\n");
+               return;
+       }
+
+       /* Some broken devices only support dword access to LTR */
+       cap = &save_state->cap.data[0];
+       pci_read_config_dword(dev, ltr + PCI_LTR_MAX_SNOOP_LAT, cap);
+}
+
+void pci_restore_ltr_state(struct pci_dev *dev)
+{
+       struct pci_cap_saved_state *save_state;
+       int ltr;
+       u32 *cap;
+
+       save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_LTR);
+       ltr = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_LTR);
+       if (!save_state || !ltr)
+               return;
+
+       /* Some broken devices only support dword access to LTR */
+       cap = &save_state->cap.data[0];
+       pci_write_config_dword(dev, ltr + PCI_LTR_MAX_SNOOP_LAT, *cap);
+}
+
+void pci_configure_aspm_l1ss(struct pci_dev *pdev)
+{
+       int rc;
+
+       pdev->l1ss = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_L1SS);
+
+       rc = pci_add_ext_cap_save_buffer(pdev, PCI_EXT_CAP_ID_L1SS,
+                                        2 * sizeof(u32));
+       if (rc)
+               pci_err(pdev, "unable to allocate ASPM L1SS save buffer (%pe)\n",
+                       ERR_PTR(rc));
+}
+
+void pci_save_aspm_l1ss_state(struct pci_dev *pdev)
+{
+       struct pci_cap_saved_state *save_state;
+       u16 l1ss = pdev->l1ss;
+       u32 *cap;
+
+       /*
+        * Save L1 substate configuration. The ASPM L0s/L1 configuration
+        * in PCI_EXP_LNKCTL_ASPMC is saved by pci_save_pcie_state().
+        */
+       if (!l1ss)
+               return;
+
+       save_state = pci_find_saved_ext_cap(pdev, PCI_EXT_CAP_ID_L1SS);
+       if (!save_state)
+               return;
+
+       cap = &save_state->cap.data[0];
+       pci_read_config_dword(pdev, l1ss + PCI_L1SS_CTL2, cap++);
+       pci_read_config_dword(pdev, l1ss + PCI_L1SS_CTL1, cap++);
+}
+
+void pci_restore_aspm_l1ss_state(struct pci_dev *pdev)
+{
+       struct pci_cap_saved_state *pl_save_state, *cl_save_state;
+       struct pci_dev *parent = pdev->bus->self;
+       u32 *cap, pl_ctl1, pl_ctl2, pl_l1_2_enable;
+       u32 cl_ctl1, cl_ctl2, cl_l1_2_enable;
+       u16 clnkctl, plnkctl;
+
+       /*
+        * In case BIOS enabled L1.2 when resuming, we need to disable it first
+        * on the downstream component before the upstream. So, don't attempt to
+        * restore either until we are at the downstream component.
+        */
+       if (pcie_downstream_port(pdev) || !parent)
+               return;
+
+       if (!pdev->l1ss || !parent->l1ss)
+               return;
+
+       cl_save_state = pci_find_saved_ext_cap(pdev, PCI_EXT_CAP_ID_L1SS);
+       pl_save_state = pci_find_saved_ext_cap(parent, PCI_EXT_CAP_ID_L1SS);
+       if (!cl_save_state || !pl_save_state)
+               return;
+
+       cap = &cl_save_state->cap.data[0];
+       cl_ctl2 = *cap++;
+       cl_ctl1 = *cap;
+       cap = &pl_save_state->cap.data[0];
+       pl_ctl2 = *cap++;
+       pl_ctl1 = *cap;
+
+       /* Make sure L0s/L1 are disabled before updating L1SS config */
+       pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &clnkctl);
+       pcie_capability_read_word(parent, PCI_EXP_LNKCTL, &plnkctl);
+       if (FIELD_GET(PCI_EXP_LNKCTL_ASPMC, clnkctl) ||
+           FIELD_GET(PCI_EXP_LNKCTL_ASPMC, plnkctl)) {
+               pcie_capability_write_word(pdev, PCI_EXP_LNKCTL,
+                                          clnkctl & ~PCI_EXP_LNKCTL_ASPMC);
+               pcie_capability_write_word(parent, PCI_EXP_LNKCTL,
+                                          plnkctl & ~PCI_EXP_LNKCTL_ASPMC);
+       }
+
+       /*
+        * Disable L1.2 on this downstream endpoint device first, followed
+        * by the upstream
+        */
+       pci_clear_and_set_config_dword(pdev, pdev->l1ss + PCI_L1SS_CTL1,
+                                      PCI_L1SS_CTL1_L1_2_MASK, 0);
+       pci_clear_and_set_config_dword(parent, parent->l1ss + PCI_L1SS_CTL1,
+                                      PCI_L1SS_CTL1_L1_2_MASK, 0);
+
+       /*
+        * In addition, Common_Mode_Restore_Time and LTR_L1.2_THRESHOLD
+        * in PCI_L1SS_CTL1 must be programmed *before* setting the L1.2
+        * enable bits, even though they're all in PCI_L1SS_CTL1.
+        */
+       pl_l1_2_enable = pl_ctl1 & PCI_L1SS_CTL1_L1_2_MASK;
+       pl_ctl1 &= ~PCI_L1SS_CTL1_L1_2_MASK;
+       cl_l1_2_enable = cl_ctl1 & PCI_L1SS_CTL1_L1_2_MASK;
+       cl_ctl1 &= ~PCI_L1SS_CTL1_L1_2_MASK;
+
+       /* Write back without enables first (above we cleared them in ctl1) */
+       pci_write_config_dword(parent, parent->l1ss + PCI_L1SS_CTL2, pl_ctl2);
+       pci_write_config_dword(pdev, pdev->l1ss + PCI_L1SS_CTL2, cl_ctl2);
+       pci_write_config_dword(parent, parent->l1ss + PCI_L1SS_CTL1, pl_ctl1);
+       pci_write_config_dword(pdev, pdev->l1ss + PCI_L1SS_CTL1, cl_ctl1);
+
+       /* Then write back the enables */
+       if (pl_l1_2_enable || cl_l1_2_enable) {
+               pci_write_config_dword(parent, parent->l1ss + PCI_L1SS_CTL1,
+                                      pl_ctl1 | pl_l1_2_enable);
+               pci_write_config_dword(pdev, pdev->l1ss + PCI_L1SS_CTL1,
+                                      cl_ctl1 | cl_l1_2_enable);
+       }
+
+       /* Restore L0s/L1 if they were enabled */
+       if (FIELD_GET(PCI_EXP_LNKCTL_ASPMC, clnkctl) ||
+           FIELD_GET(PCI_EXP_LNKCTL_ASPMC, plnkctl)) {
+               pcie_capability_write_word(parent, PCI_EXP_LNKCTL, clnkctl);
+               pcie_capability_write_word(pdev, PCI_EXP_LNKCTL, plnkctl);
+       }
+}
+
+#ifdef CONFIG_PCIEASPM
+
 #ifdef MODULE_PARAM_PREFIX
 #undef MODULE_PARAM_PREFIX
 #endif
@@ -141,16 +301,42 @@ static int policy_to_clkpm_state(struct pcie_link_state *link)
        return 0;
 }
 
+static void pci_update_aspm_saved_state(struct pci_dev *dev)
+{
+       struct pci_cap_saved_state *save_state;
+       u16 *cap, lnkctl, aspm_ctl;
+
+       save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP);
+       if (!save_state)
+               return;
+
+       pcie_capability_read_word(dev, PCI_EXP_LNKCTL, &lnkctl);
+
+       /*
+        * Update ASPM and CLKREQ bits of LNKCTL in save_state. We only
+        * write PCI_EXP_LNKCTL_CCC during enumeration, so it shouldn't
+        * change after being captured in save_state.
+        */
+       aspm_ctl = lnkctl & (PCI_EXP_LNKCTL_ASPMC | PCI_EXP_LNKCTL_CLKREQ_EN);
+       lnkctl &= ~(PCI_EXP_LNKCTL_ASPMC | PCI_EXP_LNKCTL_CLKREQ_EN);
+
+       /* Depends on pci_save_pcie_state(): cap[1] is LNKCTL */
+       cap = (u16 *)&save_state->cap.data[0];
+       cap[1] = lnkctl | aspm_ctl;
+}
+
 static void pcie_set_clkpm_nocheck(struct pcie_link_state *link, int enable)
 {
        struct pci_dev *child;
        struct pci_bus *linkbus = link->pdev->subordinate;
        u32 val = enable ? PCI_EXP_LNKCTL_CLKREQ_EN : 0;
 
-       list_for_each_entry(child, &linkbus->devices, bus_list)
+       list_for_each_entry(child, &linkbus->devices, bus_list) {
                pcie_capability_clear_and_set_word(child, PCI_EXP_LNKCTL,
                                                   PCI_EXP_LNKCTL_CLKREQ_EN,
                                                   val);
+               pci_update_aspm_saved_state(child);
+       }
        link->clkpm_enabled = !!enable;
 }
 
@@ -769,6 +955,12 @@ static void pcie_config_aspm_link(struct pcie_link_state *link, u32 state)
                pcie_config_aspm_dev(parent, upstream);
 
        link->aspm_enabled = state;
+
+       /* Update latest ASPM configuration in saved context */
+       pci_save_aspm_l1ss_state(link->downstream);
+       pci_update_aspm_saved_state(link->downstream);
+       pci_save_aspm_l1ss_state(parent);
+       pci_update_aspm_saved_state(parent);
 }
 
 static void pcie_config_aspm_path(struct pcie_link_state *link)
@@ -938,6 +1130,78 @@ out:
        up_read(&pci_bus_sem);
 }
 
+void pci_bridge_reconfigure_ltr(struct pci_dev *pdev)
+{
+       struct pci_dev *bridge;
+       u32 ctl;
+
+       bridge = pci_upstream_bridge(pdev);
+       if (bridge && bridge->ltr_path) {
+               pcie_capability_read_dword(bridge, PCI_EXP_DEVCTL2, &ctl);
+               if (!(ctl & PCI_EXP_DEVCTL2_LTR_EN)) {
+                       pci_dbg(bridge, "re-enabling LTR\n");
+                       pcie_capability_set_word(bridge, PCI_EXP_DEVCTL2,
+                                                PCI_EXP_DEVCTL2_LTR_EN);
+               }
+       }
+}
+
+void pci_configure_ltr(struct pci_dev *pdev)
+{
+       struct pci_host_bridge *host = pci_find_host_bridge(pdev->bus);
+       struct pci_dev *bridge;
+       u32 cap, ctl;
+
+       if (!pci_is_pcie(pdev))
+               return;
+
+       pcie_capability_read_dword(pdev, PCI_EXP_DEVCAP2, &cap);
+       if (!(cap & PCI_EXP_DEVCAP2_LTR))
+               return;
+
+       pcie_capability_read_dword(pdev, PCI_EXP_DEVCTL2, &ctl);
+       if (ctl & PCI_EXP_DEVCTL2_LTR_EN) {
+               if (pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT) {
+                       pdev->ltr_path = 1;
+                       return;
+               }
+
+               bridge = pci_upstream_bridge(pdev);
+               if (bridge && bridge->ltr_path)
+                       pdev->ltr_path = 1;
+
+               return;
+       }
+
+       if (!host->native_ltr)
+               return;
+
+       /*
+        * Software must not enable LTR in an Endpoint unless the Root
+        * Complex and all intermediate Switches indicate support for LTR.
+        * PCIe r4.0, sec 6.18.
+        */
+       if (pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT) {
+               pcie_capability_set_word(pdev, PCI_EXP_DEVCTL2,
+                                        PCI_EXP_DEVCTL2_LTR_EN);
+               pdev->ltr_path = 1;
+               return;
+       }
+
+       /*
+        * If we're configuring a hot-added device, LTR was likely
+        * disabled in the upstream bridge, so re-enable it before enabling
+        * it in the new device.
+        */
+       bridge = pci_upstream_bridge(pdev);
+       if (bridge && bridge->ltr_path) {
+               pci_bridge_reconfigure_ltr(pdev);
+               pcie_capability_set_word(pdev, PCI_EXP_DEVCTL2,
+                                        PCI_EXP_DEVCTL2_LTR_EN);
+               pdev->ltr_path = 1;
+       }
+}
+
 /* Recheck latencies and update aspm_capable for links under the root */
 static void pcie_update_aspm_capable(struct pcie_link_state *root)
 {
@@ -1442,3 +1706,5 @@ bool pcie_aspm_support_enabled(void)
 {
        return aspm_support_enabled;
 }
+
+#endif /* CONFIG_PCIEASPM */
index 94111e4382413dc57ff10a079e1bdfc50c0e978e..a668820696dc0faee03455933182910409a5c03e 100644 (file)
@@ -190,7 +190,8 @@ out:
 static void dpc_process_rp_pio_error(struct pci_dev *pdev)
 {
        u16 cap = pdev->dpc_cap, dpc_status, first_error;
-       u32 status, mask, sev, syserr, exc, dw0, dw1, dw2, dw3, log, prefix;
+       u32 status, mask, sev, syserr, exc, log, prefix;
+       struct pcie_tlp_log tlp_log;
        int i;
 
        pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_STATUS, &status);
@@ -216,16 +217,9 @@ static void dpc_process_rp_pio_error(struct pci_dev *pdev)
 
        if (pdev->dpc_rp_log_size < 4)
                goto clear_status;
-       pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_HEADER_LOG,
-                             &dw0);
-       pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_HEADER_LOG + 4,
-                             &dw1);
-       pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_HEADER_LOG + 8,
-                             &dw2);
-       pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_HEADER_LOG + 12,
-                             &dw3);
+       pcie_read_tlp_log(pdev, cap + PCI_EXP_DPC_RP_PIO_HEADER_LOG, &tlp_log);
        pci_err(pdev, "TLP Header: %#010x %#010x %#010x %#010x\n",
-               dw0, dw1, dw2, dw3);
+               tlp_log.dw[0], tlp_log.dw[1], tlp_log.dw[2], tlp_log.dw[3]);
 
        if (pdev->dpc_rp_log_size < 5)
                goto clear_status;
@@ -234,7 +228,7 @@ static void dpc_process_rp_pio_error(struct pci_dev *pdev)
 
        for (i = 0; i < pdev->dpc_rp_log_size - 5; i++) {
                pci_read_config_dword(pdev,
-                       cap + PCI_EXP_DPC_RP_PIO_TLPPREFIX_LOG, &prefix);
+                       cap + PCI_EXP_DPC_RP_PIO_TLPPREFIX_LOG + i * 4, &prefix);
                pci_err(pdev, "TLP Prefix Header: dw%d, %#010x\n", i, prefix);
        }
  clear_status:
@@ -303,10 +297,70 @@ void dpc_process_error(struct pci_dev *pdev)
        }
 }
 
+static void pci_clear_surpdn_errors(struct pci_dev *pdev)
+{
+       if (pdev->dpc_rp_extensions)
+               pci_write_config_dword(pdev, pdev->dpc_cap +
+                                      PCI_EXP_DPC_RP_PIO_STATUS, ~0);
+
+       /*
+        * In practice, Surprise Down errors have been observed to also set
+        * error bits in the Status Register as well as the Fatal Error
+        * Detected bit in the Device Status Register.
+        */
+       pci_write_config_word(pdev, PCI_STATUS, 0xffff);
+
+       pcie_capability_write_word(pdev, PCI_EXP_DEVSTA, PCI_EXP_DEVSTA_FED);
+}
+
+static void dpc_handle_surprise_removal(struct pci_dev *pdev)
+{
+       if (!pcie_wait_for_link(pdev, false)) {
+               pci_info(pdev, "Data Link Layer Link Active not cleared in 1000 msec\n");
+               goto out;
+       }
+
+       if (pdev->dpc_rp_extensions && dpc_wait_rp_inactive(pdev))
+               goto out;
+
+       pci_aer_raw_clear_status(pdev);
+       pci_clear_surpdn_errors(pdev);
+
+       pci_write_config_word(pdev, pdev->dpc_cap + PCI_EXP_DPC_STATUS,
+                             PCI_EXP_DPC_STATUS_TRIGGER);
+
+out:
+       clear_bit(PCI_DPC_RECOVERED, &pdev->priv_flags);
+       wake_up_all(&dpc_completed_waitqueue);
+}
+
+static bool dpc_is_surprise_removal(struct pci_dev *pdev)
+{
+       u16 status;
+
+       if (!pdev->is_hotplug_bridge)
+               return false;
+
+       if (pci_read_config_word(pdev, pdev->aer_cap + PCI_ERR_UNCOR_STATUS,
+                                &status))
+               return false;
+
+       return status & PCI_ERR_UNC_SURPDN;
+}
+
 static irqreturn_t dpc_handler(int irq, void *context)
 {
        struct pci_dev *pdev = context;
 
+       /*
+        * According to PCIe r6.0 sec 6.7.6, errors are an expected side effect
+        * of async removal and should be ignored by software.
+        */
+       if (dpc_is_surprise_removal(pdev)) {
+               dpc_handle_surprise_removal(pdev);
+               return IRQ_HANDLED;
+       }
+
        dpc_process_error(pdev);
 
        /* We configure DPC so it only triggers on ERR_FATAL */
index 59c90d04a609afbc6f2c485604e8038fbaecddc2..705893b5f7b09babb7ff2b003dd49d74f408f0fe 100644 (file)
@@ -13,6 +13,7 @@
 #define dev_fmt(fmt) "AER: " fmt
 
 #include <linux/pci.h>
+#include <linux/pm_runtime.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
@@ -85,6 +86,18 @@ static int report_error_detected(struct pci_dev *dev,
        return 0;
 }
 
+static int pci_pm_runtime_get_sync(struct pci_dev *pdev, void *data)
+{
+       pm_runtime_get_sync(&pdev->dev);
+       return 0;
+}
+
+static int pci_pm_runtime_put(struct pci_dev *pdev, void *data)
+{
+       pm_runtime_put(&pdev->dev);
+       return 0;
+}
+
 static int report_frozen_detected(struct pci_dev *dev, void *data)
 {
        return report_error_detected(dev, pci_channel_io_frozen, data);
@@ -207,6 +220,8 @@ pci_ers_result_t pcie_do_recovery(struct pci_dev *dev,
        else
                bridge = pci_upstream_bridge(dev);
 
+       pci_walk_bridge(bridge, pci_pm_runtime_get_sync, NULL);
+
        pci_dbg(bridge, "broadcast error_detected message\n");
        if (state == pci_channel_io_frozen) {
                pci_walk_bridge(bridge, report_frozen_detected, &status);
@@ -251,10 +266,15 @@ pci_ers_result_t pcie_do_recovery(struct pci_dev *dev,
                pcie_clear_device_status(dev);
                pci_aer_clear_nonfatal_status(dev);
        }
+
+       pci_walk_bridge(bridge, pci_pm_runtime_put, NULL);
+
        pci_info(bridge, "device recovery successful\n");
        return status;
 
 failed:
+       pci_walk_bridge(bridge, pci_pm_runtime_put, NULL);
+
        pci_uevent_ers(bridge, PCI_ERS_RESULT_DISCONNECT);
 
        /* TODO: Should kernel panic here? */
index 1f3803bde7ee16067d4aa801057076268dfe4b51..12c89ea0313b9c4c5aa73744ea6aff9dee844d84 100644 (file)
@@ -96,7 +96,7 @@ struct pcie_port_service_driver {
 int pcie_port_service_register(struct pcie_port_service_driver *new);
 void pcie_port_service_unregister(struct pcie_port_service_driver *new);
 
-extern struct bus_type pcie_port_bus_type;
+extern const struct bus_type pcie_port_bus_type;
 
 struct pci_dev;
 
index b7335be56008f76ce0da493b56b40a35928af756..1325fbae2f28fb10dbbbd6c6ff65ce2cf9193f3d 100644 (file)
@@ -2209,67 +2209,6 @@ static void pci_configure_relaxed_ordering(struct pci_dev *dev)
        }
 }
 
-static void pci_configure_ltr(struct pci_dev *dev)
-{
-#ifdef CONFIG_PCIEASPM
-       struct pci_host_bridge *host = pci_find_host_bridge(dev->bus);
-       struct pci_dev *bridge;
-       u32 cap, ctl;
-
-       if (!pci_is_pcie(dev))
-               return;
-
-       /* Read L1 PM substate capabilities */
-       dev->l1ss = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_L1SS);
-
-       pcie_capability_read_dword(dev, PCI_EXP_DEVCAP2, &cap);
-       if (!(cap & PCI_EXP_DEVCAP2_LTR))
-               return;
-
-       pcie_capability_read_dword(dev, PCI_EXP_DEVCTL2, &ctl);
-       if (ctl & PCI_EXP_DEVCTL2_LTR_EN) {
-               if (pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT) {
-                       dev->ltr_path = 1;
-                       return;
-               }
-
-               bridge = pci_upstream_bridge(dev);
-               if (bridge && bridge->ltr_path)
-                       dev->ltr_path = 1;
-
-               return;
-       }
-
-       if (!host->native_ltr)
-               return;
-
-       /*
-        * Software must not enable LTR in an Endpoint unless the Root
-        * Complex and all intermediate Switches indicate support for LTR.
-        * PCIe r4.0, sec 6.18.
-        */
-       if (pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT) {
-               pcie_capability_set_word(dev, PCI_EXP_DEVCTL2,
-                                        PCI_EXP_DEVCTL2_LTR_EN);
-               dev->ltr_path = 1;
-               return;
-       }
-
-       /*
-        * If we're configuring a hot-added device, LTR was likely
-        * disabled in the upstream bridge, so re-enable it before enabling
-        * it in the new device.
-        */
-       bridge = pci_upstream_bridge(dev);
-       if (bridge && bridge->ltr_path) {
-               pci_bridge_reconfigure_ltr(dev);
-               pcie_capability_set_word(dev, PCI_EXP_DEVCTL2,
-                                        PCI_EXP_DEVCTL2_LTR_EN);
-               dev->ltr_path = 1;
-       }
-#endif
-}
-
 static void pci_configure_eetlp_prefix(struct pci_dev *dev)
 {
 #ifdef CONFIG_PCI_PASID
@@ -2320,6 +2259,7 @@ static void pci_configure_device(struct pci_dev *dev)
        pci_configure_extended_tags(dev, NULL);
        pci_configure_relaxed_ordering(dev);
        pci_configure_ltr(dev);
+       pci_configure_aspm_l1ss(dev);
        pci_configure_eetlp_prefix(dev);
        pci_configure_serr(dev);
 
@@ -2357,6 +2297,10 @@ static void pci_release_dev(struct device *dev)
        kfree(pci_dev);
 }
 
+static const struct device_type pci_dev_type = {
+       .groups = pci_dev_attr_groups,
+};
+
 struct pci_dev *pci_alloc_dev(struct pci_bus *bus)
 {
        struct pci_dev *dev;
index d797df6e5f3e917d08dfce4e40f594e322a5782e..bf4833221816d492d4adca02d508d33a74879a92 100644 (file)
@@ -3765,6 +3765,14 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x003e, quirk_no_bus_reset);
  */
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_CAVIUM, 0xa100, quirk_no_bus_reset);
 
+/*
+ * Apparently the LSI / Agere FW643 can't recover after a Secondary Bus
+ * Reset and requires a power-off or suspend/resume and rescan.  Prevent
+ * use of that reset.
+ */
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATT, 0x5900, quirk_no_bus_reset);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATT, 0x5901, quirk_no_bus_reset);
+
 /*
  * Some TI KeyStone C667X devices do not support bus/hot reset.  The PCIESS
  * automatically disables LTSSM when Secondary Bus Reset is received and
@@ -5527,6 +5535,7 @@ static void quirk_no_ext_tags(struct pci_dev *pdev)
 
        pci_walk_bus(bridge->bus, pci_configure_extended_tags, NULL);
 }
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_3WARE, 0x1004, quirk_no_ext_tags);
 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0132, quirk_no_ext_tags);
 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0140, quirk_no_ext_tags);
 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0141, quirk_no_ext_tags);
@@ -6225,6 +6234,8 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9a2b, dpc_log_size);
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9a2d, dpc_log_size);
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9a2f, dpc_log_size);
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9a31, dpc_log_size);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0xa73f, dpc_log_size);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0xa76e, dpc_log_size);
 #endif
 
 /*
diff --git a/drivers/pci/setup-irq.c b/drivers/pci/setup-irq.c
deleted file mode 100644 (file)
index cc7d26b..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Support routines for initializing a PCI subsystem
- *
- * Extruded from code written by
- *      Dave Rusling (david.rusling@reo.mts.dec.com)
- *      David Mosberger (davidm@cs.arizona.edu)
- *     David Miller (davem@redhat.com)
- */
-
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/cache.h>
-#include "pci.h"
-
-void pci_assign_irq(struct pci_dev *dev)
-{
-       u8 pin;
-       u8 slot = -1;
-       int irq = 0;
-       struct pci_host_bridge *hbrg = pci_find_host_bridge(dev->bus);
-
-       if (!(hbrg->map_irq)) {
-               pci_dbg(dev, "runtime IRQ mapping not provided by arch\n");
-               return;
-       }
-
-       /*
-        * If this device is not on the primary bus, we need to figure out
-        * which interrupt pin it will come in on. We know which slot it
-        * will come in on because that slot is where the bridge is. Each
-        * time the interrupt line passes through a PCI-PCI bridge we must
-        * apply the swizzle function.
-        */
-       pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
-       /* Cope with illegal. */
-       if (pin > 4)
-               pin = 1;
-
-       if (pin) {
-               /* Follow the chain of bridges, swizzling as we go. */
-               if (hbrg->swizzle_irq)
-                       slot = (*(hbrg->swizzle_irq))(dev, &pin);
-
-               /*
-                * If a swizzling function is not used, map_irq() must
-                * ignore slot.
-                */
-               irq = (*(hbrg->map_irq))(dev, slot, pin);
-               if (irq == -1)
-                       irq = 0;
-       }
-       dev->irq = irq;
-
-       pci_dbg(dev, "assign IRQ: got %d\n", dev->irq);
-
-       /*
-        * Always tell the device, so the driver knows what is the real IRQ
-        * to use; the device does not use it.
-        */
-       pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
-}
index 1804794d0e686f22febe508c58aa340f03eecd23..5a4adf6c04cf89eb06fb649656bfa3be32407248 100644 (file)
@@ -1672,7 +1672,7 @@ static int switchtec_pci_probe(struct pci_dev *pdev,
        rc = switchtec_init_isr(stdev);
        if (rc) {
                dev_err(&stdev->dev, "failed to init isr.\n");
-               goto err_put;
+               goto err_exit_pci;
        }
 
        iowrite32(SWITCHTEC_EVENT_CLEAR |
@@ -1693,6 +1693,8 @@ static int switchtec_pci_probe(struct pci_dev *pdev,
 
 err_devadd:
        stdev_kill(stdev);
+err_exit_pci:
+       switchtec_exit_pci(stdev);
 err_put:
        ida_free(&switchtec_minor_ida, MINOR(stdev->dev.devt));
        put_device(&stdev->dev);
index ae0fae70d4bd2c15a7109ba89dcfd5974177a930..4b97f38f3fcf22faffb00a2839b306453a453da4 100644 (file)
 
 struct pci_dev;
 
-struct aer_header_log_regs {
-       u32 dw0;
-       u32 dw1;
-       u32 dw2;
-       u32 dw3;
+struct pcie_tlp_log {
+       u32 dw[4];
 };
 
 struct aer_capability_regs {
@@ -33,13 +30,15 @@ struct aer_capability_regs {
        u32 cor_status;
        u32 cor_mask;
        u32 cap_control;
-       struct aer_header_log_regs header_log;
+       struct pcie_tlp_log header_log;
        u32 root_command;
        u32 root_status;
        u16 cor_err_source;
        u16 uncor_err_source;
 };
 
+int pcie_read_tlp_log(struct pci_dev *dev, int where, struct pcie_tlp_log *log);
+
 #if defined(CONFIG_PCIEAER)
 int pci_aer_clear_nonfatal_status(struct pci_dev *dev);
 int pcie_aer_is_native(struct pci_dev *dev);
index 40ea18f5aa029ef5bebc3d4a56ae3e061afa4a28..cc2f70d061c83b551af24c866312147a09cdf820 100644 (file)
@@ -145,6 +145,37 @@ struct pci_epc {
        unsigned long                   function_num_map;
 };
 
+/**
+ * @BAR_PROGRAMMABLE: The BAR mask can be configured by the EPC.
+ * @BAR_FIXED: The BAR mask is fixed by the hardware.
+ * @BAR_RESERVED: The BAR should not be touched by an EPF driver.
+ */
+enum pci_epc_bar_type {
+       BAR_PROGRAMMABLE = 0,
+       BAR_FIXED,
+       BAR_RESERVED,
+};
+
+/**
+ * struct pci_epc_bar_desc - hardware description for a BAR
+ * @type: the type of the BAR
+ * @fixed_size: the fixed size, only applicable if type is BAR_FIXED_MASK.
+ * @only_64bit: if true, an EPF driver is not allowed to choose if this BAR
+ *             should be configured as 32-bit or 64-bit, the EPF driver must
+ *             configure this BAR as 64-bit. Additionally, the BAR succeeding
+ *             this BAR must be set to type BAR_RESERVED.
+ *
+ *             only_64bit should not be set on a BAR of type BAR_RESERVED.
+ *             (If BARx is a 64-bit BAR that an EPF driver is not allowed to
+ *             touch, then both BARx and BARx+1 must be set to type
+ *             BAR_RESERVED.)
+ */
+struct pci_epc_bar_desc {
+       enum pci_epc_bar_type type;
+       u64 fixed_size;
+       bool only_64bit;
+};
+
 /**
  * struct pci_epc_features - features supported by a EPC device per function
  * @linkup_notifier: indicate if the EPC device can notify EPF driver on link up
@@ -152,9 +183,7 @@ struct pci_epc {
  *                     for initialization
  * @msi_capable: indicate if the endpoint function has MSI capability
  * @msix_capable: indicate if the endpoint function has MSI-X capability
- * @reserved_bar: bitmap to indicate reserved BAR unavailable to function driver
- * @bar_fixed_64bit: bitmap to indicate fixed 64bit BARs
- * @bar_fixed_size: Array specifying the size supported by each BAR
+ * @bar: array specifying the hardware description for each BAR
  * @align: alignment size required for BAR buffer allocation
  */
 struct pci_epc_features {
@@ -162,9 +191,7 @@ struct pci_epc_features {
        unsigned int    core_init_notifier : 1;
        unsigned int    msi_capable : 1;
        unsigned int    msix_capable : 1;
-       u8      reserved_bar;
-       u8      bar_fixed_64bit;
-       u64     bar_fixed_size[PCI_STD_NUM_BARS];
+       struct  pci_epc_bar_desc bar[PCI_STD_NUM_BARS];
        size_t  align;
 };
 
index 77b146e0f6727e2e8b9820b90b16584714063044..adee6a1b35db70e50fa2b95bda6a0fb3632e4f75 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/pci.h>
 
 struct pci_epf;
+struct pci_epc_features;
 enum pci_epc_interface_type;
 
 enum pci_barno {
@@ -216,7 +217,8 @@ int __pci_epf_register_driver(struct pci_epf_driver *driver,
                              struct module *owner);
 void pci_epf_unregister_driver(struct pci_epf_driver *driver);
 void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar,
-                         size_t align, enum pci_epc_interface_type type);
+                         const struct pci_epc_features *epc_features,
+                         enum pci_epc_interface_type type);
 void pci_epf_free_space(struct pci_epf *epf, void *addr, enum pci_barno bar,
                        enum pci_epc_interface_type type);
 int pci_epf_bind(struct pci_epf *epf);
index add9368e6314b9d7038a651af3f8e1b9e08d7ffa..6967ae7b41154e395d96e50a8524a11289559aa9 100644 (file)
@@ -390,9 +390,9 @@ struct pci_dev {
        unsigned int    d3hot_delay;    /* D3hot->D0 transition time in ms */
        unsigned int    d3cold_delay;   /* D3cold->D0 transition time in ms */
 
+       u16             l1ss;           /* L1SS Capability pointer */
 #ifdef CONFIG_PCIEASPM
        struct pcie_link_state  *link_state;    /* ASPM link state */
-       u16             l1ss;           /* L1SS Capability pointer */
        unsigned int    ltr_path:1;     /* Latency Tolerance Reporting
                                           supported from root to here */
 #endif
index cbd3ddd7c33d4d12326bafbc3c33c60c6317358e..c011ea236e9b7fe0fd403262214f223334a7adb0 100644 (file)
@@ -300,7 +300,7 @@ TRACE_EVENT(aer_event,
                 const u32 status,
                 const u8 severity,
                 const u8 tlp_header_valid,
-                struct aer_header_log_regs *tlp),
+                struct pcie_tlp_log *tlp),
 
        TP_ARGS(dev_name, status, severity, tlp_header_valid, tlp),
 
@@ -318,10 +318,10 @@ TRACE_EVENT(aer_event,
                __entry->severity       = severity;
                __entry->tlp_header_valid = tlp_header_valid;
                if (tlp_header_valid) {
-                       __entry->tlp_header[0] = tlp->dw0;
-                       __entry->tlp_header[1] = tlp->dw1;
-                       __entry->tlp_header[2] = tlp->dw2;
-                       __entry->tlp_header[3] = tlp->dw3;
+                       __entry->tlp_header[0] = tlp->dw[0];
+                       __entry->tlp_header[1] = tlp->dw[1];
+                       __entry->tlp_header[2] = tlp->dw[2];
+                       __entry->tlp_header[3] = tlp->dw[3];
                }
        ),
 
index 5ddda7c2ed9b3387375fa54ecec6b539f921d951..4557bb8a5256516e95019a5dc683d1e0617749aa 100644 (file)
@@ -70,9 +70,6 @@ source "lib/math/Kconfig"
 config NO_GENERIC_PCI_IOPORT_MAP
        bool
 
-config GENERIC_PCI_IOMAP
-       bool
-
 config GENERIC_IOMAP
        bool
        select GENERIC_PCI_IOMAP
index 6b09731d8e6195603aab99a3fd3f5dc56331f567..0800289ec6c52e78530cc59c5ab414d007d74749 100644 (file)
@@ -153,7 +153,6 @@ CFLAGS_debug_info.o += $(call cc-option, -femit-struct-debug-detailed=any)
 obj-y += math/ crypto/
 
 obj-$(CONFIG_GENERIC_IOMAP) += iomap.o
-obj-$(CONFIG_GENERIC_PCI_IOMAP) += pci_iomap.o
 obj-$(CONFIG_HAS_IOMEM) += iomap_copy.o devres.o
 obj-$(CONFIG_CHECK_SIGNATURE) += check_signature.o
 obj-$(CONFIG_DEBUG_LOCKING_API_SELFTESTS) += locking-selftest.o
index c44f104b58d58178555525919e9a4059987f49c1..fe0c63caeb6892132ea208529715b71176c9ea26 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
+#include <linux/device.h>
 #include <linux/err.h>
-#include <linux/pci.h>
 #include <linux/io.h>
 #include <linux/gfp.h>
 #include <linux/export.h>
@@ -311,212 +311,6 @@ void devm_ioport_unmap(struct device *dev, void __iomem *addr)
 EXPORT_SYMBOL(devm_ioport_unmap);
 #endif /* CONFIG_HAS_IOPORT_MAP */
 
-#ifdef CONFIG_PCI
-/*
- * PCI iomap devres
- */
-#define PCIM_IOMAP_MAX PCI_STD_NUM_BARS
-
-struct pcim_iomap_devres {
-       void __iomem *table[PCIM_IOMAP_MAX];
-};
-
-static void pcim_iomap_release(struct device *gendev, void *res)
-{
-       struct pci_dev *dev = to_pci_dev(gendev);
-       struct pcim_iomap_devres *this = res;
-       int i;
-
-       for (i = 0; i < PCIM_IOMAP_MAX; i++)
-               if (this->table[i])
-                       pci_iounmap(dev, this->table[i]);
-}
-
-/**
- * pcim_iomap_table - access iomap allocation table
- * @pdev: PCI device to access iomap table for
- *
- * Access iomap allocation table for @dev.  If iomap table doesn't
- * exist and @pdev is managed, it will be allocated.  All iomaps
- * recorded in the iomap table are automatically unmapped on driver
- * detach.
- *
- * This function might sleep when the table is first allocated but can
- * be safely called without context and guaranteed to succeed once
- * allocated.
- */
-void __iomem * const *pcim_iomap_table(struct pci_dev *pdev)
-{
-       struct pcim_iomap_devres *dr, *new_dr;
-
-       dr = devres_find(&pdev->dev, pcim_iomap_release, NULL, NULL);
-       if (dr)
-               return dr->table;
-
-       new_dr = devres_alloc_node(pcim_iomap_release, sizeof(*new_dr), GFP_KERNEL,
-                                  dev_to_node(&pdev->dev));
-       if (!new_dr)
-               return NULL;
-       dr = devres_get(&pdev->dev, new_dr, NULL, NULL);
-       return dr->table;
-}
-EXPORT_SYMBOL(pcim_iomap_table);
-
-/**
- * pcim_iomap - Managed pcim_iomap()
- * @pdev: PCI device to iomap for
- * @bar: BAR to iomap
- * @maxlen: Maximum length of iomap
- *
- * Managed pci_iomap().  Map is automatically unmapped on driver
- * detach.
- */
-void __iomem *pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen)
-{
-       void __iomem **tbl;
-
-       BUG_ON(bar >= PCIM_IOMAP_MAX);
-
-       tbl = (void __iomem **)pcim_iomap_table(pdev);
-       if (!tbl || tbl[bar])   /* duplicate mappings not allowed */
-               return NULL;
-
-       tbl[bar] = pci_iomap(pdev, bar, maxlen);
-       return tbl[bar];
-}
-EXPORT_SYMBOL(pcim_iomap);
-
-/**
- * pcim_iounmap - Managed pci_iounmap()
- * @pdev: PCI device to iounmap for
- * @addr: Address to unmap
- *
- * Managed pci_iounmap().  @addr must have been mapped using pcim_iomap().
- */
-void pcim_iounmap(struct pci_dev *pdev, void __iomem *addr)
-{
-       void __iomem **tbl;
-       int i;
-
-       pci_iounmap(pdev, addr);
-
-       tbl = (void __iomem **)pcim_iomap_table(pdev);
-       BUG_ON(!tbl);
-
-       for (i = 0; i < PCIM_IOMAP_MAX; i++)
-               if (tbl[i] == addr) {
-                       tbl[i] = NULL;
-                       return;
-               }
-       WARN_ON(1);
-}
-EXPORT_SYMBOL(pcim_iounmap);
-
-/**
- * pcim_iomap_regions - Request and iomap PCI BARs
- * @pdev: PCI device to map IO resources for
- * @mask: Mask of BARs to request and iomap
- * @name: Name used when requesting regions
- *
- * Request and iomap regions specified by @mask.
- */
-int pcim_iomap_regions(struct pci_dev *pdev, int mask, const char *name)
-{
-       void __iomem * const *iomap;
-       int i, rc;
-
-       iomap = pcim_iomap_table(pdev);
-       if (!iomap)
-               return -ENOMEM;
-
-       for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
-               unsigned long len;
-
-               if (!(mask & (1 << i)))
-                       continue;
-
-               rc = -EINVAL;
-               len = pci_resource_len(pdev, i);
-               if (!len)
-                       goto err_inval;
-
-               rc = pci_request_region(pdev, i, name);
-               if (rc)
-                       goto err_inval;
-
-               rc = -ENOMEM;
-               if (!pcim_iomap(pdev, i, 0))
-                       goto err_region;
-       }
-
-       return 0;
-
- err_region:
-       pci_release_region(pdev, i);
- err_inval:
-       while (--i >= 0) {
-               if (!(mask & (1 << i)))
-                       continue;
-               pcim_iounmap(pdev, iomap[i]);
-               pci_release_region(pdev, i);
-       }
-
-       return rc;
-}
-EXPORT_SYMBOL(pcim_iomap_regions);
-
-/**
- * pcim_iomap_regions_request_all - Request all BARs and iomap specified ones
- * @pdev: PCI device to map IO resources for
- * @mask: Mask of BARs to iomap
- * @name: Name used when requesting regions
- *
- * Request all PCI BARs and iomap regions specified by @mask.
- */
-int pcim_iomap_regions_request_all(struct pci_dev *pdev, int mask,
-                                  const char *name)
-{
-       int request_mask = ((1 << 6) - 1) & ~mask;
-       int rc;
-
-       rc = pci_request_selected_regions(pdev, request_mask, name);
-       if (rc)
-               return rc;
-
-       rc = pcim_iomap_regions(pdev, mask, name);
-       if (rc)
-               pci_release_selected_regions(pdev, request_mask);
-       return rc;
-}
-EXPORT_SYMBOL(pcim_iomap_regions_request_all);
-
-/**
- * pcim_iounmap_regions - Unmap and release PCI BARs
- * @pdev: PCI device to map IO resources for
- * @mask: Mask of BARs to unmap and release
- *
- * Unmap and release regions specified by @mask.
- */
-void pcim_iounmap_regions(struct pci_dev *pdev, int mask)
-{
-       void __iomem * const *iomap;
-       int i;
-
-       iomap = pcim_iomap_table(pdev);
-       if (!iomap)
-               return;
-
-       for (i = 0; i < PCIM_IOMAP_MAX; i++) {
-               if (!(mask & (1 << i)))
-                       continue;
-
-               pcim_iounmap(pdev, iomap[i]);
-               pci_release_region(pdev, i);
-       }
-}
-EXPORT_SYMBOL(pcim_iounmap_regions);
-#endif /* CONFIG_PCI */
-
 static void devm_arch_phys_ac_add_release(struct device *dev, void *res)
 {
        arch_phys_wc_del(*((int *)res));