2018-04-30 05:52:17

by Jan Kiszka

[permalink] [raw]
Subject: [PATCH v2 00/10] PCI: leak fixes, removable generic PCI host, assorted stuff

Changes in v2:
- patch 1: commit message reworking as suggested by Lorenzo
- patch 3-6: split-up as suggested by Bjorn
- patch 8: new
- patch 10: select PCI_DOMAINS from PCI_HOST_GENERIC, rather than
allowing manual choice, as suggested by Lorenzo

This primarily enables to unbind the generic PCI host controller without
leaving lots of memory leaks behind. A previous proposal patch 5 was
rejected because of those issues [1].

The fixes have been validated in the Jailhouse setup, where we add and
remove a virtual PCI host controller on hypervisor activation/
deactivation, with the help of kmemleak.

Besides that, there is tiny PCI API cleanup at the beginning and
support for manually enabled PCI domains at the end that enables the
Jailhouse scenario.

Jan

[1] http://lkml.iu.edu/hypermail/linux/kernel/1606.3/00072.html


CC: Jingoo Han <[email protected]>
CC: Joao Pinto <[email protected]>
CC: Lorenzo Pieralisi <[email protected]>
CC: Will Deacon <[email protected]>

Jan Kiszka (10):
PCI: Make pci_get_new_domain_nr() static
PCI: Fix memory leak of devm_pci_alloc_host_bridge()
PCI: Factor out __of_pci_get_host_bridge_resources()
PCI: Add dev parameter to __of_pci_get_host_bridge_resources()
PCI: Replace pr_*() with dev_*() in
__of_pci_get_host_bridge_resources()
PCI: Introduce devm_of_pci_get_host_bridge_resources()
PCI: Convert of_pci_get_host_bridge_resources() users to devm variant
PCI: Deprecate of_pci_get_host_bridge_resources()
PCI: Add support for unbinding the generic PCI host controller
PCI: Enable PCI_DOMAINS along with generic PCI host controller

drivers/pci/dwc/pcie-designware-host.c | 2 +-
drivers/pci/host/Kconfig | 1 +
drivers/pci/host/pci-aardvark.c | 5 +-
drivers/pci/host/pci-ftpci100.c | 4 +-
drivers/pci/host/pci-host-common.c | 13 ++++
drivers/pci/host/pci-host-generic.c | 1 +
drivers/pci/host/pci-v3-semi.c | 3 +-
drivers/pci/host/pci-versatile.c | 3 +-
drivers/pci/host/pci-xgene.c | 3 +-
drivers/pci/host/pcie-altera.c | 5 +-
drivers/pci/host/pcie-iproc-platform.c | 4 +-
drivers/pci/host/pcie-rcar.c | 5 +-
drivers/pci/host/pcie-rockchip.c | 4 +-
drivers/pci/host/pcie-xilinx-nwl.c | 4 +-
drivers/pci/host/pcie-xilinx.c | 4 +-
drivers/pci/of.c | 105 +++++++++++++++++++++------------
drivers/pci/pci.c | 6 +-
drivers/pci/probe.c | 4 +-
include/linux/of_pci.h | 42 ++++++++++++-
include/linux/pci-ecam.h | 1 +
include/linux/pci.h | 3 -
21 files changed, 149 insertions(+), 73 deletions(-)

--
2.13.6



2018-04-30 05:50:05

by Jan Kiszka

[permalink] [raw]
Subject: [PATCH v2 07/10] PCI: Convert of_pci_get_host_bridge_resources() users to devm variant

From: Jan Kiszka <[email protected]>

Straightforward for all of them, no more leaks afterwards.

CC: Jingoo Han <[email protected]>
CC: Joao Pinto <[email protected]>
CC: Lorenzo Pieralisi <[email protected]>
Signed-off-by: Jan Kiszka <[email protected]>
Acked-by: Jingoo Han <[email protected]>
---
drivers/pci/dwc/pcie-designware-host.c | 2 +-
drivers/pci/host/pci-aardvark.c | 5 ++---
drivers/pci/host/pci-ftpci100.c | 4 ++--
drivers/pci/host/pci-v3-semi.c | 3 ++-
drivers/pci/host/pci-versatile.c | 3 +--
drivers/pci/host/pci-xgene.c | 3 ++-
drivers/pci/host/pcie-altera.c | 5 ++---
drivers/pci/host/pcie-iproc-platform.c | 4 ++--
drivers/pci/host/pcie-rcar.c | 5 ++---
drivers/pci/host/pcie-rockchip.c | 4 ++--
drivers/pci/host/pcie-xilinx-nwl.c | 4 ++--
drivers/pci/host/pcie-xilinx.c | 4 ++--
drivers/pci/of.c | 4 ++--
13 files changed, 24 insertions(+), 26 deletions(-)

diff --git a/drivers/pci/dwc/pcie-designware-host.c b/drivers/pci/dwc/pcie-designware-host.c
index 6c409079d514..a8f6ab54b4c0 100644
--- a/drivers/pci/dwc/pcie-designware-host.c
+++ b/drivers/pci/dwc/pcie-designware-host.c
@@ -342,7 +342,7 @@ int dw_pcie_host_init(struct pcie_port *pp)
if (!bridge)
return -ENOMEM;

- ret = of_pci_get_host_bridge_resources(np, 0, 0xff,
+ ret = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff,
&bridge->windows, &pp->io_base);
if (ret)
return ret;
diff --git a/drivers/pci/host/pci-aardvark.c b/drivers/pci/host/pci-aardvark.c
index 9abf549631b4..1e048dd806dc 100644
--- a/drivers/pci/host/pci-aardvark.c
+++ b/drivers/pci/host/pci-aardvark.c
@@ -822,14 +822,13 @@ static int advk_pcie_parse_request_of_pci_ranges(struct advk_pcie *pcie)
{
int err, res_valid = 0;
struct device *dev = &pcie->pdev->dev;
- struct device_node *np = dev->of_node;
struct resource_entry *win, *tmp;
resource_size_t iobase;

INIT_LIST_HEAD(&pcie->resources);

- err = of_pci_get_host_bridge_resources(np, 0, 0xff, &pcie->resources,
- &iobase);
+ err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff,
+ &pcie->resources, &iobase);
if (err)
return err;

diff --git a/drivers/pci/host/pci-ftpci100.c b/drivers/pci/host/pci-ftpci100.c
index 5008fd87956a..87748eaeaaed 100644
--- a/drivers/pci/host/pci-ftpci100.c
+++ b/drivers/pci/host/pci-ftpci100.c
@@ -476,8 +476,8 @@ static int faraday_pci_probe(struct platform_device *pdev)
if (IS_ERR(p->base))
return PTR_ERR(p->base);

- ret = of_pci_get_host_bridge_resources(dev->of_node, 0, 0xff,
- &res, &io_base);
+ ret = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff,
+ &res, &io_base);
if (ret)
return ret;

diff --git a/drivers/pci/host/pci-v3-semi.c b/drivers/pci/host/pci-v3-semi.c
index 0a4dea796663..167bf6f6b378 100644
--- a/drivers/pci/host/pci-v3-semi.c
+++ b/drivers/pci/host/pci-v3-semi.c
@@ -791,7 +791,8 @@ static int v3_pci_probe(struct platform_device *pdev)
if (IS_ERR(v3->config_base))
return PTR_ERR(v3->config_base);

- ret = of_pci_get_host_bridge_resources(np, 0, 0xff, &res, &io_base);
+ ret = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, &res,
+ &io_base);
if (ret)
return ret;

diff --git a/drivers/pci/host/pci-versatile.c b/drivers/pci/host/pci-versatile.c
index 5b3876f5312b..ff2cd12b3978 100644
--- a/drivers/pci/host/pci-versatile.c
+++ b/drivers/pci/host/pci-versatile.c
@@ -64,11 +64,10 @@ static int versatile_pci_parse_request_of_pci_ranges(struct device *dev,
struct list_head *res)
{
int err, mem = 1, res_valid = 0;
- struct device_node *np = dev->of_node;
resource_size_t iobase;
struct resource_entry *win, *tmp;

- err = of_pci_get_host_bridge_resources(np, 0, 0xff, res, &iobase);
+ err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, res, &iobase);
if (err)
return err;

diff --git a/drivers/pci/host/pci-xgene.c b/drivers/pci/host/pci-xgene.c
index 0a0d7ee6d3c9..7b3ed6e34b6c 100644
--- a/drivers/pci/host/pci-xgene.c
+++ b/drivers/pci/host/pci-xgene.c
@@ -632,7 +632,8 @@ static int xgene_pcie_probe(struct platform_device *pdev)
if (ret)
return ret;

- ret = of_pci_get_host_bridge_resources(dn, 0, 0xff, &res, &iobase);
+ ret = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, &res,
+ &iobase);
if (ret)
return ret;

diff --git a/drivers/pci/host/pcie-altera.c b/drivers/pci/host/pcie-altera.c
index a6af62e0256d..49410c7ba0cc 100644
--- a/drivers/pci/host/pcie-altera.c
+++ b/drivers/pci/host/pcie-altera.c
@@ -488,11 +488,10 @@ static int altera_pcie_parse_request_of_pci_ranges(struct altera_pcie *pcie)
{
int err, res_valid = 0;
struct device *dev = &pcie->pdev->dev;
- struct device_node *np = dev->of_node;
struct resource_entry *win;

- err = of_pci_get_host_bridge_resources(np, 0, 0xff, &pcie->resources,
- NULL);
+ err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff
+ &pcie->resources, NULL);
if (err)
return err;

diff --git a/drivers/pci/host/pcie-iproc-platform.c b/drivers/pci/host/pcie-iproc-platform.c
index e764a2a2693c..99c2022813e4 100644
--- a/drivers/pci/host/pcie-iproc-platform.c
+++ b/drivers/pci/host/pcie-iproc-platform.c
@@ -99,8 +99,8 @@ static int iproc_pcie_pltfm_probe(struct platform_device *pdev)
pcie->phy = NULL;
}

- ret = of_pci_get_host_bridge_resources(np, 0, 0xff, &resources,
- &iobase);
+ ret = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, &resources,
+ &iobase);
if (ret) {
dev_err(dev, "unable to get PCI host bridge resources\n");
return ret;
diff --git a/drivers/pci/host/pcie-rcar.c b/drivers/pci/host/pcie-rcar.c
index 6ab28f29ac6a..6eb36c924983 100644
--- a/drivers/pci/host/pcie-rcar.c
+++ b/drivers/pci/host/pcie-rcar.c
@@ -1067,12 +1067,11 @@ static int rcar_pcie_parse_request_of_pci_ranges(struct rcar_pcie *pci)
{
int err;
struct device *dev = pci->dev;
- struct device_node *np = dev->of_node;
resource_size_t iobase;
struct resource_entry *win, *tmp;

- err = of_pci_get_host_bridge_resources(np, 0, 0xff, &pci->resources,
- &iobase);
+ err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff,
+ &pci->resources, &iobase);
if (err)
return err;

diff --git a/drivers/pci/host/pcie-rockchip.c b/drivers/pci/host/pcie-rockchip.c
index f1e8f97ea1fb..27b97fcddf15 100644
--- a/drivers/pci/host/pcie-rockchip.c
+++ b/drivers/pci/host/pcie-rockchip.c
@@ -1560,8 +1560,8 @@ static int rockchip_pcie_probe(struct platform_device *pdev)
if (err < 0)
goto err_deinit_port;

- err = of_pci_get_host_bridge_resources(dev->of_node, 0, 0xff,
- &res, &io_base);
+ err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff,
+ &res, &io_base);
if (err)
goto err_remove_irq_domain;

diff --git a/drivers/pci/host/pcie-xilinx-nwl.c b/drivers/pci/host/pcie-xilinx-nwl.c
index 4839ae578711..64df768c795c 100644
--- a/drivers/pci/host/pcie-xilinx-nwl.c
+++ b/drivers/pci/host/pcie-xilinx-nwl.c
@@ -825,7 +825,6 @@ static const struct of_device_id nwl_pcie_of_match[] = {
static int nwl_pcie_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct device_node *node = dev->of_node;
struct nwl_pcie *pcie;
struct pci_bus *bus;
struct pci_bus *child;
@@ -855,7 +854,8 @@ static int nwl_pcie_probe(struct platform_device *pdev)
return err;
}

- err = of_pci_get_host_bridge_resources(node, 0, 0xff, &res, &iobase);
+ err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, &res,
+ &iobase);
if (err) {
dev_err(dev, "Getting bridge resources failed\n");
return err;
diff --git a/drivers/pci/host/pcie-xilinx.c b/drivers/pci/host/pcie-xilinx.c
index 0ad188effc09..88c96e5669e0 100644
--- a/drivers/pci/host/pcie-xilinx.c
+++ b/drivers/pci/host/pcie-xilinx.c
@@ -643,8 +643,8 @@ static int xilinx_pcie_probe(struct platform_device *pdev)
return err;
}

- err = of_pci_get_host_bridge_resources(dev->of_node, 0, 0xff, &res,
- &iobase);
+ err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, &res,
+ &iobase);
if (err) {
dev_err(dev, "Getting bridge resources failed\n");
return err;
diff --git a/drivers/pci/of.c b/drivers/pci/of.c
index f16b343d3b85..5a88d46a41b7 100644
--- a/drivers/pci/of.c
+++ b/drivers/pci/of.c
@@ -645,12 +645,12 @@ int pci_parse_request_of_pci_ranges(struct device *dev,
struct resource **bus_range)
{
int err, res_valid = 0;
- struct device_node *np = dev->of_node;
resource_size_t iobase;
struct resource_entry *win, *tmp;

INIT_LIST_HEAD(resources);
- err = of_pci_get_host_bridge_resources(np, 0, 0xff, resources, &iobase);
+ err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, resources,
+ &iobase);
if (err)
return err;

--
2.13.6


2018-04-30 05:50:11

by Jan Kiszka

[permalink] [raw]
Subject: [PATCH v2 02/10] PCI: Fix memory leak of devm_pci_alloc_host_bridge()

From: Jan Kiszka <[email protected]>

devm_pci_release_host_bridge_dev() failed to release the resource list.

Fixes: 5c3f18cce083 ("PCI: Add devm_pci_alloc_host_bridge() interface")
Signed-off-by: Jan Kiszka <[email protected]>
---
drivers/pci/probe.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index ac91b6fd0bcd..eccf204c9160 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -526,12 +526,14 @@ static void devm_pci_release_host_bridge_dev(struct device *dev)

if (bridge->release_fn)
bridge->release_fn(bridge);
+
+ pci_free_resource_list(&bridge->windows);
}

static void pci_release_host_bridge_dev(struct device *dev)
{
devm_pci_release_host_bridge_dev(dev);
- pci_free_host_bridge(to_pci_host_bridge(dev));
+ kfree(to_pci_host_bridge(dev));
}

struct pci_host_bridge *pci_alloc_host_bridge(size_t priv)
--
2.13.6


2018-04-30 05:50:47

by Jan Kiszka

[permalink] [raw]
Subject: [PATCH v2 04/10] PCI: Add dev parameter to __of_pci_get_host_bridge_resources()

From: Jan Kiszka <[email protected]>

When non-NULL, use the new dev parameter of
__of_pci_get_host_bridge_resources() to allocate the resource data
structures via devm_kzalloc. That allows to release them automatically
during device destruction.

Signed-off-by: Jan Kiszka <[email protected]>
---
drivers/pci/of.c | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/drivers/pci/of.c b/drivers/pci/of.c
index 375de447a58e..bfa282b538d5 100644
--- a/drivers/pci/of.c
+++ b/drivers/pci/of.c
@@ -243,7 +243,7 @@ void of_pci_check_probe_only(void)
EXPORT_SYMBOL_GPL(of_pci_check_probe_only);

#if defined(CONFIG_OF_ADDRESS)
-static int __of_pci_get_host_bridge_resources(
+static int __of_pci_get_host_bridge_resources(struct device *dev,
struct device_node *dev_node,
unsigned char busno, unsigned char bus_max,
struct list_head *resources, resource_size_t *io_base)
@@ -259,7 +259,10 @@ static int __of_pci_get_host_bridge_resources(
if (io_base)
*io_base = (resource_size_t)OF_BAD_ADDR;

- bus_range = kzalloc(sizeof(*bus_range), GFP_KERNEL);
+ if (dev)
+ bus_range = devm_kzalloc(dev,sizeof(*bus_range), GFP_KERNEL);
+ else
+ bus_range = kzalloc(sizeof(*bus_range), GFP_KERNEL);
if (!bus_range)
return -ENOMEM;

@@ -303,7 +306,11 @@ static int __of_pci_get_host_bridge_resources(
if (range.cpu_addr == OF_BAD_ADDR || range.size == 0)
continue;

- res = kzalloc(sizeof(struct resource), GFP_KERNEL);
+ if (dev)
+ res = devm_kzalloc(dev, sizeof(struct resource),
+ GFP_KERNEL);
+ else
+ res = kzalloc(sizeof(struct resource), GFP_KERNEL);
if (!res) {
err = -ENOMEM;
goto parse_failed;
@@ -365,7 +372,7 @@ int of_pci_get_host_bridge_resources(struct device_node *dev_node,
unsigned char busno, unsigned char bus_max,
struct list_head *resources, resource_size_t *io_base)
{
- return __of_pci_get_host_bridge_resources(dev_node, busno,
+ return __of_pci_get_host_bridge_resources(NULL, dev_node, busno,
bus_max, resources, io_base);
}
EXPORT_SYMBOL_GPL(of_pci_get_host_bridge_resources);
--
2.13.6


2018-04-30 05:51:11

by Jan Kiszka

[permalink] [raw]
Subject: [PATCH v2 03/10] PCI: Factor out __of_pci_get_host_bridge_resources()

From: Jan Kiszka <[email protected]>

This will be needed for sharing the core logic between current
of_pci_get_host_bridge_resources() and upcoming
devm_of_pci_get_host_bridge_resources().

Already rename the dev parameter to dev_node in order to free the
namespace for a real device parameter.

No functional changes.

Signed-off-by: Jan Kiszka <[email protected]>
---
drivers/pci/of.c | 63 ++++++++++++++++++++++++++++----------------------
include/linux/of_pci.h | 4 ++--
2 files changed, 38 insertions(+), 29 deletions(-)

diff --git a/drivers/pci/of.c b/drivers/pci/of.c
index a28355c273ae..375de447a58e 100644
--- a/drivers/pci/of.c
+++ b/drivers/pci/of.c
@@ -243,26 +243,8 @@ void of_pci_check_probe_only(void)
EXPORT_SYMBOL_GPL(of_pci_check_probe_only);

#if defined(CONFIG_OF_ADDRESS)
-/**
- * of_pci_get_host_bridge_resources - Parse PCI host bridge resources from DT
- * @dev: device node of the host bridge having the range property
- * @busno: bus number associated with the bridge root bus
- * @bus_max: maximum number of buses for this bridge
- * @resources: list where the range of resources will be added after DT parsing
- * @io_base: pointer to a variable that will contain on return the physical
- * address for the start of the I/O range. Can be NULL if the caller doesn't
- * expect I/O ranges to be present in the device tree.
- *
- * It is the caller's job to free the @resources list.
- *
- * This function will parse the "ranges" property of a PCI host bridge device
- * node and setup the resource mapping based on its content. It is expected
- * that the property conforms with the Power ePAPR document.
- *
- * It returns zero if the range parsing has been successful or a standard error
- * value if it failed.
- */
-int of_pci_get_host_bridge_resources(struct device_node *dev,
+static int __of_pci_get_host_bridge_resources(
+ struct device_node *dev_node,
unsigned char busno, unsigned char bus_max,
struct list_head *resources, resource_size_t *io_base)
{
@@ -281,15 +263,15 @@ int of_pci_get_host_bridge_resources(struct device_node *dev,
if (!bus_range)
return -ENOMEM;

- pr_info("host bridge %pOF ranges:\n", dev);
+ pr_info("host bridge %pOF ranges:\n", dev_node);

- err = of_pci_parse_bus_range(dev, bus_range);
+ err = of_pci_parse_bus_range(dev_node, bus_range);
if (err) {
bus_range->start = busno;
bus_range->end = bus_max;
bus_range->flags = IORESOURCE_BUS;
pr_info(" No bus range found for %pOF, using %pR\n",
- dev, bus_range);
+ dev_node, bus_range);
} else {
if (bus_range->end > bus_range->start + bus_max)
bus_range->end = bus_range->start + bus_max;
@@ -297,7 +279,7 @@ int of_pci_get_host_bridge_resources(struct device_node *dev,
pci_add_resource(resources, bus_range);

/* Check for ranges property */
- err = of_pci_range_parser_init(&parser, dev);
+ err = of_pci_range_parser_init(&parser, dev_node);
if (err)
goto parse_failed;

@@ -327,7 +309,7 @@ int of_pci_get_host_bridge_resources(struct device_node *dev,
goto parse_failed;
}

- err = of_pci_range_to_resource(&range, dev, res);
+ err = of_pci_range_to_resource(&range, dev_node, res);
if (err) {
kfree(res);
continue;
@@ -336,13 +318,13 @@ int of_pci_get_host_bridge_resources(struct device_node *dev,
if (resource_type(res) == IORESOURCE_IO) {
if (!io_base) {
pr_err("I/O range found for %pOF. Please provide an io_base pointer to save CPU base address\n",
- dev);
+ dev_node);
err = -EINVAL;
goto conversion_failed;
}
if (*io_base != (resource_size_t)OF_BAD_ADDR)
pr_warn("More than one I/O resource converted for %pOF. CPU base address for old range lost!\n",
- dev);
+ dev_node);
*io_base = range.cpu_addr;
}

@@ -359,6 +341,33 @@ int of_pci_get_host_bridge_resources(struct device_node *dev,
pci_free_resource_list(resources);
return err;
}
+
+/**
+ * of_pci_get_host_bridge_resources() - Parse PCI host bridge resources from DT
+ * @dev_node: device node of the host bridge having the range property
+ * @busno: bus number associated with the bridge root bus
+ * @bus_max: maximum number of buses for this bridge
+ * @resources: list where the range of resources will be added after DT parsing
+ * @io_base: pointer to a variable that will contain on return the physical
+ * address for the start of the I/O range. Can be NULL if the caller doesn't
+ * expect I/O ranges to be present in the device tree.
+ *
+ * It is the caller's job to free the @resources list.
+ *
+ * This function will parse the "ranges" property of a PCI host bridge device
+ * node and setup the resource mapping based on its content. It is expected
+ * that the property conforms with the Power ePAPR document.
+ *
+ * It returns zero if the range parsing has been successful or a standard error
+ * value if it failed.
+ */
+int of_pci_get_host_bridge_resources(struct device_node *dev_node,
+ unsigned char busno, unsigned char bus_max,
+ struct list_head *resources, resource_size_t *io_base)
+{
+ return __of_pci_get_host_bridge_resources(dev_node, busno,
+ bus_max, resources, io_base);
+}
EXPORT_SYMBOL_GPL(of_pci_get_host_bridge_resources);
#endif /* CONFIG_OF_ADDRESS */

diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h
index 091033a6b836..74eec1943ad2 100644
--- a/include/linux/of_pci.h
+++ b/include/linux/of_pci.h
@@ -71,11 +71,11 @@ of_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 pin)
#endif

#if defined(CONFIG_OF_ADDRESS)
-int of_pci_get_host_bridge_resources(struct device_node *dev,
+int of_pci_get_host_bridge_resources(struct device_node *dev_node,
unsigned char busno, unsigned char bus_max,
struct list_head *resources, resource_size_t *io_base);
#else
-static inline int of_pci_get_host_bridge_resources(struct device_node *dev,
+static inline int of_pci_get_host_bridge_resources(struct device_node *dev_node,
unsigned char busno, unsigned char bus_max,
struct list_head *resources, resource_size_t *io_base)
{
--
2.13.6


2018-04-30 05:51:29

by Jan Kiszka

[permalink] [raw]
Subject: [PATCH v2 06/10] PCI: Introduce devm_of_pci_get_host_bridge_resources()

From: Jan Kiszka <[email protected]>

of_pci_get_host_bridge_resources() allocates the resource structures it
fills dynamically, but none of its callers care to release them so far.
Rather than requiring everyone to do this explicitly, introduce a
managed version of that service. This differs API-wise only in taking a
reference to the associated device, rather than to the device tree node.

As of_pci_get_host_bridge_resources() is an exported interface, we
cannot simply drop it at this point. After converting all in-tree users
to the new API, we will phase out the unmanaged one.

Signed-off-by: Jan Kiszka <[email protected]>
---
drivers/pci/of.c | 28 ++++++++++++++++++++++++++++
include/linux/of_pci.h | 10 ++++++++++
2 files changed, 38 insertions(+)

diff --git a/drivers/pci/of.c b/drivers/pci/of.c
index 8f6cbf13e18d..f16b343d3b85 100644
--- a/drivers/pci/of.c
+++ b/drivers/pci/of.c
@@ -378,6 +378,34 @@ int of_pci_get_host_bridge_resources(struct device_node *dev_node,
bus_max, resources, io_base);
}
EXPORT_SYMBOL_GPL(of_pci_get_host_bridge_resources);
+
+/**
+ * of_pci_get_host_bridge_resources() - Resource-managed parsing of PCI host
+ * bridge resources from DT
+ * @dev: host bridge device
+ * @busno: bus number associated with the bridge root bus
+ * @bus_max: maximum number of buses for this bridge
+ * @resources: list where the range of resources will be added after DT parsing
+ * @io_base: pointer to a variable that will contain on return the physical
+ * address for the start of the I/O range. Can be NULL if the caller doesn't
+ * expect I/O ranges to be present in the device tree.
+ *
+ * This function will parse the "ranges" property of a PCI host bridge device
+ * node and setup the resource mapping based on its content. It is expected
+ * that the property conforms with the Power ePAPR document.
+ *
+ * It returns zero if the range parsing has been successful or a standard error
+ * value if it failed.
+ */
+int devm_of_pci_get_host_bridge_resources(struct device *dev,
+ unsigned char busno, unsigned char bus_max,
+ struct list_head *resources, resource_size_t *io_base)
+{
+ return __of_pci_get_host_bridge_resources(dev, dev->of_node, busno,
+ bus_max, resources, io_base);
+}
+EXPORT_SYMBOL_GPL(devm_of_pci_get_host_bridge_resources);
+
#endif /* CONFIG_OF_ADDRESS */

/**
diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h
index 74eec1943ad2..08b8f02426a5 100644
--- a/include/linux/of_pci.h
+++ b/include/linux/of_pci.h
@@ -74,6 +74,9 @@ of_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 pin)
int of_pci_get_host_bridge_resources(struct device_node *dev_node,
unsigned char busno, unsigned char bus_max,
struct list_head *resources, resource_size_t *io_base);
+int devm_of_pci_get_host_bridge_resources(struct device *dev,
+ unsigned char busno, unsigned char bus_max,
+ struct list_head *resources, resource_size_t *io_base);
#else
static inline int of_pci_get_host_bridge_resources(struct device_node *dev_node,
unsigned char busno, unsigned char bus_max,
@@ -81,6 +84,13 @@ static inline int of_pci_get_host_bridge_resources(struct device_node *dev_node,
{
return -EINVAL;
}
+
+static inline int devm_of_pci_get_host_bridge_resources(struct device *dev,
+ unsigned char busno, unsigned char bus_max,
+ struct list_head *resources, resource_size_t *io_base)
+{
+ return -EINVAL;
+}
#endif

#endif
--
2.13.6


2018-04-30 05:52:06

by Jan Kiszka

[permalink] [raw]
Subject: [PATCH v2 05/10] PCI: Replace pr_*() with dev_*() in __of_pci_get_host_bridge_resources()

From: Jan Kiszka <[email protected]>

Now that we have a device reference, make use of it for printing. And as
long as dev can still be NULL, we will still get some reasonable output
nevertheless.

Signed-off-by: Jan Kiszka <[email protected]>
---
drivers/pci/of.c | 22 ++++++++++++----------
1 file changed, 12 insertions(+), 10 deletions(-)

diff --git a/drivers/pci/of.c b/drivers/pci/of.c
index bfa282b538d5..8f6cbf13e18d 100644
--- a/drivers/pci/of.c
+++ b/drivers/pci/of.c
@@ -266,15 +266,15 @@ static int __of_pci_get_host_bridge_resources(struct device *dev,
if (!bus_range)
return -ENOMEM;

- pr_info("host bridge %pOF ranges:\n", dev_node);
+ dev_info(dev, "host bridge %pOF ranges:\n", dev_node);

err = of_pci_parse_bus_range(dev_node, bus_range);
if (err) {
bus_range->start = busno;
bus_range->end = bus_max;
bus_range->flags = IORESOURCE_BUS;
- pr_info(" No bus range found for %pOF, using %pR\n",
- dev_node, bus_range);
+ dev_info(dev, " No bus range found for %pOF, using %pR\n",
+ dev_node, bus_range);
} else {
if (bus_range->end > bus_range->start + bus_max)
bus_range->end = bus_range->start + bus_max;
@@ -286,7 +286,7 @@ static int __of_pci_get_host_bridge_resources(struct device *dev,
if (err)
goto parse_failed;

- pr_debug("Parsing ranges property...\n");
+ dev_dbg(dev, "Parsing ranges property...\n");
for_each_of_pci_range(&parser, &range) {
/* Read next ranges element */
if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_IO)
@@ -295,9 +295,9 @@ static int __of_pci_get_host_bridge_resources(struct device *dev,
snprintf(range_type, 4, "MEM");
else
snprintf(range_type, 4, "err");
- pr_info(" %s %#010llx..%#010llx -> %#010llx\n", range_type,
- range.cpu_addr, range.cpu_addr + range.size - 1,
- range.pci_addr);
+ dev_info(dev, " %s %#010llx..%#010llx -> %#010llx\n",
+ range_type, range.cpu_addr,
+ range.cpu_addr + range.size - 1, range.pci_addr);

/*
* If we failed translation or got a zero-sized region
@@ -324,14 +324,16 @@ static int __of_pci_get_host_bridge_resources(struct device *dev,

if (resource_type(res) == IORESOURCE_IO) {
if (!io_base) {
- pr_err("I/O range found for %pOF. Please provide an io_base pointer to save CPU base address\n",
+ dev_err(dev,
+ "I/O range found for %pOF. Please provide an io_base pointer to save CPU base address\n",
dev_node);
err = -EINVAL;
goto conversion_failed;
}
if (*io_base != (resource_size_t)OF_BAD_ADDR)
- pr_warn("More than one I/O resource converted for %pOF. CPU base address for old range lost!\n",
- dev_node);
+ dev_warn(dev,
+ "More than one I/O resource converted for %pOF. CPU base address for old range lost!\n",
+ dev_node);
*io_base = range.cpu_addr;
}

--
2.13.6


2018-04-30 05:52:09

by Jan Kiszka

[permalink] [raw]
Subject: [PATCH v2 08/10] PCI: Deprecate of_pci_get_host_bridge_resources()

From: Jan Kiszka <[email protected]>

There are no in-tree users remaining, all are converted to the managed
variant. And it is unlikely that any out-of-tree user got the resource
management right as well. So deprecate the interface and push users to
the managed version instead.

To avoid raising a warning when exporting a deprecated symbol, wrap the
API with an inline and export an internal name.

Signed-off-by: Jan Kiszka <[email protected]>
---
drivers/pci/of.c | 23 ++---------------------
include/linux/of_pci.h | 36 ++++++++++++++++++++++++++++++++----
2 files changed, 34 insertions(+), 25 deletions(-)

diff --git a/drivers/pci/of.c b/drivers/pci/of.c
index 5a88d46a41b7..ccf8c7544e10 100644
--- a/drivers/pci/of.c
+++ b/drivers/pci/of.c
@@ -351,33 +351,14 @@ static int __of_pci_get_host_bridge_resources(struct device *dev,
return err;
}

-/**
- * of_pci_get_host_bridge_resources() - Parse PCI host bridge resources from DT
- * @dev_node: device node of the host bridge having the range property
- * @busno: bus number associated with the bridge root bus
- * @bus_max: maximum number of buses for this bridge
- * @resources: list where the range of resources will be added after DT parsing
- * @io_base: pointer to a variable that will contain on return the physical
- * address for the start of the I/O range. Can be NULL if the caller doesn't
- * expect I/O ranges to be present in the device tree.
- *
- * It is the caller's job to free the @resources list.
- *
- * This function will parse the "ranges" property of a PCI host bridge device
- * node and setup the resource mapping based on its content. It is expected
- * that the property conforms with the Power ePAPR document.
- *
- * It returns zero if the range parsing has been successful or a standard error
- * value if it failed.
- */
-int of_pci_get_host_bridge_resources(struct device_node *dev_node,
+int __of_pci_get_host_bridge_resources_deprecated(struct device_node *dev_node,
unsigned char busno, unsigned char bus_max,
struct list_head *resources, resource_size_t *io_base)
{
return __of_pci_get_host_bridge_resources(NULL, dev_node, busno,
bus_max, resources, io_base);
}
-EXPORT_SYMBOL_GPL(of_pci_get_host_bridge_resources);
+EXPORT_SYMBOL_GPL(__of_pci_get_host_bridge_resources_deprecated);

/**
* of_pci_get_host_bridge_resources() - Resource-managed parsing of PCI host
diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h
index 08b8f02426a5..c6408bd6f862 100644
--- a/include/linux/of_pci.h
+++ b/include/linux/of_pci.h
@@ -71,26 +71,54 @@ of_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 pin)
#endif

#if defined(CONFIG_OF_ADDRESS)
-int of_pci_get_host_bridge_resources(struct device_node *dev_node,
+int __of_pci_get_host_bridge_resources_deprecated(struct device_node *dev_node,
unsigned char busno, unsigned char bus_max,
struct list_head *resources, resource_size_t *io_base);
int devm_of_pci_get_host_bridge_resources(struct device *dev,
unsigned char busno, unsigned char bus_max,
struct list_head *resources, resource_size_t *io_base);
#else
-static inline int of_pci_get_host_bridge_resources(struct device_node *dev_node,
+static inline int devm_of_pci_get_host_bridge_resources(struct device *dev,
unsigned char busno, unsigned char bus_max,
struct list_head *resources, resource_size_t *io_base)
{
return -EINVAL;
}
+#endif

-static inline int devm_of_pci_get_host_bridge_resources(struct device *dev,
+/**
+ * of_pci_get_host_bridge_resources() - Parse PCI host bridge resources from DT
+ * @dev_node: device node of the host bridge having the range property
+ * @busno: bus number associated with the bridge root bus
+ * @bus_max: maximum number of buses for this bridge
+ * @resources: list where the range of resources will be added after DT parsing
+ * @io_base: pointer to a variable that will contain on return the physical
+ * address for the start of the I/O range. Can be NULL if the caller doesn't
+ * expect I/O ranges to be present in the device tree.
+ *
+ * It is the caller's job to free the @resources list.
+ *
+ * This function will parse the "ranges" property of a PCI host bridge device
+ * node and setup the resource mapping based on its content. It is expected
+ * that the property conforms with the Power ePAPR document.
+ *
+ * It returns zero if the range parsing has been successful or a standard error
+ * value if it failed.
+ *
+ * Note: This function is deprecated and will eventually be removed. Use
+ * devm_of_pci_get_host_bridge_resources() instead.
+ */
+static inline int __deprecated of_pci_get_host_bridge_resources(
+ struct device_node *dev_node,
unsigned char busno, unsigned char bus_max,
struct list_head *resources, resource_size_t *io_base)
{
+#if defined(CONFIG_OF_ADDRESS)
+ return __of_pci_get_host_bridge_resources_deprecated(dev_node, busno,
+ bus_max, resources, io_base);
+#else
return -EINVAL;
-}
#endif
+}

#endif
--
2.13.6


2018-04-30 05:52:30

by Jan Kiszka

[permalink] [raw]
Subject: [PATCH v2 10/10] PCI: Enable PCI_DOMAINS along with generic PCI host controller

From: Jan Kiszka <[email protected]>

This controller is often instantiated by hypervisors, and they may add
multiple of them or add them in addition to a physical host controller
like the Jailhouse hypervisor is doing. Therefore allow for multiple
domains so that we can handle them all.

Signed-off-by: Jan Kiszka <[email protected]>
---
drivers/pci/host/Kconfig | 1 +
1 file changed, 1 insertion(+)

diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
index 0d0177ce436c..3d25b35bb5ab 100644
--- a/drivers/pci/host/Kconfig
+++ b/drivers/pci/host/Kconfig
@@ -68,6 +68,7 @@ config PCI_HOST_GENERIC
depends on (ARM || ARM64) && OF
select PCI_HOST_COMMON
select IRQ_DOMAIN
+ select PCI_DOMAINS
help
Say Y here if you want to support a simple generic PCI host
controller, such as the one emulated by kvmtool.
--
2.13.6


2018-04-30 05:52:33

by Jan Kiszka

[permalink] [raw]
Subject: [PATCH v2 01/10] PCI: Make pci_get_new_domain_nr() static

From: Jan Kiszka <[email protected]>

The only user of pci_get_new_domain_nr() is of_pci_bus_find_domain_nr().
Since they are defined in the same compilation unit,
pci_get_new_domain_nr() can be made static, which also simplifies
preprocessor conditionals.

No functional change intended.

Signed-off-by: Jan Kiszka <[email protected]>
Acked-by: Lorenzo Pieralisi <[email protected]>
---
drivers/pci/pci.c | 6 ++----
include/linux/pci.h | 3 ---
2 files changed, 2 insertions(+), 7 deletions(-)

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index a04197ce767d..811d71e7ee05 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -5702,15 +5702,14 @@ static void pci_no_domains(void)
#endif
}

-#ifdef CONFIG_PCI_DOMAINS
+#ifdef CONFIG_PCI_DOMAINS_GENERIC
static atomic_t __domain_nr = ATOMIC_INIT(-1);

-int pci_get_new_domain_nr(void)
+static int pci_get_new_domain_nr(void)
{
return atomic_inc_return(&__domain_nr);
}

-#ifdef CONFIG_PCI_DOMAINS_GENERIC
static int of_pci_bus_find_domain_nr(struct device *parent)
{
static int use_dt_domains = -1;
@@ -5765,7 +5764,6 @@ int pci_bus_find_domain_nr(struct pci_bus *bus, struct device *parent)
acpi_pci_bus_find_domain_nr(bus);
}
#endif
-#endif

/**
* pci_ext_cfg_avail - can we access extended PCI config space?
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 73178a2fcee0..963232a6cd2e 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1510,12 +1510,10 @@ void pci_cfg_access_unlock(struct pci_dev *dev);
*/
#ifdef CONFIG_PCI_DOMAINS
extern int pci_domains_supported;
-int pci_get_new_domain_nr(void);
#else
enum { pci_domains_supported = 0 };
static inline int pci_domain_nr(struct pci_bus *bus) { return 0; }
static inline int pci_proc_domain(struct pci_bus *bus) { return 0; }
-static inline int pci_get_new_domain_nr(void) { return -ENOSYS; }
#endif /* CONFIG_PCI_DOMAINS */

/*
@@ -1670,7 +1668,6 @@ static inline struct pci_dev *pci_get_domain_bus_and_slot(int domain,

static inline int pci_domain_nr(struct pci_bus *bus) { return 0; }
static inline struct pci_dev *pci_dev_get(struct pci_dev *dev) { return NULL; }
-static inline int pci_get_new_domain_nr(void) { return -ENOSYS; }

#define dev_is_pci(d) (false)
#define dev_is_pf(d) (false)
--
2.13.6


2018-04-30 05:53:02

by Jan Kiszka

[permalink] [raw]
Subject: [PATCH v2 09/10] PCI: Add support for unbinding the generic PCI host controller

From: Jan Kiszka <[email protected]>

Particularly useful when working in virtual environments where the
controller may come and go, but possibly not only there.

CC: Will Deacon <[email protected]>
CC: Lorenzo Pieralisi <[email protected]>
Signed-off-by: Jan Kiszka <[email protected]>
---
drivers/pci/host/pci-host-common.c | 13 +++++++++++++
drivers/pci/host/pci-host-generic.c | 1 +
include/linux/pci-ecam.h | 1 +
3 files changed, 15 insertions(+)

diff --git a/drivers/pci/host/pci-host-common.c b/drivers/pci/host/pci-host-common.c
index 5d028f53fdcd..d8f10451f273 100644
--- a/drivers/pci/host/pci-host-common.c
+++ b/drivers/pci/host/pci-host-common.c
@@ -101,5 +101,18 @@ int pci_host_common_probe(struct platform_device *pdev,
return ret;
}

+ platform_set_drvdata(pdev, bridge->bus);
+ return 0;
+}
+
+int pci_host_common_remove(struct platform_device *pdev)
+{
+ struct pci_bus *bus = platform_get_drvdata(pdev);
+
+ pci_lock_rescan_remove();
+ pci_stop_root_bus(bus);
+ pci_remove_root_bus(bus);
+ pci_unlock_rescan_remove();
+
return 0;
}
diff --git a/drivers/pci/host/pci-host-generic.c b/drivers/pci/host/pci-host-generic.c
index 45319ee3b484..dea3ec7592a2 100644
--- a/drivers/pci/host/pci-host-generic.c
+++ b/drivers/pci/host/pci-host-generic.c
@@ -95,5 +95,6 @@ static struct platform_driver gen_pci_driver = {
.suppress_bind_attrs = true,
},
.probe = gen_pci_probe,
+ .remove = pci_host_common_remove,
};
builtin_platform_driver(gen_pci_driver);
diff --git a/include/linux/pci-ecam.h b/include/linux/pci-ecam.h
index baadad1aabbc..29efa09d686b 100644
--- a/include/linux/pci-ecam.h
+++ b/include/linux/pci-ecam.h
@@ -62,5 +62,6 @@ extern struct pci_ecam_ops xgene_v2_pcie_ecam_ops; /* APM X-Gene PCIe v2.x */
/* for DT-based PCI controllers that support ECAM */
int pci_host_common_probe(struct platform_device *pdev,
struct pci_ecam_ops *ops);
+int pci_host_common_remove(struct platform_device *pdev);
#endif
#endif
--
2.13.6


2018-05-02 12:40:11

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [PATCH v2 08/10] PCI: Deprecate of_pci_get_host_bridge_resources()

On Mon, Apr 30, 2018 at 07:48:42AM +0200, Jan Kiszka wrote:
> From: Jan Kiszka <[email protected]>
>
> There are no in-tree users remaining, all are converted to the managed
> variant. And it is unlikely that any out-of-tree user got the resource
> management right as well. So deprecate the interface and push users to
> the managed version instead.
>
> To avoid raising a warning when exporting a deprecated symbol, wrap the
> API with an inline and export an internal name.

Don't deprecated it, just remove it.

2018-05-03 07:14:28

by Vladimir Zapolskiy

[permalink] [raw]
Subject: Re: [PATCH v2 00/10] PCI: leak fixes, removable generic PCI host, assorted stuff

Hi Jan,

On 04/30/2018 08:48 AM, Jan Kiszka wrote:
> Changes in v2:
> - patch 1: commit message reworking as suggested by Lorenzo
> - patch 3-6: split-up as suggested by Bjorn
> - patch 8: new
> - patch 10: select PCI_DOMAINS from PCI_HOST_GENERIC, rather than
> allowing manual choice, as suggested by Lorenzo
>
> This primarily enables to unbind the generic PCI host controller without
> leaving lots of memory leaks behind. A previous proposal patch 5 was
> rejected because of those issues [1].
>
> The fixes have been validated in the Jailhouse setup, where we add and
> remove a virtual PCI host controller on hypervisor activation/
> deactivation, with the help of kmemleak.

by chance I was looking into a memleak in of_pci_get_host_bridge_resources(),
so I can give you a number of review tags.

FWIW the state of unfixably broken https://patchwork.kernel.org/patch/9662893/
should be changed to obsoleted/deprecated/rejected.

--
With best wishes,
Vladimir

2018-05-03 07:14:40

by Vladimir Zapolskiy

[permalink] [raw]
Subject: Re: [PATCH v2 03/10] PCI: Factor out __of_pci_get_host_bridge_resources()

On 04/30/2018 08:48 AM, Jan Kiszka wrote:
> From: Jan Kiszka <[email protected]>
>
> This will be needed for sharing the core logic between current
> of_pci_get_host_bridge_resources() and upcoming
> devm_of_pci_get_host_bridge_resources().
>
> Already rename the dev parameter to dev_node in order to free the
> namespace for a real device parameter.
>
> No functional changes.
>
> Signed-off-by: Jan Kiszka <[email protected]>

Reviewed-by: Vladimir Zapolskiy <[email protected]>
Tested-by: Vladimir Zapolskiy <[email protected]>

--
With best wishes,
Vladimir

2018-05-03 07:15:49

by Vladimir Zapolskiy

[permalink] [raw]
Subject: Re: [PATCH v2 05/10] PCI: Replace pr_*() with dev_*() in __of_pci_get_host_bridge_resources()

On 04/30/2018 08:48 AM, Jan Kiszka wrote:
> From: Jan Kiszka <[email protected]>
>
> Now that we have a device reference, make use of it for printing. And as
> long as dev can still be NULL, we will still get some reasonable output
> nevertheless.
>
> Signed-off-by: Jan Kiszka <[email protected]>

Reviewed-by: Vladimir Zapolskiy <[email protected]>
Tested-by: Vladimir Zapolskiy <[email protected]>

--
With best wishes,
Vladimir

2018-05-03 07:16:03

by Vladimir Zapolskiy

[permalink] [raw]
Subject: Re: [PATCH v2 04/10] PCI: Add dev parameter to __of_pci_get_host_bridge_resources()

On 04/30/2018 08:48 AM, Jan Kiszka wrote:
> From: Jan Kiszka <[email protected]>
>
> When non-NULL, use the new dev parameter of
> __of_pci_get_host_bridge_resources() to allocate the resource data
> structures via devm_kzalloc. That allows to release them automatically
> during device destruction.
>
> Signed-off-by: Jan Kiszka <[email protected]>

Reviewed-by: Vladimir Zapolskiy <[email protected]>
Tested-by: Vladimir Zapolskiy <[email protected]>

--
With best wishes,
Vladimir

2018-05-03 07:16:09

by Vladimir Zapolskiy

[permalink] [raw]
Subject: Re: [PATCH v2 06/10] PCI: Introduce devm_of_pci_get_host_bridge_resources()

On 04/30/2018 08:48 AM, Jan Kiszka wrote:
> From: Jan Kiszka <[email protected]>
>
> of_pci_get_host_bridge_resources() allocates the resource structures it
> fills dynamically, but none of its callers care to release them so far.
> Rather than requiring everyone to do this explicitly, introduce a
> managed version of that service. This differs API-wise only in taking a
> reference to the associated device, rather than to the device tree node.
>
> As of_pci_get_host_bridge_resources() is an exported interface, we
> cannot simply drop it at this point. After converting all in-tree users
> to the new API, we will phase out the unmanaged one.
>
> Signed-off-by: Jan Kiszka <[email protected]>

Reviewed-by: Vladimir Zapolskiy <[email protected]>
Tested-by: Vladimir Zapolskiy <[email protected]>

--
With best wishes,
Vladimir

2018-05-03 07:18:57

by Vladimir Zapolskiy

[permalink] [raw]
Subject: Re: [PATCH v2 07/10] PCI: Convert of_pci_get_host_bridge_resources() users to devm variant

Hi Jan,

On 04/30/2018 08:48 AM, Jan Kiszka wrote:
> From: Jan Kiszka <[email protected]>
>
> Straightforward for all of them, no more leaks afterwards.
>
> CC: Jingoo Han <[email protected]>
> CC: Joao Pinto <[email protected]>
> CC: Lorenzo Pieralisi <[email protected]>
> Signed-off-by: Jan Kiszka <[email protected]>
> Acked-by: Jingoo Han <[email protected]>

[snip]

> diff --git a/drivers/pci/host/pcie-rcar.c b/drivers/pci/host/pcie-rcar.c
> index 6ab28f29ac6a..6eb36c924983 100644
> --- a/drivers/pci/host/pcie-rcar.c
> +++ b/drivers/pci/host/pcie-rcar.c
> @@ -1067,12 +1067,11 @@ static int rcar_pcie_parse_request_of_pci_ranges(struct rcar_pcie *pci)
> {
> int err;
> struct device *dev = pci->dev;
> - struct device_node *np = dev->of_node;
> resource_size_t iobase;
> struct resource_entry *win, *tmp;
>
> - err = of_pci_get_host_bridge_resources(np, 0, 0xff, &pci->resources,
> - &iobase);
> + err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff,
> + &pci->resources, &iobase);
> if (err)
> return err;
>

this one snippet is obsoleted by https://patchwork.ozlabs.org/patch/904326/

If 08/10 remains a deprecation, then it is sufficient to exclude the R-Car change,
otherwise I hope maintainers can deal with the proper ordering.

For PCI OF change:

> diff --git a/drivers/pci/of.c b/drivers/pci/of.c
> index f16b343d3b85..5a88d46a41b7 100644
> --- a/drivers/pci/of.c
> +++ b/drivers/pci/of.c
> @@ -645,12 +645,12 @@ int pci_parse_request_of_pci_ranges(struct device *dev,
> struct resource **bus_range)
> {
> int err, res_valid = 0;
> - struct device_node *np = dev->of_node;
> resource_size_t iobase;
> struct resource_entry *win, *tmp;
>
> INIT_LIST_HEAD(resources);
> - err = of_pci_get_host_bridge_resources(np, 0, 0xff, resources, &iobase);
> + err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, resources,
> + &iobase);
> if (err)
> return err;
>
>

Reviewed-by: Vladimir Zapolskiy <[email protected]>
Tested-by: Vladimir Zapolskiy <[email protected]>

--
With best wishes,
Vladimir

2018-05-03 07:53:18

by Jan Kiszka

[permalink] [raw]
Subject: Re: [PATCH v2 00/10] PCI: leak fixes, removable generic PCI host, assorted stuff

Hey Vladimir,

On 2018-05-03 09:12, Vladimir Zapolskiy wrote:
> Hi Jan,
>
> On 04/30/2018 08:48 AM, Jan Kiszka wrote:
>> Changes in v2:
>> - patch 1: commit message reworking as suggested by Lorenzo
>> - patch 3-6: split-up as suggested by Bjorn
>> - patch 8: new
>> - patch 10: select PCI_DOMAINS from PCI_HOST_GENERIC, rather than
>> allowing manual choice, as suggested by Lorenzo
>>
>> This primarily enables to unbind the generic PCI host controller without
>> leaving lots of memory leaks behind. A previous proposal patch 5 was
>> rejected because of those issues [1].
>>
>> The fixes have been validated in the Jailhouse setup, where we add and
>> remove a virtual PCI host controller on hypervisor activation/
>> deactivation, with the help of kmemleak.
>
> by chance I was looking into a memleak in of_pci_get_host_bridge_resources(),
> so I can give you a number of review tags.

Thanks for the reviews and tests! And the pointer for the maintainers to
the conflict around patch 7.

>
> FWIW the state of unfixably broken https://patchwork.kernel.org/patch/9662893/
> should be changed to obsoleted/deprecated/rejected.

Indeed.

Jan

--
Siemens AG, Corporate Technology, CT RDA IOT SES-DE
Corporate Competence Center Embedded Linux

2018-05-03 07:54:55

by Jan Kiszka

[permalink] [raw]
Subject: Re: [PATCH v2 08/10] PCI: Deprecate of_pci_get_host_bridge_resources()

On 2018-05-02 14:39, Christoph Hellwig wrote:
> On Mon, Apr 30, 2018 at 07:48:42AM +0200, Jan Kiszka wrote:
>> From: Jan Kiszka <[email protected]>
>>
>> There are no in-tree users remaining, all are converted to the managed
>> variant. And it is unlikely that any out-of-tree user got the resource
>> management right as well. So deprecate the interface and push users to
>> the managed version instead.
>>
>> To avoid raising a warning when exporting a deprecated symbol, wrap the
>> API with an inline and export an internal name.
>
> Don't deprecated it, just remove it.
>

I see a clear favorite now: consider this patch obsolete. I'll send a
separate removal patch, or a v3 of this series when otherwise needed.

Jan

--
Siemens AG, Corporate Technology, CT RDA IOT SES-DE
Corporate Competence Center Embedded Linux

2018-05-04 16:44:35

by Lorenzo Pieralisi

[permalink] [raw]
Subject: Re: [PATCH v2 07/10] PCI: Convert of_pci_get_host_bridge_resources() users to devm variant

On Thu, May 03, 2018 at 10:18:24AM +0300, Vladimir Zapolskiy wrote:
> Hi Jan,
>
> On 04/30/2018 08:48 AM, Jan Kiszka wrote:
> > From: Jan Kiszka <[email protected]>
> >
> > Straightforward for all of them, no more leaks afterwards.
> >
> > CC: Jingoo Han <[email protected]>
> > CC: Joao Pinto <[email protected]>
> > CC: Lorenzo Pieralisi <[email protected]>
> > Signed-off-by: Jan Kiszka <[email protected]>
> > Acked-by: Jingoo Han <[email protected]>
>
> [snip]
>
> > diff --git a/drivers/pci/host/pcie-rcar.c b/drivers/pci/host/pcie-rcar.c
> > index 6ab28f29ac6a..6eb36c924983 100644
> > --- a/drivers/pci/host/pcie-rcar.c
> > +++ b/drivers/pci/host/pcie-rcar.c
> > @@ -1067,12 +1067,11 @@ static int rcar_pcie_parse_request_of_pci_ranges(struct rcar_pcie *pci)
> > {
> > int err;
> > struct device *dev = pci->dev;
> > - struct device_node *np = dev->of_node;
> > resource_size_t iobase;
> > struct resource_entry *win, *tmp;
> >
> > - err = of_pci_get_host_bridge_resources(np, 0, 0xff, &pci->resources,
> > - &iobase);
> > + err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff,
> > + &pci->resources, &iobase);
> > if (err)
> > return err;
> >
>
> this one snippet is obsoleted by https://patchwork.ozlabs.org/patch/904326/
>
> If 08/10 remains a deprecation, then it is sufficient to exclude the R-Car change,
> otherwise I hope maintainers can deal with the proper ordering.

Isn't applying your patch:

https://patchwork.ozlabs.org/patch/904326/

and dropping the rcar hunk from this patch enough ?

Lorenzo

2018-05-05 07:44:04

by Vladimir Zapolskiy

[permalink] [raw]
Subject: Re: [PATCH v2 07/10] PCI: Convert of_pci_get_host_bridge_resources() users to devm variant

Hi Lorenzo,

On 05/04/2018 07:44 PM, Lorenzo Pieralisi wrote:
> On Thu, May 03, 2018 at 10:18:24AM +0300, Vladimir Zapolskiy wrote:
>> Hi Jan,
>>
>> On 04/30/2018 08:48 AM, Jan Kiszka wrote:
>>> From: Jan Kiszka <[email protected]>
>>>
>>> Straightforward for all of them, no more leaks afterwards.
>>>
>>> CC: Jingoo Han <[email protected]>
>>> CC: Joao Pinto <[email protected]>
>>> CC: Lorenzo Pieralisi <[email protected]>
>>> Signed-off-by: Jan Kiszka <[email protected]>
>>> Acked-by: Jingoo Han <[email protected]>
>>
>> [snip]
>>
>>> diff --git a/drivers/pci/host/pcie-rcar.c b/drivers/pci/host/pcie-rcar.c
>>> index 6ab28f29ac6a..6eb36c924983 100644
>>> --- a/drivers/pci/host/pcie-rcar.c
>>> +++ b/drivers/pci/host/pcie-rcar.c
>>> @@ -1067,12 +1067,11 @@ static int rcar_pcie_parse_request_of_pci_ranges(struct rcar_pcie *pci)
>>> {
>>> int err;
>>> struct device *dev = pci->dev;
>>> - struct device_node *np = dev->of_node;
>>> resource_size_t iobase;
>>> struct resource_entry *win, *tmp;
>>>
>>> - err = of_pci_get_host_bridge_resources(np, 0, 0xff, &pci->resources,
>>> - &iobase);
>>> + err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff,
>>> + &pci->resources, &iobase);
>>> if (err)
>>> return err;
>>>
>>
>> this one snippet is obsoleted by https://patchwork.ozlabs.org/patch/904326/
>>
>> If 08/10 remains a deprecation, then it is sufficient to exclude the R-Car change,
>> otherwise I hope maintainers can deal with the proper ordering.
>
> Isn't applying your patch:
>
> https://patchwork.ozlabs.org/patch/904326/
>
> and dropping the rcar hunk from this patch enough ?
>

absolutely, but it relies on any of two assumptions that
* my unmodified change is applied first, then Jan's adjusted change is applied,
* Jan's unmodified change is applied first, then my adjusted change is applied.

Otherwise there will be a trivial merge conflict, or even worse, if R-Car hunk
is removed as suggested, then of_pci_get_host_bridge_resources() is removed
instead of deprecation, and then my unmodified change is applied on top, it will
result in a window of commits, where R-Car PCIe driver won't be buildable, and
git-bisect users can be disappointed.

It makes little sense to include my change into Jan's series, thus I rely on
maintainers' awareness and smooth resolution of the issue by maintainers.

For what it's worth, I vote for of_pci_get_host_bridge_resources() removal.

--
With best wishes,
Vladimir

2018-05-08 13:30:17

by Bjorn Helgaas

[permalink] [raw]
Subject: Re: [PATCH v2 08/10] PCI: Deprecate of_pci_get_host_bridge_resources()

On Thu, May 03, 2018 at 09:53:58AM +0200, Jan Kiszka wrote:
> On 2018-05-02 14:39, Christoph Hellwig wrote:
> > On Mon, Apr 30, 2018 at 07:48:42AM +0200, Jan Kiszka wrote:
> >> From: Jan Kiszka <[email protected]>
> >>
> >> There are no in-tree users remaining, all are converted to the managed
> >> variant. And it is unlikely that any out-of-tree user got the resource
> >> management right as well. So deprecate the interface and push users to
> >> the managed version instead.
> >>
> >> To avoid raising a warning when exporting a deprecated symbol, wrap the
> >> API with an inline and export an internal name.
> >
> > Don't deprecated it, just remove it.
>
> I see a clear favorite now: consider this patch obsolete. I'll send a
> separate removal patch, or a v3 of this series when otherwise needed.

Can you just send an update to this patch to remove it? I've got these on
a branch and will just update my branch with the removal.

Then I'll coordinate with Lorenzo and make sure the dependency issue is
resolved.

2018-05-09 19:05:59

by Jan Kiszka

[permalink] [raw]
Subject: [PATCH v3 08/10] PCI: Remove of_pci_get_host_bridge_resources()

There are no in-tree users remaining, all are converted to the managed
variant. And it is unlikely that any out-of-tree user got the resource
management right as well. So remove the interface.

Signed-off-by: Jan Kiszka <[email protected]>
---

This replaces "PCI: Deprecate of_pci_get_host_bridge_resources()" from
the round v2.

drivers/pci/of.c | 88 +++++++++++++-------------------------------------
include/linux/of_pci.h | 10 ------
2 files changed, 22 insertions(+), 76 deletions(-)

diff --git a/drivers/pci/of.c b/drivers/pci/of.c
index 5a88d46a41b7..38469ffd1d7e 100644
--- a/drivers/pci/of.c
+++ b/drivers/pci/of.c
@@ -243,11 +243,29 @@ void of_pci_check_probe_only(void)
EXPORT_SYMBOL_GPL(of_pci_check_probe_only);

#if defined(CONFIG_OF_ADDRESS)
-static int __of_pci_get_host_bridge_resources(struct device *dev,
- struct device_node *dev_node,
+/**
+ * devm_of_pci_get_host_bridge_resources() - Resource-managed parsing of PCI
+ * host bridge resources from DT
+ * @dev: host bridge device
+ * @busno: bus number associated with the bridge root bus
+ * @bus_max: maximum number of buses for this bridge
+ * @resources: list where the range of resources will be added after DT parsing
+ * @io_base: pointer to a variable that will contain on return the physical
+ * address for the start of the I/O range. Can be NULL if the caller doesn't
+ * expect I/O ranges to be present in the device tree.
+ *
+ * This function will parse the "ranges" property of a PCI host bridge device
+ * node and setup the resource mapping based on its content. It is expected
+ * that the property conforms with the Power ePAPR document.
+ *
+ * It returns zero if the range parsing has been successful or a standard error
+ * value if it failed.
+ */
+int devm_of_pci_get_host_bridge_resources(struct device *dev,
unsigned char busno, unsigned char bus_max,
struct list_head *resources, resource_size_t *io_base)
{
+ struct device_node *dev_node = dev->of_node;
struct resource_entry *window;
struct resource *res;
struct resource *bus_range;
@@ -259,10 +277,7 @@ static int __of_pci_get_host_bridge_resources(struct device *dev,
if (io_base)
*io_base = (resource_size_t)OF_BAD_ADDR;

- if (dev)
- bus_range = devm_kzalloc(dev,sizeof(*bus_range), GFP_KERNEL);
- else
- bus_range = kzalloc(sizeof(*bus_range), GFP_KERNEL);
+ bus_range = devm_kzalloc(dev,sizeof(*bus_range), GFP_KERNEL);
if (!bus_range)
return -ENOMEM;

@@ -306,11 +321,7 @@ static int __of_pci_get_host_bridge_resources(struct device *dev,
if (range.cpu_addr == OF_BAD_ADDR || range.size == 0)
continue;

- if (dev)
- res = devm_kzalloc(dev, sizeof(struct resource),
- GFP_KERNEL);
- else
- res = kzalloc(sizeof(struct resource), GFP_KERNEL);
+ res = devm_kzalloc(dev, sizeof(struct resource), GFP_KERNEL);
if (!res) {
err = -ENOMEM;
goto parse_failed;
@@ -350,62 +361,7 @@ static int __of_pci_get_host_bridge_resources(struct device *dev,
pci_free_resource_list(resources);
return err;
}
-
-/**
- * of_pci_get_host_bridge_resources() - Parse PCI host bridge resources from DT
- * @dev_node: device node of the host bridge having the range property
- * @busno: bus number associated with the bridge root bus
- * @bus_max: maximum number of buses for this bridge
- * @resources: list where the range of resources will be added after DT parsing
- * @io_base: pointer to a variable that will contain on return the physical
- * address for the start of the I/O range. Can be NULL if the caller doesn't
- * expect I/O ranges to be present in the device tree.
- *
- * It is the caller's job to free the @resources list.
- *
- * This function will parse the "ranges" property of a PCI host bridge device
- * node and setup the resource mapping based on its content. It is expected
- * that the property conforms with the Power ePAPR document.
- *
- * It returns zero if the range parsing has been successful or a standard error
- * value if it failed.
- */
-int of_pci_get_host_bridge_resources(struct device_node *dev_node,
- unsigned char busno, unsigned char bus_max,
- struct list_head *resources, resource_size_t *io_base)
-{
- return __of_pci_get_host_bridge_resources(NULL, dev_node, busno,
- bus_max, resources, io_base);
-}
-EXPORT_SYMBOL_GPL(of_pci_get_host_bridge_resources);
-
-/**
- * of_pci_get_host_bridge_resources() - Resource-managed parsing of PCI host
- * bridge resources from DT
- * @dev: host bridge device
- * @busno: bus number associated with the bridge root bus
- * @bus_max: maximum number of buses for this bridge
- * @resources: list where the range of resources will be added after DT parsing
- * @io_base: pointer to a variable that will contain on return the physical
- * address for the start of the I/O range. Can be NULL if the caller doesn't
- * expect I/O ranges to be present in the device tree.
- *
- * This function will parse the "ranges" property of a PCI host bridge device
- * node and setup the resource mapping based on its content. It is expected
- * that the property conforms with the Power ePAPR document.
- *
- * It returns zero if the range parsing has been successful or a standard error
- * value if it failed.
- */
-int devm_of_pci_get_host_bridge_resources(struct device *dev,
- unsigned char busno, unsigned char bus_max,
- struct list_head *resources, resource_size_t *io_base)
-{
- return __of_pci_get_host_bridge_resources(dev, dev->of_node, busno,
- bus_max, resources, io_base);
-}
EXPORT_SYMBOL_GPL(devm_of_pci_get_host_bridge_resources);
-
#endif /* CONFIG_OF_ADDRESS */

/**
diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h
index 08b8f02426a5..fa4463a52900 100644
--- a/include/linux/of_pci.h
+++ b/include/linux/of_pci.h
@@ -71,20 +71,10 @@ of_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 pin)
#endif

#if defined(CONFIG_OF_ADDRESS)
-int of_pci_get_host_bridge_resources(struct device_node *dev_node,
- unsigned char busno, unsigned char bus_max,
- struct list_head *resources, resource_size_t *io_base);
int devm_of_pci_get_host_bridge_resources(struct device *dev,
unsigned char busno, unsigned char bus_max,
struct list_head *resources, resource_size_t *io_base);
#else
-static inline int of_pci_get_host_bridge_resources(struct device_node *dev_node,
- unsigned char busno, unsigned char bus_max,
- struct list_head *resources, resource_size_t *io_base)
-{
- return -EINVAL;
-}
-
static inline int devm_of_pci_get_host_bridge_resources(struct device *dev,
unsigned char busno, unsigned char bus_max,
struct list_head *resources, resource_size_t *io_base)
--
2.13.6

2018-05-10 22:51:59

by Bjorn Helgaas

[permalink] [raw]
Subject: Re: [PATCH v2 00/10] PCI: leak fixes, removable generic PCI host, assorted stuff

On Mon, Apr 30, 2018 at 07:48:34AM +0200, Jan Kiszka wrote:
> Changes in v2:
> - patch 1: commit message reworking as suggested by Lorenzo
> - patch 3-6: split-up as suggested by Bjorn
> - patch 8: new
> - patch 10: select PCI_DOMAINS from PCI_HOST_GENERIC, rather than
> allowing manual choice, as suggested by Lorenzo
>
> This primarily enables to unbind the generic PCI host controller without
> leaving lots of memory leaks behind. A previous proposal patch 5 was
> rejected because of those issues [1].
>
> The fixes have been validated in the Jailhouse setup, where we add and
> remove a virtual PCI host controller on hypervisor activation/
> deactivation, with the help of kmemleak.
>
> Besides that, there is tiny PCI API cleanup at the beginning and
> support for manually enabled PCI domains at the end that enables the
> Jailhouse scenario.
>
> Jan
>
> [1] http://lkml.iu.edu/hypermail/linux/kernel/1606.3/00072.html
>
>
> CC: Jingoo Han <[email protected]>
> CC: Joao Pinto <[email protected]>
> CC: Lorenzo Pieralisi <[email protected]>
> CC: Will Deacon <[email protected]>
>
> Jan Kiszka (10):
> PCI: Make pci_get_new_domain_nr() static
> PCI: Fix memory leak of devm_pci_alloc_host_bridge()
> PCI: Factor out __of_pci_get_host_bridge_resources()
> PCI: Add dev parameter to __of_pci_get_host_bridge_resources()
> PCI: Replace pr_*() with dev_*() in
> __of_pci_get_host_bridge_resources()
> PCI: Introduce devm_of_pci_get_host_bridge_resources()
> PCI: Convert of_pci_get_host_bridge_resources() users to devm variant
> PCI: Deprecate of_pci_get_host_bridge_resources()
> PCI: Add support for unbinding the generic PCI host controller
> PCI: Enable PCI_DOMAINS along with generic PCI host controller

Applied to pci/resource for v4.18, thanks!

I added the reviewed-by tags from Vladimir (thank you!) and replaced the
"Deprecate" patch by the v3 "Remove" patch.

> drivers/pci/dwc/pcie-designware-host.c | 2 +-
> drivers/pci/host/Kconfig | 1 +
> drivers/pci/host/pci-aardvark.c | 5 +-
> drivers/pci/host/pci-ftpci100.c | 4 +-
> drivers/pci/host/pci-host-common.c | 13 ++++
> drivers/pci/host/pci-host-generic.c | 1 +
> drivers/pci/host/pci-v3-semi.c | 3 +-
> drivers/pci/host/pci-versatile.c | 3 +-
> drivers/pci/host/pci-xgene.c | 3 +-
> drivers/pci/host/pcie-altera.c | 5 +-
> drivers/pci/host/pcie-iproc-platform.c | 4 +-
> drivers/pci/host/pcie-rcar.c | 5 +-
> drivers/pci/host/pcie-rockchip.c | 4 +-
> drivers/pci/host/pcie-xilinx-nwl.c | 4 +-
> drivers/pci/host/pcie-xilinx.c | 4 +-
> drivers/pci/of.c | 105 +++++++++++++++++++++------------
> drivers/pci/pci.c | 6 +-
> drivers/pci/probe.c | 4 +-
> include/linux/of_pci.h | 42 ++++++++++++-
> include/linux/pci-ecam.h | 1 +
> include/linux/pci.h | 3 -
> 21 files changed, 149 insertions(+), 73 deletions(-)
>
> --
> 2.13.6
>