Commit 987a878e authored by Michael Shavit's avatar Michael Shavit Committed by Will Deacon

iommu/arm-smmu-v3: Move ctx_desc out of s1_cfg

arm_smmu_s1_cfg (and by extension arm_smmu_domain) owns both a CD table
and the CD inserted into that table's non-pasid CD entry. This limits
arm_smmu_domain's ability to represent non-pasid domains, where multiple
domains need to be inserted into a common CD table. Rather than describing
an STE entry (which may have multiple domains installed into it with
PASID), a domain should describe a single CD entry instead. This is
precisely the role of arm_smmu_ctx_desc. A subsequent commit will also
move the CD table outside of arm_smmu_domain.
Reviewed-by: default avatarJason Gunthorpe <jgg@nvidia.com>
Reviewed-by: default avatarNicolin Chen <nicolinc@nvidia.com>
Signed-off-by: default avatarMichael Shavit <mshavit@google.com>
Tested-by: default avatarNicolin Chen <nicolinc@nvidia.com>
Link: https://lore.kernel.org/r/20230915211705.v8.1.I67ab103c18d882aedc8a08985af1fba70bca084e@changeidSigned-off-by: default avatarWill Deacon <will@kernel.org>
parent 70c61360
...@@ -62,7 +62,7 @@ arm_smmu_share_asid(struct mm_struct *mm, u16 asid) ...@@ -62,7 +62,7 @@ arm_smmu_share_asid(struct mm_struct *mm, u16 asid)
return cd; return cd;
} }
smmu_domain = container_of(cd, struct arm_smmu_domain, s1_cfg.cd); smmu_domain = container_of(cd, struct arm_smmu_domain, cd);
smmu = smmu_domain->smmu; smmu = smmu_domain->smmu;
ret = xa_alloc(&arm_smmu_asid_xa, &new_asid, cd, ret = xa_alloc(&arm_smmu_asid_xa, &new_asid, cd,
......
...@@ -1869,7 +1869,7 @@ static void arm_smmu_tlb_inv_context(void *cookie) ...@@ -1869,7 +1869,7 @@ static void arm_smmu_tlb_inv_context(void *cookie)
* careful, 007. * careful, 007.
*/ */
if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) { if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) {
arm_smmu_tlb_inv_asid(smmu, smmu_domain->s1_cfg.cd.asid); arm_smmu_tlb_inv_asid(smmu, smmu_domain->cd.asid);
} else { } else {
cmd.opcode = CMDQ_OP_TLBI_S12_VMALL; cmd.opcode = CMDQ_OP_TLBI_S12_VMALL;
cmd.tlbi.vmid = smmu_domain->s2_cfg.vmid; cmd.tlbi.vmid = smmu_domain->s2_cfg.vmid;
...@@ -1962,7 +1962,7 @@ static void arm_smmu_tlb_inv_range_domain(unsigned long iova, size_t size, ...@@ -1962,7 +1962,7 @@ static void arm_smmu_tlb_inv_range_domain(unsigned long iova, size_t size,
if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) { if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) {
cmd.opcode = smmu_domain->smmu->features & ARM_SMMU_FEAT_E2H ? cmd.opcode = smmu_domain->smmu->features & ARM_SMMU_FEAT_E2H ?
CMDQ_OP_TLBI_EL2_VA : CMDQ_OP_TLBI_NH_VA; CMDQ_OP_TLBI_EL2_VA : CMDQ_OP_TLBI_NH_VA;
cmd.tlbi.asid = smmu_domain->s1_cfg.cd.asid; cmd.tlbi.asid = smmu_domain->cd.asid;
} else { } else {
cmd.opcode = CMDQ_OP_TLBI_S2_IPA; cmd.opcode = CMDQ_OP_TLBI_S2_IPA;
cmd.tlbi.vmid = smmu_domain->s2_cfg.vmid; cmd.tlbi.vmid = smmu_domain->s2_cfg.vmid;
...@@ -2075,7 +2075,7 @@ static void arm_smmu_domain_free(struct iommu_domain *domain) ...@@ -2075,7 +2075,7 @@ static void arm_smmu_domain_free(struct iommu_domain *domain)
mutex_lock(&arm_smmu_asid_lock); mutex_lock(&arm_smmu_asid_lock);
if (cfg->cdcfg.cdtab) if (cfg->cdcfg.cdtab)
arm_smmu_free_cd_tables(smmu_domain); arm_smmu_free_cd_tables(smmu_domain);
arm_smmu_free_asid(&cfg->cd); arm_smmu_free_asid(&smmu_domain->cd);
mutex_unlock(&arm_smmu_asid_lock); mutex_unlock(&arm_smmu_asid_lock);
} else { } else {
struct arm_smmu_s2_cfg *cfg = &smmu_domain->s2_cfg; struct arm_smmu_s2_cfg *cfg = &smmu_domain->s2_cfg;
...@@ -2094,13 +2094,14 @@ static int arm_smmu_domain_finalise_s1(struct arm_smmu_domain *smmu_domain, ...@@ -2094,13 +2094,14 @@ static int arm_smmu_domain_finalise_s1(struct arm_smmu_domain *smmu_domain,
u32 asid; u32 asid;
struct arm_smmu_device *smmu = smmu_domain->smmu; struct arm_smmu_device *smmu = smmu_domain->smmu;
struct arm_smmu_s1_cfg *cfg = &smmu_domain->s1_cfg; struct arm_smmu_s1_cfg *cfg = &smmu_domain->s1_cfg;
struct arm_smmu_ctx_desc *cd = &smmu_domain->cd;
typeof(&pgtbl_cfg->arm_lpae_s1_cfg.tcr) tcr = &pgtbl_cfg->arm_lpae_s1_cfg.tcr; typeof(&pgtbl_cfg->arm_lpae_s1_cfg.tcr) tcr = &pgtbl_cfg->arm_lpae_s1_cfg.tcr;
refcount_set(&cfg->cd.refs, 1); refcount_set(&cd->refs, 1);
/* Prevent SVA from modifying the ASID until it is written to the CD */ /* Prevent SVA from modifying the ASID until it is written to the CD */
mutex_lock(&arm_smmu_asid_lock); mutex_lock(&arm_smmu_asid_lock);
ret = xa_alloc(&arm_smmu_asid_xa, &asid, &cfg->cd, ret = xa_alloc(&arm_smmu_asid_xa, &asid, cd,
XA_LIMIT(1, (1 << smmu->asid_bits) - 1), GFP_KERNEL); XA_LIMIT(1, (1 << smmu->asid_bits) - 1), GFP_KERNEL);
if (ret) if (ret)
goto out_unlock; goto out_unlock;
...@@ -2113,23 +2114,23 @@ static int arm_smmu_domain_finalise_s1(struct arm_smmu_domain *smmu_domain, ...@@ -2113,23 +2114,23 @@ static int arm_smmu_domain_finalise_s1(struct arm_smmu_domain *smmu_domain,
if (ret) if (ret)
goto out_free_asid; goto out_free_asid;
cfg->cd.asid = (u16)asid; cd->asid = (u16)asid;
cfg->cd.ttbr = pgtbl_cfg->arm_lpae_s1_cfg.ttbr; cd->ttbr = pgtbl_cfg->arm_lpae_s1_cfg.ttbr;
cfg->cd.tcr = FIELD_PREP(CTXDESC_CD_0_TCR_T0SZ, tcr->tsz) | cd->tcr = FIELD_PREP(CTXDESC_CD_0_TCR_T0SZ, tcr->tsz) |
FIELD_PREP(CTXDESC_CD_0_TCR_TG0, tcr->tg) | FIELD_PREP(CTXDESC_CD_0_TCR_TG0, tcr->tg) |
FIELD_PREP(CTXDESC_CD_0_TCR_IRGN0, tcr->irgn) | FIELD_PREP(CTXDESC_CD_0_TCR_IRGN0, tcr->irgn) |
FIELD_PREP(CTXDESC_CD_0_TCR_ORGN0, tcr->orgn) | FIELD_PREP(CTXDESC_CD_0_TCR_ORGN0, tcr->orgn) |
FIELD_PREP(CTXDESC_CD_0_TCR_SH0, tcr->sh) | FIELD_PREP(CTXDESC_CD_0_TCR_SH0, tcr->sh) |
FIELD_PREP(CTXDESC_CD_0_TCR_IPS, tcr->ips) | FIELD_PREP(CTXDESC_CD_0_TCR_IPS, tcr->ips) |
CTXDESC_CD_0_TCR_EPD1 | CTXDESC_CD_0_AA64; CTXDESC_CD_0_TCR_EPD1 | CTXDESC_CD_0_AA64;
cfg->cd.mair = pgtbl_cfg->arm_lpae_s1_cfg.mair; cd->mair = pgtbl_cfg->arm_lpae_s1_cfg.mair;
/* /*
* Note that this will end up calling arm_smmu_sync_cd() before * Note that this will end up calling arm_smmu_sync_cd() before
* the master has been added to the devices list for this domain. * the master has been added to the devices list for this domain.
* This isn't an issue because the STE hasn't been installed yet. * This isn't an issue because the STE hasn't been installed yet.
*/ */
ret = arm_smmu_write_ctx_desc(smmu_domain, IOMMU_NO_PASID, &cfg->cd); ret = arm_smmu_write_ctx_desc(smmu_domain, IOMMU_NO_PASID, cd);
if (ret) if (ret)
goto out_free_cd_tables; goto out_free_cd_tables;
...@@ -2139,7 +2140,7 @@ static int arm_smmu_domain_finalise_s1(struct arm_smmu_domain *smmu_domain, ...@@ -2139,7 +2140,7 @@ static int arm_smmu_domain_finalise_s1(struct arm_smmu_domain *smmu_domain,
out_free_cd_tables: out_free_cd_tables:
arm_smmu_free_cd_tables(smmu_domain); arm_smmu_free_cd_tables(smmu_domain);
out_free_asid: out_free_asid:
arm_smmu_free_asid(&cfg->cd); arm_smmu_free_asid(cd);
out_unlock: out_unlock:
mutex_unlock(&arm_smmu_asid_lock); mutex_unlock(&arm_smmu_asid_lock);
return ret; return ret;
......
...@@ -599,7 +599,6 @@ struct arm_smmu_ctx_desc_cfg { ...@@ -599,7 +599,6 @@ struct arm_smmu_ctx_desc_cfg {
struct arm_smmu_s1_cfg { struct arm_smmu_s1_cfg {
struct arm_smmu_ctx_desc_cfg cdcfg; struct arm_smmu_ctx_desc_cfg cdcfg;
struct arm_smmu_ctx_desc cd;
u8 s1fmt; u8 s1fmt;
u8 s1cdmax; u8 s1cdmax;
}; };
...@@ -724,7 +723,10 @@ struct arm_smmu_domain { ...@@ -724,7 +723,10 @@ struct arm_smmu_domain {
enum arm_smmu_domain_stage stage; enum arm_smmu_domain_stage stage;
union { union {
struct arm_smmu_s1_cfg s1_cfg; struct {
struct arm_smmu_ctx_desc cd;
struct arm_smmu_s1_cfg s1_cfg;
};
struct arm_smmu_s2_cfg s2_cfg; struct arm_smmu_s2_cfg s2_cfg;
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment