ANDROID: iommu/io-pgtable-arm: Fix block split for IO_PGTABLE_QUIRK_UNMAP_INVAL

When a block is split to a table because of a partial unmap,
a new table is populated, where the unmapped part are 0.

However, IO_PGTABLE_QUIRK_UNMAP_INVAL relies on the ability to
walk the tables after unmap to decrement their refcount, so
change the code to convert the block to a table, then unmap
the requested part.

Bug: 357781595
Bug: 384432312
Change-Id: I78be194b9af8e5454507d4b787232b84a38d41b7
Signed-off-by: Mostafa Saleh <smostafa@google.com>
This commit is contained in:
Mostafa Saleh
2025-01-29 16:10:54 +00:00
committed by Treehugger Robot
parent a6a082c356
commit bdb9c5d1b2
+2 -20
View File
@@ -380,9 +380,7 @@ static size_t arm_lpae_split_blk_unmap(struct arm_lpae_io_pgtable *data,
arm_lpae_iopte pte, *tablep;
phys_addr_t blk_paddr;
size_t tablesz = ARM_LPAE_GRANULE(data);
size_t split_sz = ARM_LPAE_BLOCK_SIZE(lvl, data);
int ptes_per_table = ARM_LPAE_PTES_PER_TABLE(data);
int i, unmap_idx_start = -1, num_entries = 0, max_entries;
if (WARN_ON(lvl == ARM_LPAE_MAX_LEVELS))
return 0;
@@ -391,22 +389,11 @@ static size_t arm_lpae_split_blk_unmap(struct arm_lpae_io_pgtable *data,
if (!tablep)
return 0; /* Bytes unmapped */
if (size == split_sz) {
unmap_idx_start = ARM_LPAE_LVL_IDX(iova, lvl, data);
max_entries = arm_lpae_max_entries(unmap_idx_start, data);
num_entries = min_t(int, pgcount, max_entries);
}
blk_paddr = iopte_to_paddr(blk_pte, data);
pte = iopte_prot(blk_pte);
for (i = 0; i < ptes_per_table; i++, blk_paddr += split_sz) {
/* Unmap! */
if (i >= unmap_idx_start && i < (unmap_idx_start + num_entries))
continue;
__arm_lpae_init_pte(data, blk_paddr, pte, lvl, 1, &tablep[i]);
}
/* Fully populate the table. */
__arm_lpae_init_pte(data, blk_paddr, pte, lvl, ptes_per_table, tablep);
pte = arm_lpae_install_table(tablep, ptep, blk_pte, data);
if (pte != blk_pte) {
@@ -420,11 +407,6 @@ static size_t arm_lpae_split_blk_unmap(struct arm_lpae_io_pgtable *data,
return 0;
tablep = iopte_deref(pte, data);
} else if (unmap_idx_start >= 0) {
for (i = 0; i < num_entries; i++)
io_pgtable_tlb_add_page(&data->iop, gather, iova + i * size, size);
return num_entries * size;
}
return __arm_lpae_unmap(data, gather, iova, size, pgcount, lvl, tablep);