diff options
-rw-r--r-- | drivers/pci/pci-uclass.c | 57 | ||||
-rw-r--r-- | include/pci.h | 20 |
2 files changed, 46 insertions, 31 deletions
diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c index 0424cd339e..997ca0d5e4 100644 --- a/drivers/pci/pci-uclass.c +++ b/drivers/pci/pci-uclass.c @@ -1390,12 +1390,13 @@ void dm_pci_write_bar32(struct udevice *dev, int barnum, u32 addr) dm_pci_write_config32(dev, bar, addr); } -static int _dm_pci_bus_to_phys(struct udevice *ctlr, - pci_addr_t bus_addr, unsigned long flags, +static int _dm_pci_bus_to_phys(struct udevice *ctlr, pci_addr_t bus_addr, + size_t len, unsigned long flags, unsigned long skip_mask, phys_addr_t *pa) { struct pci_controller *hose = dev_get_uclass_priv(ctlr); struct pci_region *res; + pci_addr_t offset; int i; if (hose->region_count == 0) { @@ -1412,18 +1413,25 @@ static int _dm_pci_bus_to_phys(struct udevice *ctlr, if (res->flags & skip_mask) continue; - if (bus_addr >= res->bus_start && - (bus_addr - res->bus_start) < res->size) { - *pa = (bus_addr - res->bus_start + res->phys_start); - return 0; - } + if (bus_addr < res->bus_start) + continue; + + offset = bus_addr - res->bus_start; + if (offset >= res->size) + continue; + + if (len > res->size - offset) + continue; + + *pa = res->phys_start + offset; + return 0; } return 1; } phys_addr_t dm_pci_bus_to_phys(struct udevice *dev, pci_addr_t bus_addr, - unsigned long flags) + size_t len, unsigned long flags) { phys_addr_t phys_addr = 0; struct udevice *ctlr; @@ -1437,14 +1445,14 @@ phys_addr_t dm_pci_bus_to_phys(struct udevice *dev, pci_addr_t bus_addr, * on matches that don't have PCI_REGION_SYS_MEMORY set */ if ((flags & PCI_REGION_TYPE) == PCI_REGION_MEM) { - ret = _dm_pci_bus_to_phys(ctlr, bus_addr, + ret = _dm_pci_bus_to_phys(ctlr, bus_addr, len, flags, PCI_REGION_SYS_MEMORY, &phys_addr); if (!ret) return phys_addr; } - ret = _dm_pci_bus_to_phys(ctlr, bus_addr, flags, 0, &phys_addr); + ret = _dm_pci_bus_to_phys(ctlr, bus_addr, len, flags, 0, &phys_addr); if (ret) puts("pci_hose_bus_to_phys: invalid physical address\n"); @@ -1453,12 +1461,12 @@ phys_addr_t dm_pci_bus_to_phys(struct udevice *dev, pci_addr_t bus_addr, } static int _dm_pci_phys_to_bus(struct udevice *dev, phys_addr_t phys_addr, - unsigned long flags, unsigned long skip_mask, - pci_addr_t *ba) + size_t len, unsigned long flags, + unsigned long skip_mask, pci_addr_t *ba) { struct pci_region *res; struct udevice *ctlr; - pci_addr_t bus_addr; + phys_addr_t offset; int i; struct pci_controller *hose; @@ -1480,20 +1488,25 @@ static int _dm_pci_phys_to_bus(struct udevice *dev, phys_addr_t phys_addr, if (res->flags & skip_mask) continue; - bus_addr = phys_addr - res->phys_start + res->bus_start; + if (phys_addr < res->phys_start) + continue; - if (bus_addr >= res->bus_start && - (bus_addr - res->bus_start) < res->size) { - *ba = bus_addr; - return 0; - } + offset = phys_addr - res->phys_start; + if (offset >= res->size) + continue; + + if (len > res->size - offset) + continue; + + *ba = res->bus_start + offset; + return 0; } return 1; } pci_addr_t dm_pci_phys_to_bus(struct udevice *dev, phys_addr_t phys_addr, - unsigned long flags) + size_t len, unsigned long flags) { pci_addr_t bus_addr = 0; int ret; @@ -1503,13 +1516,13 @@ pci_addr_t dm_pci_phys_to_bus(struct udevice *dev, phys_addr_t phys_addr, * on matches that don't have PCI_REGION_SYS_MEMORY set */ if ((flags & PCI_REGION_TYPE) == PCI_REGION_MEM) { - ret = _dm_pci_phys_to_bus(dev, phys_addr, flags, + ret = _dm_pci_phys_to_bus(dev, phys_addr, len, flags, PCI_REGION_SYS_MEMORY, &bus_addr); if (!ret) return bus_addr; } - ret = _dm_pci_phys_to_bus(dev, phys_addr, flags, 0, &bus_addr); + ret = _dm_pci_phys_to_bus(dev, phys_addr, len, flags, 0, &bus_addr); if (ret) puts("pci_hose_phys_to_bus: invalid physical address\n"); diff --git a/include/pci.h b/include/pci.h index 3d0356b8fd..966b84c148 100644 --- a/include/pci.h +++ b/include/pci.h @@ -1313,14 +1313,15 @@ void dm_pci_write_bar32(struct udevice *dev, int barnum, u32 addr); u32 dm_pci_read_bar32(const struct udevice *dev, int barnum); /** - * dm_pci_bus_to_phys() - convert a PCI bus address to a physical address + * dm_pci_bus_to_phys() - convert a PCI bus address range to a physical address * * @dev: Device containing the PCI address * @addr: PCI address to convert + * @len: Length of the address range * @flags: Flags for the region type (PCI_REGION_...) * Return: physical address corresponding to that PCI bus address */ -phys_addr_t dm_pci_bus_to_phys(struct udevice *dev, pci_addr_t addr, +phys_addr_t dm_pci_bus_to_phys(struct udevice *dev, pci_addr_t addr, size_t len, unsigned long flags); /** @@ -1328,10 +1329,11 @@ phys_addr_t dm_pci_bus_to_phys(struct udevice *dev, pci_addr_t addr, * * @dev: Device containing the bus address * @addr: Physical address to convert + * @len: Length of the address range * @flags: Flags for the region type (PCI_REGION_...) * Return: PCI bus address corresponding to that physical address */ -pci_addr_t dm_pci_phys_to_bus(struct udevice *dev, phys_addr_t addr, +pci_addr_t dm_pci_phys_to_bus(struct udevice *dev, phys_addr_t addr, size_t len, unsigned long flags); /** @@ -1453,19 +1455,19 @@ int dm_pci_find_ext_capability(struct udevice *dev, int cap); int dm_pci_flr(struct udevice *dev); #define dm_pci_virt_to_bus(dev, addr, flags) \ - dm_pci_phys_to_bus(dev, (virt_to_phys(addr)), (flags)) + dm_pci_phys_to_bus(dev, (virt_to_phys(addr)), 0, (flags)) #define dm_pci_bus_to_virt(dev, addr, flags, len, map_flags) \ - map_physmem(dm_pci_bus_to_phys(dev, (addr), (flags)), \ + map_physmem(dm_pci_bus_to_phys(dev, (addr), (len), (flags)), \ (len), (map_flags)) #define dm_pci_phys_to_mem(dev, addr) \ - dm_pci_phys_to_bus((dev), (addr), PCI_REGION_MEM) + dm_pci_phys_to_bus((dev), (addr), 0, PCI_REGION_MEM) #define dm_pci_mem_to_phys(dev, addr) \ - dm_pci_bus_to_phys((dev), (addr), PCI_REGION_MEM) + dm_pci_bus_to_phys((dev), (addr), 0, PCI_REGION_MEM) #define dm_pci_phys_to_io(dev, addr) \ - dm_pci_phys_to_bus((dev), (addr), PCI_REGION_IO) + dm_pci_phys_to_bus((dev), (addr), 0, PCI_REGION_IO) #define dm_pci_io_to_phys(dev, addr) \ - dm_pci_bus_to_phys((dev), (addr), PCI_REGION_IO) + dm_pci_bus_to_phys((dev), (addr), 0, PCI_REGION_IO) #define dm_pci_virt_to_mem(dev, addr) \ dm_pci_virt_to_bus((dev), (addr), PCI_REGION_MEM) |