Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

[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
Loading
Loading
Loading
Loading
+90 −23
Original line number Diff line number Diff line
@@ -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
#define lba_claim_dev_resources(dev)
#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.

		/*   Overlaps with elmmio can (and should) fail here.
		 *   We will prune (or ignore) the distributed range.
		 *
			 *   BEWARE: conflicts with this lmmio range may be
			 *   elmmio range which is pointing down another rope.
		 *   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("FAILED: lba_fixup_bus() request for "
			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) {