From 06d0efe05719adcd75a48dd831c2e9a14c618f18 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Thu, 26 Dec 2019 14:17:08 -0800 Subject: iommu/arm-smmu: Expose s2cr and smr structs to impl Move the arm_smmu_s2cr and arm_smmu_smr structs to the internal header file, in order to expose them to the platform specific arm-smmu implementations. Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20191226221709.3844244-3-bjorn.andersson@linaro.org Signed-off-by: Bjorn Andersson --- drivers/iommu/arm-smmu.c | 14 -------------- drivers/iommu/arm-smmu.h | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 243bc4cb2705..acc7a135f527 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -68,24 +68,10 @@ module_param(disable_bypass, bool, S_IRUGO); MODULE_PARM_DESC(disable_bypass, "Disable bypass streams such that incoming transactions from devices that are not attached to an iommu domain will report an abort back to the device and will not be allowed to pass through the SMMU."); -struct arm_smmu_s2cr { - struct iommu_group *group; - int count; - enum arm_smmu_s2cr_type type; - enum arm_smmu_s2cr_privcfg privcfg; - u8 cbndx; -}; - #define s2cr_init_val (struct arm_smmu_s2cr){ \ .type = disable_bypass ? S2CR_TYPE_FAULT : S2CR_TYPE_BYPASS, \ } -struct arm_smmu_smr { - u16 mask; - u16 id; - bool valid; -}; - struct arm_smmu_cb { u64 ttbr[2]; u32 tcr[2]; diff --git a/drivers/iommu/arm-smmu.h b/drivers/iommu/arm-smmu.h index d172c024be61..7a5014d599d3 100644 --- a/drivers/iommu/arm-smmu.h +++ b/drivers/iommu/arm-smmu.h @@ -251,6 +251,20 @@ enum arm_smmu_implementation { QCOM_SMMUV2, }; +struct arm_smmu_s2cr { + struct iommu_group *group; + int count; + enum arm_smmu_s2cr_type type; + enum arm_smmu_s2cr_privcfg privcfg; + u8 cbndx; +}; + +struct arm_smmu_smr { + u16 mask; + u16 id; + bool valid; +}; + struct arm_smmu_device { struct device *dev; -- cgit v1.2.3 From 38b1df238ea8bfec4d81995890fefa9c91df7daf Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Thu, 26 Dec 2019 14:17:09 -0800 Subject: iommu/arm-smmu: Allow inherting stream mapping from bootloader The Qualcomm bootloaders leaves the IOMMU with stream mapping for the display hardware to be able to read the framebuffer memory in DDR, to continuously display a boot splash or to implement EFI framebuffer. This patch implements support for implementations to pin stream mappings and adds the code to the Qualcomm implementation for reading out the stream mapping from the bootloader, with the result of maintaining the display hardware's access to DDR until the context bank is enabled. Heavily based on downstream implementation by Patrick Daly . Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20191226221709.3844244-4-bjorn.andersson@linaro.org Signed-off-by: Bjorn Andersson --- drivers/iommu/arm-smmu-qcom.c | 35 +++++++++++++++++++++++++++++++++++ drivers/iommu/arm-smmu.c | 30 ++++++++++++++++++++++++------ drivers/iommu/arm-smmu.h | 1 + 3 files changed, 60 insertions(+), 6 deletions(-) diff --git a/drivers/iommu/arm-smmu-qcom.c b/drivers/iommu/arm-smmu-qcom.c index cf01d0215a39..56c3e25b4bca 100644 --- a/drivers/iommu/arm-smmu-qcom.c +++ b/drivers/iommu/arm-smmu-qcom.c @@ -4,6 +4,7 @@ */ #include +#include #include #include "arm-smmu.h" @@ -29,6 +30,39 @@ static int qcom_smmu_def_domain_type(struct device *dev) of_match_device(qcom_smmu_client_of_match, dev); return match ? IOMMU_DOMAIN_IDENTITY : 0; +}; + +static int qcom_sdm845_smmu500_cfg_probe(struct arm_smmu_device *smmu) +{ + u32 s2cr; + u32 smr; + int i; + + for (i = 0; i < smmu->num_mapping_groups; i++) { + smr = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_SMR(i)); + s2cr = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_S2CR(i)); + + smmu->smrs[i].mask = FIELD_GET(ARM_SMMU_SMR_MASK, smr); + smmu->smrs[i].id = FIELD_GET(ARM_SMMU_SMR_ID, smr); + if (smmu->features & ARM_SMMU_FEAT_EXIDS) + smmu->smrs[i].valid = FIELD_GET(ARM_SMMU_S2CR_EXIDVALID, s2cr); + else + smmu->smrs[i].valid = FIELD_GET(ARM_SMMU_SMR_VALID, smr); + + smmu->s2crs[i].group = NULL; + smmu->s2crs[i].count = 0; + smmu->s2crs[i].type = FIELD_GET(ARM_SMMU_S2CR_TYPE, s2cr); + smmu->s2crs[i].privcfg = FIELD_GET(ARM_SMMU_S2CR_PRIVCFG, s2cr); + smmu->s2crs[i].cbndx = FIELD_GET(ARM_SMMU_S2CR_CBNDX, s2cr); + + if (!smmu->smrs[i].valid) + continue; + + smmu->s2crs[i].pinned = true; + bitmap_set(smmu->context_map, smmu->s2crs[i].cbndx, 1); + } + + return 0; } static int qcom_sdm845_smmu500_reset(struct arm_smmu_device *smmu) @@ -63,6 +97,7 @@ static int qcom_smmu500_reset(struct arm_smmu_device *smmu) static const struct arm_smmu_impl qcom_smmu_impl = { .def_domain_type = qcom_smmu_def_domain_type, .reset = qcom_smmu500_reset, + .cfg_probe = qcom_sdm845_smmu500_cfg_probe, }; struct arm_smmu_device *qcom_smmu_impl_init(struct arm_smmu_device *smmu) diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index acc7a135f527..c7add09f11c1 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -223,9 +223,20 @@ static int arm_smmu_register_legacy_master(struct device *dev, } #endif /* CONFIG_ARM_SMMU_LEGACY_DT_BINDINGS */ -static int __arm_smmu_alloc_bitmap(unsigned long *map, int start, int end) +static int __arm_smmu_alloc_cb(struct arm_smmu_device *smmu, int start, + struct device *dev) { + struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev); + struct arm_smmu_master_cfg *cfg = dev_iommu_priv_get(dev); + unsigned long *map = smmu->context_map; + int end = smmu->num_context_banks; int idx; + int i; + + for_each_cfg_sme(cfg, fwspec, i, idx) { + if (smmu->s2crs[idx].pinned) + return smmu->s2crs[idx].cbndx; + } do { idx = find_next_zero_bit(map, end, start); @@ -650,7 +661,8 @@ static void arm_smmu_write_context_bank(struct arm_smmu_device *smmu, int idx) } static int arm_smmu_init_domain_context(struct iommu_domain *domain, - struct arm_smmu_device *smmu) + struct arm_smmu_device *smmu, + struct device *dev) { int irq, start, ret = 0; unsigned long ias, oas; @@ -764,8 +776,7 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain, ret = -EINVAL; goto out_unlock; } - ret = __arm_smmu_alloc_bitmap(smmu->context_map, start, - smmu->num_context_banks); + ret = __arm_smmu_alloc_cb(smmu, start, dev); if (ret < 0) goto out_unlock; @@ -1032,12 +1043,19 @@ static int arm_smmu_find_sme(struct arm_smmu_device *smmu, u16 id, u16 mask) static bool arm_smmu_free_sme(struct arm_smmu_device *smmu, int idx) { + bool pinned = smmu->s2crs[idx].pinned; + u8 cbndx = smmu->s2crs[idx].cbndx;; + if (--smmu->s2crs[idx].count) return false; smmu->s2crs[idx] = s2cr_init_val; - if (smmu->smrs) + if (pinned) { + smmu->s2crs[idx].pinned = true; + smmu->s2crs[idx].cbndx = cbndx; + } else if (smmu->smrs) { smmu->smrs[idx].valid = false; + } return true; } @@ -1164,7 +1182,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev) return ret; /* Ensure that the domain is finalised */ - ret = arm_smmu_init_domain_context(domain, smmu); + ret = arm_smmu_init_domain_context(domain, smmu, dev); if (ret < 0) goto rpm_put; diff --git a/drivers/iommu/arm-smmu.h b/drivers/iommu/arm-smmu.h index 7a5014d599d3..f5d9d1d42b88 100644 --- a/drivers/iommu/arm-smmu.h +++ b/drivers/iommu/arm-smmu.h @@ -257,6 +257,7 @@ struct arm_smmu_s2cr { enum arm_smmu_s2cr_type type; enum arm_smmu_s2cr_privcfg privcfg; u8 cbndx; + bool pinned; }; struct arm_smmu_smr { -- cgit v1.2.3