Commit 6ca45a24 authored by Grant Grundler's avatar Grant Grundler Committed by Kyle McMartin

[PARISC] Truncate overlapping PAT PDC reported ranges

Deal with overlapping LBA MMIO resources,

rp3440 PDC BUG: PDC reports lmmio range for the last rope that overlaps
with the CPU HPA. Console output was:

...
Found devices:
1. Storm Peak Fast at 0xfffffffffe798000 [152] { 0, 0x0, 0x889, 0x00004 }
2. Storm Peak Fast at 0xfffffffffe799000 [153] { 0, 0x0, 0x889, 0x00004 }
...
FAILED: lba_fixup_bus() request for lmmio_space
[fffffffff0000000/fffffffffecffffe]

Output is now:

LBA: Truncating lmmio_space [fffffffff0000000/fffffffffecffffe] to
[fffffffff0000000,fffffffffe797fff]

My only concern with this patch is how C8000 (PAT PDC) will report
elmmio ranges when a gfx card is installed. I'll have to test this
another day.
Signed-off-by: default avatarGrant Grundler <grundler@parisc-linux.org>
Signed-off-by: default avatarJames Bottomley <jejb@parisc-linux.org>
Signed-off-by: default avatarMatthew Wilcox <willy@parisc-linux.org>
Signed-off-by: default avatarKyle McMartin <kyle@parisc-linux.org>
parent 110957f0
...@@ -695,11 +695,71 @@ lba_claim_dev_resources(struct pci_dev *dev) ...@@ -695,11 +695,71 @@ lba_claim_dev_resources(struct pci_dev *dev)
} }
} }
} }
/*
* truncate_pat_collision: Deal with overlaps or outright collisions
* between PAT PDC reported ranges.
*
* Broken PA8800 firmware will report lmmio range that
* overlaps with CPU HPA. Just truncate the lmmio range.
*
* BEWARE: conflicts with this lmmio range may be an
* elmmio range which is pointing down another rope.
*
* FIXME: only deals with one collision per range...theoretically we
* could have several. Supporting more than one collision will get messy.
*/
static unsigned long
truncate_pat_collision(struct resource *root, struct resource *new)
{
unsigned long start = new->start;
unsigned long end = new->end;
struct resource *tmp = root->child;
if (end <= start || start < root->start || !tmp)
return 0;
/* find first overlap */
while (tmp && tmp->end < start)
tmp = tmp->sibling;
/* no entries overlap */
if (!tmp) return 0;
/* found one that starts behind the new one
** Don't need to do anything.
*/
if (tmp->start >= end) return 0;
if (tmp->start <= start) {
/* "front" of new one overlaps */
new->start = tmp->end + 1;
if (tmp->end >= end) {
/* AACCKK! totally overlaps! drop this range. */
return 1;
}
}
if (tmp->end < end ) {
/* "end" of new one overlaps */
new->end = tmp->start - 1;
}
printk(KERN_WARNING "LBA: Truncating lmmio_space [%lx/%lx] "
"to [%lx,%lx]\n",
start, end,
new->start, new->end );
return 0; /* truncation successful */
}
#else #else
#define lba_claim_dev_resources(dev) #define lba_claim_dev_resources(dev) do { } while (0)
#define truncate_pat_collision(r,n) (0)
#endif #endif
/* /*
** The algorithm is generic code. ** The algorithm is generic code.
** But it needs to access local data structures to get the IRQ base. ** But it needs to access local data structures to get the IRQ base.
...@@ -747,6 +807,9 @@ lba_fixup_bus(struct pci_bus *bus) ...@@ -747,6 +807,9 @@ lba_fixup_bus(struct pci_bus *bus)
lba_dump_res(&ioport_resource, 2); lba_dump_res(&ioport_resource, 2);
BUG(); BUG();
} }
/* advertize Host bridge resources to PCI bus */
bus->resource[0] = &(ldev->hba.io_space);
i = 1;
if (ldev->hba.elmmio_space.start) { if (ldev->hba.elmmio_space.start) {
err = request_resource(&iomem_resource, err = request_resource(&iomem_resource,
...@@ -760,23 +823,35 @@ lba_fixup_bus(struct pci_bus *bus) ...@@ -760,23 +823,35 @@ lba_fixup_bus(struct pci_bus *bus)
/* lba_dump_res(&iomem_resource, 2); */ /* lba_dump_res(&iomem_resource, 2); */
/* BUG(); */ /* BUG(); */
} } else
bus->resource[i++] = &(ldev->hba.elmmio_space);
} }
err = request_resource(&iomem_resource, &(ldev->hba.lmmio_space));
if (err < 0) { /* Overlaps with elmmio can (and should) fail here.
/* FIXME overlaps with elmmio will fail here. * We will prune (or ignore) the distributed range.
* Need to prune (or disable) the distributed range. *
* * FIXME: SBA code should register all elmmio ranges first.
* BEWARE: conflicts with this lmmio range may be * that would take care of elmmio ranges routed
* elmmio range which is pointing down another rope. * to a different rope (already discovered) from
*/ * getting registered *after* LBA code has already
* registered it's distributed lmmio range.
printk("FAILED: lba_fixup_bus() request for " */
if (truncate_pat_collision(&iomem_resource,
&(ldev->hba.lmmio_space))) {
printk(KERN_WARNING "LBA: lmmio_space [%lx/%lx] duplicate!\n",
ldev->hba.lmmio_space.start,
ldev->hba.lmmio_space.end);
} else {
err = request_resource(&iomem_resource, &(ldev->hba.lmmio_space));
if (err < 0) {
printk(KERN_ERR "FAILED: lba_fixup_bus() request for "
"lmmio_space [%lx/%lx]\n", "lmmio_space [%lx/%lx]\n",
ldev->hba.lmmio_space.start, ldev->hba.lmmio_space.start,
ldev->hba.lmmio_space.end); ldev->hba.lmmio_space.end);
/* lba_dump_res(&iomem_resource, 2); */ } else
bus->resource[i++] = &(ldev->hba.lmmio_space);
} }
#ifdef CONFIG_64BIT #ifdef CONFIG_64BIT
...@@ -791,18 +866,10 @@ lba_fixup_bus(struct pci_bus *bus) ...@@ -791,18 +866,10 @@ lba_fixup_bus(struct pci_bus *bus)
lba_dump_res(&iomem_resource, 2); lba_dump_res(&iomem_resource, 2);
BUG(); BUG();
} }
bus->resource[i++] = &(ldev->hba.gmmio_space);
} }
#endif #endif
/* advertize Host bridge resources to PCI bus */
bus->resource[0] = &(ldev->hba.io_space);
bus->resource[1] = &(ldev->hba.lmmio_space);
i=2;
if (ldev->hba.elmmio_space.start)
bus->resource[i++] = &(ldev->hba.elmmio_space);
if (ldev->hba.gmmio_space.start)
bus->resource[i++] = &(ldev->hba.gmmio_space);
} }
list_for_each(ln, &bus->devices) { list_for_each(ln, &bus->devices) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment