+ return IOMMU_DOMAIN_IDENTITY;
+ }
+
+ return IOMMU_DOMAIN_DMA;
}
static const struct iommu_ops tegra_smmu_ops = {
.identity_domain = &tegra_smmu_identity_domain,
+ .release_domain = &tegra_smmu_identity_domain,
.def_domain_type = &tegra_smmu_def_domain_type,
.domain_alloc_paging = tegra_smmu_domain_alloc_paging,
.probe_device = tegra_smmu_probe_device,
@@ -1108,6 +1123,40 @@ static void tegra_smmu_debugfs_exit(struct tegra_smmu
*smmu)
debugfs_remove_recursive(smmu->debugfs);
}
+/*
+ * The default domain type is a property of the IOMMU group, so all swgroups in
+ * one group must agree on use_dma_api. Otherwise the core sees conflicting
+ * def_domain_type and falls back to identity for the whole group.
+ */
+static void tegra_smmu_check_groups(struct tegra_smmu *smmu)
+{
+ const struct tegra_smmu_soc *soc = smmu->soc;
+ unsigned int i, j;
+
+ for (i = 0; i < soc->num_groups; i++) {
+ const struct tegra_smmu_group_soc *group = &soc->groups[i];
+ int dma_api = -1;
+
+ for (j = 0; j < group->num_swgroups; j++) {
+ const struct tegra_smmu_swgroup *swgrp;
+
+ swgrp = tegra_smmu_find_swgroup(smmu,
+ group->swgroups[j]);
+ if (!swgrp)
+ continue;
+
+ if (dma_api < 0)
+ dma_api = swgrp->use_dma_api;
+ else if (swgrp->use_dma_api != !!dma_api)
+ break;
+ }
+
+ WARN(j < group->num_swgroups,
+ "SMMU group %s mixes DMA API and identity swgroups\n",
+ group->name);
+ }
+}
+
struct tegra_smmu *tegra_smmu_probe(struct device *dev,
const struct tegra_smmu_soc *soc,
struct tegra_mc *mc)
@@ -1142,6 +1191,8 @@ struct tegra_smmu *tegra_smmu_probe(struct device *dev,
smmu->dev = dev;
smmu->mc = mc;
+ tegra_smmu_check_groups(smmu);
+
smmu->pfn_mask =
BIT_MASK(mc->soc->num_address_bits - SMMU_PTE_SHIFT) - 1;
dev_dbg(dev, "address bits: %u, PFN mask: %#lx\n",
diff --git a/drivers/memory/tegra/tegra114.c b/drivers/memory/tegra/tegra114.c
index 2883c4f91144..024c63bdd480 100644
--- a/drivers/memory/tegra/tegra114.c
+++ b/drivers/memory/tegra/tegra114.c
@@ -1029,15 +1029,18 @@ static const struct tegra_mc_client
tegra114_mc_clients[] = {
static const struct tegra_smmu_swgroup tegra114_swgroups[] = {
{ .name = "dc", .swgroup = TEGRA_SWGROUP_DC, .reg = 0x240,
- .defer_enable = true },
+ .defer_enable = true, .use_dma_api = true },
{ .name = "dcb", .swgroup = TEGRA_SWGROUP_DCB, .reg = 0x244,
- .defer_enable = true },
+ .defer_enable = true, .use_dma_api = true },
{ .name = "epp", .swgroup = TEGRA_SWGROUP_EPP, .reg = 0x248
},
- { .name = "g2", .swgroup = TEGRA_SWGROUP_G2, .reg = 0x24c
},
+ { .name = "g2", .swgroup = TEGRA_SWGROUP_G2, .reg = 0x24c,
+ .use_dma_api = true },
{ .name = "avpc", .swgroup = TEGRA_SWGROUP_AVPC, .reg = 0x23c
},
- { .name = "nv", .swgroup = TEGRA_SWGROUP_NV, .reg = 0x268
},
+ { .name = "nv", .swgroup = TEGRA_SWGROUP_NV, .reg = 0x268,
+ .use_dma_api = true },
{ .name = "hda", .swgroup = TEGRA_SWGROUP_HDA, .reg = 0x254
},
- { .name = "hc", .swgroup = TEGRA_SWGROUP_HC, .reg = 0x250
},
+ { .name = "hc", .swgroup = TEGRA_SWGROUP_HC, .reg = 0x250,
+ .use_dma_api = true },
{ .name = "msenc", .swgroup = TEGRA_SWGROUP_MSENC, .reg = 0x264
},
{ .name = "ppcs", .swgroup = TEGRA_SWGROUP_PPCS, .reg = 0x270
},
{ .name = "vde", .swgroup = TEGRA_SWGROUP_VDE, .reg = 0x27c
},
diff --git a/drivers/memory/tegra/tegra124.c b/drivers/memory/tegra/tegra124.c
index a38fbf2baf6c..17068aaf163f 100644
--- a/drivers/memory/tegra/tegra124.c
+++ b/drivers/memory/tegra/tegra124.c
@@ -1071,13 +1071,14 @@ static const struct tegra_mc_client
tegra124_mc_clients[] = {
static const struct tegra_smmu_swgroup tegra124_swgroups[] = {
{ .name = "dc", .swgroup = TEGRA_SWGROUP_DC, .reg = 0x240,
- .defer_enable = true },
+ .defer_enable = true, .use_dma_api = true },
{ .name = "dcb", .swgroup = TEGRA_SWGROUP_DCB, .reg = 0x244,
- .defer_enable = true },
+ .defer_enable = true, .use_dma_api = true },
{ .name = "afi", .swgroup = TEGRA_SWGROUP_AFI, .reg = 0x238
},
{ .name = "avpc", .swgroup = TEGRA_SWGROUP_AVPC, .reg = 0x23c
},
{ .name = "hda", .swgroup = TEGRA_SWGROUP_HDA, .reg = 0x254
},
- { .name = "hc", .swgroup = TEGRA_SWGROUP_HC, .reg = 0x250
},
+ { .name = "hc", .swgroup = TEGRA_SWGROUP_HC, .reg = 0x250,
+ .use_dma_api = true },
{ .name = "msenc", .swgroup = TEGRA_SWGROUP_MSENC, .reg = 0x264
},
{ .name = "ppcs", .swgroup = TEGRA_SWGROUP_PPCS, .reg = 0x270
},
{ .name = "sata", .swgroup = TEGRA_SWGROUP_SATA, .reg = 0x274
},
@@ -1093,7 +1094,8 @@ static const struct tegra_smmu_swgroup
tegra124_swgroups[] = {
{ .name = "sdmmc2a", .swgroup = TEGRA_SWGROUP_SDMMC2A, .reg = 0xa98
},
{ .name = "sdmmc3a", .swgroup = TEGRA_SWGROUP_SDMMC3A, .reg = 0xa9c
},
{ .name = "sdmmc4a", .swgroup = TEGRA_SWGROUP_SDMMC4A, .reg = 0xaa0
},
- { .name = "vic", .swgroup = TEGRA_SWGROUP_VIC, .reg = 0x284
},
+ { .name = "vic", .swgroup = TEGRA_SWGROUP_VIC, .reg = 0x284,
+ .use_dma_api = true },
{ .name = "vi", .swgroup = TEGRA_SWGROUP_VI, .reg = 0x280
},
};
diff --git a/drivers/memory/tegra/tegra30.c b/drivers/memory/tegra/tegra30.c
index 0ee4715413ba..df6b5a499ccc 100644
--- a/drivers/memory/tegra/tegra30.c
+++ b/drivers/memory/tegra/tegra30.c
@@ -1140,19 +1140,23 @@ static const struct tegra_mc_client
tegra30_mc_clients[] = {
static const struct tegra_smmu_swgroup tegra30_swgroups[] = {
{ .name = "dc", .swgroup = TEGRA_SWGROUP_DC, .reg = 0x240,
- .defer_enable = true },
+ .defer_enable = true, .use_dma_api = true },
{ .name = "dcb", .swgroup = TEGRA_SWGROUP_DCB, .reg = 0x244,
- .defer_enable = true },
+ .defer_enable = true, .use_dma_api = true },
{ .name = "epp", .swgroup = TEGRA_SWGROUP_EPP, .reg = 0x248 },
- { .name = "g2", .swgroup = TEGRA_SWGROUP_G2, .reg = 0x24c },
+ { .name = "g2", .swgroup = TEGRA_SWGROUP_G2, .reg = 0x24c,
+ .use_dma_api = true },
{ .name = "mpe", .swgroup = TEGRA_SWGROUP_MPE, .reg = 0x264 },
{ .name = "vi", .swgroup = TEGRA_SWGROUP_VI, .reg = 0x280 },
{ .name = "afi", .swgroup = TEGRA_SWGROUP_AFI, .reg = 0x238 },
{ .name = "avpc", .swgroup = TEGRA_SWGROUP_AVPC, .reg = 0x23c },
- { .name = "nv", .swgroup = TEGRA_SWGROUP_NV, .reg = 0x268 },
- { .name = "nv2", .swgroup = TEGRA_SWGROUP_NV2, .reg = 0x26c },
+ { .name = "nv", .swgroup = TEGRA_SWGROUP_NV, .reg = 0x268,
+ .use_dma_api = true },
+ { .name = "nv2", .swgroup = TEGRA_SWGROUP_NV2, .reg = 0x26c,
+ .use_dma_api = true },
{ .name = "hda", .swgroup = TEGRA_SWGROUP_HDA, .reg = 0x254 },
- { .name = "hc", .swgroup = TEGRA_SWGROUP_HC, .reg = 0x250 },
+ { .name = "hc", .swgroup = TEGRA_SWGROUP_HC, .reg = 0x250,
+ .use_dma_api = true },
{ .name = "ppcs", .swgroup = TEGRA_SWGROUP_PPCS, .reg = 0x270 },
{ .name = "sata", .swgroup = TEGRA_SWGROUP_SATA, .reg = 0x278 },
{ .name = "vde", .swgroup = TEGRA_SWGROUP_VDE, .reg = 0x27c },
diff --git a/include/soc/tegra/mc.h b/include/soc/tegra/mc.h
index ea67972fd585..1cbd990fc0f4 100644
--- a/include/soc/tegra/mc.h
+++ b/include/soc/tegra/mc.h
@@ -78,6 +78,13 @@ struct tegra_smmu_swgroup {
* tegra_smmu_enable_translation().
*/
bool defer_enable;
+
+ /*
+ * Set once the clients behind this swgroup are known to work with an
+ * IOMMU_DOMAIN_DMA default domain. All swgroups of a
+ * tegra_smmu_group_soc must agree.
+ */
+ bool use_dma_api;
};
struct tegra_smmu_group_soc {