Browse Source

Merge branch 'for-linus'

* for-linus:
  PCI: Fix is_added/is_busmaster race condition
  PCI: mobiveil: Avoid integer overflow in IB_WIN_SIZE
  PCI/AER: Work around use-after-free in pcie_do_fatal_recovery()
  PCI: v3-semi: Fix I/O space page leak
  PCI: mediatek: Fix I/O space page leak
  PCI: faraday: Fix I/O space page leak
  PCI: aardvark: Fix I/O space page leak
  PCI: designware: Fix I/O space page leak
  PCI: versatile: Fix I/O space page leak
  PCI: xgene: Fix I/O space page leak
  PCI: OF: Fix I/O space page leak
  PCI: endpoint: Fix NULL pointer dereference error when CONFIGFS is disabled
  PCI: hv: Disable/enable IRQs rather than BH in hv_compose_msi_msg()
  nfp: stop limiting VFs to 0
  PCI/IOV: Reset total_VFs limit after detaching PF driver
  PCI: faraday: Add missing of_node_put()
  PCI: xilinx-nwl: Add missing of_node_put()
  PCI: xilinx: Add missing of_node_put()
  PCI: endpoint: Use after free in pci_epf_unregister_driver()
  PCI: controller: dwc: Do not let PCIE_DW_PLAT_HOST default to yes
  PCI: rcar: Clean up PHY init on failure
  PCI: rcar: Shut the PHY down in failpath
  PCI: controller: Move PCI_DOMAINS selection to arch Kconfig
  PCI: Initialize endpoint library before controllers
  PCI: shpchp: Manage SHPC unconditionally on non-ACPI systems
Bjorn Helgaas 7 years ago
parent
commit
af863d18a1

+ 7 - 1
arch/arm/Kconfig

@@ -1245,8 +1245,14 @@ config PCI
 	  VESA. If you have PCI, say Y, otherwise N.
 	  VESA. If you have PCI, say Y, otherwise N.
 
 
 config PCI_DOMAINS
 config PCI_DOMAINS
-	bool
+	bool "Support for multiple PCI domains"
 	depends on PCI
 	depends on PCI
+	help
+	  Enable PCI domains kernel management. Say Y if your machine
+	  has a PCI bus hierarchy that requires more than one PCI
+	  domain (aka segment) to be correctly managed. Say N otherwise.
+
+	  If you don't know what to do here, say N.
 
 
 config PCI_DOMAINS_GENERIC
 config PCI_DOMAINS_GENERIC
 	def_bool PCI_DOMAINS
 	def_bool PCI_DOMAINS

+ 1 - 0
arch/arm/mach-bcm/Kconfig

@@ -20,6 +20,7 @@ config ARCH_BCM_IPROC
 	select GPIOLIB
 	select GPIOLIB
 	select ARM_AMBA
 	select ARM_AMBA
 	select PINCTRL
 	select PINCTRL
+	select PCI_DOMAINS if PCI
 	help
 	help
 	  This enables support for systems based on Broadcom IPROC architected SoCs.
 	  This enables support for systems based on Broadcom IPROC architected SoCs.
 	  The IPROC complex contains one or more ARM CPUs along with common
 	  The IPROC complex contains one or more ARM CPUs along with common

+ 1 - 0
arch/arm/mach-socfpga/Kconfig

@@ -10,6 +10,7 @@ menuconfig ARCH_SOCFPGA
 	select HAVE_ARM_SCU
 	select HAVE_ARM_SCU
 	select HAVE_ARM_TWD if SMP
 	select HAVE_ARM_TWD if SMP
 	select MFD_SYSCON
 	select MFD_SYSCON
+	select PCI_DOMAINS if PCI
 
 
 if ARCH_SOCFPGA
 if ARCH_SOCFPGA
 config SOCFPGA_SUSPEND
 config SOCFPGA_SUSPEND

+ 3 - 1
arch/powerpc/kernel/pci-common.c

@@ -42,6 +42,8 @@
 #include <asm/ppc-pci.h>
 #include <asm/ppc-pci.h>
 #include <asm/eeh.h>
 #include <asm/eeh.h>
 
 
+#include "../../../drivers/pci/pci.h"
+
 /* hose_spinlock protects accesses to the the phb_bitmap. */
 /* hose_spinlock protects accesses to the the phb_bitmap. */
 static DEFINE_SPINLOCK(hose_spinlock);
 static DEFINE_SPINLOCK(hose_spinlock);
 LIST_HEAD(hose_list);
 LIST_HEAD(hose_list);
@@ -1014,7 +1016,7 @@ void pcibios_setup_bus_devices(struct pci_bus *bus)
 		/* Cardbus can call us to add new devices to a bus, so ignore
 		/* Cardbus can call us to add new devices to a bus, so ignore
 		 * those who are already fully discovered
 		 * those who are already fully discovered
 		 */
 		 */
-		if (dev->is_added)
+		if (pci_dev_is_added(dev))
 			continue;
 			continue;
 
 
 		pcibios_setup_device(dev);
 		pcibios_setup_device(dev);

+ 2 - 1
arch/powerpc/platforms/powernv/pci-ioda.c

@@ -46,6 +46,7 @@
 
 
 #include "powernv.h"
 #include "powernv.h"
 #include "pci.h"
 #include "pci.h"
+#include "../../../../drivers/pci/pci.h"
 
 
 #define PNV_IODA1_M64_NUM	16	/* Number of M64 BARs	*/
 #define PNV_IODA1_M64_NUM	16	/* Number of M64 BARs	*/
 #define PNV_IODA1_M64_SEGS	8	/* Segments per M64 BAR	*/
 #define PNV_IODA1_M64_SEGS	8	/* Segments per M64 BAR	*/
@@ -3138,7 +3139,7 @@ static void pnv_pci_ioda_fixup_iov_resources(struct pci_dev *pdev)
 	struct pci_dn *pdn;
 	struct pci_dn *pdn;
 	int mul, total_vfs;
 	int mul, total_vfs;
 
 
-	if (!pdev->is_physfn || pdev->is_added)
+	if (!pdev->is_physfn || pci_dev_is_added(pdev))
 		return;
 		return;
 
 
 	pdn = pci_get_pdn(pdev);
 	pdn = pci_get_pdn(pdev);

+ 2 - 1
arch/powerpc/platforms/pseries/setup.c

@@ -71,6 +71,7 @@
 #include <asm/security_features.h>
 #include <asm/security_features.h>
 
 
 #include "pseries.h"
 #include "pseries.h"
+#include "../../../../drivers/pci/pci.h"
 
 
 int CMO_PrPSP = -1;
 int CMO_PrPSP = -1;
 int CMO_SecPSP = -1;
 int CMO_SecPSP = -1;
@@ -664,7 +665,7 @@ static void pseries_pci_fixup_iov_resources(struct pci_dev *pdev)
 	const int *indexes;
 	const int *indexes;
 	struct device_node *dn = pci_device_to_OF_node(pdev);
 	struct device_node *dn = pci_device_to_OF_node(pdev);
 
 
-	if (!pdev->is_physfn || pdev->is_added)
+	if (!pdev->is_physfn || pci_dev_is_added(pdev))
 		return;
 		return;
 	/*Firmware must support open sriov otherwise dont configure*/
 	/*Firmware must support open sriov otherwise dont configure*/
 	indexes = of_get_property(dn, "ibm,open-sriov-vf-bar-info", NULL);
 	indexes = of_get_property(dn, "ibm,open-sriov-vf-bar-info", NULL);

+ 1 - 5
drivers/net/ethernet/netronome/nfp/nfp_main.c

@@ -240,7 +240,6 @@ static int nfp_pcie_sriov_read_nfd_limit(struct nfp_pf *pf)
 		return pci_sriov_set_totalvfs(pf->pdev, pf->limit_vfs);
 		return pci_sriov_set_totalvfs(pf->pdev, pf->limit_vfs);
 
 
 	pf->limit_vfs = ~0;
 	pf->limit_vfs = ~0;
-	pci_sriov_set_totalvfs(pf->pdev, 0); /* 0 is unset */
 	/* Allow any setting for backwards compatibility if symbol not found */
 	/* Allow any setting for backwards compatibility if symbol not found */
 	if (err == -ENOENT)
 	if (err == -ENOENT)
 		return 0;
 		return 0;
@@ -668,7 +667,7 @@ static int nfp_pci_probe(struct pci_dev *pdev,
 
 
 	err = nfp_net_pci_probe(pf);
 	err = nfp_net_pci_probe(pf);
 	if (err)
 	if (err)
-		goto err_sriov_unlimit;
+		goto err_fw_unload;
 
 
 	err = nfp_hwmon_register(pf);
 	err = nfp_hwmon_register(pf);
 	if (err) {
 	if (err) {
@@ -680,8 +679,6 @@ static int nfp_pci_probe(struct pci_dev *pdev,
 
 
 err_net_remove:
 err_net_remove:
 	nfp_net_pci_remove(pf);
 	nfp_net_pci_remove(pf);
-err_sriov_unlimit:
-	pci_sriov_set_totalvfs(pf->pdev, 0);
 err_fw_unload:
 err_fw_unload:
 	kfree(pf->rtbl);
 	kfree(pf->rtbl);
 	nfp_mip_close(pf->mip);
 	nfp_mip_close(pf->mip);
@@ -715,7 +712,6 @@ static void nfp_pci_remove(struct pci_dev *pdev)
 	nfp_hwmon_unregister(pf);
 	nfp_hwmon_unregister(pf);
 
 
 	nfp_pcie_sriov_disable(pdev);
 	nfp_pcie_sriov_disable(pdev);
-	pci_sriov_set_totalvfs(pf->pdev, 0);
 
 
 	nfp_net_pci_remove(pf);
 	nfp_net_pci_remove(pf);
 
 

+ 3 - 3
drivers/pci/Makefile

@@ -28,10 +28,10 @@ obj-$(CONFIG_PCI_PF_STUB)	+= pci-pf-stub.o
 obj-$(CONFIG_PCI_ECAM)		+= ecam.o
 obj-$(CONFIG_PCI_ECAM)		+= ecam.o
 obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += xen-pcifront.o
 obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += xen-pcifront.o
 
 
-obj-y				+= controller/
-obj-y				+= switch/
-
 # Endpoint library must be initialized before its users
 # Endpoint library must be initialized before its users
 obj-$(CONFIG_PCI_ENDPOINT)	+= endpoint/
 obj-$(CONFIG_PCI_ENDPOINT)	+= endpoint/
 
 
+obj-y				+= controller/
+obj-y				+= switch/
+
 ccflags-$(CONFIG_PCI_DEBUG) := -DDEBUG
 ccflags-$(CONFIG_PCI_DEBUG) := -DDEBUG

+ 3 - 3
drivers/pci/bus.c

@@ -330,7 +330,7 @@ void pci_bus_add_device(struct pci_dev *dev)
 		return;
 		return;
 	}
 	}
 
 
-	dev->is_added = 1;
+	pci_dev_assign_added(dev, true);
 }
 }
 EXPORT_SYMBOL_GPL(pci_bus_add_device);
 EXPORT_SYMBOL_GPL(pci_bus_add_device);
 
 
@@ -347,14 +347,14 @@ void pci_bus_add_devices(const struct pci_bus *bus)
 
 
 	list_for_each_entry(dev, &bus->devices, bus_list) {
 	list_for_each_entry(dev, &bus->devices, bus_list) {
 		/* Skip already-added devices */
 		/* Skip already-added devices */
-		if (dev->is_added)
+		if (pci_dev_is_added(dev))
 			continue;
 			continue;
 		pci_bus_add_device(dev);
 		pci_bus_add_device(dev);
 	}
 	}
 
 
 	list_for_each_entry(dev, &bus->devices, bus_list) {
 	list_for_each_entry(dev, &bus->devices, bus_list) {
 		/* Skip if device attach failed */
 		/* Skip if device attach failed */
-		if (!dev->is_added)
+		if (!pci_dev_is_added(dev))
 			continue;
 			continue;
 		child = dev->subordinate;
 		child = dev->subordinate;
 		if (child)
 		if (child)

+ 0 - 3
drivers/pci/controller/Kconfig

@@ -96,7 +96,6 @@ config PCI_HOST_GENERIC
 	depends on OF
 	depends on OF
 	select PCI_HOST_COMMON
 	select PCI_HOST_COMMON
 	select IRQ_DOMAIN
 	select IRQ_DOMAIN
-	select PCI_DOMAINS
 	help
 	help
 	  Say Y here if you want to support a simple generic PCI host
 	  Say Y here if you want to support a simple generic PCI host
 	  controller, such as the one emulated by kvmtool.
 	  controller, such as the one emulated by kvmtool.
@@ -138,7 +137,6 @@ config PCI_VERSATILE
 
 
 config PCIE_IPROC
 config PCIE_IPROC
 	tristate
 	tristate
-	select PCI_DOMAINS
 	help
 	help
 	  This enables the iProc PCIe core controller support for Broadcom's
 	  This enables the iProc PCIe core controller support for Broadcom's
 	  iProc family of SoCs. An appropriate bus interface driver needs
 	  iProc family of SoCs. An appropriate bus interface driver needs
@@ -176,7 +174,6 @@ config PCIE_IPROC_MSI
 config PCIE_ALTERA
 config PCIE_ALTERA
 	bool "Altera PCIe controller"
 	bool "Altera PCIe controller"
 	depends on ARM || NIOS2 || COMPILE_TEST
 	depends on ARM || NIOS2 || COMPILE_TEST
-	select PCI_DOMAINS
 	help
 	help
 	  Say Y here if you want to enable PCIe controller support on Altera
 	  Say Y here if you want to enable PCIe controller support on Altera
 	  FPGA.
 	  FPGA.

+ 0 - 1
drivers/pci/controller/dwc/Kconfig

@@ -58,7 +58,6 @@ config PCIE_DW_PLAT_HOST
 	depends on PCI && PCI_MSI_IRQ_DOMAIN
 	depends on PCI && PCI_MSI_IRQ_DOMAIN
 	select PCIE_DW_HOST
 	select PCIE_DW_HOST
 	select PCIE_DW_PLAT
 	select PCIE_DW_PLAT
-	default y
 	help
 	help
 	  Enables support for the PCIe controller in the Designware IP to
 	  Enables support for the PCIe controller in the Designware IP to
 	  work in host mode. There are two instances of PCIe controller in
 	  work in host mode. There are two instances of PCIe controller in

+ 2 - 1
drivers/pci/controller/dwc/pcie-designware-host.c

@@ -363,7 +363,8 @@ int dw_pcie_host_init(struct pcie_port *pp)
 	resource_list_for_each_entry_safe(win, tmp, &bridge->windows) {
 	resource_list_for_each_entry_safe(win, tmp, &bridge->windows) {
 		switch (resource_type(win->res)) {
 		switch (resource_type(win->res)) {
 		case IORESOURCE_IO:
 		case IORESOURCE_IO:
-			ret = pci_remap_iospace(win->res, pp->io_base);
+			ret = devm_pci_remap_iospace(dev, win->res,
+						     pp->io_base);
 			if (ret) {
 			if (ret) {
 				dev_warn(dev, "Error %d: failed to map resource %pR\n",
 				dev_warn(dev, "Error %d: failed to map resource %pR\n",
 					 ret, win->res);
 					 ret, win->res);

+ 1 - 1
drivers/pci/controller/pci-aardvark.c

@@ -849,7 +849,7 @@ static int advk_pcie_parse_request_of_pci_ranges(struct advk_pcie *pcie)
 					     0,	0xF8000000, 0,
 					     0,	0xF8000000, 0,
 					     lower_32_bits(res->start),
 					     lower_32_bits(res->start),
 					     OB_PCIE_IO);
 					     OB_PCIE_IO);
-			err = pci_remap_iospace(res, iobase);
+			err = devm_pci_remap_iospace(dev, res, iobase);
 			if (err) {
 			if (err) {
 				dev_warn(dev, "error %d: failed to map resource %pR\n",
 				dev_warn(dev, "error %d: failed to map resource %pR\n",
 					 err, res);
 					 err, res);

+ 3 - 1
drivers/pci/controller/pci-ftpci100.c

@@ -355,11 +355,13 @@ static int faraday_pci_setup_cascaded_irq(struct faraday_pci *p)
 	irq = of_irq_get(intc, 0);
 	irq = of_irq_get(intc, 0);
 	if (irq <= 0) {
 	if (irq <= 0) {
 		dev_err(p->dev, "failed to get parent IRQ\n");
 		dev_err(p->dev, "failed to get parent IRQ\n");
+		of_node_put(intc);
 		return irq ?: -EINVAL;
 		return irq ?: -EINVAL;
 	}
 	}
 
 
 	p->irqdomain = irq_domain_add_linear(intc, PCI_NUM_INTX,
 	p->irqdomain = irq_domain_add_linear(intc, PCI_NUM_INTX,
 					     &faraday_pci_irqdomain_ops, p);
 					     &faraday_pci_irqdomain_ops, p);
+	of_node_put(intc);
 	if (!p->irqdomain) {
 	if (!p->irqdomain) {
 		dev_err(p->dev, "failed to create Gemini PCI IRQ domain\n");
 		dev_err(p->dev, "failed to create Gemini PCI IRQ domain\n");
 		return -EINVAL;
 		return -EINVAL;
@@ -501,7 +503,7 @@ static int faraday_pci_probe(struct platform_device *pdev)
 				dev_err(dev, "illegal IO mem size\n");
 				dev_err(dev, "illegal IO mem size\n");
 				return -EINVAL;
 				return -EINVAL;
 			}
 			}
-			ret = pci_remap_iospace(io, io_base);
+			ret = devm_pci_remap_iospace(dev, io, io_base);
 			if (ret) {
 			if (ret) {
 				dev_warn(dev, "error %d: failed to map resource %pR\n",
 				dev_warn(dev, "error %d: failed to map resource %pR\n",
 					 ret, io);
 					 ret, io);

+ 5 - 3
drivers/pci/controller/pci-hyperv.c

@@ -1073,6 +1073,7 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
 	struct pci_bus *pbus;
 	struct pci_bus *pbus;
 	struct pci_dev *pdev;
 	struct pci_dev *pdev;
 	struct cpumask *dest;
 	struct cpumask *dest;
+	unsigned long flags;
 	struct compose_comp_ctxt comp;
 	struct compose_comp_ctxt comp;
 	struct tran_int_desc *int_desc;
 	struct tran_int_desc *int_desc;
 	struct {
 	struct {
@@ -1164,14 +1165,15 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
 		 * the channel callback directly when channel->target_cpu is
 		 * the channel callback directly when channel->target_cpu is
 		 * the current CPU. When the higher level interrupt code
 		 * the current CPU. When the higher level interrupt code
 		 * calls us with interrupt enabled, let's add the
 		 * calls us with interrupt enabled, let's add the
-		 * local_bh_disable()/enable() to avoid race.
+		 * local_irq_save()/restore() to avoid race:
+		 * hv_pci_onchannelcallback() can also run in tasklet.
 		 */
 		 */
-		local_bh_disable();
+		local_irq_save(flags);
 
 
 		if (hbus->hdev->channel->target_cpu == smp_processor_id())
 		if (hbus->hdev->channel->target_cpu == smp_processor_id())
 			hv_pci_onchannelcallback(hbus);
 			hv_pci_onchannelcallback(hbus);
 
 
-		local_bh_enable();
+		local_irq_restore(flags);
 
 
 		if (hpdev->state == hv_pcichild_ejecting) {
 		if (hpdev->state == hv_pcichild_ejecting) {
 			dev_err_once(&hbus->hdev->device,
 			dev_err_once(&hbus->hdev->device,

+ 1 - 1
drivers/pci/controller/pci-v3-semi.c

@@ -537,7 +537,7 @@ static int v3_pci_setup_resource(struct v3_pci *v3,
 		v3->io_bus_addr = io->start - win->offset;
 		v3->io_bus_addr = io->start - win->offset;
 		dev_dbg(dev, "I/O window %pR, bus addr %pap\n",
 		dev_dbg(dev, "I/O window %pR, bus addr %pap\n",
 			io, &v3->io_bus_addr);
 			io, &v3->io_bus_addr);
-		ret = pci_remap_iospace(io, io_base);
+		ret = devm_pci_remap_iospace(dev, io, io_base);
 		if (ret) {
 		if (ret) {
 			dev_warn(dev,
 			dev_warn(dev,
 				 "error %d: failed to map resource %pR\n",
 				 "error %d: failed to map resource %pR\n",

+ 1 - 1
drivers/pci/controller/pci-versatile.c

@@ -82,7 +82,7 @@ static int versatile_pci_parse_request_of_pci_ranges(struct device *dev,
 
 
 		switch (resource_type(res)) {
 		switch (resource_type(res)) {
 		case IORESOURCE_IO:
 		case IORESOURCE_IO:
-			err = pci_remap_iospace(res, iobase);
+			err = devm_pci_remap_iospace(dev, res, iobase);
 			if (err) {
 			if (err) {
 				dev_warn(dev, "error %d: failed to map resource %pR\n",
 				dev_warn(dev, "error %d: failed to map resource %pR\n",
 					 err, res);
 					 err, res);

+ 1 - 1
drivers/pci/controller/pci-xgene.c

@@ -423,7 +423,7 @@ static int xgene_pcie_map_ranges(struct xgene_pcie_port *port,
 		case IORESOURCE_IO:
 		case IORESOURCE_IO:
 			xgene_pcie_setup_ob_reg(port, res, OMR3BARL, io_base,
 			xgene_pcie_setup_ob_reg(port, res, OMR3BARL, io_base,
 						res->start - window->offset);
 						res->start - window->offset);
-			ret = pci_remap_iospace(res, io_base);
+			ret = devm_pci_remap_iospace(dev, res, io_base);
 			if (ret < 0)
 			if (ret < 0)
 				return ret;
 				return ret;
 			break;
 			break;

+ 1 - 1
drivers/pci/controller/pcie-mediatek.c

@@ -1109,7 +1109,7 @@ static int mtk_pcie_request_resources(struct mtk_pcie *pcie)
 	if (err < 0)
 	if (err < 0)
 		return err;
 		return err;
 
 
-	pci_remap_iospace(&pcie->pio, pcie->io.start);
+	devm_pci_remap_iospace(dev, &pcie->pio, pcie->io.start);
 
 
 	return 0;
 	return 0;
 }
 }

+ 1 - 1
drivers/pci/controller/pcie-mobiveil.c

@@ -107,7 +107,7 @@
 #define CFG_WINDOW_TYPE	0
 #define CFG_WINDOW_TYPE	0
 #define IO_WINDOW_TYPE		1
 #define IO_WINDOW_TYPE		1
 #define MEM_WINDOW_TYPE	2
 #define MEM_WINDOW_TYPE	2
-#define IB_WIN_SIZE		(256 * 1024 * 1024 * 1024)
+#define IB_WIN_SIZE		((u64)256 * 1024 * 1024 * 1024)
 #define MAX_PIO_WINDOWS	8
 #define MAX_PIO_WINDOWS	8
 
 
 /* Parameters for the waiting for link up routine */
 /* Parameters for the waiting for link up routine */

+ 13 - 3
drivers/pci/controller/pcie-rcar.c

@@ -680,7 +680,11 @@ static int rcar_pcie_phy_init_gen3(struct rcar_pcie *pcie)
 	if (err)
 	if (err)
 		return err;
 		return err;
 
 
-	return phy_power_on(pcie->phy);
+	err = phy_power_on(pcie->phy);
+	if (err)
+		phy_exit(pcie->phy);
+
+	return err;
 }
 }
 
 
 static int rcar_msi_alloc(struct rcar_msi *chip)
 static int rcar_msi_alloc(struct rcar_msi *chip)
@@ -1165,7 +1169,7 @@ static int rcar_pcie_probe(struct platform_device *pdev)
 	if (rcar_pcie_hw_init(pcie)) {
 	if (rcar_pcie_hw_init(pcie)) {
 		dev_info(dev, "PCIe link down\n");
 		dev_info(dev, "PCIe link down\n");
 		err = -ENODEV;
 		err = -ENODEV;
-		goto err_clk_disable;
+		goto err_phy_shutdown;
 	}
 	}
 
 
 	data = rcar_pci_read_reg(pcie, MACSR);
 	data = rcar_pci_read_reg(pcie, MACSR);
@@ -1177,7 +1181,7 @@ static int rcar_pcie_probe(struct platform_device *pdev)
 			dev_err(dev,
 			dev_err(dev,
 				"failed to enable MSI support: %d\n",
 				"failed to enable MSI support: %d\n",
 				err);
 				err);
-			goto err_clk_disable;
+			goto err_phy_shutdown;
 		}
 		}
 	}
 	}
 
 
@@ -1191,6 +1195,12 @@ err_msi_teardown:
 	if (IS_ENABLED(CONFIG_PCI_MSI))
 	if (IS_ENABLED(CONFIG_PCI_MSI))
 		rcar_pcie_teardown_msi(pcie);
 		rcar_pcie_teardown_msi(pcie);
 
 
+err_phy_shutdown:
+	if (pcie->phy) {
+		phy_power_off(pcie->phy);
+		phy_exit(pcie->phy);
+	}
+
 err_clk_disable:
 err_clk_disable:
 	clk_disable_unprepare(pcie->bus_clk);
 	clk_disable_unprepare(pcie->bus_clk);
 
 

+ 1 - 1
drivers/pci/controller/pcie-xilinx-nwl.c

@@ -559,7 +559,7 @@ static int nwl_pcie_init_irq_domain(struct nwl_pcie *pcie)
 							PCI_NUM_INTX,
 							PCI_NUM_INTX,
 							&legacy_domain_ops,
 							&legacy_domain_ops,
 							pcie);
 							pcie);
-
+	of_node_put(legacy_intc_node);
 	if (!pcie->legacy_irq_domain) {
 	if (!pcie->legacy_irq_domain) {
 		dev_err(dev, "failed to create IRQ domain\n");
 		dev_err(dev, "failed to create IRQ domain\n");
 		return -ENOMEM;
 		return -ENOMEM;

+ 1 - 0
drivers/pci/controller/pcie-xilinx.c

@@ -509,6 +509,7 @@ static int xilinx_pcie_init_irq_domain(struct xilinx_pcie_port *port)
 	port->leg_domain = irq_domain_add_linear(pcie_intc_node, PCI_NUM_INTX,
 	port->leg_domain = irq_domain_add_linear(pcie_intc_node, PCI_NUM_INTX,
 						 &intx_domain_ops,
 						 &intx_domain_ops,
 						 port);
 						 port);
+	of_node_put(pcie_intc_node);
 	if (!port->leg_domain) {
 	if (!port->leg_domain) {
 		dev_err(dev, "Failed to get a INTx IRQ domain\n");
 		dev_err(dev, "Failed to get a INTx IRQ domain\n");
 		return -ENODEV;
 		return -ENODEV;

+ 43 - 19
drivers/pci/endpoint/pci-epf-core.c

@@ -137,6 +137,20 @@ void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar)
 }
 }
 EXPORT_SYMBOL_GPL(pci_epf_alloc_space);
 EXPORT_SYMBOL_GPL(pci_epf_alloc_space);
 
 
+static void pci_epf_remove_cfs(struct pci_epf_driver *driver)
+{
+	struct config_group *group, *tmp;
+
+	if (!IS_ENABLED(CONFIG_PCI_ENDPOINT_CONFIGFS))
+		return;
+
+	mutex_lock(&pci_epf_mutex);
+	list_for_each_entry_safe(group, tmp, &driver->epf_group, group_entry)
+		pci_ep_cfs_remove_epf_group(group);
+	list_del(&driver->epf_group);
+	mutex_unlock(&pci_epf_mutex);
+}
+
 /**
 /**
  * pci_epf_unregister_driver() - unregister the PCI EPF driver
  * pci_epf_unregister_driver() - unregister the PCI EPF driver
  * @driver: the PCI EPF driver that has to be unregistered
  * @driver: the PCI EPF driver that has to be unregistered
@@ -145,17 +159,38 @@ EXPORT_SYMBOL_GPL(pci_epf_alloc_space);
  */
  */
 void pci_epf_unregister_driver(struct pci_epf_driver *driver)
 void pci_epf_unregister_driver(struct pci_epf_driver *driver)
 {
 {
-	struct config_group *group;
-
-	mutex_lock(&pci_epf_mutex);
-	list_for_each_entry(group, &driver->epf_group, group_entry)
-		pci_ep_cfs_remove_epf_group(group);
-	list_del(&driver->epf_group);
-	mutex_unlock(&pci_epf_mutex);
+	pci_epf_remove_cfs(driver);
 	driver_unregister(&driver->driver);
 	driver_unregister(&driver->driver);
 }
 }
 EXPORT_SYMBOL_GPL(pci_epf_unregister_driver);
 EXPORT_SYMBOL_GPL(pci_epf_unregister_driver);
 
 
+static int pci_epf_add_cfs(struct pci_epf_driver *driver)
+{
+	struct config_group *group;
+	const struct pci_epf_device_id *id;
+
+	if (!IS_ENABLED(CONFIG_PCI_ENDPOINT_CONFIGFS))
+		return 0;
+
+	INIT_LIST_HEAD(&driver->epf_group);
+
+	id = driver->id_table;
+	while (id->name[0]) {
+		group = pci_ep_cfs_add_epf_group(id->name);
+		if (IS_ERR(group)) {
+			pci_epf_remove_cfs(driver);
+			return PTR_ERR(group);
+		}
+
+		mutex_lock(&pci_epf_mutex);
+		list_add_tail(&group->group_entry, &driver->epf_group);
+		mutex_unlock(&pci_epf_mutex);
+		id++;
+	}
+
+	return 0;
+}
+
 /**
 /**
  * __pci_epf_register_driver() - register a new PCI EPF driver
  * __pci_epf_register_driver() - register a new PCI EPF driver
  * @driver: structure representing PCI EPF driver
  * @driver: structure representing PCI EPF driver
@@ -167,8 +202,6 @@ int __pci_epf_register_driver(struct pci_epf_driver *driver,
 			      struct module *owner)
 			      struct module *owner)
 {
 {
 	int ret;
 	int ret;
-	struct config_group *group;
-	const struct pci_epf_device_id *id;
 
 
 	if (!driver->ops)
 	if (!driver->ops)
 		return -EINVAL;
 		return -EINVAL;
@@ -183,16 +216,7 @@ int __pci_epf_register_driver(struct pci_epf_driver *driver,
 	if (ret)
 	if (ret)
 		return ret;
 		return ret;
 
 
-	INIT_LIST_HEAD(&driver->epf_group);
-
-	id = driver->id_table;
-	while (id->name[0]) {
-		group = pci_ep_cfs_add_epf_group(id->name);
-		mutex_lock(&pci_epf_mutex);
-		list_add_tail(&group->group_entry, &driver->epf_group);
-		mutex_unlock(&pci_epf_mutex);
-		id++;
-	}
+	pci_epf_add_cfs(driver);
 
 
 	return 0;
 	return 0;
 }
 }

+ 9 - 1
drivers/pci/hotplug/acpi_pcihp.c

@@ -7,7 +7,6 @@
  * All rights reserved.
  * All rights reserved.
  *
  *
  * Send feedback to <kristen.c.accardi@intel.com>
  * Send feedback to <kristen.c.accardi@intel.com>
- *
  */
  */
 
 
 #include <linux/module.h>
 #include <linux/module.h>
@@ -87,8 +86,17 @@ int acpi_get_hp_hw_control_from_firmware(struct pci_dev *pdev)
 		return 0;
 		return 0;
 
 
 	/* If _OSC exists, we should not evaluate OSHP */
 	/* If _OSC exists, we should not evaluate OSHP */
+
+	/*
+	 * If there's no ACPI host bridge (i.e., ACPI support is compiled
+	 * into the kernel but the hardware platform doesn't support ACPI),
+	 * there's nothing to do here.
+	 */
 	host = pci_find_host_bridge(pdev->bus);
 	host = pci_find_host_bridge(pdev->bus);
 	root = acpi_pci_find_root(ACPI_HANDLE(&host->dev));
 	root = acpi_pci_find_root(ACPI_HANDLE(&host->dev));
+	if (!root)
+		return 0;
+
 	if (root->osc_support_set)
 	if (root->osc_support_set)
 		goto no_control;
 		goto no_control;
 
 

+ 1 - 1
drivers/pci/hotplug/acpiphp_glue.c

@@ -509,7 +509,7 @@ static void enable_slot(struct acpiphp_slot *slot)
 
 
 	list_for_each_entry(dev, &bus->devices, bus_list) {
 	list_for_each_entry(dev, &bus->devices, bus_list) {
 		/* Assume that newly added devices are powered on already. */
 		/* Assume that newly added devices are powered on already. */
-		if (!dev->is_added)
+		if (!pci_dev_is_added(dev))
 			dev->current_state = PCI_D0;
 			dev->current_state = PCI_D0;
 	}
 	}
 
 

+ 16 - 0
drivers/pci/iov.c

@@ -574,6 +574,22 @@ void pci_iov_release(struct pci_dev *dev)
 		sriov_release(dev);
 		sriov_release(dev);
 }
 }
 
 
+/**
+ * pci_iov_remove - clean up SR-IOV state after PF driver is detached
+ * @dev: the PCI device
+ */
+void pci_iov_remove(struct pci_dev *dev)
+{
+	struct pci_sriov *iov = dev->sriov;
+
+	if (!dev->is_physfn)
+		return;
+
+	iov->driver_max_VFs = iov->total_VFs;
+	if (iov->num_VFs)
+		pci_warn(dev, "driver left SR-IOV enabled after remove\n");
+}
+
 /**
 /**
  * pci_iov_update_resource - update a VF BAR
  * pci_iov_update_resource - update a VF BAR
  * @dev: the PCI device
  * @dev: the PCI device

+ 1 - 1
drivers/pci/of.c

@@ -612,7 +612,7 @@ int pci_parse_request_of_pci_ranges(struct device *dev,
 
 
 		switch (resource_type(res)) {
 		switch (resource_type(res)) {
 		case IORESOURCE_IO:
 		case IORESOURCE_IO:
-			err = pci_remap_iospace(res, iobase);
+			err = devm_pci_remap_iospace(dev, res, iobase);
 			if (err) {
 			if (err) {
 				dev_warn(dev, "error %d: failed to map resource %pR\n",
 				dev_warn(dev, "error %d: failed to map resource %pR\n",
 					 err, res);
 					 err, res);

+ 1 - 0
drivers/pci/pci-driver.c

@@ -445,6 +445,7 @@ static int pci_device_remove(struct device *dev)
 		}
 		}
 		pcibios_free_irq(pci_dev);
 		pcibios_free_irq(pci_dev);
 		pci_dev->driver = NULL;
 		pci_dev->driver = NULL;
+		pci_iov_remove(pci_dev);
 	}
 	}
 
 
 	/* Undo the runtime PM settings in local_pci_probe() */
 	/* Undo the runtime PM settings in local_pci_probe() */

+ 38 - 0
drivers/pci/pci.c

@@ -3579,6 +3579,44 @@ void pci_unmap_iospace(struct resource *res)
 }
 }
 EXPORT_SYMBOL(pci_unmap_iospace);
 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()
  * devm_pci_remap_cfgspace - Managed pci_remap_cfgspace()
  * @dev: Generic device to remap IO address for
  * @dev: Generic device to remap IO address for

+ 15 - 0
drivers/pci/pci.h

@@ -288,6 +288,7 @@ struct pci_sriov {
 
 
 /* pci_dev priv_flags */
 /* pci_dev priv_flags */
 #define PCI_DEV_DISCONNECTED 0
 #define PCI_DEV_DISCONNECTED 0
+#define PCI_DEV_ADDED 1
 
 
 static inline int pci_dev_set_disconnected(struct pci_dev *dev, void *unused)
 static inline int pci_dev_set_disconnected(struct pci_dev *dev, void *unused)
 {
 {
@@ -300,6 +301,16 @@ static inline bool pci_dev_is_disconnected(const struct pci_dev *dev)
 	return test_bit(PCI_DEV_DISCONNECTED, &dev->priv_flags);
 	return test_bit(PCI_DEV_DISCONNECTED, &dev->priv_flags);
 }
 }
 
 
+static inline void pci_dev_assign_added(struct pci_dev *dev, bool added)
+{
+	assign_bit(PCI_DEV_ADDED, &dev->priv_flags, added);
+}
+
+static inline bool pci_dev_is_added(const struct pci_dev *dev)
+{
+	return test_bit(PCI_DEV_ADDED, &dev->priv_flags);
+}
+
 #ifdef CONFIG_PCI_ATS
 #ifdef CONFIG_PCI_ATS
 void pci_restore_ats_state(struct pci_dev *dev);
 void pci_restore_ats_state(struct pci_dev *dev);
 #else
 #else
@@ -311,6 +322,7 @@ static inline void pci_restore_ats_state(struct pci_dev *dev)
 #ifdef CONFIG_PCI_IOV
 #ifdef CONFIG_PCI_IOV
 int pci_iov_init(struct pci_dev *dev);
 int pci_iov_init(struct pci_dev *dev);
 void pci_iov_release(struct pci_dev *dev);
 void pci_iov_release(struct pci_dev *dev);
+void pci_iov_remove(struct pci_dev *dev);
 void pci_iov_update_resource(struct pci_dev *dev, int resno);
 void pci_iov_update_resource(struct pci_dev *dev, int resno);
 resource_size_t pci_sriov_resource_alignment(struct pci_dev *dev, int resno);
 resource_size_t pci_sriov_resource_alignment(struct pci_dev *dev, int resno);
 void pci_restore_iov_state(struct pci_dev *dev);
 void pci_restore_iov_state(struct pci_dev *dev);
@@ -323,6 +335,9 @@ static inline int pci_iov_init(struct pci_dev *dev)
 }
 }
 static inline void pci_iov_release(struct pci_dev *dev)
 static inline void pci_iov_release(struct pci_dev *dev)
 
 
+{
+}
+static inline void pci_iov_remove(struct pci_dev *dev)
 {
 {
 }
 }
 static inline void pci_restore_iov_state(struct pci_dev *dev)
 static inline void pci_restore_iov_state(struct pci_dev *dev)

+ 2 - 0
drivers/pci/pcie/err.c

@@ -295,6 +295,7 @@ void pcie_do_fatal_recovery(struct pci_dev *dev, u32 service)
 
 
 	parent = udev->subordinate;
 	parent = udev->subordinate;
 	pci_lock_rescan_remove();
 	pci_lock_rescan_remove();
+	pci_dev_get(dev);
 	list_for_each_entry_safe_reverse(pdev, temp, &parent->devices,
 	list_for_each_entry_safe_reverse(pdev, temp, &parent->devices,
 					 bus_list) {
 					 bus_list) {
 		pci_dev_get(pdev);
 		pci_dev_get(pdev);
@@ -328,6 +329,7 @@ void pcie_do_fatal_recovery(struct pci_dev *dev, u32 service)
 		pci_info(dev, "Device recovery from fatal error failed\n");
 		pci_info(dev, "Device recovery from fatal error failed\n");
 	}
 	}
 
 
+	pci_dev_put(dev);
 	pci_unlock_rescan_remove();
 	pci_unlock_rescan_remove();
 }
 }
 
 

+ 2 - 2
drivers/pci/probe.c

@@ -2433,13 +2433,13 @@ int pci_scan_slot(struct pci_bus *bus, int devfn)
 	dev = pci_scan_single_device(bus, devfn);
 	dev = pci_scan_single_device(bus, devfn);
 	if (!dev)
 	if (!dev)
 		return 0;
 		return 0;
-	if (!dev->is_added)
+	if (!pci_dev_is_added(dev))
 		nr++;
 		nr++;
 
 
 	for (fn = next_fn(bus, dev, 0); fn > 0; fn = next_fn(bus, dev, fn)) {
 	for (fn = next_fn(bus, dev, 0); fn > 0; fn = next_fn(bus, dev, fn)) {
 		dev = pci_scan_single_device(bus, devfn + fn);
 		dev = pci_scan_single_device(bus, devfn + fn);
 		if (dev) {
 		if (dev) {
-			if (!dev->is_added)
+			if (!pci_dev_is_added(dev))
 				nr++;
 				nr++;
 			dev->multifunction = 1;
 			dev->multifunction = 1;
 		}
 		}

+ 3 - 2
drivers/pci/remove.c

@@ -19,11 +19,12 @@ static void pci_stop_dev(struct pci_dev *dev)
 {
 {
 	pci_pme_active(dev, false);
 	pci_pme_active(dev, false);
 
 
-	if (dev->is_added) {
+	if (pci_dev_is_added(dev)) {
 		device_release_driver(&dev->dev);
 		device_release_driver(&dev->dev);
 		pci_proc_detach_device(dev);
 		pci_proc_detach_device(dev);
 		pci_remove_sysfs_dev_files(dev);
 		pci_remove_sysfs_dev_files(dev);
-		dev->is_added = 0;
+
+		pci_dev_assign_added(dev, false);
 	}
 	}
 
 
 	if (dev->bus->self)
 	if (dev->bus->self)

+ 2 - 1
include/linux/pci.h

@@ -368,7 +368,6 @@ struct pci_dev {
 	unsigned int	transparent:1;		/* Subtractive decode bridge */
 	unsigned int	transparent:1;		/* Subtractive decode bridge */
 	unsigned int	multifunction:1;	/* Multi-function device */
 	unsigned int	multifunction:1;	/* Multi-function device */
 
 
-	unsigned int	is_added:1;
 	unsigned int	is_busmaster:1;		/* Is busmaster */
 	unsigned int	is_busmaster:1;		/* Is busmaster */
 	unsigned int	no_msi:1;		/* May not use MSI */
 	unsigned int	no_msi:1;		/* May not use MSI */
 	unsigned int	no_64bit_msi:1; 	/* May only use 32-bit MSIs */
 	unsigned int	no_64bit_msi:1; 	/* May only use 32-bit MSIs */
@@ -1240,6 +1239,8 @@ int pci_register_io_range(struct fwnode_handle *fwnode, phys_addr_t addr,
 unsigned long pci_address_to_pio(phys_addr_t addr);
 unsigned long pci_address_to_pio(phys_addr_t addr);
 phys_addr_t pci_pio_to_address(unsigned long pio);
 phys_addr_t pci_pio_to_address(unsigned long pio);
 int pci_remap_iospace(const struct resource *res, phys_addr_t phys_addr);
 int pci_remap_iospace(const struct resource *res, phys_addr_t phys_addr);
+int devm_pci_remap_iospace(struct device *dev, const struct resource *res,
+			   phys_addr_t phys_addr);
 void pci_unmap_iospace(struct resource *res);
 void pci_unmap_iospace(struct resource *res);
 void __iomem *devm_pci_remap_cfgspace(struct device *dev,
 void __iomem *devm_pci_remap_cfgspace(struct device *dev,
 				      resource_size_t offset,
 				      resource_size_t offset,