aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iommu
diff options
context:
space:
mode:
authorWill Deacon <will.deacon@arm.com>2014-07-15 06:22:24 -0400
committerWill Deacon <will.deacon@arm.com>2014-09-02 05:04:33 -0400
commit43b412bedb782e27a8771b61870dd45a24975266 (patch)
treeb8abdc086bb801a3cb58b1389bff2a370a691c87 /drivers/iommu
parent93b14135cf24668b45eb57348312b627a8539bc4 (diff)
iommu/arm-smmu: fix s2cr and smr teardown on device detach from domain
When we attach a device to a domain, we configure the SMRs (if we have any) to match the Stream IDs for the corresponding SMMU master and program the s2crs accordingly. However, on detach we tear down the s2crs assuming stream-indexing (as opposed to stream-matching) and SMRs assuming they are present. This patch fixes the device detach code so that it operates as a converse of the attach code. Cc: <stable@vger.kernel.org> Signed-off-by: Will Deacon <will.deacon@arm.com>
Diffstat (limited to 'drivers/iommu')
-rw-r--r--drivers/iommu/arm-smmu.c27
1 files changed, 12 insertions, 15 deletions
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 398802ad9d2d..b7cd5d07d6fb 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -1116,6 +1116,9 @@ static void arm_smmu_master_free_smrs(struct arm_smmu_device *smmu,
1116 void __iomem *gr0_base = ARM_SMMU_GR0(smmu); 1116 void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
1117 struct arm_smmu_smr *smrs = cfg->smrs; 1117 struct arm_smmu_smr *smrs = cfg->smrs;
1118 1118
1119 if (!smrs)
1120 return;
1121
1119 /* Invalidate the SMRs before freeing back to the allocator */ 1122 /* Invalidate the SMRs before freeing back to the allocator */
1120 for (i = 0; i < cfg->num_streamids; ++i) { 1123 for (i = 0; i < cfg->num_streamids; ++i) {
1121 u8 idx = smrs[i].idx; 1124 u8 idx = smrs[i].idx;
@@ -1128,20 +1131,6 @@ static void arm_smmu_master_free_smrs(struct arm_smmu_device *smmu,
1128 kfree(smrs); 1131 kfree(smrs);
1129} 1132}
1130 1133
1131static void arm_smmu_bypass_stream_mapping(struct arm_smmu_device *smmu,
1132 struct arm_smmu_master_cfg *cfg)
1133{
1134 int i;
1135 void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
1136
1137 for (i = 0; i < cfg->num_streamids; ++i) {
1138 u16 sid = cfg->streamids[i];
1139
1140 writel_relaxed(S2CR_TYPE_BYPASS,
1141 gr0_base + ARM_SMMU_GR0_S2CR(sid));
1142 }
1143}
1144
1145static int arm_smmu_domain_add_master(struct arm_smmu_domain *smmu_domain, 1134static int arm_smmu_domain_add_master(struct arm_smmu_domain *smmu_domain,
1146 struct arm_smmu_master_cfg *cfg) 1135 struct arm_smmu_master_cfg *cfg)
1147{ 1136{
@@ -1168,13 +1157,21 @@ static int arm_smmu_domain_add_master(struct arm_smmu_domain *smmu_domain,
1168static void arm_smmu_domain_remove_master(struct arm_smmu_domain *smmu_domain, 1157static void arm_smmu_domain_remove_master(struct arm_smmu_domain *smmu_domain,
1169 struct arm_smmu_master_cfg *cfg) 1158 struct arm_smmu_master_cfg *cfg)
1170{ 1159{
1160 int i;
1171 struct arm_smmu_device *smmu = smmu_domain->smmu; 1161 struct arm_smmu_device *smmu = smmu_domain->smmu;
1162 void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
1172 1163
1173 /* 1164 /*
1174 * We *must* clear the S2CR first, because freeing the SMR means 1165 * We *must* clear the S2CR first, because freeing the SMR means
1175 * that it can be re-allocated immediately. 1166 * that it can be re-allocated immediately.
1176 */ 1167 */
1177 arm_smmu_bypass_stream_mapping(smmu, cfg); 1168 for (i = 0; i < cfg->num_streamids; ++i) {
1169 u32 idx = cfg->smrs ? cfg->smrs[i].idx : cfg->streamids[i];
1170
1171 writel_relaxed(S2CR_TYPE_BYPASS,
1172 gr0_base + ARM_SMMU_GR0_S2CR(idx));
1173 }
1174
1178 arm_smmu_master_free_smrs(smmu, cfg); 1175 arm_smmu_master_free_smrs(smmu, cfg);
1179} 1176}
1180 1177