Skip to content

Commit

Permalink
iommu/qcom: Add support for AArch64 IOMMU pagetables
Browse files Browse the repository at this point in the history
Some IOMMUs associated with some TZ firmwares may support switching
to the AArch64 pagetable format by sending a "set pagetable format"
scm command indicating the IOMMU secure ID and the context number
to switch.

Add a DT property "qcom,use-aarch64-pagetables" for this driver to
send this command to the secure world and to switch the pagetable
format to benefit of the ARM64 IOMMU pagetables, where possible.

Note that, even though the command should be valid to switch each
context, the property is made global because:
1. It doesn't make too much sense to switch only one or two
   context(s) to AA64 instead of just the entire thing
2. Some IOMMUs will go crazy and produce spectacular results when
   trying to mix up the pagetables on a per-context basis.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>
Signed-off-by: Marijn Suijten <marijn.suijten@somainline.org>
Signed-off-by: Konrad Dybcio <konrad.dybcio@somainline.org>
  • Loading branch information
kholk authored and intel-lab-lkp committed May 27, 2022
1 parent 4dd6f9a commit 0744f7d
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 9 deletions.
2 changes: 2 additions & 0 deletions Documentation/devicetree/bindings/iommu/qcom,iommu.txt
Expand Up @@ -47,6 +47,8 @@ to non-secure vs secure interrupt line.
secure lines. (Ie. if the iommu contains secure
context banks)
- qcom,ctx-num : The number associated to the context bank
- qcom,use-aarch64-pagetables : Switch to AArch64 pagetable format on all
contexts declared in this IOMMU


** Examples:
Expand Down
54 changes: 45 additions & 9 deletions drivers/iommu/arm/arm-smmu/qcom_iommu.c
Expand Up @@ -52,6 +52,7 @@ struct qcom_iommu_dev {
void __iomem *local_base;
u32 sec_id;
u8 num_ctxs;
bool use_aarch64_pt;
struct qcom_iommu_ctx *ctxs[]; /* indexed by asid-1 */
};

Expand Down Expand Up @@ -164,11 +165,17 @@ static void qcom_iommu_tlb_inv_range_nosync(unsigned long iova, size_t size,
reg = leaf ? ARM_SMMU_CB_S1_TLBIVAL : ARM_SMMU_CB_S1_TLBIVA;

for (i = 0; i < fwspec->num_ids; i++) {
struct qcom_iommu_dev *qcom_iommu = qcom_domain->iommu;
struct qcom_iommu_ctx *ctx = to_ctx(qcom_domain, fwspec->ids[i]);
size_t s = size;

iova = (iova >> 12) << 12;
iova |= ctx->asid;
if (qcom_iommu->use_aarch64_pt) {
iova >>= 12;
iova |= (unsigned long)ctx->asid << 48;
} else {
iova &= (1UL << 12) - 1UL;
iova |= ctx->asid;
}
do {
iommu_writel(ctx, reg, iova);
iova += granule;
Expand Down Expand Up @@ -248,25 +255,36 @@ static int qcom_iommu_init_domain(struct iommu_domain *domain,
struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
struct io_pgtable_ops *pgtbl_ops;
struct io_pgtable_cfg pgtbl_cfg;
enum io_pgtable_fmt pgtbl_fmt;
unsigned long ias, oas;
int i, ret = 0;
u32 reg;

mutex_lock(&qcom_domain->init_mutex);
if (qcom_domain->iommu)
goto out_unlock;

if (qcom_iommu->use_aarch64_pt) {
pgtbl_fmt = ARM_64_LPAE_S1;
ias = oas = 48;
} else {
pgtbl_fmt = ARM_32_LPAE_S1;
ias = 32;
oas = 40;
}

pgtbl_cfg = (struct io_pgtable_cfg) {
.pgsize_bitmap = qcom_iommu_ops.pgsize_bitmap,
.ias = 32,
.oas = 40,
.ias = ias,
.oas = oas,
.tlb = &qcom_flush_ops,
.iommu_dev = qcom_iommu->dev,
};

qcom_domain->iommu = qcom_iommu;
qcom_domain->fwspec = fwspec;

pgtbl_ops = alloc_io_pgtable_ops(ARM_32_LPAE_S1, &pgtbl_cfg, qcom_domain);
pgtbl_ops = alloc_io_pgtable_ops(pgtbl_fmt, &pgtbl_cfg, qcom_domain);
if (!pgtbl_ops) {
dev_err(qcom_iommu->dev, "failed to allocate pagetable ops\n");
ret = -ENOMEM;
Expand All @@ -280,6 +298,7 @@ static int qcom_iommu_init_domain(struct iommu_domain *domain,

for (i = 0; i < fwspec->num_ids; i++) {
struct qcom_iommu_ctx *ctx = to_ctx(qcom_domain, fwspec->ids[i]);
u32 tcr[2];

if (!ctx->secure_init) {
ret = qcom_scm_restore_sec_cfg(qcom_iommu->sec_id, ctx->asid);
Expand All @@ -292,11 +311,25 @@ static int qcom_iommu_init_domain(struct iommu_domain *domain,

qcom_iommu_reset_ctx(ctx);


tcr[0] = arm_smmu_lpae_tcr(&pgtbl_cfg);
tcr[1] = arm_smmu_lpae_tcr2(&pgtbl_cfg);

if (!qcom_iommu->use_aarch64_pt) {
tcr[0] |= ARM_SMMU_TCR_EAE;
} else {
/* This shall not fail, or spectacular things happen! */
if (qcom_scm_iommu_set_pt_format(qcom_iommu->sec_id, ctx->asid, 1)) {
dev_warn(qcom_iommu->dev, "Cannot set AArch64 pt format\n");
goto out_clear_iommu;
}

tcr[1] |= ARM_SMMU_TCR2_AS;
}

/* TCR */
iommu_writel(ctx, ARM_SMMU_CB_TCR2,
arm_smmu_lpae_tcr2(&pgtbl_cfg));
iommu_writel(ctx, ARM_SMMU_CB_TCR,
arm_smmu_lpae_tcr(&pgtbl_cfg) | ARM_SMMU_TCR_EAE);
iommu_writel(ctx, ARM_SMMU_CB_TCR2, tcr[1]);
iommu_writel(ctx, ARM_SMMU_CB_TCR, tcr[0]);

/* TTBRs */
iommu_writeq(ctx, ARM_SMMU_CB_TTBR0,
Expand Down Expand Up @@ -844,6 +877,9 @@ static int qcom_iommu_device_probe(struct platform_device *pdev)
return -ENODEV;
}

if (of_property_read_bool(dev->of_node, "qcom,use-aarch64-pagetables"))
qcom_iommu->use_aarch64_pt = true;

if (qcom_iommu_has_secure_context(qcom_iommu)) {
ret = qcom_iommu_sec_ptbl_init(dev);
if (ret) {
Expand Down

0 comments on commit 0744f7d

Please sign in to comment.