aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iommu/arm-smmu.c
diff options
context:
space:
mode:
authorRobin Murphy <robin.murphy@arm.com>2016-09-12 12:13:50 -0400
committerWill Deacon <will.deacon@arm.com>2016-09-16 04:34:18 -0400
commit8e8b203eabd8b9e96d02d6339e4abce3e5a7ea4b (patch)
treeae8e934e6061d725c285e46e99b1d72501627fa7 /drivers/iommu/arm-smmu.c
parent1f3d5ca43019bff1105838712d55be087d93c0da (diff)
iommu/arm-smmu: Keep track of S2CR state
Making S2CRs first-class citizens within the driver with a high-level representation of their state offers a neat solution to a few problems: Firstly, the information about which context a device's stream IDs are associated with is already present by necessity in the S2CR. With that state easily accessible we can refer directly to it and obviate the need to track an IOMMU domain in each device's archdata (its earlier purpose of enforcing correct attachment of multi-device groups now being handled by the IOMMU core itself). Secondly, the core API now deprecates explicit domain detach and expects domain attach to move devices smoothly from one domain to another; for SMMUv2, this notion maps directly to simply rewriting the S2CRs assigned to the device. By giving the driver a suitable abstraction of those S2CRs to work with, we can massively reduce the overhead of the current heavy-handed "detach, free resources, reallocate resources, attach" approach. Thirdly, making the software state hardware-shaped and attached to the SMMU instance once again makes suspend/resume of this register group that much simpler to implement in future. Signed-off-by: Robin Murphy <robin.murphy@arm.com> Signed-off-by: Will Deacon <will.deacon@arm.com>
Diffstat (limited to 'drivers/iommu/arm-smmu.c')
-rw-r--r--drivers/iommu/arm-smmu.c159
1 files changed, 93 insertions, 66 deletions
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index dfe13780ba54..69b6cab65421 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -170,12 +170,20 @@
170#define S2CR_CBNDX_MASK 0xff 170#define S2CR_CBNDX_MASK 0xff
171#define S2CR_TYPE_SHIFT 16 171#define S2CR_TYPE_SHIFT 16
172#define S2CR_TYPE_MASK 0x3 172#define S2CR_TYPE_MASK 0x3
173#define S2CR_TYPE_TRANS (0 << S2CR_TYPE_SHIFT) 173enum arm_smmu_s2cr_type {
174#define S2CR_TYPE_BYPASS (1 << S2CR_TYPE_SHIFT) 174 S2CR_TYPE_TRANS,
175#define S2CR_TYPE_FAULT (2 << S2CR_TYPE_SHIFT) 175 S2CR_TYPE_BYPASS,
176 S2CR_TYPE_FAULT,
177};
176 178
177#define S2CR_PRIVCFG_SHIFT 24 179#define S2CR_PRIVCFG_SHIFT 24
178#define S2CR_PRIVCFG_UNPRIV (2 << S2CR_PRIVCFG_SHIFT) 180#define S2CR_PRIVCFG_MASK 0x3
181enum arm_smmu_s2cr_privcfg {
182 S2CR_PRIVCFG_DEFAULT,
183 S2CR_PRIVCFG_DIPAN,
184 S2CR_PRIVCFG_UNPRIV,
185 S2CR_PRIVCFG_PRIV,
186};
179 187
180/* Context bank attribute registers */ 188/* Context bank attribute registers */
181#define ARM_SMMU_GR1_CBAR(n) (0x0 + ((n) << 2)) 189#define ARM_SMMU_GR1_CBAR(n) (0x0 + ((n) << 2))
@@ -292,6 +300,16 @@ enum arm_smmu_implementation {
292 CAVIUM_SMMUV2, 300 CAVIUM_SMMUV2,
293}; 301};
294 302
303struct arm_smmu_s2cr {
304 enum arm_smmu_s2cr_type type;
305 enum arm_smmu_s2cr_privcfg privcfg;
306 u8 cbndx;
307};
308
309#define s2cr_init_val (struct arm_smmu_s2cr){ \
310 .type = disable_bypass ? S2CR_TYPE_FAULT : S2CR_TYPE_BYPASS, \
311}
312
295struct arm_smmu_smr { 313struct arm_smmu_smr {
296 u16 mask; 314 u16 mask;
297 u16 id; 315 u16 id;
@@ -346,6 +364,7 @@ struct arm_smmu_device {
346 u16 streamid_mask; 364 u16 streamid_mask;
347 u16 smr_mask_mask; 365 u16 smr_mask_mask;
348 struct arm_smmu_smr *smrs; 366 struct arm_smmu_smr *smrs;
367 struct arm_smmu_s2cr *s2crs;
349 368
350 unsigned long va_size; 369 unsigned long va_size;
351 unsigned long ipa_size; 370 unsigned long ipa_size;
@@ -1108,6 +1127,23 @@ static void arm_smmu_write_smr(struct arm_smmu_device *smmu, int idx)
1108 writel_relaxed(reg, ARM_SMMU_GR0(smmu) + ARM_SMMU_GR0_SMR(idx)); 1127 writel_relaxed(reg, ARM_SMMU_GR0(smmu) + ARM_SMMU_GR0_SMR(idx));
1109} 1128}
1110 1129
1130static void arm_smmu_write_s2cr(struct arm_smmu_device *smmu, int idx)
1131{
1132 struct arm_smmu_s2cr *s2cr = smmu->s2crs + idx;
1133 u32 reg = (s2cr->type & S2CR_TYPE_MASK) << S2CR_TYPE_SHIFT |
1134 (s2cr->cbndx & S2CR_CBNDX_MASK) << S2CR_CBNDX_SHIFT |
1135 (s2cr->privcfg & S2CR_PRIVCFG_MASK) << S2CR_PRIVCFG_SHIFT;
1136
1137 writel_relaxed(reg, ARM_SMMU_GR0(smmu) + ARM_SMMU_GR0_S2CR(idx));
1138}
1139
1140static void arm_smmu_write_sme(struct arm_smmu_device *smmu, int idx)
1141{
1142 arm_smmu_write_s2cr(smmu, idx);
1143 if (smmu->smrs)
1144 arm_smmu_write_smr(smmu, idx);
1145}
1146
1111static int arm_smmu_master_alloc_smes(struct arm_smmu_device *smmu, 1147static int arm_smmu_master_alloc_smes(struct arm_smmu_device *smmu,
1112 struct arm_smmu_master_cfg *cfg) 1148 struct arm_smmu_master_cfg *cfg)
1113{ 1149{
@@ -1158,6 +1194,23 @@ static void arm_smmu_master_free_smes(struct arm_smmu_device *smmu,
1158{ 1194{
1159 int i; 1195 int i;
1160 1196
1197 /*
1198 * We *must* clear the S2CR first, because freeing the SMR means
1199 * that it can be re-allocated immediately.
1200 */
1201 for (i = 0; i < cfg->num_streamids; ++i) {
1202 int idx = cfg->smendx[i];
1203
1204 /* An IOMMU group is torn down by the first device to be removed */
1205 if (idx == INVALID_SMENDX)
1206 return;
1207
1208 smmu->s2crs[idx] = s2cr_init_val;
1209 arm_smmu_write_s2cr(smmu, idx);
1210 }
1211 /* Sync S2CR updates before touching anything else */
1212 __iowmb();
1213
1161 /* Invalidate the SMRs before freeing back to the allocator */ 1214 /* Invalidate the SMRs before freeing back to the allocator */
1162 for (i = 0; i < cfg->num_streamids; ++i) { 1215 for (i = 0; i < cfg->num_streamids; ++i) {
1163 if (smmu->smrs) 1216 if (smmu->smrs)
@@ -1170,9 +1223,16 @@ static void arm_smmu_master_free_smes(struct arm_smmu_device *smmu,
1170static int arm_smmu_domain_add_master(struct arm_smmu_domain *smmu_domain, 1223static int arm_smmu_domain_add_master(struct arm_smmu_domain *smmu_domain,
1171 struct arm_smmu_master_cfg *cfg) 1224 struct arm_smmu_master_cfg *cfg)
1172{ 1225{
1173 int i, ret; 1226 int i, ret = 0;
1174 struct arm_smmu_device *smmu = smmu_domain->smmu; 1227 struct arm_smmu_device *smmu = smmu_domain->smmu;
1175 void __iomem *gr0_base = ARM_SMMU_GR0(smmu); 1228 struct arm_smmu_s2cr *s2cr = smmu->s2crs;
1229 enum arm_smmu_s2cr_type type = S2CR_TYPE_TRANS;
1230 u8 cbndx = smmu_domain->cfg.cbndx;
1231
1232 if (cfg->smendx[0] == INVALID_SMENDX)
1233 ret = arm_smmu_master_alloc_smes(smmu, cfg);
1234 if (ret)
1235 return ret;
1176 1236
1177 /* 1237 /*
1178 * FIXME: This won't be needed once we have IOMMU-backed DMA ops 1238 * FIXME: This won't be needed once we have IOMMU-backed DMA ops
@@ -1181,58 +1241,21 @@ static int arm_smmu_domain_add_master(struct arm_smmu_domain *smmu_domain,
1181 * and a PCI device (i.e. a PCI host controller) 1241 * and a PCI device (i.e. a PCI host controller)
1182 */ 1242 */
1183 if (smmu_domain->domain.type == IOMMU_DOMAIN_DMA) 1243 if (smmu_domain->domain.type == IOMMU_DOMAIN_DMA)
1184 return 0; 1244 type = S2CR_TYPE_BYPASS;
1185
1186 /* Devices in an IOMMU group may already be configured */
1187 ret = arm_smmu_master_alloc_smes(smmu, cfg);
1188 if (ret)
1189 return ret == -EEXIST ? 0 : ret;
1190 1245
1191 for (i = 0; i < cfg->num_streamids; ++i) { 1246 for (i = 0; i < cfg->num_streamids; ++i) {
1192 u32 idx, s2cr;
1193
1194 idx = cfg->smendx[i];
1195 s2cr = S2CR_TYPE_TRANS | S2CR_PRIVCFG_UNPRIV |
1196 (smmu_domain->cfg.cbndx << S2CR_CBNDX_SHIFT);
1197 writel_relaxed(s2cr, gr0_base + ARM_SMMU_GR0_S2CR(idx));
1198 }
1199
1200 return 0;
1201}
1202
1203static void arm_smmu_domain_remove_master(struct arm_smmu_domain *smmu_domain,
1204 struct arm_smmu_master_cfg *cfg)
1205{
1206 int i;
1207 struct arm_smmu_device *smmu = smmu_domain->smmu;
1208 void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
1209
1210 /*
1211 * We *must* clear the S2CR first, because freeing the SMR means
1212 * that it can be re-allocated immediately.
1213 */
1214 for (i = 0; i < cfg->num_streamids; ++i) {
1215 int idx = cfg->smendx[i]; 1247 int idx = cfg->smendx[i];
1216 u32 reg = disable_bypass ? S2CR_TYPE_FAULT : S2CR_TYPE_BYPASS;
1217 1248
1218 /* An IOMMU group is torn down by the first device to be removed */ 1249 /* Devices in an IOMMU group may already be configured */
1219 if (idx == INVALID_SMENDX) 1250 if (type == s2cr[idx].type && cbndx == s2cr[idx].cbndx)
1220 return; 1251 break;
1221 1252
1222 writel_relaxed(reg, gr0_base + ARM_SMMU_GR0_S2CR(idx)); 1253 s2cr[idx].type = type;
1254 s2cr[idx].privcfg = S2CR_PRIVCFG_UNPRIV;
1255 s2cr[idx].cbndx = cbndx;
1256 arm_smmu_write_s2cr(smmu, idx);
1223 } 1257 }
1224 1258 return 0;
1225 arm_smmu_master_free_smes(smmu, cfg);
1226}
1227
1228static void arm_smmu_detach_dev(struct device *dev,
1229 struct arm_smmu_master_cfg *cfg)
1230{
1231 struct iommu_domain *domain = dev->archdata.iommu;
1232 struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
1233
1234 dev->archdata.iommu = NULL;
1235 arm_smmu_domain_remove_master(smmu_domain, cfg);
1236} 1259}
1237 1260
1238static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev) 1261static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
@@ -1269,14 +1292,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
1269 if (!cfg) 1292 if (!cfg)
1270 return -ENODEV; 1293 return -ENODEV;
1271 1294
1272 /* Detach the dev from its current domain */ 1295 return arm_smmu_domain_add_master(smmu_domain, cfg);
1273 if (dev->archdata.iommu)
1274 arm_smmu_detach_dev(dev, cfg);
1275
1276 ret = arm_smmu_domain_add_master(smmu_domain, cfg);
1277 if (!ret)
1278 dev->archdata.iommu = domain;
1279 return ret;
1280} 1296}
1281 1297
1282static int arm_smmu_map(struct iommu_domain *domain, unsigned long iova, 1298static int arm_smmu_map(struct iommu_domain *domain, unsigned long iova,
@@ -1477,6 +1493,12 @@ static int arm_smmu_add_device(struct device *dev)
1477 1493
1478static void arm_smmu_remove_device(struct device *dev) 1494static void arm_smmu_remove_device(struct device *dev)
1479{ 1495{
1496 struct arm_smmu_device *smmu = find_smmu_for_device(dev);
1497 struct arm_smmu_master_cfg *cfg = find_smmu_master_cfg(dev);
1498
1499 if (smmu && cfg)
1500 arm_smmu_master_free_smes(smmu, cfg);
1501
1480 iommu_group_remove_device(dev); 1502 iommu_group_remove_device(dev);
1481} 1503}
1482 1504
@@ -1582,12 +1604,8 @@ static void arm_smmu_device_reset(struct arm_smmu_device *smmu)
1582 * Reset stream mapping groups: Initial values mark all SMRn as 1604 * Reset stream mapping groups: Initial values mark all SMRn as
1583 * invalid and all S2CRn as bypass unless overridden. 1605 * invalid and all S2CRn as bypass unless overridden.
1584 */ 1606 */
1585 reg = disable_bypass ? S2CR_TYPE_FAULT : S2CR_TYPE_BYPASS; 1607 for (i = 0; i < smmu->num_mapping_groups; ++i)
1586 for (i = 0; i < smmu->num_mapping_groups; ++i) { 1608 arm_smmu_write_sme(smmu, i);
1587 if (smmu->smrs)
1588 arm_smmu_write_smr(smmu, i);
1589 writel_relaxed(reg, gr0_base + ARM_SMMU_GR0_S2CR(i));
1590 }
1591 1609
1592 /* 1610 /*
1593 * Before clearing ARM_MMU500_ACTLR_CPRE, need to 1611 * Before clearing ARM_MMU500_ACTLR_CPRE, need to
@@ -1676,6 +1694,7 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
1676 void __iomem *gr0_base = ARM_SMMU_GR0(smmu); 1694 void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
1677 u32 id; 1695 u32 id;
1678 bool cttw_dt, cttw_reg; 1696 bool cttw_dt, cttw_reg;
1697 int i;
1679 1698
1680 dev_notice(smmu->dev, "probing hardware configuration...\n"); 1699 dev_notice(smmu->dev, "probing hardware configuration...\n");
1681 dev_notice(smmu->dev, "SMMUv%d with:\n", 1700 dev_notice(smmu->dev, "SMMUv%d with:\n",
@@ -1773,6 +1792,14 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
1773 "\tstream matching with %lu register groups, mask 0x%x", 1792 "\tstream matching with %lu register groups, mask 0x%x",
1774 size, smmu->smr_mask_mask); 1793 size, smmu->smr_mask_mask);
1775 } 1794 }
1795 /* s2cr->type == 0 means translation, so initialise explicitly */
1796 smmu->s2crs = devm_kmalloc_array(smmu->dev, size, sizeof(*smmu->s2crs),
1797 GFP_KERNEL);
1798 if (!smmu->s2crs)
1799 return -ENOMEM;
1800 for (i = 0; i < size; i++)
1801 smmu->s2crs[i] = s2cr_init_val;
1802
1776 smmu->num_mapping_groups = size; 1803 smmu->num_mapping_groups = size;
1777 1804
1778 if (smmu->version < ARM_SMMU_V2 || !(id & ID0_PTFS_NO_AARCH32)) { 1805 if (smmu->version < ARM_SMMU_V2 || !(id & ID0_PTFS_NO_AARCH32)) {