blob: c8564556fe759fcab849dcd88c61c85300e8b32d [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <mach/msm_subsystem_map.h>
14#include <linux/memory_alloc.h>
15#include <linux/iommu.h>
16#include <asm/sizes.h>
17#include <asm/page.h>
18#include <linux/init.h>
19#include <mach/iommu.h>
20#include <mach/iommu_domains.h>
Laura Abbott9f4a8e62011-08-29 19:08:07 -070021#include <mach/socinfo.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070022
Laura Abbotte956cce2011-10-25 13:33:20 -070023/* dummy 4k for overmapping */
24char iommu_dummy[2*PAGE_SIZE-4];
25
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070026struct msm_iommu_domain {
Laura Abbott9f4a8e62011-08-29 19:08:07 -070027 /* iommu domain to map in */
28 struct iommu_domain *domain;
29 /* total number of allocations from this domain */
30 atomic_t allocation_cnt;
31 /* number of iova pools */
32 int npools;
33 /*
34 * array of gen_pools for allocating iovas.
35 * behavior is undefined if these overlap
36 */
37 struct mem_pool *iova_pools;
38
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070039};
40
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070041
42struct {
43 char *name;
44 int domain;
45} msm_iommu_ctx_names[] = {
Laura Abbott9f4a8e62011-08-29 19:08:07 -070046};
47
48
49static struct msm_iommu_domain msm_iommu_domains[] = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070050};
51
Laura Abbotte956cce2011-10-25 13:33:20 -070052int msm_iommu_map_extra(struct iommu_domain *domain,
53 unsigned long start_iova,
54 unsigned long size,
55 int cached)
56{
57 int i, ret;
58 unsigned long temp_iova;
59
60 for (i = size, temp_iova = start_iova; i > 0; i -= SZ_4K,
61 temp_iova += SZ_4K) {
62 ret = iommu_map(domain, temp_iova,
63 PFN_ALIGN(virt_to_phys(iommu_dummy)),
64 get_order(SZ_4K),
65 0);
66
67 if (ret) {
68 pr_err("%s: could not map %lx to dummy page in domain"
69 " %p\n",
70 __func__, temp_iova, domain);
71 goto out;
72 }
73 }
74
75 return 0;
76
77out:
78
79 for ( ; i < size; i += SZ_4K, temp_iova -= SZ_4K)
80 iommu_unmap(domain, temp_iova, get_order(SZ_4K));
81
82 return -EINVAL;
83
84}
85
86
Laura Abbott9f4a8e62011-08-29 19:08:07 -070087struct iommu_domain *msm_get_iommu_domain(int domain_num)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070088{
Laura Abbott9f4a8e62011-08-29 19:08:07 -070089 if (domain_num >= 0 && domain_num < MAX_DOMAINS)
90 return msm_iommu_domains[domain_num].domain;
91 else
92 return NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070093}
94
Laura Abbott9f4a8e62011-08-29 19:08:07 -070095unsigned long msm_subsystem_get_domain_no(int subsys_id)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070096{
Laura Abbott9f4a8e62011-08-29 19:08:07 -070097 return GLOBAL_DOMAIN;
98}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070099
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700100unsigned long msm_subsystem_get_partition_no(int subsys_id)
101{
102 switch (subsys_id) {
103 case MSM_SUBSYSTEM_VIDEO_FWARE:
104 return VIDEO_FIRMWARE_POOL;
105 case MSM_SUBSYSTEM_VIDEO:
106 return LOW_256MB_POOL;
107 case MSM_SUBSYSTEM_CAMERA:
108 case MSM_SUBSYSTEM_DISPLAY:
109 case MSM_SUBSYSTEM_ROTATOR:
110 return HIGH_POOL;
111 default:
112 return 0xFFFFFFFF;
113 }
114}
115
116unsigned long msm_allocate_iova_address(unsigned int iommu_domain,
117 unsigned int partition_no,
118 unsigned long size,
119 unsigned long align)
120{
121 struct mem_pool *pool;
122 unsigned long iova;
123
124 if (iommu_domain >= MAX_DOMAINS)
125 return 0;
126
127 if (partition_no >= msm_iommu_domains[iommu_domain].npools)
128 return 0;
129
130 pool = &msm_iommu_domains[iommu_domain].iova_pools[partition_no];
131
132 if (!pool->gpool)
133 return 0;
134
135 iova = gen_pool_alloc_aligned(pool->gpool, size, ilog2(align));
136 if (iova)
137 pool->free -= size;
138
139 return iova;
140}
141
142void msm_free_iova_address(unsigned long iova,
143 unsigned int iommu_domain,
144 unsigned int partition_no,
145 unsigned long size)
146{
147 struct mem_pool *pool;
148
149 if (iommu_domain >= MAX_DOMAINS) {
150 WARN(1, "Invalid domain %d\n", iommu_domain);
151 return;
152 }
153
154 if (partition_no >= msm_iommu_domains[iommu_domain].npools) {
155 WARN(1, "Invalid partition %d for domain %d\n",
156 partition_no, iommu_domain);
157 return;
158 }
159
160 pool = &msm_iommu_domains[iommu_domain].iova_pools[partition_no];
161
162 if (!pool)
163 return;
164
165 pool->free += size;
166 gen_pool_free(pool->gpool, iova, size);
167}
168
169int msm_use_iommu()
170{
Laura Abbottd561f342012-02-07 16:26:39 -0800171 /* Kill use of the iommu by these clients for now. */
172 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700173}
174
175static int __init msm_subsystem_iommu_init(void)
176{
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700177 int i, j;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700178
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700179 for (i = 0; i < ARRAY_SIZE(msm_iommu_domains); i++) {
180 msm_iommu_domains[i].domain = iommu_domain_alloc(0);
181 if (!msm_iommu_domains[i].domain)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700182 continue;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700183
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700184 for (j = 0; j < msm_iommu_domains[i].npools; j++) {
185 struct mem_pool *pool = &msm_iommu_domains[i].
186 iova_pools[j];
187 mutex_init(&pool->pool_mutex);
188 pool->gpool = gen_pool_create(PAGE_SHIFT, -1);
189
190 if (!pool->gpool) {
191 pr_err("%s: domain %d: could not allocate iova"
192 " pool. iommu programming will not work"
193 " with iova space %d\n", __func__,
194 i, j);
195 continue;
196 }
197
198 if (gen_pool_add(pool->gpool, pool->paddr, pool->size,
199 -1)) {
200 pr_err("%s: domain %d: could not add memory to"
201 " iova pool. iommu programming will not"
202 " work with iova space %d\n", __func__,
203 i, j);
204 gen_pool_destroy(pool->gpool);
205 pool->gpool = NULL;
206 continue;
207 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700208 }
209 }
210
211 for (i = 0; i < ARRAY_SIZE(msm_iommu_ctx_names); i++) {
212 int domain_idx;
213 struct device *ctx = msm_iommu_get_ctx(
214 msm_iommu_ctx_names[i].name);
215
216 if (!ctx)
217 continue;
218
219 domain_idx = msm_iommu_ctx_names[i].domain;
220
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700221 if (!msm_iommu_domains[domain_idx].domain)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700222 continue;
223
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700224 if (iommu_attach_device(msm_iommu_domains[domain_idx].domain,
225 ctx)) {
226 WARN(1, "%s: could not attach domain %d to context %s."
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700227 " iommu programming will not occur.\n",
228 __func__, domain_idx,
229 msm_iommu_ctx_names[i].name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700230 continue;
231 }
232 }
233
234 return 0;
235}
236device_initcall(msm_subsystem_iommu_init);