aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinaro CI <ci_notify@linaro.org>2020-04-14 08:53:14 +0000
committerLinaro CI <ci_notify@linaro.org>2020-04-14 08:53:14 +0000
commitd295a40d1d7377c4c43c2b454a1c2c0dc4dbb25f (patch)
treef9248572f3f719be69e2df228022b877e4548611
parent1ef24977c52b9d0d6594cdf661c062745705714e (diff)
parent01c3ae892cfd8565136562bb993572708c7418cd (diff)
Merge remote-tracking branch 'iommu/tracking-qcomlt-iommu' into integration-linux-qcomlt
-rw-r--r--drivers/iommu/arm-smmu-qcom.c35
-rw-r--r--drivers/iommu/arm-smmu.c44
-rw-r--r--drivers/iommu/arm-smmu.h15
3 files changed, 74 insertions, 20 deletions
diff --git a/drivers/iommu/arm-smmu-qcom.c b/drivers/iommu/arm-smmu-qcom.c
index 24c071c1d8b0..4dbe599a456b 100644
--- a/drivers/iommu/arm-smmu-qcom.c
+++ b/drivers/iommu/arm-smmu-qcom.c
@@ -3,6 +3,7 @@
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
*/
+#include <linux/bitfield.h>
#include <linux/qcom_scm.h>
#include "arm-smmu.h"
@@ -11,6 +12,39 @@ struct qcom_smmu {
struct arm_smmu_device smmu;
};
+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)
{
int ret;
@@ -31,6 +65,7 @@ static int qcom_sdm845_smmu500_reset(struct arm_smmu_device *smmu)
}
static const struct arm_smmu_impl qcom_smmu_impl = {
+ .cfg_probe = qcom_sdm845_smmu500_cfg_probe,
.reset = qcom_sdm845_smmu500_reset,
};
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index a6a5796e9c41..57651237decc 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];
@@ -237,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);
@@ -664,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;
@@ -778,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;
@@ -1046,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;
}
@@ -1188,7 +1192,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 8d1cd54d82a6..e6c75fe3f2c9 100644
--- a/drivers/iommu/arm-smmu.h
+++ b/drivers/iommu/arm-smmu.h
@@ -251,6 +251,21 @@ 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;
+ bool pinned;
+};
+
+struct arm_smmu_smr {
+ u16 mask;
+ u16 id;
+ bool valid;
+};
+
struct arm_smmu_device {
struct device *dev;