diff --git a/drivers/pci/controller/pcie-rzg3s-host.c b/drivers/pci/controller/pcie-rzg3s-host.c index 986f0a319b3c..872683211bab 100644 --- a/drivers/pci/controller/pcie-rzg3s-host.c +++ b/drivers/pci/controller/pcie-rzg3s-host.c @@ -1271,50 +1271,55 @@ static int rzg3s_pcie_set_inbound_windows(struct rzg3s_pcie_host *host, u64 pci_addr = entry->res->start - entry->offset; u64 cpu_addr = entry->res->start; u64 cpu_end = entry->res->end; - u64 size_id = 0; int id = *index; u64 size; - while (cpu_addr < cpu_end) { + /* + * According to the RZ/G3S HW manual (Rev.1.10, section 34.6.6.7) and + * RZ/G3E HW manual (Rev.1.15, section 6.6.7.6): + * - Each window must be a single memory size of power of two + * - Mask registers must be set to (2^N - 1) + * - Bit carry must not occur when adding base and mask registers, + * meaning the base address must be aligned to the window size + * + * Split non-power-of-2 regions into multiple windows to satisfy + * these constraints without over-mapping. + */ + while (cpu_addr <= cpu_end) { + u64 remaining_size = cpu_end - cpu_addr + 1; + u64 align_limit; + if (id >= RZG3S_MAX_WINDOWS) return dev_err_probe(host->dev, -ENOSPC, "Failed to map inbound window for resource (%s)\n", entry->res->name); - size = resource_size(entry->res) - size_id; + /* Start with largest power-of-two that fits in remaining size */ + size = 1ULL << __fls(remaining_size); /* - * According to the RZ/G3S HW manual (Rev.1.10, - * section 34.3.1.71 AXI Window Mask (Lower) Registers) the min - * size is 4K. + * The "no bit carry" rule requires base addresses to be + * aligned to the window size. Find the maximum window size + * that both addresses can support based on their natural + * alignment (lowest set bit). + */ + align_limit = min(cpu_addr ? (1ULL << __ffs(cpu_addr)) : ~0ULL, + pci_addr ? (1ULL << __ffs(pci_addr)) : ~0ULL); + + size = min(size, align_limit); + + /* + * Minimum window size is 4KB. + * See RZ/G3S HW manual (Rev.1.10, section 34.3.1.71) and + * RZ/G3E HW manual (Rev.1.15, section 6.6.4.1.3.(74)). */ size = max(size, SZ_4K); - /* - * According the RZ/G3S HW manual (Rev.1.10, sections: - * - 34.3.1.69 AXI Window Base (Lower) Registers - * - 34.3.1.71 AXI Window Mask (Lower) Registers - * - 34.3.1.73 AXI Destination (Lower) Registers) - * the CPU addr, PCIe addr, size should be 4K aligned and be a - * power of 2. - */ - size = ALIGN(size, SZ_4K); - size = roundup_pow_of_two(size); - - cpu_addr = ALIGN(cpu_addr, SZ_4K); - pci_addr = ALIGN(pci_addr, SZ_4K); - - /* - * According to the RZ/G3S HW manual (Rev.1.10, section - * 34.3.1.71 AXI Window Mask (Lower) Registers) HW expects first - * 12 LSB bits to be 0xfff. Subtract 1 from size for this. - */ rzg3s_pcie_set_inbound_window(host, cpu_addr, pci_addr, size - 1, id); pci_addr += size; cpu_addr += size; - size_id = size; id++; } *index = id;