Skip to content

Commit d17a200

Browse files
John MadieuMani-Sadhasivam
authored andcommitted
PCI: rzg3s-host: Rework inbound window algorithm for supporting RZ/G3E SoC
The existing inbound window configuration algorithm has two issues that prevent proper operation on RZ/G3E: 1. Over-mapping: Using roundup_pow_of_two() on the remaining region size can result in windows that extend beyond the intended memory region. 2. Alignment violation: Addresses are only aligned to 4K regardless of the actual window size. 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), bit carry must not occur when adding AXI Window Base and AXI Window Mask registers. This effectively requires the base address to be aligned to the window size. RZ/G3E strictly enforces these constraints and requires precise window boundaries with properly aligned addresses. Rework the algorithm to properly handle arbitrary region sizes and alignment constraints by splitting non-power-of-2 regions into multiple windows. The new approach iteratively selects the largest power-of-2 size that: - Fits within the remaining region (__fls of remaining size) - Does not exceed the natural alignment of the CPU address (__ffs) - Does not exceed the natural alignment of the PCI address (__ffs) This ensures windows never over-map beyond the intended region and satisfies the hardware requirement that base address + mask must not cause bit carry, while maintaining the 4K * 2^N byte window size constraint. The reworked algorithm is required for RZ/G3E support and remains fully compatible with RZ/G3S. Signed-off-by: John Madieu <john.madieu.xa@bp.renesas.com> Signed-off-by: Manivannan Sadhasivam <mani@kernel.org> Tested-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com> # RZ/V2N EVK Tested-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com> Reviewed-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com> Link: https://patch.msgid.link/20260306143423.19562-4-john.madieu.xa@bp.renesas.com
1 parent 34735f6 commit d17a200

1 file changed

Lines changed: 29 additions & 24 deletions

File tree

drivers/pci/controller/pcie-rzg3s-host.c

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1271,50 +1271,55 @@ static int rzg3s_pcie_set_inbound_windows(struct rzg3s_pcie_host *host,
12711271
u64 pci_addr = entry->res->start - entry->offset;
12721272
u64 cpu_addr = entry->res->start;
12731273
u64 cpu_end = entry->res->end;
1274-
u64 size_id = 0;
12751274
int id = *index;
12761275
u64 size;
12771276

1278-
while (cpu_addr < cpu_end) {
1277+
/*
1278+
* According to the RZ/G3S HW manual (Rev.1.10, section 34.6.6.7) and
1279+
* RZ/G3E HW manual (Rev.1.15, section 6.6.7.6):
1280+
* - Each window must be a single memory size of power of two
1281+
* - Mask registers must be set to (2^N - 1)
1282+
* - Bit carry must not occur when adding base and mask registers,
1283+
* meaning the base address must be aligned to the window size
1284+
*
1285+
* Split non-power-of-2 regions into multiple windows to satisfy
1286+
* these constraints without over-mapping.
1287+
*/
1288+
while (cpu_addr <= cpu_end) {
1289+
u64 remaining_size = cpu_end - cpu_addr + 1;
1290+
u64 align_limit;
1291+
12791292
if (id >= RZG3S_MAX_WINDOWS)
12801293
return dev_err_probe(host->dev, -ENOSPC,
12811294
"Failed to map inbound window for resource (%s)\n",
12821295
entry->res->name);
12831296

1284-
size = resource_size(entry->res) - size_id;
1297+
/* Start with largest power-of-two that fits in remaining size */
1298+
size = 1ULL << __fls(remaining_size);
12851299

12861300
/*
1287-
* According to the RZ/G3S HW manual (Rev.1.10,
1288-
* section 34.3.1.71 AXI Window Mask (Lower) Registers) the min
1289-
* size is 4K.
1301+
* The "no bit carry" rule requires base addresses to be
1302+
* aligned to the window size. Find the maximum window size
1303+
* that both addresses can support based on their natural
1304+
* alignment (lowest set bit).
12901305
*/
1291-
size = max(size, SZ_4K);
1306+
align_limit = min(cpu_addr ? (1ULL << __ffs(cpu_addr)) : ~0ULL,
1307+
pci_addr ? (1ULL << __ffs(pci_addr)) : ~0ULL);
12921308

1293-
/*
1294-
* According the RZ/G3S HW manual (Rev.1.10, sections:
1295-
* - 34.3.1.69 AXI Window Base (Lower) Registers
1296-
* - 34.3.1.71 AXI Window Mask (Lower) Registers
1297-
* - 34.3.1.73 AXI Destination (Lower) Registers)
1298-
* the CPU addr, PCIe addr, size should be 4K aligned and be a
1299-
* power of 2.
1300-
*/
1301-
size = ALIGN(size, SZ_4K);
1302-
size = roundup_pow_of_two(size);
1303-
1304-
cpu_addr = ALIGN(cpu_addr, SZ_4K);
1305-
pci_addr = ALIGN(pci_addr, SZ_4K);
1309+
size = min(size, align_limit);
13061310

13071311
/*
1308-
* According to the RZ/G3S HW manual (Rev.1.10, section
1309-
* 34.3.1.71 AXI Window Mask (Lower) Registers) HW expects first
1310-
* 12 LSB bits to be 0xfff. Subtract 1 from size for this.
1312+
* Minimum window size is 4KB.
1313+
* See RZ/G3S HW manual (Rev.1.10, section 34.3.1.71) and
1314+
* RZ/G3E HW manual (Rev.1.15, section 6.6.4.1.3.(74)).
13111315
*/
1316+
size = max(size, SZ_4K);
1317+
13121318
rzg3s_pcie_set_inbound_window(host, cpu_addr, pci_addr,
13131319
size - 1, id);
13141320

13151321
pci_addr += size;
13161322
cpu_addr += size;
1317-
size_id = size;
13181323
id++;
13191324
}
13201325
*index = id;

0 commit comments

Comments
 (0)