msm: iommu: Allow mapping of extra iova space
In some cases, it may be adventageous to map more iommu
virtual address space than there is actual buffer space.
Add apis to map the extra iova space to a dummy buffer.
Change-Id: I93420cddaac7256e95e98650bc59e61faf56e55e
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 28e98de..48eae0c 100644
--- a/arch/arm/mach-msm/include/mach/iommu_domains.h
+++ b/arch/arm/mach-msm/include/mach/iommu_domains.h
@@ -44,6 +44,12 @@
extern unsigned long msm_subsystem_get_partition_no(int subsys_id);
extern int msm_use_iommu(void);
+
+extern int msm_iommu_map_extra(struct iommu_domain *domain,
+ unsigned long start_iova,
+ unsigned long size,
+ int cached);
+
#else
static inline struct iommu_domain
*msm_get_iommu_domain(int subsys_id) { return NULL; }
@@ -74,6 +80,14 @@
{
return 0;
}
+
+static inline int msm_iommu_map_extra(struct iommu_domain *domain,
+ unsigned long start_iova,
+ unsigned long size,
+ int cached)
+{
+ return -ENODEV;
+}
#endif
#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_subsystem_map.h b/arch/arm/mach-msm/include/mach/msm_subsystem_map.h
index 0e74235..ebb2327 100644
--- a/arch/arm/mach-msm/include/mach/msm_subsystem_map.h
+++ b/arch/arm/mach-msm/include/mach/msm_subsystem_map.h
@@ -25,6 +25,11 @@
/* ioremaps in the kernel address space are uncached */
#define MSM_SUBSYSTEM_MAP_UNCACHED 0x8
/*
+ * Will map 2x the length requested.
+ */
+#define MSM_SUBSYSTEM_MAP_IOMMU_2X 0x10
+
+/*
* Shortcut flags for alignment.
* The flag must be equal to the alignment requested.
* e.g. for 8k alignment the flags must be (0x2000 | other flags)
diff --git a/arch/arm/mach-msm/iommu_domains.c b/arch/arm/mach-msm/iommu_domains.c
index e849cdb..600a2e9 100644
--- a/arch/arm/mach-msm/iommu_domains.c
+++ b/arch/arm/mach-msm/iommu_domains.c
@@ -20,6 +20,9 @@
#include <mach/iommu_domains.h>
#include <mach/socinfo.h>
+/* dummy 4k for overmapping */
+char iommu_dummy[2*PAGE_SIZE-4];
+
struct msm_iommu_domain {
/* iommu domain to map in */
struct iommu_domain *domain;
@@ -159,6 +162,41 @@
}
};
+int msm_iommu_map_extra(struct iommu_domain *domain,
+ unsigned long start_iova,
+ unsigned long size,
+ int cached)
+{
+ int i, ret;
+ unsigned long temp_iova;
+
+ for (i = size, temp_iova = start_iova; i > 0; i -= SZ_4K,
+ temp_iova += SZ_4K) {
+ ret = iommu_map(domain, temp_iova,
+ PFN_ALIGN(virt_to_phys(iommu_dummy)),
+ get_order(SZ_4K),
+ 0);
+
+ if (ret) {
+ pr_err("%s: could not map %lx to dummy page in domain"
+ " %p\n",
+ __func__, temp_iova, domain);
+ goto out;
+ }
+ }
+
+ return 0;
+
+out:
+
+ for ( ; i < size; i += SZ_4K, temp_iova -= SZ_4K)
+ iommu_unmap(domain, temp_iova, get_order(SZ_4K));
+
+ return -EINVAL;
+
+}
+
+
struct iommu_domain *msm_get_iommu_domain(int domain_num)
{
if (domain_num >= 0 && domain_num < MAX_DOMAINS)
diff --git a/arch/arm/mach-msm/subsystem_map.c b/arch/arm/mach-msm/subsystem_map.c
index 11fe26c..db9ab30 100644
--- a/arch/arm/mach-msm/subsystem_map.c
+++ b/arch/arm/mach-msm/subsystem_map.c
@@ -236,6 +236,7 @@
int i = 0, j = 0, ret;
unsigned long iova_start = 0, temp_phys, temp_va = 0;
struct iommu_domain *d = NULL;
+ int map_size = length;
if (!((flags & MSM_SUBSYSTEM_MAP_KADDR) ||
(flags & MSM_SUBSYSTEM_MAP_IOVA))) {
@@ -302,6 +303,11 @@
length = round_up(length, SZ_4K);
+ if (flags & MSM_SUBSYSTEM_MAP_IOMMU_2X)
+ map_size = 2 * length;
+ else
+ map_size = length;
+
buf->iova = kzalloc(sizeof(unsigned long)*nsubsys, GFP_ATOMIC);
if (!buf->iova) {
err = ERR_PTR(-ENOMEM);
@@ -337,7 +343,7 @@
iova_start = msm_allocate_iova_address(domain_no,
partition_no,
- length,
+ map_size,
max(min_align, SZ_4K));
if (!iova_start) {
@@ -363,13 +369,17 @@
}
}
buf->iova[i] = iova_start;
+
+ if (flags & MSM_SUBSYSTEM_MAP_IOMMU_2X)
+ msm_iommu_map_extra
+ (d, temp_va, length, 0);
}
}
node->buf = buf;
node->subsystems = subsys_ids;
- node->length = length;
+ node->length = map_size;
node->nsubsys = nsubsys;
if (add_buffer(node)) {