Re: [PATCH v7 02/60] sparc/PCI: Use correct bus address to resource offset
From: Yinghai Lu
Date: Tue Oct 20 2015 - 20:26:06 EST
On Tue, Oct 20, 2015 at 5:03 PM, Yinghai Lu <yinghai@xxxxxxxxxx> wrote:
>> The failing T4 booted up with updated patches.
>>
>
> Thanks, will post updated patch2 and patches3 and patch 4 with
> pcibios_bus_to_resource as Bjorn requested.
Please double test attached three patches that should replace patch 2, 3, 4.
esp on T4.
Thanks
Yinghai
Subject: [PATCH] PCI: Return host bridge window res for bus addr converting
We need to check if there is window or not, and also need to
use that window res as parent for resource requesting.
Signed-off-by: Yinghai Lu <yinghai@xxxxxxxxxx>
---
drivers/pci/host-bridge.c | 10 +++++++++-
include/linux/pci.h | 5 +++--
2 files changed, 12 insertions(+), 3 deletions(-)
Index: linux-2.6/drivers/pci/host-bridge.c
===================================================================
--- linux-2.6.orig/drivers/pci/host-bridge.c
+++ linux-2.6/drivers/pci/host-bridge.c
@@ -70,12 +70,17 @@ static bool region_contains(struct pci_b
return region1->start <= region2->start && region1->end >= region2->end;
}
-void pcibios_bus_to_resource(struct pci_bus *bus, struct resource *res,
+/*
+ * return host bridge window resource
+ */
+struct resource *pcibios_bus_to_resource(struct pci_bus *bus,
+ struct resource *res,
struct pci_bus_region *region)
{
struct pci_host_bridge *bridge = pci_find_host_bridge(bus);
struct resource_entry *window;
resource_size_t offset = 0;
+ struct resource *res_ret = NULL;
resource_list_for_each_entry(window, &bridge->windows) {
struct pci_bus_region bus_region;
@@ -88,11 +93,14 @@ void pcibios_bus_to_resource(struct pci_
if (region_contains(&bus_region, region)) {
offset = window->offset;
+ res_ret = window->res;
break;
}
}
res->start = region->start + offset;
res->end = region->end + offset;
+
+ return res_ret;
}
EXPORT_SYMBOL(pcibios_bus_to_resource);
Index: linux-2.6/include/linux/pci.h
===================================================================
--- linux-2.6.orig/include/linux/pci.h
+++ linux-2.6/include/linux/pci.h
@@ -781,8 +781,9 @@ void pci_fixup_cardbus(struct pci_bus *)
void pcibios_resource_to_bus(struct pci_bus *bus, struct pci_bus_region *region,
struct resource *res);
-void pcibios_bus_to_resource(struct pci_bus *bus, struct resource *res,
- struct pci_bus_region *region);
+struct resource *pcibios_bus_to_resource(struct pci_bus *bus,
+ struct resource *res,
+ struct pci_bus_region *region);
void pcibios_scan_specific_bus(int busn);
struct pci_bus *pci_find_bus(int domain, int busnr);
void pci_bus_add_devices(const struct pci_bus *bus);
Subject: [PATCH] sparc/PCI: Use correct bus address to resource offset
After we add 64bit mmio parsing, we got some "no compatible bridge window"
warning on anther new model that support 64bit resource.
It turns out that we can not use mem_space.start as 64bit mem space
offset, aka mem_space.start != offset.
Use child_phys_addr to calculate exact offset and recorder offset in
pbm.
After patch we get correct offset.
/pci@305: PCI IO [io 0x2007e00000000-0x2007e0fffffff] offset 2007e00000000
/pci@305: PCI MEM [mem 0x2000000100000-0x200007effffff] offset 2000000000000
/pci@305: PCI MEM64 [mem 0x2000100000000-0x2000dffffffff] offset 2000000000000
...
pci_sun4v f02ae7f8: PCI host bridge to bus 0000:00
pci_bus 0000:00: root bus resource [io 0x2007e00000000-0x2007e0fffffff] (bus address [0x0000-0xfffffff])
pci_bus 0000:00: root bus resource [mem 0x2000000100000-0x200007effffff] (bus address [0x00100000-0x7effffff])
pci_bus 0000:00: root bus resource [mem 0x2000100000000-0x2000dffffffff] (bus address [0x100000000-0xdffffffff])
-v2: to make is simple, do not add mem64_offset, and assume
mem64_offset == mem_offset, otherwise would make
pci_mmap_resource() path too complicated.
-v3: put back mem64_offset, as we found T4 has mem_offset != mem64_offset
check overlapping between mem64_space and mem_space.
-v4: use pcibios_bus_to_region() all the way.
Signed-off-by: Yinghai Lu <yinghai@xxxxxxxxxx>
Tested-by: Khalid Aziz <khalid.aziz@xxxxxxxxxx>
---
arch/sparc/kernel/pci.c | 49 +++++++++++++++++------------------------
arch/sparc/kernel/pci_common.c | 32 ++++++++++++++++++++------
arch/sparc/kernel/pci_impl.h | 4 +++
3 files changed, 49 insertions(+), 36 deletions(-)
Index: linux-2.6/arch/sparc/kernel/pci.c
===================================================================
--- linux-2.6.orig/arch/sparc/kernel/pci.c
+++ linux-2.6/arch/sparc/kernel/pci.c
@@ -654,12 +654,12 @@ struct pci_bus *pci_scan_one_pbm(struct
printk("PCI: Scanning PBM %s\n", node->full_name);
pci_add_resource_offset(&resources, &pbm->io_space,
- pbm->io_space.start);
+ pbm->io_offset);
pci_add_resource_offset(&resources, &pbm->mem_space,
- pbm->mem_space.start);
+ pbm->mem_offset);
if (pbm->mem64_space.flags)
pci_add_resource_offset(&resources, &pbm->mem64_space,
- pbm->mem_space.start);
+ pbm->mem64_offset);
pbm->busn.start = pbm->pci_first_busno;
pbm->busn.end = pbm->pci_last_busno;
pbm->busn.flags = IORESOURCE_BUS;
@@ -733,30 +733,27 @@ int pcibios_enable_device(struct pci_dev
static int __pci_mmap_make_offset_bus(struct pci_dev *pdev, struct vm_area_struct *vma,
enum pci_mmap_state mmap_state)
{
- struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
- unsigned long space_size, user_offset, user_size;
-
- if (mmap_state == pci_mmap_io) {
- space_size = resource_size(&pbm->io_space);
- } else {
- space_size = resource_size(&pbm->mem_space);
- }
+ unsigned long user_offset, user_size;
+ struct resource res, *res_ret;
+ struct pci_bus_region region;
/* Make sure the request is in range. */
user_offset = vma->vm_pgoff << PAGE_SHIFT;
user_size = vma->vm_end - vma->vm_start;
- if (user_offset >= space_size ||
- (user_offset + user_size) > space_size)
+ region.start = user_offset;
+ region.end = user_offset + user_size - 1;
+ memset(&res, 0, sizeof(res));
+ if (mmap_state == pci_mmap_io)
+ res.flags = IORESOURCE_IO;
+ else
+ res.flags = IORESOURCE_MEM;
+
+ res_ret = pcibios_bus_to_resource(pdev->bus, &res, ®ion);
+ if (!res_ret)
return -EINVAL;
- if (mmap_state == pci_mmap_io) {
- vma->vm_pgoff = (pbm->io_space.start +
- user_offset) >> PAGE_SHIFT;
- } else {
- vma->vm_pgoff = (pbm->mem_space.start +
- user_offset) >> PAGE_SHIFT;
- }
+ vma->vm_pgoff = res.start >> PAGE_SHIFT;
return 0;
}
@@ -977,16 +974,12 @@ void pci_resource_to_user(const struct p
const struct resource *rp, resource_size_t *start,
resource_size_t *end)
{
- struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
- unsigned long offset;
+ struct pci_bus_region region;
- if (rp->flags & IORESOURCE_IO)
- offset = pbm->io_space.start;
- else
- offset = pbm->mem_space.start;
+ pcibios_resource_to_bus(pdev->bus, ®ion, (struct resource *)rp);
- *start = rp->start - offset;
- *end = rp->end - offset;
+ *start = region.start;
+ *end = region.end;
}
void pcibios_set_master(struct pci_dev *dev)
Index: linux-2.6/arch/sparc/kernel/pci_common.c
===================================================================
--- linux-2.6.orig/arch/sparc/kernel/pci_common.c
+++ linux-2.6/arch/sparc/kernel/pci_common.c
@@ -410,13 +410,16 @@ void pci_determine_mem_io_space(struct p
for (i = 0; i < num_pbm_ranges; i++) {
const struct linux_prom_pci_ranges *pr = &pbm_ranges[i];
- unsigned long a, size;
+ unsigned long a, size, region_a;
u32 parent_phys_hi, parent_phys_lo;
+ u32 child_phys_mid, child_phys_lo;
u32 size_hi, size_lo;
int type;
parent_phys_hi = pr->parent_phys_hi;
parent_phys_lo = pr->parent_phys_lo;
+ child_phys_mid = pr->child_phys_mid;
+ child_phys_lo = pr->child_phys_lo;
if (tlb_type == hypervisor)
parent_phys_hi &= 0x0fffffff;
@@ -426,6 +429,8 @@ void pci_determine_mem_io_space(struct p
type = (pr->child_phys_hi >> 24) & 0x3;
a = (((unsigned long)parent_phys_hi << 32UL) |
((unsigned long)parent_phys_lo << 0UL));
+ region_a = (((unsigned long)child_phys_mid << 32UL) |
+ ((unsigned long)child_phys_lo << 0UL));
size = (((unsigned long)size_hi << 32UL) |
((unsigned long)size_lo << 0UL));
@@ -440,6 +445,7 @@ void pci_determine_mem_io_space(struct p
pbm->io_space.start = a;
pbm->io_space.end = a + size - 1UL;
pbm->io_space.flags = IORESOURCE_IO;
+ pbm->io_offset = a - region_a;
saw_io = 1;
break;
@@ -448,6 +454,7 @@ void pci_determine_mem_io_space(struct p
pbm->mem_space.start = a;
pbm->mem_space.end = a + size - 1UL;
pbm->mem_space.flags = IORESOURCE_MEM;
+ pbm->mem_offset = a - region_a;
saw_mem = 1;
break;
@@ -456,6 +463,7 @@ void pci_determine_mem_io_space(struct p
pbm->mem64_space.start = a;
pbm->mem64_space.end = a + size - 1UL;
pbm->mem64_space.flags = IORESOURCE_MEM;
+ pbm->mem64_offset = a - region_a;
saw_mem = 1;
break;
@@ -471,14 +479,22 @@ void pci_determine_mem_io_space(struct p
prom_halt();
}
- printk("%s: PCI IO[%llx] MEM[%llx]",
- pbm->name,
- pbm->io_space.start,
- pbm->mem_space.start);
+ if (pbm->io_space.flags)
+ printk("%s: PCI IO %pR offset %llx\n",
+ pbm->name, &pbm->io_space, pbm->io_offset);
+ if (pbm->mem_space.flags)
+ printk("%s: PCI MEM %pR offset %llx\n",
+ pbm->name, &pbm->mem_space, pbm->mem_offset);
+ if (pbm->mem64_space.flags && pbm->mem_space.flags) {
+ if (pbm->mem64_space.start <= pbm->mem_space.end)
+ pbm->mem64_space.start = pbm->mem_space.end + 1;
+ if (pbm->mem64_space.start > pbm->mem64_space.end)
+ pbm->mem64_space.flags = 0;
+ }
+
if (pbm->mem64_space.flags)
- printk(" MEM64[%llx]",
- pbm->mem64_space.start);
- printk("\n");
+ printk("%s: PCI MEM64 %pR offset %llx\n",
+ pbm->name, &pbm->mem64_space, pbm->mem64_offset);
pbm->io_space.name = pbm->mem_space.name = pbm->name;
pbm->mem64_space.name = pbm->name;
Index: linux-2.6/arch/sparc/kernel/pci_impl.h
===================================================================
--- linux-2.6.orig/arch/sparc/kernel/pci_impl.h
+++ linux-2.6/arch/sparc/kernel/pci_impl.h
@@ -99,6 +99,10 @@ struct pci_pbm_info {
struct resource mem_space;
struct resource mem64_space;
struct resource busn;
+ /* offset */
+ resource_size_t io_offset;
+ resource_size_t mem_offset;
+ resource_size_t mem64_offset;
/* Base of PCI Config space, can be per-PBM or shared. */
unsigned long config_space;
Subject: [PATCH] sparc/PCI: Reserve legacy mmio after PCI mmio
On one system found bunch of claim resource fail from pci device.
pci_sun4v f02b894c: PCI host bridge to bus 0000:00
pci_bus 0000:00: root bus resource [io 0x2007e00000000-0x2007e0fffffff] (bus address [0x0000-0xfffffff])
pci_bus 0000:00: root bus resource [mem 0x2000000000000-0x200007effffff] (bus address [0x00000000-0x7effffff])
pci_bus 0000:00: root bus resource [mem 0x2000100000000-0x20007ffffffff] (bus address [0x100000000-0x7ffffffff])
...
PCI: Claiming 0000:00:02.0: Resource 14: 0002000000000000..00020000004fffff [200]
pci 0000:00:02.0: can't claim BAR 14 [mem 0x2000000000000-0x20000004fffff]: address conflict with Video RAM area [??? 0x20000000a0000-0x20000000bffff flags 0x80000000]
pci 0000:02:00.0: can't claim BAR 0 [mem 0x2000000000000-0x20000000fffff]: no compatible bridge window
PCI: Claiming 0000:02:00.0: Resource 3: 0002000000100000..0002000000103fff [200]
pci 0000:02:00.0: can't claim BAR 3 [mem 0x2000000100000-0x2000000103fff]: no compatible bridge window
PCI: Claiming 0000:02:00.1: Resource 0: 0002000000200000..00020000002fffff [200]
pci 0000:02:00.1: can't claim BAR 0 [mem 0x2000000200000-0x20000002fffff]: no compatible bridge window
PCI: Claiming 0000:02:00.1: Resource 3: 0002000000104000..0002000000107fff [200]
pci 0000:02:00.1: can't claim BAR 3 [mem 0x2000000104000-0x2000000107fff]: no compatible bridge window
PCI: Claiming 0000:02:00.2: Resource 0: 0002000000300000..00020000003fffff [200]
pci 0000:02:00.2: can't claim BAR 0 [mem 0x2000000300000-0x20000003fffff]: no compatible bridge window
PCI: Claiming 0000:02:00.2: Resource 3: 0002000000108000..000200000010bfff [200]
pci 0000:02:00.2: can't claim BAR 3 [mem 0x2000000108000-0x200000010bfff]: no compatible bridge window
PCI: Claiming 0000:02:00.3: Resource 0: 0002000000400000..00020000004fffff [200]
pci 0000:02:00.3: can't claim BAR 0 [mem 0x2000000400000-0x20000004fffff]: no compatible bridge window
PCI: Claiming 0000:02:00.3: Resource 3: 000200000010c000..000200000010ffff [200]
pci 0000:02:00.3: can't claim BAR 3 [mem 0x200000010c000-0x200000010ffff]: no compatible bridge window
The bridge 00:02.0 resource does not get reserved as Video RAM take the position early,
and following children all failed.
Move down Video RAM area reservation after pci mmio get reserved,
so we leave pci driver to use those regions.
-v2: merge simplify one and use pcibios_bus_to_resource()
Signed-off-by: Yinghai Lu <yinghai@xxxxxxxxxx>
Tested-by: Khalid Aziz <khalid.aziz@xxxxxxxxxx>
---
arch/sparc/kernel/pci.c | 1
arch/sparc/kernel/pci_common.c | 56 ++++++++++++++++++++---------------------
arch/sparc/kernel/pci_impl.h | 1
3 files changed, 30 insertions(+), 28 deletions(-)
Index: linux-2.6/arch/sparc/kernel/pci_common.c
===================================================================
--- linux-2.6.orig/arch/sparc/kernel/pci_common.c
+++ linux-2.6/arch/sparc/kernel/pci_common.c
@@ -328,41 +328,43 @@ void pci_get_pbm_props(struct pci_pbm_in
}
}
-static void pci_register_legacy_regions(struct resource *io_res,
- struct resource *mem_res)
+static void pci_register_region(struct pci_bus *bus, const char *name,
+ resource_size_t rstart, resource_size_t size)
{
- struct resource *p;
+ struct resource *res, *conflict, *res_ret = NULL;
+ struct pci_bus_region region;
- /* VGA Video RAM. */
- p = kzalloc(sizeof(*p), GFP_KERNEL);
- if (!p)
+ res = kzalloc(sizeof(*res), GFP_KERNEL);
+ if (!res)
return;
- p->name = "Video RAM area";
- p->start = mem_res->start + 0xa0000UL;
- p->end = p->start + 0x1ffffUL;
- p->flags = IORESOURCE_BUSY;
- request_resource(mem_res, p);
+ res->flags = IORESOURCE_MEM;
- p = kzalloc(sizeof(*p), GFP_KERNEL);
- if (!p)
+ region.start = rstart;
+ region.end = rstart + size - 1UL;
+ res_ret = pcibios_bus_to_resource(bus, res, ®ion);
+ if (!res_ret)
return;
- p->name = "System ROM";
- p->start = mem_res->start + 0xf0000UL;
- p->end = p->start + 0xffffUL;
- p->flags = IORESOURCE_BUSY;
- request_resource(mem_res, p);
+ res->name = name;
+ res->flags |= IORESOURCE_BUSY;
+ conflict = request_resource_conflict(res_ret, res);
+ if (conflict) {
+ dev_printk(KERN_DEBUG, &bus->dev,
+ " can't claim %s %pR: address conflict with %s %pR\n",
+ res->name, res, conflict->name, conflict);
+ kfree(res);
+ }
+}
- p = kzalloc(sizeof(*p), GFP_KERNEL);
- if (!p)
- return;
+void pci_register_legacy_regions(struct pci_bus *bus)
+{
+ /* VGA Video RAM. */
+ pci_register_region(bus, "Video RAM area", 0xa0000UL, 0x20000UL);
+
+ pci_register_region(bus, "System ROM", 0xf0000UL, 0x10000UL);
- p->name = "Video ROM";
- p->start = mem_res->start + 0xc0000UL;
- p->end = p->start + 0x7fffUL;
- p->flags = IORESOURCE_BUSY;
- request_resource(mem_res, p);
+ pci_register_region(bus, "Video ROM", 0xc0000UL, 0x8000UL);
}
static void pci_register_iommu_region(struct pci_pbm_info *pbm)
@@ -504,8 +506,6 @@ void pci_determine_mem_io_space(struct p
if (pbm->mem64_space.flags)
request_resource(&iomem_resource, &pbm->mem64_space);
- pci_register_legacy_regions(&pbm->io_space,
- &pbm->mem_space);
pci_register_iommu_region(pbm);
}
Index: linux-2.6/arch/sparc/kernel/pci.c
===================================================================
--- linux-2.6.orig/arch/sparc/kernel/pci.c
+++ linux-2.6/arch/sparc/kernel/pci.c
@@ -677,6 +677,7 @@ struct pci_bus *pci_scan_one_pbm(struct
pci_bus_register_of_sysfs(bus);
pci_claim_bus_resources(bus);
+ pci_register_legacy_regions(bus);
pci_bus_add_devices(bus);
return bus;
}
Index: linux-2.6/arch/sparc/kernel/pci_impl.h
===================================================================
--- linux-2.6.orig/arch/sparc/kernel/pci_impl.h
+++ linux-2.6/arch/sparc/kernel/pci_impl.h
@@ -167,6 +167,7 @@ void pci_get_pbm_props(struct pci_pbm_in
struct pci_bus *pci_scan_one_pbm(struct pci_pbm_info *pbm,
struct device *parent);
void pci_determine_mem_io_space(struct pci_pbm_info *pbm);
+void pci_register_legacy_regions(struct pci_bus *bus);
/* Error reporting support. */
void pci_scan_for_target_abort(struct pci_pbm_info *, struct pci_bus *);