Skip to content

Commit 4dcac84

Browse files
misalehwilldeacon
authored andcommitted
iommu/io-pgtable-arm: Fix stage-2 concatenation with 16K
At the moment, io-pgtable-arm uses concatenation only if it is possible at level 0, which misses a case where concatenation is mandatory at level 1 according to R_SRKBC in Arm spec DDI0487 K.a. Also, that means concatenation can be used when not mandated, contradicting the comment on the code. However, these cases can only happen if the SMMUv3 driver is changed to use ias != oas for stage-2. This patch re-writes the code to use concatenation only if mandatory, fixing the missing case for level-1 and granule 16K with PA = 40 bits. Signed-off-by: Mostafa Saleh <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Will Deacon <[email protected]>
1 parent cdfb984 commit 4dcac84

File tree

1 file changed

+33
-12
lines changed

1 file changed

+33
-12
lines changed

drivers/iommu/io-pgtable-arm.c

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,33 @@ static inline int arm_lpae_max_entries(int i, struct arm_lpae_io_pgtable *data)
223223
return ptes_per_table - (i & (ptes_per_table - 1));
224224
}
225225

226+
/*
227+
* Check if concatenated PGDs are mandatory according to Arm DDI0487 (K.a)
228+
* 1) R_DXBSH: For 16KB, and 48-bit input size, use level 1 instead of 0.
229+
* 2) R_SRKBC: After de-ciphering the table for PA size and valid initial lookup
230+
* a) 40 bits PA size with 4K: use level 1 instead of level 0 (2 tables for ias = oas)
231+
* b) 40 bits PA size with 16K: use level 2 instead of level 1 (16 tables for ias = oas)
232+
* c) 42 bits PA size with 4K: use level 1 instead of level 0 (8 tables for ias = oas)
233+
* d) 48 bits PA size with 16K: use level 1 instead of level 0 (2 tables for ias = oas)
234+
*/
235+
static inline bool arm_lpae_concat_mandatory(struct arm_lpae_io_pgtable *data)
236+
{
237+
unsigned int ias = data->iop.cfg.ias;
238+
unsigned int oas = data->iop.cfg.oas;
239+
240+
/* Covers 1 and 2.d */
241+
if ((ARM_LPAE_GRANULE(data) == SZ_16K) && (data->start_level == 0))
242+
return (oas == 48) || (ias == 48);
243+
244+
/* Covers 2.a and 2.c */
245+
if ((ARM_LPAE_GRANULE(data) == SZ_4K) && (data->start_level == 0))
246+
return (oas == 40) || (oas == 42);
247+
248+
/* Case 2.b */
249+
return (ARM_LPAE_GRANULE(data) == SZ_16K) &&
250+
(data->start_level == 1) && (oas == 40);
251+
}
252+
226253
static bool selftest_running = false;
227254

228255
static dma_addr_t __arm_lpae_dma_addr(void *pages)
@@ -1006,18 +1033,12 @@ arm_64_lpae_alloc_pgtable_s2(struct io_pgtable_cfg *cfg, void *cookie)
10061033
if (!data)
10071034
return NULL;
10081035

1009-
/*
1010-
* Concatenate PGDs at level 1 if possible in order to reduce
1011-
* the depth of the stage-2 walk.
1012-
*/
1013-
if (data->start_level == 0) {
1014-
unsigned long pgd_pages;
1015-
1016-
pgd_pages = ARM_LPAE_PGD_SIZE(data) / sizeof(arm_lpae_iopte);
1017-
if (pgd_pages <= ARM_LPAE_S2_MAX_CONCAT_PAGES) {
1018-
data->pgd_bits += data->bits_per_level;
1019-
data->start_level++;
1020-
}
1036+
if (arm_lpae_concat_mandatory(data)) {
1037+
if (WARN_ON((ARM_LPAE_PGD_SIZE(data) / sizeof(arm_lpae_iopte)) >
1038+
ARM_LPAE_S2_MAX_CONCAT_PAGES))
1039+
return NULL;
1040+
data->pgd_bits += data->bits_per_level;
1041+
data->start_level++;
10211042
}
10221043

10231044
/* VTCR */

0 commit comments

Comments
 (0)