From: Bjorn Helgaas <bhelgaas@google.com>
To: linux-pci@vger.kernel.org
Cc: linux-arch@vger.kernel.org
Subject: [RFC PATCH v1 04/18] PCI: convert bus addresses to resource when reading BARs
Date: Mon, 30 Jan 2012 09:57:29 -0700 [thread overview]
Message-ID: <20120130165729.3231.45754.stgit@bhelgaas.mtv.corp.google.com> (raw)
In-Reply-To: <20120130165430.3231.97740.stgit@bhelgaas.mtv.corp.google.com>
Some PCI host bridges translate CPU addresses to PCI bus addresses.
Previously, we initialized pci_dev resources with PCI bus addresses,
then converted them to CPU addresses later in arch-specific code
(pcibios_fixup_resources()), which leaves a window of time where the
pci_dev resources are incorrect.
This patch adds support in the core for this address translation.
When the arch creates the root bus, it can supply the host bridge
address translation information, and the core can use it to set the
pci_dev resources correctly from the beginning.
This gives us a way to fix the problem that quirks that run between device
discovery and pcibios_fixup_resources() fail because they use pci_dev
resources that haven't been converted. The reference below is to one
such problem that affected ARM and ia64.
Note that this patch has no effect until an arch starts using
pci_add_resource_offset() with a non-zero offset: before that, all
all host bridge windows have a zero offset and pci_bus_to_resource()
copies the pci_bus_region directly to the struct resource.
Reference: https://lkml.org/lkml/2009/10/12/405
---
drivers/pci/probe.c | 129 +++++++++++++++++++++++++++++++++++++++++----------
1 files changed, 104 insertions(+), 25 deletions(-)
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 4c28aec..ba60f41 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -61,6 +61,63 @@ static struct pci_host_bridge *pci_host_bridge(struct pci_dev *dev)
return NULL;
}
+static bool resource_contains(struct resource *res1, struct resource *res2)
+{
+ return res1->start <= res2->start && res1->end >= res2->end;
+}
+
+void pci_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
+ struct resource *res)
+{
+ struct pci_host_bridge *bridge = pci_host_bridge(dev);
+ struct pci_host_bridge_window *window;
+ resource_size_t offset = 0;
+
+ list_for_each_entry(window, &bridge->windows, list) {
+ if (resource_type(res) != resource_type(window->res))
+ continue;
+
+ if (resource_contains(window->res, res)) {
+ offset = window->offset;
+ break;
+ }
+ }
+
+ region->start = res->start - offset;
+ region->end = res->end - offset;
+}
+
+static bool region_contains(struct pci_bus_region *region1,
+ struct pci_bus_region *region2)
+{
+ return region1->start <= region2->start && region1->end >= region2->end;
+}
+
+void pci_bus_to_resource(struct pci_dev *dev, struct resource *res,
+ struct pci_bus_region *region)
+{
+ struct pci_host_bridge *bridge = pci_host_bridge(dev);
+ struct pci_host_bridge_window *window;
+ struct pci_bus_region bus_region;
+ resource_size_t offset = 0;
+
+ list_for_each_entry(window, &bridge->windows, list) {
+ if (resource_type(res) != resource_type(window->res))
+ continue;
+
+ bus_region.start = window->res->start - window->offset;
+ bus_region.end = window->res->end - window->offset;
+
+ if (region_contains(&bus_region, region)) {
+ offset = window->offset;
+ break;
+ }
+ }
+
+ res->start = region->start + offset;
+ res->end = region->end + offset;
+}
+
/*
* PCI Bus Class
*/
@@ -154,6 +211,7 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
{
u32 l, sz, mask;
u16 orig_cmd;
+ struct pci_bus_region region;
mask = type ? PCI_ROM_ADDRESS_MASK : ~0;
@@ -233,11 +291,13 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
/* Address above 32-bit boundary; disable the BAR */
pci_write_config_dword(dev, pos, 0);
pci_write_config_dword(dev, pos + 4, 0);
- res->start = 0;
- res->end = sz64;
+ region.start = 0;
+ region.end = sz64;
+ pci_bus_to_resource(dev, res, ®ion);
} else {
- res->start = l64;
- res->end = l64 + sz64;
+ region.start = l64;
+ region.end = l64 + sz64;
+ pci_bus_to_resource(dev, res, ®ion);
dev_printk(KERN_DEBUG, &dev->dev, "reg %x: %pR\n",
pos, res);
}
@@ -247,8 +307,9 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
if (!sz)
goto fail;
- res->start = l;
- res->end = l + sz;
+ region.start = l;
+ region.end = l + sz;
+ pci_bus_to_resource(dev, res, ®ion);
dev_printk(KERN_DEBUG, &dev->dev, "reg %x: %pR\n", pos, res);
}
@@ -285,7 +346,8 @@ static void __devinit pci_read_bridge_io(struct pci_bus *child)
struct pci_dev *dev = child->self;
u8 io_base_lo, io_limit_lo;
unsigned long base, limit;
- struct resource *res;
+ struct pci_bus_region region;
+ struct resource *res, res2;
res = child->resource[0];
pci_read_config_byte(dev, PCI_IO_BASE, &io_base_lo);
@@ -303,10 +365,13 @@ static void __devinit pci_read_bridge_io(struct pci_bus *child)
if (base && base <= limit) {
res->flags = (io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO;
+ region.start = base;
+ region.end = limit + 0xfff;
+ pci_bus_to_resource(dev, &res2, ®ion);
if (!res->start)
- res->start = base;
+ res->start = res2.start;
if (!res->end)
- res->end = limit + 0xfff;
+ res->end = res2.end;
dev_printk(KERN_DEBUG, &dev->dev, " bridge window %pR\n", res);
}
}
@@ -316,6 +381,7 @@ static void __devinit pci_read_bridge_mmio(struct pci_bus *child)
struct pci_dev *dev = child->self;
u16 mem_base_lo, mem_limit_lo;
unsigned long base, limit;
+ struct pci_bus_region region;
struct resource *res;
res = child->resource[1];
@@ -325,8 +391,9 @@ static void __devinit pci_read_bridge_mmio(struct pci_bus *child)
limit = (mem_limit_lo & PCI_MEMORY_RANGE_MASK) << 16;
if (base && base <= limit) {
res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM;
- res->start = base;
- res->end = limit + 0xfffff;
+ region.start = base;
+ region.end = limit + 0xfffff;
+ pci_bus_to_resource(dev, res, ®ion);
dev_printk(KERN_DEBUG, &dev->dev, " bridge window %pR\n", res);
}
}
@@ -336,6 +403,7 @@ static void __devinit pci_read_bridge_mmio_pref(struct pci_bus *child)
struct pci_dev *dev = child->self;
u16 mem_base_lo, mem_limit_lo;
unsigned long base, limit;
+ struct pci_bus_region region;
struct resource *res;
res = child->resource[2];
@@ -372,8 +440,9 @@ static void __devinit pci_read_bridge_mmio_pref(struct pci_bus *child)
IORESOURCE_MEM | IORESOURCE_PREFETCH;
if (res->flags & PCI_PREF_RANGE_TYPE_64)
res->flags |= IORESOURCE_MEM_64;
- res->start = base;
- res->end = limit + 0xfffff;
+ region.start = base;
+ region.end = limit + 0xfffff;
+ pci_bus_to_resource(dev, res, ®ion);
dev_printk(KERN_DEBUG, &dev->dev, " bridge window %pR\n", res);
}
}
@@ -914,6 +983,8 @@ int pci_setup_device(struct pci_dev *dev)
u8 hdr_type;
struct pci_slot *slot;
int pos = 0;
+ struct pci_bus_region region;
+ struct resource *res;
if (pci_read_config_byte(dev, PCI_HEADER_TYPE, &hdr_type))
return -EIO;
@@ -977,20 +1048,28 @@ int pci_setup_device(struct pci_dev *dev)
u8 progif;
pci_read_config_byte(dev, PCI_CLASS_PROG, &progif);
if ((progif & 1) == 0) {
- dev->resource[0].start = 0x1F0;
- dev->resource[0].end = 0x1F7;
- dev->resource[0].flags = LEGACY_IO_RESOURCE;
- dev->resource[1].start = 0x3F6;
- dev->resource[1].end = 0x3F6;
- dev->resource[1].flags = LEGACY_IO_RESOURCE;
+ region.start = 0x1F0;
+ region.end = 0x1F7;
+ res = &dev->resource[0];
+ res->flags = LEGACY_IO_RESOURCE;
+ pci_bus_to_resource(dev, res, ®ion);
+ region.start = 0x3F6;
+ region.end = 0x3F6;
+ res = &dev->resource[1];
+ res->flags = LEGACY_IO_RESOURCE;
+ pci_bus_to_resource(dev, res, ®ion);
}
if ((progif & 4) == 0) {
- dev->resource[2].start = 0x170;
- dev->resource[2].end = 0x177;
- dev->resource[2].flags = LEGACY_IO_RESOURCE;
- dev->resource[3].start = 0x376;
- dev->resource[3].end = 0x376;
- dev->resource[3].flags = LEGACY_IO_RESOURCE;
+ region.start = 0x170;
+ region.end = 0x177;
+ res = &dev->resource[2];
+ res->flags = LEGACY_IO_RESOURCE;
+ pci_bus_to_resource(dev, res, ®ion);
+ region.start = 0x376;
+ region.end = 0x376;
+ res = &dev->resource[3];
+ res->flags = LEGACY_IO_RESOURCE;
+ pci_bus_to_resource(dev, res, ®ion);
}
}
break;
next prev parent reply other threads:[~2012-01-30 16:57 UTC|newest]
Thread overview: 57+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-01-30 16:57 [RFC PATCH v1 00/18] add PCI bus-to-resource offset support in core Bjorn Helgaas
2012-01-30 16:57 ` Bjorn Helgaas
2012-01-30 16:57 ` [RFC PATCH v1 01/18] PCI: don't publish new root bus until it's fully initialized Bjorn Helgaas
2012-01-30 16:57 ` Bjorn Helgaas
2012-01-30 16:57 ` [RFC PATCH v1 02/18] PCI: add struct pci_host_bridge and a list of all bridges found Bjorn Helgaas
2012-01-30 16:57 ` Bjorn Helgaas
2012-01-30 20:52 ` Yinghai Lu
2012-01-30 20:52 ` Yinghai Lu
2012-01-30 22:00 ` Bjorn Helgaas
2012-01-30 22:00 ` Bjorn Helgaas
2012-01-30 22:29 ` Yinghai Lu
2012-01-30 22:29 ` Yinghai Lu
2012-01-30 16:57 ` [RFC PATCH v1 03/18] PCI: add struct pci_host_bridge_window with CPU/bus address offset Bjorn Helgaas
2012-01-30 16:57 ` Bjorn Helgaas
2012-01-30 16:57 ` Bjorn Helgaas [this message]
2012-01-30 16:57 ` [RFC PATCH v1 05/18] PCI: add generic pcibios_resource_to_bus() Bjorn Helgaas
2012-01-30 16:57 ` [RFC PATCH v1 06/18] alpha/PCI: get rid of device resource fixups Bjorn Helgaas
2012-01-30 16:57 ` Bjorn Helgaas
2012-01-30 16:57 ` [RFC PATCH v1 07/18] arm/PCI: " Bjorn Helgaas
2012-01-30 16:57 ` Bjorn Helgaas
2012-02-03 16:01 ` Russell King - ARM Linux
2012-02-03 16:01 ` Russell King - ARM Linux
2012-02-03 16:12 ` Bjorn Helgaas
2012-02-03 16:55 ` Russell King - ARM Linux
2012-02-03 16:55 ` Russell King - ARM Linux
2012-02-03 17:51 ` Bjorn Helgaas
2012-01-30 16:57 ` [RFC PATCH v1 08/18] ia64/PCI: SN: convert to pci_scan_root_bus() for correct root bus resources Bjorn Helgaas
2012-01-30 16:57 ` [RFC PATCH v1 09/18] ia64/PCI: get rid of device resource fixups Bjorn Helgaas
2012-01-30 16:57 ` Bjorn Helgaas
2012-01-30 16:58 ` [RFC PATCH v1 10/18] microblaze/PCI: " Bjorn Helgaas
2012-01-30 16:58 ` Bjorn Helgaas
2012-02-02 10:50 ` Michal Simek
2012-02-02 10:50 ` Michal Simek
2012-02-03 11:46 ` Benjamin Herrenschmidt
2012-02-03 11:46 ` Benjamin Herrenschmidt
2012-01-30 16:58 ` [RFC PATCH v1 11/18] mips/PCI: " Bjorn Helgaas
2012-01-30 16:58 ` Bjorn Helgaas
2012-01-31 2:42 ` Yoichi Yuasa
2012-01-31 2:42 ` Yoichi Yuasa
2012-01-31 3:54 ` Bjorn Helgaas
2012-01-31 3:54 ` Bjorn Helgaas
2012-02-08 2:56 ` Bjorn Helgaas
2012-02-08 2:56 ` Bjorn Helgaas
[not found] ` <20120208132234.710f19be.yuasa@linux-mips.org>
2012-02-08 21:16 ` Bjorn Helgaas
2012-01-30 16:58 ` [RFC PATCH v1 12/18] mn10300/PCI: " Bjorn Helgaas
2012-01-30 16:58 ` Bjorn Helgaas
2012-01-30 16:58 ` [RFC PATCH v1 13/18] parisc/PCI: " Bjorn Helgaas
2012-01-30 16:58 ` Bjorn Helgaas
2012-01-30 16:58 ` [RFC PATCH v1 14/18] powerpc/PCI: " Bjorn Helgaas
2012-01-30 20:49 ` Benjamin Herrenschmidt
2012-01-30 21:46 ` Bjorn Helgaas
2012-01-30 21:46 ` Bjorn Helgaas
2012-01-30 16:58 ` [RFC PATCH v1 15/18] sh/PCI: " Bjorn Helgaas
2012-01-30 16:58 ` [RFC PATCH v1 16/18] sparc/PCI: " Bjorn Helgaas
2012-01-30 16:58 ` [RFC PATCH v1 17/18] xtensa/PCI: " Bjorn Helgaas
2012-01-30 16:58 ` Bjorn Helgaas
2012-01-30 16:58 ` [RFC PATCH v1 18/18] PCI: collapse pcibios_resource_to_bus Bjorn Helgaas
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20120130165729.3231.45754.stgit@bhelgaas.mtv.corp.google.com \
--to=bhelgaas@google.com \
--cc=linux-arch@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox