pci: Map bars with offset and length

Evolve dm_pci_map_bar() to include an offset and length parameter. These
allow a portion of the memory to be mapped and range checks to be
applied.

Passing both the offset and length as zero results in the previous
behaviour and this is used to migrate the previous callers.

Signed-off-by: Andrew Scull <ascull@google.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c
index 997ca0d..9fe07cf 100644
--- a/drivers/pci/pci-uclass.c
+++ b/drivers/pci/pci-uclass.c
@@ -1561,7 +1561,8 @@
 	return addr;
 }
 
-static void *dm_pci_map_ea_bar(struct udevice *dev, int bar, int ea_off,
+static void *dm_pci_map_ea_bar(struct udevice *dev, int bar, size_t offset,
+			       size_t len, int ea_off,
 			       struct pci_child_plat *pdata)
 {
 	int ea_cnt, i, entry_size;
@@ -1604,14 +1605,18 @@
 		if (IS_ENABLED(CONFIG_PCI_SRIOV))
 			addr += dm_pci_map_ea_virt(dev, ea_off, pdata);
 
+		if (~((phys_addr_t)0) - addr < offset)
+			return NULL;
+
 		/* size ignored for now */
-		return map_physmem(addr, 0, MAP_NOCACHE);
+		return map_physmem(addr + offset, len, MAP_NOCACHE);
 	}
 
 	return 0;
 }
 
-void *dm_pci_map_bar(struct udevice *dev, int bar, unsigned long flags)
+void *dm_pci_map_bar(struct udevice *dev, int bar, size_t offset, size_t len,
+		     unsigned long flags)
 {
 	struct pci_child_plat *pdata = dev_get_parent_plat(dev);
 	struct udevice *udev = dev;
@@ -1636,19 +1641,23 @@
 	 */
 	ea_off = dm_pci_find_capability(udev, PCI_CAP_ID_EA);
 	if (ea_off)
-		return dm_pci_map_ea_bar(udev, bar, ea_off, pdata);
+		return dm_pci_map_ea_bar(udev, bar, offset, len, ea_off, pdata);
 
 	/* read BAR address */
 	dm_pci_read_config32(udev, bar, &bar_response);
 	pci_bus_addr = (pci_addr_t)(bar_response & ~0xf);
 
+	if (~((pci_addr_t)0) - pci_bus_addr < offset)
+		return NULL;
+
 	/*
-	 * Pass "0" as the length argument to pci_bus_to_virt.  The arg
-	 * isn't actually used on any platform because U-Boot assumes a static
-	 * linear mapping.  In the future, this could read the BAR size
-	 * and pass that as the size if needed.
+	 * Forward the length argument to dm_pci_bus_to_virt. The length will
+	 * be used to check that the entire address range has been declared as
+	 * a PCI range, but a better check would be to probe for the size of
+	 * the bar and prevent overflow more locally.
 	 */
-	return dm_pci_bus_to_virt(udev, pci_bus_addr, flags, 0, MAP_NOCACHE);
+	return dm_pci_bus_to_virt(udev, pci_bus_addr + offset, flags, len,
+				  MAP_NOCACHE);
 }
 
 static int _dm_pci_find_next_capability(struct udevice *dev, u8 pos, int cap)