msm: Add simple APIs to map contiguous buffer
Typicall, most iommu mapping happens through Ion or another
API. There may be other cases when clients need a simple
API to map a contiguous physical address into an iommu.
Add apis to support mapping and unmapping a physical range
into the iommu. The client is responsible for any reference
counting that needs to occur.
Change-Id: Ie5cb330417f7dd967748bb76cfdf9d123c579e04
Signed-off-by: Laura Abbott <lauraa@codeaurora.org>
diff --git a/arch/arm/mach-msm/include/mach/iommu_domains.h b/arch/arm/mach-msm/include/mach/iommu_domains.h
index 52e70ec..e232d00 100644
--- a/arch/arm/mach-msm/include/mach/iommu_domains.h
+++ b/arch/arm/mach-msm/include/mach/iommu_domains.h
@@ -77,6 +77,20 @@
unsigned long size,
int cached);
+extern int msm_iommu_map_contig_buffer(unsigned long phys,
+ unsigned int domain_no,
+ unsigned int partition_no,
+ unsigned long size,
+ unsigned long align,
+ unsigned long cached,
+ unsigned long *iova_val);
+
+
+extern void msm_iommu_unmap_contig_buffer(unsigned long iova,
+ unsigned int domain_no,
+ unsigned int partition_no,
+ unsigned long size);
+
#else
static inline struct iommu_domain
*msm_get_iommu_domain(int subsys_id) { return NULL; }
@@ -104,7 +118,30 @@
int cached)
{
return -ENODEV;
+
}
+
+
+static inline int msm_iommu_map_contig_buffer(unsigned long phys,
+ unsigned int domain_no,
+ unsigned int partition_no,
+ unsigned long size,
+ unsigned long align,
+ unsigned long cached,
+ unsigned long *iova_val)
+{
+ *iova_val = phys;
+ return 0;
+}
+
+static inline void msm_iommu_unmap_contig_buffer(unsigned long iova,
+ unsigned int domain_no,
+ unsigned int partition_no,
+ unsigned long size)
+{
+ return;
+}
+
#endif
#endif
diff --git a/arch/arm/mach-msm/iommu_domains.c b/arch/arm/mach-msm/iommu_domains.c
index 8f4af3b..4afb9bd 100644
--- a/arch/arm/mach-msm/iommu_domains.c
+++ b/arch/arm/mach-msm/iommu_domains.c
@@ -65,6 +65,76 @@
return ret;
}
+static int msm_iommu_map_iova_phys(struct iommu_domain *domain,
+ unsigned long iova,
+ unsigned long phys,
+ unsigned long size,
+ int cached)
+{
+ int ret;
+ struct scatterlist *sglist;
+
+ sglist = vmalloc(sizeof(*sglist));
+ if (!sglist) {
+ ret = -ENOMEM;
+ goto err1;
+ }
+
+ sg_init_table(sglist, 1);
+ sglist->length = size;
+ sglist->offset = 0;
+ sglist->dma_address = phys;
+
+ ret = iommu_map_range(domain, iova, sglist, size, cached);
+ if (ret) {
+ pr_err("%s: could not map extra %lx in domain %p\n",
+ __func__, iova, domain);
+ }
+
+ vfree(sglist);
+err1:
+ return ret;
+
+}
+
+int msm_iommu_map_contig_buffer(unsigned long phys,
+ unsigned int domain_no,
+ unsigned int partition_no,
+ unsigned long size,
+ unsigned long align,
+ unsigned long cached,
+ unsigned long *iova_val)
+{
+ unsigned long iova;
+ int ret;
+
+ if (size & (align - 1))
+ return -EINVAL;
+
+ iova = msm_allocate_iova_address(domain_no, partition_no, size, align);
+
+ if (!iova)
+ return -ENOMEM;
+
+ ret = msm_iommu_map_iova_phys(msm_get_iommu_domain(domain_no), iova,
+ phys, size, cached);
+
+ if (ret)
+ msm_free_iova_address(iova, domain_no, partition_no, size);
+ else
+ *iova_val = iova;
+
+ return ret;
+}
+
+void msm_iommu_unmap_contig_buffer(unsigned long iova,
+ unsigned int domain_no,
+ unsigned int partition_no,
+ unsigned long size)
+{
+ iommu_unmap_range(msm_get_iommu_domain(domain_no), iova, size);
+ msm_free_iova_address(iova, domain_no, partition_no, size);
+}
struct iommu_domain *msm_get_iommu_domain(int domain_num)
{