[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: Grant Grundler <grundler@parisc-linux.org> Signed-off-by: James Bottomley <jejb@parisc-linux.org> Signed-off-by: Matthew Wilcox <willy@parisc-linux.org> Signed-off-by: Kyle McMartin <kyle@parisc-linux.org>
This commit is contained in:
parent
110957f0e5
commit
6ca45a24cc
1 changed files with 90 additions and 23 deletions
|
@ -695,11 +695,71 @@ lba_claim_dev_resources(struct pci_dev *dev)
|
|||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define lba_claim_dev_resources(dev)
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* 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
|
||||
#define lba_claim_dev_resources(dev) do { } while (0)
|
||||
#define truncate_pat_collision(r,n) (0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The algorithm is generic code.
|
||||
** But it needs to access local data structures to get the IRQ base.
|
||||
|
@ -747,6 +807,9 @@ lba_fixup_bus(struct pci_bus *bus)
|
|||
lba_dump_res(&ioport_resource, 2);
|
||||
BUG();
|
||||
}
|
||||
/* advertize Host bridge resources to PCI bus */
|
||||
bus->resource[0] = &(ldev->hba.io_space);
|
||||
i = 1;
|
||||
|
||||
if (ldev->hba.elmmio_space.start) {
|
||||
err = request_resource(&iomem_resource,
|
||||
|
@ -760,23 +823,35 @@ lba_fixup_bus(struct pci_bus *bus)
|
|||
|
||||
/* lba_dump_res(&iomem_resource, 2); */
|
||||
/* BUG(); */
|
||||
}
|
||||
} else
|
||||
bus->resource[i++] = &(ldev->hba.elmmio_space);
|
||||
}
|
||||
|
||||
err = request_resource(&iomem_resource, &(ldev->hba.lmmio_space));
|
||||
if (err < 0) {
|
||||
/* FIXME overlaps with elmmio will fail here.
|
||||
* Need to prune (or disable) the distributed range.
|
||||
*
|
||||
* BEWARE: conflicts with this lmmio range may be
|
||||
* elmmio range which is pointing down another rope.
|
||||
*/
|
||||
|
||||
printk("FAILED: lba_fixup_bus() request for "
|
||||
/* Overlaps with elmmio can (and should) fail here.
|
||||
* We will prune (or ignore) the distributed range.
|
||||
*
|
||||
* FIXME: SBA code should register all elmmio ranges first.
|
||||
* that would take care of elmmio ranges routed
|
||||
* to a different rope (already discovered) from
|
||||
* getting registered *after* LBA code has already
|
||||
* registered it's distributed lmmio range.
|
||||
*/
|
||||
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",
|
||||
ldev->hba.lmmio_space.start,
|
||||
ldev->hba.lmmio_space.end);
|
||||
/* lba_dump_res(&iomem_resource, 2); */
|
||||
} else
|
||||
bus->resource[i++] = &(ldev->hba.lmmio_space);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_64BIT
|
||||
|
@ -791,18 +866,10 @@ lba_fixup_bus(struct pci_bus *bus)
|
|||
lba_dump_res(&iomem_resource, 2);
|
||||
BUG();
|
||||
}
|
||||
bus->resource[i++] = &(ldev->hba.gmmio_space);
|
||||
}
|
||||
#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) {
|
||||
|
|
Loading…
Reference in a new issue