Skip to content

Commit e94dc6d

Browse files
nicolincwilldeacon
authored andcommitted
iommu/tegra241-cmdqv: Read SMMU IDR1.CMDQS instead of hardcoding
The hardware limitation "max=19" actually comes from SMMU Command Queue. So, it'd be more natural for tegra241-cmdqv driver to read it out rather than hardcoding it itself. This is not an issue yet for a kernel on a baremetal system, but a guest kernel setting the queue base/size in form of IPA/gPA might result in a noncontiguous queue in the physical address space, if underlying physical pages backing up the guest RAM aren't contiguous entirely: e.g. 2MB-page backed guest RAM cannot guarantee a contiguous queue if it is 8MB (capped to VCMDQ_LOG2SIZE_MAX=19). This might lead to command errors when HW does linear-read from a noncontiguous queue memory. Adding this extra IDR1.CMDQS cap (in the guest kernel) allows VMM to set SMMU's IDR1.CMDQS=17 for the case mentioned above, so a guest-level queue will be capped to maximum 2MB, ensuring a contiguous queue memory. Fixes: a379971 ("iommu/tegra241-cmdqv: Fix alignment failure at max_n_shift") Reported-by: Ian Kalinowski <[email protected]> Cc: [email protected] Signed-off-by: Nicolin Chen <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Will Deacon <[email protected]>
1 parent b7b8a63 commit e94dc6d

File tree

1 file changed

+5
-3
lines changed

1 file changed

+5
-3
lines changed

drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,6 @@
7979
#define TEGRA241_VCMDQ_PAGE1(q) (TEGRA241_VCMDQ_PAGE1_BASE + 0x80*(q))
8080
#define VCMDQ_ADDR GENMASK(47, 5)
8181
#define VCMDQ_LOG2SIZE GENMASK(4, 0)
82-
#define VCMDQ_LOG2SIZE_MAX 19
8382

8483
#define TEGRA241_VCMDQ_BASE 0x00000
8584
#define TEGRA241_VCMDQ_CONS_INDX_BASE 0x00008
@@ -505,12 +504,15 @@ static int tegra241_vcmdq_alloc_smmu_cmdq(struct tegra241_vcmdq *vcmdq)
505504
struct arm_smmu_cmdq *cmdq = &vcmdq->cmdq;
506505
struct arm_smmu_queue *q = &cmdq->q;
507506
char name[16];
507+
u32 regval;
508508
int ret;
509509

510510
snprintf(name, 16, "vcmdq%u", vcmdq->idx);
511511

512-
/* Queue size, capped to ensure natural alignment */
513-
q->llq.max_n_shift = min_t(u32, CMDQ_MAX_SZ_SHIFT, VCMDQ_LOG2SIZE_MAX);
512+
/* Cap queue size to SMMU's IDR1.CMDQS and ensure natural alignment */
513+
regval = readl_relaxed(smmu->base + ARM_SMMU_IDR1);
514+
q->llq.max_n_shift =
515+
min_t(u32, CMDQ_MAX_SZ_SHIFT, FIELD_GET(IDR1_CMDQS, regval));
514516

515517
/* Use the common helper to init the VCMDQ, and then... */
516518
ret = arm_smmu_init_one_queue(smmu, q, vcmdq->page0,

0 commit comments

Comments
 (0)