Discussion:
[PATCH RFC 2/2] drivers: pci: convert generic host controller to DT resource parsing API
Lorenzo Pieralisi
2014-10-23 15:23:07 UTC
Permalink
In order to consolidate DT configuration for PCI host controllers in the
kernel, a new API (ie of_pci_get_host_bridge_resources()) was developed
to allow parsing and assigning IO/BUS/MEM resources from DT, removing
duplicated code present in the majority of pci host driver implementations.

This patch converts the existing PCI generic host controller driver to
the new API. Most of the code parsing ranges and creating resources is
now delegated to of_pci_get_host_bridge_resources() API.

The PCI host controller code carries out resources filtering on the
resulting resource list and maps IO space by using the newly introduced
pci_ioremap_iospace() API.

New code supports only one IO resource per generic host controller, which
should cater for all existing host controller configurations.

Cc: Arnd Bergmann <***@arndb.de>
Cc: Will Deacon <***@arm.com>
Cc: Bjorn Helgaas <***@google.com>
Signed-off-by: Lorenzo Pieralisi <***@arm.com>
---
drivers/pci/host/pci-host-generic.c | 120 ++++++++----------------------------
1 file changed, 27 insertions(+), 93 deletions(-)

diff --git a/drivers/pci/host/pci-host-generic.c b/drivers/pci/host/pci-host-generic.c
index 1e1a80f..1895907 100644
--- a/drivers/pci/host/pci-host-generic.c
+++ b/drivers/pci/host/pci-host-generic.c
@@ -32,7 +32,7 @@ struct gen_pci_cfg_bus_ops {

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

const struct gen_pci_cfg_bus_ops *ops;
@@ -50,7 +50,7 @@ static void __iomem *gen_pci_map_cfg_bus_cam(struct pci_bus *bus,
{
struct pci_sys_data *sys = bus->sysdata;
struct gen_pci *pci = sys->private_data;
- resource_size_t idx = bus->number - pci->cfg.bus_range.start;
+ resource_size_t idx = bus->number - pci->cfg.bus_range->start;

return pci->cfg.win[idx] + ((devfn << 8) | where);
}
@@ -66,7 +66,7 @@ static void __iomem *gen_pci_map_cfg_bus_ecam(struct pci_bus *bus,
{
struct pci_sys_data *sys = bus->sysdata;
struct gen_pci *pci = sys->private_data;
- resource_size_t idx = bus->number - pci->cfg.bus_range.start;
+ resource_size_t idx = bus->number - pci->cfg.bus_range->start;

return pci->cfg.win[idx] + ((devfn << 12) | where);
}
@@ -138,106 +138,50 @@ static const struct of_device_id gen_pci_of_match[] = {
};
MODULE_DEVICE_TABLE(of, gen_pci_of_match);

-static int gen_pci_calc_io_offset(struct device *dev,
- struct of_pci_range *range,
- struct resource *res,
- resource_size_t *offset)
-{
- static atomic_t wins = ATOMIC_INIT(0);
- int err, idx, max_win;
- unsigned int window;
-
- if (!PAGE_ALIGNED(range->cpu_addr))
- return -EINVAL;
-
- max_win = (IO_SPACE_LIMIT + 1) / SZ_64K;
- idx = atomic_inc_return(&wins);
- if (idx > max_win)
- return -ENOSPC;
-
- window = (idx - 1) * SZ_64K;
- err = pci_ioremap_io(window, range->cpu_addr);
- if (err)
- return err;
-
- of_pci_range_to_resource(range, dev->of_node, res);
- res->start = window;
- res->end = res->start + range->size - 1;
- *offset = window - range->pci_addr;
- return 0;
-}
-
-static int gen_pci_calc_mem_offset(struct device *dev,
- struct of_pci_range *range,
- struct resource *res,
- resource_size_t *offset)
-{
- of_pci_range_to_resource(range, dev->of_node, res);
- *offset = range->cpu_addr - range->pci_addr;
- return 0;
-}
-
static void gen_pci_release_of_pci_ranges(struct gen_pci *pci)
{
- struct pci_host_bridge_window *win;
-
- list_for_each_entry(win, &pci->resources, list)
- release_resource(win->res);
-
pci_free_resource_list(&pci->resources);
}

static int gen_pci_parse_request_of_pci_ranges(struct gen_pci *pci)
{
- struct of_pci_range range;
- struct of_pci_range_parser parser;
int err, res_valid = 0;
struct device *dev = pci->host.dev.parent;
struct device_node *np = dev->of_node;
+ resource_size_t iobase;
+ struct pci_host_bridge_window *win;

- if (of_pci_range_parser_init(&parser, np)) {
- dev_err(dev, "missing \"ranges\" property\n");
- return -EINVAL;
- }
+ err = of_pci_get_host_bridge_resources(np, 0, 0xff, &pci->resources,
+ &iobase);
+ if (err)
+ return err;

- for_each_of_pci_range(&parser, &range) {
- struct resource *parent, *res;
- resource_size_t offset;
- u32 restype = range.flags & IORESOURCE_TYPE_BITS;
+ list_for_each_entry(win, &pci->resources, list) {
+ struct resource *parent, *res = win->res;

- res = devm_kmalloc(dev, sizeof(*res), GFP_KERNEL);
- if (!res) {
- err = -ENOMEM;
- goto out_release_res;
- }
-
- switch (restype) {
+ switch (resource_type(res)) {
case IORESOURCE_IO:
parent = &ioport_resource;
- err = gen_pci_calc_io_offset(dev, &range, res, &offset);
+ err = pci_remap_iospace(res, iobase);
+ if (err) {
+ dev_warn(dev, "error %d: failed to map resource %pR\n",
+ err, res);
+ continue;
+ }
break;
case IORESOURCE_MEM:
parent = &iomem_resource;
- err = gen_pci_calc_mem_offset(dev, &range, res, &offset);
- res_valid |= !(res->flags & IORESOURCE_PREFETCH || err);
+ res_valid |= !(res->flags & IORESOURCE_PREFETCH);
break;
+ case IORESOURCE_BUS:
+ pci->cfg.bus_range = res;
default:
- err = -EINVAL;
continue;
}

- if (err) {
- dev_warn(dev,
- "error %d: failed to add resource [type 0x%x, %lld bytes]\n",
- err, restype, range.size);
- continue;
- }
-
- err = request_resource(parent, res);
+ err = devm_request_resource(dev, parent, res);
if (err)
goto out_release_res;
-
- pci_add_resource_offset(&pci->resources, res, offset);
}

if (!res_valid) {
@@ -262,14 +206,6 @@ static int gen_pci_parse_map_cfg_windows(struct gen_pci *pci)
struct device *dev = pci->host.dev.parent;
struct device_node *np = dev->of_node;

- if (of_pci_parse_bus_range(np, &pci->cfg.bus_range))
- pci->cfg.bus_range = (struct resource) {
- .name = np->name,
- .start = 0,
- .end = 0xff,
- .flags = IORESOURCE_BUS,
- };
-
err = of_address_to_resource(np, 0, &pci->cfg.res);
if (err) {
dev_err(dev, "missing \"reg\" property\n");
@@ -277,12 +213,12 @@ static int gen_pci_parse_map_cfg_windows(struct gen_pci *pci)
}

/* Limit the bus-range to fit within reg */
- bus_max = pci->cfg.bus_range.start +
+ 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.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),
+ pci->cfg.win = devm_kcalloc(dev, resource_size(pci->cfg.bus_range),
sizeof(*pci->cfg.win), GFP_KERNEL);
if (!pci->cfg.win)
return -ENOMEM;
@@ -293,7 +229,7 @@ static int gen_pci_parse_map_cfg_windows(struct gen_pci *pci)
"Configuration Space"))
return -ENOMEM;

- bus_range = &pci->cfg.bus_range;
+ bus_range = pci->cfg.bus_range;
for (busn = bus_range->start; busn <= bus_range->end; ++busn) {
u32 idx = busn - bus_range->start;
u32 sz = 1 << pci->cfg.ops->bus_shift;
@@ -305,8 +241,6 @@ static int gen_pci_parse_map_cfg_windows(struct gen_pci *pci)
return -ENOMEM;
}

- /* Register bus resource */
- pci_add_resource(&pci->resources, bus_range);
return 0;
}
--
2.1.2
Bjorn Helgaas
2014-10-23 22:27:07 UTC
Permalink
The number of windows allocated for the host bridge depends on the
bus resource. Instead of first allocating the windows and then
limit the bus resource, this patch reshuffles the code so that if any
limitation is applied to the bus resource it is taken into account in
the windows allocation.
Hi Lorenzo,

I can *read* your patches just fine, but when I save them using mutt to
apply them, they look like this:

--- a/drivers/pci/host/pci-host-generic.c
+++ b/drivers/pci/host/pci-host-generic.c
@@ -276,17 +276,17 @@ static int gen_pci_parse_map_cfg_windows(struct gen_p=
ci *pci)
=09=09return err;
=09}
=20
-=09pci->cfg.win =3D devm_kcalloc(dev,
resource_size(&pci->cfg.bus_range),

I can work around this by downloading them another way, but it is a
bit of a hassle. I *think* this is because your email has

Content-Type: text/plain; charset=WINDOWS-1252

which apparently confuses mutt. Any idea why this is? Anybody know how I
can fix mutt to deal with this?

Bjorn
Lorenzo Pieralisi
2014-10-24 08:53:44 UTC
Permalink
Post by Bjorn Helgaas
The number of windows allocated for the host bridge depends on the
bus resource. Instead of first allocating the windows and then
limit the bus resource, this patch reshuffles the code so that if any
limitation is applied to the bus resource it is taken into account in
the windows allocation.
Hi Lorenzo,
I can *read* your patches just fine, but when I save them using mutt to
--- a/drivers/pci/host/pci-host-generic.c
+++ b/drivers/pci/host/pci-host-generic.c
@@ -276,17 +276,17 @@ static int gen_pci_parse_map_cfg_windows(struct gen_p=
ci *pci)
=09=09return err;
=09}
=20
-=09pci->cfg.win =3D devm_kcalloc(dev,
resource_size(&pci->cfg.bus_range),
I can work around this by downloading them another way, but it is a
bit of a hassle. I *think* this is because your email has
Content-Type: text/plain; charset=WINDOWS-1252
Yes, it is the SMTP server messing about with patches, I will have to switch
to another one, sorry.

I pushed a branch on my arm git:

git://linux-arm.org/linux-2.6-lp.git pci-host-generic

I can also resend the patches, whatever it is best for you.

Thanks,
Lorenzo
Liviu Dudau
2014-10-24 09:04:09 UTC
Permalink
Post by Bjorn Helgaas
The number of windows allocated for the host bridge depends on the
bus resource. Instead of first allocating the windows and then
limit the bus resource, this patch reshuffles the code so that if a=
ny
Post by Bjorn Helgaas
limitation is applied to the bus resource it is taken into account =
in
Post by Bjorn Helgaas
the windows allocation.
=20
=20
Hi Lorenzo,
=20
I can *read* your patches just fine, but when I save them using mutt =
to
Post by Bjorn Helgaas
=20
--- a/drivers/pci/host/pci-host-generic.c
+++ b/drivers/pci/host/pci-host-generic.c
@@ -276,17 +276,17 @@ static int gen_pci_parse_map_cfg_windows(stru=
ct gen_p=3D
Post by Bjorn Helgaas
ci *pci)
=3D09=3D09return err;
=3D09}
=3D20
-=3D09pci->cfg.win =3D3D devm_kcalloc(dev,
resource_size(&pci->cfg.bus_range),
=20
I can work around this by downloading them another way, but it is a
bit of a hassle. I *think* this is because your email has
=20
Content-Type: text/plain; charset=3DWINDOWS-1252
=20
which apparently confuses mutt. Any idea why this is? Anybody know =
how I
Post by Bjorn Helgaas
can fix mutt to deal with this?
I use decode-save (<Esc>s on my setup) to save the attachment(s). Somet=
imes
it works well enough, although more often than not tabs get lost.

Best regards,
Liviu
Post by Bjorn Helgaas
=20
Bjorn
=20
--=20
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
| I would like to |
| fix the world, |
| but they're not |
| giving me the |
\ source code! /
---------------
=C2=AF\_(=E3=83=84)_/=C2=AF
Arnd Bergmann
2014-10-24 10:55:33 UTC
Permalink
Post by Bjorn Helgaas
The number of windows allocated for the host bridge depends on the
bus resource. Instead of first allocating the windows and then
limit the bus resource, this patch reshuffles the code so that if any
limitation is applied to the bus resource it is taken into account in
the windows allocation.
Hi Lorenzo,
I can *read* your patches just fine, but when I save them using mutt to
--- a/drivers/pci/host/pci-host-generic.c
+++ b/drivers/pci/host/pci-host-generic.c
@@ -276,17 +276,17 @@ static int gen_pci_parse_map_cfg_windows(struct gen_p=
ci *pci)
=09=09return err;
=09}
=20
-=09pci->cfg.win =3D devm_kcalloc(dev,
resource_size(&pci->cfg.bus_range),
I can work around this by downloading them another way, but it is a
bit of a hassle. I *think* this is because your email has
Content-Type: text/plain; charset=WINDOWS-1252
which apparently confuses mutt. Any idea why this is? Anybody know how I
can fix mutt to deal with this?
I use decode-save (<Esc>s on my setup) to save the attachment(s). Sometimes
it works well enough, although more often than not tabs get lost.
I just tried applying the patches locally here. The patch looks the same way
for me, but 'git am' actually works while 'patch' does not.

Maybe Bjorn is using an outdated git version. While the patch clearly shouldn't
have been sent that way, I think git has been changed now to work around that.
I'm using a git-2.1 snapshot here.

Arnd

Loading...