Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1958e717 authored by Jayachandran C's avatar Jayachandran C Committed by Bjorn Helgaas
Browse files

PCI: generic, thunder: Use generic ECAM API



Use functions provided by drivers/pci/ecam.h for mapping the config space
in drivers/pci/host/pci-host-common.c, and update its users to use 'struct
pci_config_window' and 'struct pci_ecam_ops'.

The changes are mostly to use 'struct pci_config_window' in place of
'struct gen_pci'.  Some of the fields of gen_pci were only used temporarily
and can be eliminated by using local variables or function arguments, these
are not carried over to struct pci_config_window.

pci-thunder-ecam.c and pci-thunder-pem.c are the only users of the
pci_host_common_probe function and the gen_pci structure; these have been
updated to use the new API as well.

The patch does not introduce any functional changes other than a very minor
one: with the new code, on 64-bit platforms, we do just a single ioremap
for the whole config space.

Signed-off-by: default avatarJayachandran C <jchandra@broadcom.com>
Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
parent 35ff9477
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -59,4 +59,9 @@ void __iomem *pci_ecam_map_bus(struct pci_bus *bus, unsigned int devfn,
/* default ECAM ops */
extern struct pci_ecam_ops pci_generic_ecam_ops;

#ifdef CONFIG_PCI_HOST_GENERIC
/* for DT-based PCI controllers that support ECAM */
int pci_host_common_probe(struct platform_device *pdev,
			  struct pci_ecam_ops *ops);
#endif
#endif
+1 −0
Original line number Diff line number Diff line
@@ -77,6 +77,7 @@ config PCI_RCAR_GEN2_PCIE

config PCI_HOST_COMMON
	bool
	select PCI_ECAM

config PCI_HOST_GENERIC
	bool "Generic PCI host controller"
+46 −68
Original line number Diff line number Diff line
@@ -22,27 +22,21 @@
#include <linux/of_pci.h>
#include <linux/platform_device.h>

#include "pci-host-common.h"
#include "../ecam.h"

static void gen_pci_release_of_pci_ranges(struct gen_pci *pci)
{
	pci_free_resource_list(&pci->resources);
}

static int gen_pci_parse_request_of_pci_ranges(struct gen_pci *pci)
static int gen_pci_parse_request_of_pci_ranges(struct device *dev,
		       struct list_head *resources, struct resource **bus_range)
{
	int err, res_valid = 0;
	struct device *dev = pci->host.dev.parent;
	struct device_node *np = dev->of_node;
	resource_size_t iobase;
	struct resource_entry *win;

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

	resource_list_for_each_entry(win, &pci->resources) {
	resource_list_for_each_entry(win, resources) {
		struct resource *parent, *res = win->res;

		switch (resource_type(res)) {
@@ -60,7 +54,7 @@ static int gen_pci_parse_request_of_pci_ranges(struct gen_pci *pci)
			res_valid |= !(res->flags & IORESOURCE_PREFETCH);
			break;
		case IORESOURCE_BUS:
			pci->cfg.bus_range = res;
			*bus_range = res;
		default:
			continue;
		}
@@ -79,65 +73,60 @@ static int gen_pci_parse_request_of_pci_ranges(struct gen_pci *pci)
	return 0;

out_release_res:
	gen_pci_release_of_pci_ranges(pci);
	return err;
}

static int gen_pci_parse_map_cfg_windows(struct gen_pci *pci)
static void gen_pci_unmap_cfg(void *ptr)
{
	pci_ecam_free((struct pci_config_window *)ptr);
}

static struct pci_config_window *gen_pci_init(struct device *dev,
		struct list_head *resources, struct pci_ecam_ops *ops)
{
	int err;
	u8 bus_max;
	resource_size_t busn;
	struct resource *bus_range;
	struct device *dev = pci->host.dev.parent;
	struct device_node *np = dev->of_node;
	u32 sz = 1 << pci->cfg.ops->bus_shift;
	struct resource cfgres;
	struct resource *bus_range = NULL;
	struct pci_config_window *cfg;

	err = of_address_to_resource(np, 0, &pci->cfg.res);
	/* Parse our PCI ranges and request their resources */
	err = gen_pci_parse_request_of_pci_ranges(dev, resources, &bus_range);
	if (err)
		goto err_out;

	err = of_address_to_resource(dev->of_node, 0, &cfgres);
	if (err) {
		dev_err(dev, "missing \"reg\" property\n");
		return err;
		goto err_out;
	}

	/* Limit the bus-range to fit within reg */
	bus_max = pci->cfg.bus_range->start +
		  (resource_size(&pci->cfg.res) >> pci->cfg.ops->bus_shift) - 1;
	pci->cfg.bus_range->end = min_t(resource_size_t,
					pci->cfg.bus_range->end, bus_max);

	pci->cfg.win = devm_kcalloc(dev, resource_size(pci->cfg.bus_range),
				    sizeof(*pci->cfg.win), GFP_KERNEL);
	if (!pci->cfg.win)
		return -ENOMEM;

	/* Map our Configuration Space windows */
	if (!devm_request_mem_region(dev, pci->cfg.res.start,
				     resource_size(&pci->cfg.res),
				     "Configuration Space"))
		return -ENOMEM;

	bus_range = pci->cfg.bus_range;
	for (busn = bus_range->start; busn <= bus_range->end; ++busn) {
		u32 idx = busn - bus_range->start;

		pci->cfg.win[idx] = devm_ioremap(dev,
						 pci->cfg.res.start + idx * sz,
						 sz);
		if (!pci->cfg.win[idx])
			return -ENOMEM;
	cfg = pci_ecam_create(dev, &cfgres, bus_range, ops);
	if (IS_ERR(cfg)) {
		err = PTR_ERR(cfg);
		goto err_out;
	}

	return 0;
	err = devm_add_action(dev, gen_pci_unmap_cfg, cfg);
	if (err) {
		gen_pci_unmap_cfg(cfg);
		goto err_out;
	}
	return cfg;

err_out:
	pci_free_resource_list(resources);
	return ERR_PTR(err);
}

int pci_host_common_probe(struct platform_device *pdev,
			  struct gen_pci *pci)
			  struct pci_ecam_ops *ops)
{
	int err;
	const char *type;
	struct device *dev = &pdev->dev;
	struct device_node *np = dev->of_node;
	struct pci_bus *bus, *child;
	struct pci_config_window *cfg;
	struct list_head resources;

	type = of_get_property(np, "device_type", NULL);
	if (!type || strcmp(type, "pci")) {
@@ -147,29 +136,18 @@ int pci_host_common_probe(struct platform_device *pdev,

	of_pci_check_probe_only();

	pci->host.dev.parent = dev;
	INIT_LIST_HEAD(&pci->host.windows);
	INIT_LIST_HEAD(&pci->resources);

	/* Parse our PCI ranges and request their resources */
	err = gen_pci_parse_request_of_pci_ranges(pci);
	if (err)
		return err;

	/* Parse and map our Configuration Space windows */
	err = gen_pci_parse_map_cfg_windows(pci);
	if (err) {
		gen_pci_release_of_pci_ranges(pci);
		return err;
	}
	INIT_LIST_HEAD(&resources);
	cfg = gen_pci_init(dev, &resources, ops);
	if (IS_ERR(cfg))
		return PTR_ERR(cfg);

	/* Do not reassign resources if probe only */
	if (!pci_has_flag(PCI_PROBE_ONLY))
		pci_add_flags(PCI_REASSIGN_ALL_RSRC | PCI_REASSIGN_ALL_BUS);


	bus = pci_scan_root_bus(dev, pci->cfg.bus_range->start,
				&pci->cfg.ops->ops, pci, &pci->resources);
	bus = pci_scan_root_bus(dev, cfg->busr.start, &ops->pci_ops, cfg,
				&resources);
	if (!bus) {
		dev_err(dev, "Scanning rootbus failed");
		return -ENODEV;
+0 −47
Original line number Diff line number Diff line
/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Copyright (C) 2014 ARM Limited
 *
 * Author: Will Deacon <will.deacon@arm.com>
 */

#ifndef _PCI_HOST_COMMON_H
#define _PCI_HOST_COMMON_H

#include <linux/kernel.h>
#include <linux/platform_device.h>

struct gen_pci_cfg_bus_ops {
	u32 bus_shift;
	struct pci_ops ops;
};

struct gen_pci_cfg_windows {
	struct resource				res;
	struct resource				*bus_range;
	void __iomem				**win;

	struct gen_pci_cfg_bus_ops		*ops;
};

struct gen_pci {
	struct pci_host_bridge			host;
	struct gen_pci_cfg_windows		cfg;
	struct list_head			resources;
};

int pci_host_common_probe(struct platform_device *pdev,
			  struct gen_pci *pci);

#endif /* _PCI_HOST_COMMON_H */
+10 −42
Original line number Diff line number Diff line
@@ -25,41 +25,12 @@
#include <linux/of_pci.h>
#include <linux/platform_device.h>

#include "pci-host-common.h"
#include "../ecam.h"

static void __iomem *gen_pci_map_cfg_bus_cam(struct pci_bus *bus,
					     unsigned int devfn,
					     int where)
{
	struct gen_pci *pci = bus->sysdata;
	resource_size_t idx = bus->number - pci->cfg.bus_range->start;

	return pci->cfg.win[idx] + ((devfn << 8) | where);
}

static struct gen_pci_cfg_bus_ops gen_pci_cfg_cam_bus_ops = {
static struct pci_ecam_ops gen_pci_cfg_cam_bus_ops = {
	.bus_shift	= 16,
	.ops		= {
		.map_bus	= gen_pci_map_cfg_bus_cam,
		.read		= pci_generic_config_read,
		.write		= pci_generic_config_write,
	}
};

static void __iomem *gen_pci_map_cfg_bus_ecam(struct pci_bus *bus,
					      unsigned int devfn,
					      int where)
{
	struct gen_pci *pci = bus->sysdata;
	resource_size_t idx = bus->number - pci->cfg.bus_range->start;

	return pci->cfg.win[idx] + ((devfn << 12) | where);
}

static struct gen_pci_cfg_bus_ops gen_pci_cfg_ecam_bus_ops = {
	.bus_shift	= 20,
	.ops		= {
		.map_bus	= gen_pci_map_cfg_bus_ecam,
	.pci_ops	= {
		.map_bus	= pci_ecam_map_bus,
		.read		= pci_generic_config_read,
		.write		= pci_generic_config_write,
	}
@@ -70,25 +41,22 @@ static const struct of_device_id gen_pci_of_match[] = {
	  .data = &gen_pci_cfg_cam_bus_ops },

	{ .compatible = "pci-host-ecam-generic",
	  .data = &gen_pci_cfg_ecam_bus_ops },
	  .data = &pci_generic_ecam_ops },

	{ },
};

MODULE_DEVICE_TABLE(of, gen_pci_of_match);

static int gen_pci_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	const struct of_device_id *of_id;
	struct gen_pci *pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL);

	if (!pci)
		return -ENOMEM;
	struct pci_ecam_ops *ops;

	of_id = of_match_node(gen_pci_of_match, dev->of_node);
	pci->cfg.ops = (struct gen_pci_cfg_bus_ops *)of_id->data;
	of_id = of_match_node(gen_pci_of_match, pdev->dev.of_node);
	ops = (struct pci_ecam_ops *)of_id->data;

	return pci_host_common_probe(pdev, pci);
	return pci_host_common_probe(pdev, ops);
}

static struct platform_driver gen_pci_driver = {
Loading