On 27.11.2023 15:54, Bibek Kumar Patro wrote: > Currently in Qualcomm SoCs the default prefetch is set to 1 which allows > the TLB to fetch just the next page table. MMU-500 features ACTLR > register which is implementation defined and is used for Qualcomm SoCs > to have a prefetch setting of 1/3/7/15 enabling TLB to prefetch > the next set of page tables accordingly allowing for faster translations. > > ACTLR value is unique for each SMR (Stream matching register) and stored > in a pre-populated table. This value is set to the register during > context bank initialisation. > > Signed-off-by: Bibek Kumar Patro <quic_bibekkum@xxxxxxxxxxx> > > --- > drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c | 56 +++++++++++++++++++++- > drivers/iommu/arm/arm-smmu/arm-smmu-qcom.h | 6 ++- > drivers/iommu/arm/arm-smmu/arm-smmu.c | 5 +- > drivers/iommu/arm/arm-smmu/arm-smmu.h | 5 ++ > 4 files changed, 68 insertions(+), 4 deletions(-) > > diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c > index 7f52ac67495f..4a38cae29be2 100644 > --- a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c > +++ b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c > @@ -14,6 +14,12 @@ > > #define QCOM_DUMMY_VAL -1 > > +struct actlr_config { > + u16 sid; > + u16 mask; > + u32 actlr; > +}; > + > static struct qcom_smmu *to_qcom_smmu(struct arm_smmu_device *smmu) > { > return container_of(smmu, struct qcom_smmu, smmu); > @@ -205,10 +211,40 @@ static bool qcom_adreno_can_do_ttbr1(struct arm_smmu_device *smmu) > return true; > } > > +static void arm_smmu_set_actlr(struct device *dev, struct arm_smmu_device *smmu, int cbndx, > + const struct actlr_config *actlrcfg, size_t actlrcfg_size) > +{ > + struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev); > + struct arm_smmu_master_cfg *cfg = dev_iommu_priv_get(dev); > + struct arm_smmu_smr *smr; > + int i; > + int j; > + u16 id; > + u16 mask; > + int idx; > + > + for (i = 0; i < actlrcfg_size; ++i) { > + id = (actlrcfg + i)->sid; > + mask = (actlrcfg + i)->mask; actrlcfg[i].id? > + > + for_each_cfg_sme(cfg, fwspec, j, idx) { > + smr = &smmu->smrs[idx]; > + if (smr_is_subset(*smr, id, mask)) Any reason for this value to be a pointer? > + arm_smmu_cb_write(smmu, cbndx, ARM_SMMU_CB_ACTLR, > + (actlrcfg + i)->actlr); ditto > + } > + } > +} > + > static int qcom_adreno_smmu_init_context(struct arm_smmu_domain *smmu_domain, > struct io_pgtable_cfg *pgtbl_cfg, struct device *dev) > { > struct adreno_smmu_priv *priv; > + struct arm_smmu_device *smmu = smmu_domain->smmu; > + struct qcom_smmu *qsmmu = to_qcom_smmu(smmu); > + const struct actlr_config *actlrcfg; > + size_t actlrcfg_size; > + int cbndx = smmu_domain->cfg.cbndx; Reverse-Christmas-tree sorting, please > > smmu_domain->cfg.flush_walk_prefer_tlbiasid = true; > > @@ -238,6 +274,12 @@ static int qcom_adreno_smmu_init_context(struct arm_smmu_domain *smmu_domain, > priv->set_stall = qcom_adreno_smmu_set_stall; > priv->resume_translation = qcom_adreno_smmu_resume_translation; > > + if (qsmmu->data->actlrcfg_gfx) { > + actlrcfg = qsmmu->data->actlrcfg_gfx; > + actlrcfg_size = qsmmu->data->actlrcfg_gfx_size; These can be passed directly s arm_smmu_set_actrl arguments > + arm_smmu_set_actlr(dev, smmu, cbndx, actlrcfg, actlrcfg_size); > + } > + > return 0; > } > > @@ -263,6 +305,18 @@ static const struct of_device_id qcom_smmu_client_of_match[] __maybe_unused = { > static int qcom_smmu_init_context(struct arm_smmu_domain *smmu_domain, > struct io_pgtable_cfg *pgtbl_cfg, struct device *dev) > { > + struct arm_smmu_device *smmu = smmu_domain->smmu; > + struct qcom_smmu *qsmmu = to_qcom_smmu(smmu); > + const struct actlr_config *actlrcfg; > + size_t actlrcfg_size; > + int cbndx = smmu_domain->cfg.cbndx; > + > + if (qsmmu->data->actlrcfg) { > + actlrcfg = qsmmu->data->actlrcfg; > + actlrcfg_size = qsmmu->data->actlrcfg_size; > + arm_smmu_set_actlr(dev, smmu, cbndx, actlrcfg, actlrcfg_size); ditto Konrad