blob: d48240af6d2eaeccc53dd225103a0ca84b047a23 [file] [log] [blame]
Vinay Kalia3766b1e2012-01-11 18:58:41 -08001/* Copyright (c) 2012, 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
14#include <linux/slab.h>
Vinay Kalia68398a42012-06-22 18:36:12 -070015#include <mach/iommu_domains.h>
Vinay Kalia3766b1e2012-01-11 18:58:41 -080016#include "msm_smem.h"
17
18struct smem_client {
19 int mem_type;
20 void *clnt;
21};
22
Vinay Kalia68398a42012-06-22 18:36:12 -070023static int get_device_address(struct ion_client *clnt,
24 struct ion_handle *hndl, int domain_num, int partition_num,
25 unsigned long align, unsigned long *iova,
26 unsigned long *buffer_size, unsigned long flags)
27{
28 int rc;
Vinay Kalia68398a42012-06-22 18:36:12 -070029 if (!iova || !buffer_size || !hndl || !clnt) {
30 pr_err("Invalid params: %p, %p, %p, %p\n",
31 clnt, hndl, iova, buffer_size);
32 return -EINVAL;
33 }
34 if (align < 4096)
35 align = 4096;
Vinay Kaliac71662f2012-08-16 17:49:28 -070036 pr_debug("\n In %s domain: %d, Partition: %d\n",
37 __func__, domain_num, partition_num);
Vinay Kalia68398a42012-06-22 18:36:12 -070038 rc = ion_map_iommu(clnt, hndl, domain_num, partition_num, align,
39 0, iova, buffer_size, flags, 0);
40 if (rc)
41 pr_err("ion_map_iommu failed(%d).domain: %d,partition: %d\n",
42 rc, domain_num, partition_num);
43
44 return rc;
45}
46
47static void put_device_address(struct ion_client *clnt,
Vinay Kaliac71662f2012-08-16 17:49:28 -070048 struct ion_handle *hndl, int domain_num, int partition_num)
Vinay Kalia68398a42012-06-22 18:36:12 -070049{
Vinay Kaliac71662f2012-08-16 17:49:28 -070050 ion_unmap_iommu(clnt, hndl, domain_num, partition_num);
Vinay Kalia68398a42012-06-22 18:36:12 -070051}
52
Vinay Kalia3766b1e2012-01-11 18:58:41 -080053static int ion_user_to_kernel(struct smem_client *client,
Vinay Kalia68398a42012-06-22 18:36:12 -070054 int fd, u32 offset, int domain, int partition,
55 struct msm_smem *mem)
Vinay Kalia3766b1e2012-01-11 18:58:41 -080056{
57 struct ion_handle *hndl;
58 unsigned long ionflag;
Vinay Kalia68398a42012-06-22 18:36:12 -070059 unsigned long iova = 0;
60 unsigned long buffer_size = 0;
Vinay Kalia3766b1e2012-01-11 18:58:41 -080061 int rc = 0;
Laura Abbottb14ed962012-01-30 14:18:08 -080062 hndl = ion_import_dma_buf(client->clnt, fd);
Vinay Kalia3766b1e2012-01-11 18:58:41 -080063 if (IS_ERR_OR_NULL(hndl)) {
64 pr_err("Failed to get handle: %p, %d, %d, %p\n",
65 client, fd, offset, hndl);
66 rc = -ENOMEM;
67 goto fail_import_fd;
68 }
69 rc = ion_handle_get_flags(client->clnt, hndl, &ionflag);
70 if (rc) {
71 pr_err("Failed to get ion flags: %d", rc);
72 goto fail_map;
73 }
Vinay Kaliae38c55f2012-08-16 19:37:28 -070074 mem->kvaddr = NULL;
Vinay Kalia68398a42012-06-22 18:36:12 -070075 mem->domain = domain;
76 mem->partition_num = partition;
77 rc = get_device_address(client->clnt, hndl, mem->domain,
Vinay Kaliae38c55f2012-08-16 19:37:28 -070078 mem->partition_num, 4096, &iova, &buffer_size, ionflag);
Vinay Kalia68398a42012-06-22 18:36:12 -070079 if (rc) {
80 pr_err("Failed to get device address: %d\n", rc);
81 goto fail_device_address;
82 }
Vinay Kalia3766b1e2012-01-11 18:58:41 -080083
84 mem->kvaddr += offset;
Vinay Kalia3766b1e2012-01-11 18:58:41 -080085 mem->mem_type = client->mem_type;
86 mem->smem_priv = hndl;
Vinay Kalia68398a42012-06-22 18:36:12 -070087 mem->device_addr = iova + offset;
88 mem->size = buffer_size;
Vinay Kaliac71662f2012-08-16 17:49:28 -070089 pr_debug("Buffer device address: 0x%lx, size: %d\n",
90 mem->device_addr, mem->size);
Vinay Kalia3766b1e2012-01-11 18:58:41 -080091 return rc;
Vinay Kalia68398a42012-06-22 18:36:12 -070092fail_device_address:
93 ion_unmap_kernel(client->clnt, hndl);
Vinay Kalia3766b1e2012-01-11 18:58:41 -080094fail_map:
95 ion_free(client->clnt, hndl);
96fail_import_fd:
97 return rc;
98}
99
100static int alloc_ion_mem(struct smem_client *client, size_t size,
Vinay Kalia68398a42012-06-22 18:36:12 -0700101 u32 align, u32 flags, int domain, int partition,
Vinay Kaliae38c55f2012-08-16 19:37:28 -0700102 struct msm_smem *mem, int map_kernel)
Vinay Kalia3766b1e2012-01-11 18:58:41 -0800103{
104 struct ion_handle *hndl;
Vinay Kalia68398a42012-06-22 18:36:12 -0700105 unsigned long iova = 0;
106 unsigned long buffer_size = 0;
Vinay Kaliae38c55f2012-08-16 19:37:28 -0700107 unsigned long ionflags = 0;
Vinay Kalia3766b1e2012-01-11 18:58:41 -0800108 int rc = 0;
Vinay Kaliae38c55f2012-08-16 19:37:28 -0700109 if (flags == SMEM_CACHED)
110 ionflags |= ION_SET_CACHE(CACHED);
111 else
112 ionflags |= ION_SET_CACHE(UNCACHED);
113
114 ionflags = ionflags | ION_HEAP(ION_CP_MM_HEAP_ID);
Vinay Kalia68398a42012-06-22 18:36:12 -0700115 if (align < 4096)
116 align = 4096;
117 size = (size + 4095) & (~4095);
Vinay Kaliac71662f2012-08-16 17:49:28 -0700118 pr_debug("\n in %s domain: %d, Partition: %d\n",
119 __func__, domain, partition);
Vinay Kaliae38c55f2012-08-16 19:37:28 -0700120 hndl = ion_alloc(client->clnt, size, align, ionflags);
Vinay Kalia3766b1e2012-01-11 18:58:41 -0800121 if (IS_ERR_OR_NULL(hndl)) {
Vinay Kaliae38c55f2012-08-16 19:37:28 -0700122 pr_err("Failed to allocate shared memory = %p, %d, %d, 0x%lx\n",
123 client, size, align, ionflags);
Vinay Kalia3766b1e2012-01-11 18:58:41 -0800124 rc = -ENOMEM;
125 goto fail_shared_mem_alloc;
126 }
127 mem->mem_type = client->mem_type;
128 mem->smem_priv = hndl;
Vinay Kalia68398a42012-06-22 18:36:12 -0700129 mem->domain = domain;
130 mem->partition_num = partition;
Vinay Kaliae38c55f2012-08-16 19:37:28 -0700131 if (map_kernel) {
132 mem->kvaddr = ion_map_kernel(client->clnt, hndl, 0);
133 if (!mem->kvaddr) {
134 pr_err("Failed to map shared mem in kernel\n");
135 rc = -EIO;
136 goto fail_map;
137 }
138 } else
139 mem->kvaddr = NULL;
140
Vinay Kalia68398a42012-06-22 18:36:12 -0700141 rc = get_device_address(client->clnt, hndl, mem->domain,
142 mem->partition_num, align, &iova, &buffer_size, UNCACHED);
143 if (rc) {
144 pr_err("Failed to get device address: %d\n", rc);
145 goto fail_device_address;
146 }
147 mem->device_addr = iova;
Vinay Kaliac71662f2012-08-16 17:49:28 -0700148 pr_debug("device_address = 0x%lx, kvaddr = 0x%p\n",
Vinay Kalia68398a42012-06-22 18:36:12 -0700149 mem->device_addr, mem->kvaddr);
150 mem->size = size;
Vinay Kalia3766b1e2012-01-11 18:58:41 -0800151 return rc;
Vinay Kalia68398a42012-06-22 18:36:12 -0700152fail_device_address:
153 ion_unmap_kernel(client->clnt, hndl);
Vinay Kalia3766b1e2012-01-11 18:58:41 -0800154fail_map:
155 ion_free(client->clnt, hndl);
156fail_shared_mem_alloc:
Vinay Kalia3766b1e2012-01-11 18:58:41 -0800157 return rc;
158}
159
160static void free_ion_mem(struct smem_client *client, struct msm_smem *mem)
161{
Vinay Kaliae38c55f2012-08-16 19:37:28 -0700162 if (mem->device_addr)
163 put_device_address(client->clnt,
164 mem->smem_priv, mem->domain, mem->partition_num);
165 if (mem->kvaddr)
166 ion_unmap_kernel(client->clnt, mem->smem_priv);
167 if (mem->smem_priv)
168 ion_free(client->clnt, mem->smem_priv);
Vinay Kalia3766b1e2012-01-11 18:58:41 -0800169}
170
171static void *ion_new_client(void)
172{
173 struct ion_client *client = NULL;
174 client = msm_ion_client_create(-1, "video_client");
175 if (!client)
176 pr_err("Failed to create smem client\n");
177 return client;
178};
179
180static void ion_delete_client(struct smem_client *client)
181{
182 ion_client_destroy(client->clnt);
183}
184
Vinay Kalia68398a42012-06-22 18:36:12 -0700185struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 offset,
186 int domain, int partition)
Vinay Kalia3766b1e2012-01-11 18:58:41 -0800187{
188 struct smem_client *client = clt;
189 int rc = 0;
190 struct msm_smem *mem;
191 if (fd < 0) {
192 pr_err("Invalid fd: %d\n", fd);
193 return NULL;
194 }
195 mem = kzalloc(sizeof(*mem), GFP_KERNEL);
196 if (!mem) {
197 pr_err("Failed to allocte shared mem\n");
198 return NULL;
199 }
200 switch (client->mem_type) {
201 case SMEM_ION:
Vinay Kalia68398a42012-06-22 18:36:12 -0700202 rc = ion_user_to_kernel(clt, fd, offset,
203 domain, partition, mem);
Vinay Kalia3766b1e2012-01-11 18:58:41 -0800204 break;
205 default:
206 pr_err("Mem type not supported\n");
207 rc = -EINVAL;
208 break;
209 }
210 if (rc) {
211 pr_err("Failed to allocate shared memory\n");
212 kfree(mem);
213 mem = NULL;
214 }
215 return mem;
216}
217
Vinay Kaliae38c55f2012-08-16 19:37:28 -0700218static int ion_mem_clean_invalidate(struct smem_client *clt,
219 struct msm_smem *mem)
220{
221 unsigned long ionflag;
222 int rc;
223 rc = ion_handle_get_flags(clt->clnt, mem->smem_priv, &ionflag);
224 if (rc) {
225 pr_err("Failed to get ion flags: %p, %p\n",
226 clt, mem->smem_priv);
227 goto fail_get_flags;
228 }
229 if (ionflag == CACHED) {
230 pr_err("Flushing the caches\n");
231 rc = msm_ion_do_cache_op(clt->clnt, mem->smem_priv, mem->kvaddr,
232 mem->size, ION_IOC_CLEAN_INV_CACHES);
233 }
234fail_get_flags:
235 return rc;
236}
237
238int msm_smem_clean_invalidate(void *clt, struct msm_smem *mem)
239{
240 struct smem_client *client = clt;
241 int rc;
242 if (!client || !mem) {
243 pr_err("Invalid client/handle passed\n");
244 return -EINVAL;
245 }
246 switch (client->mem_type) {
247 case SMEM_ION:
248 rc = ion_mem_clean_invalidate(client, mem);
249 break;
250 default:
251 pr_err("Mem type not supported\n");
252 rc = -EINVAL;
253 break;
254 }
255 return rc;
256}
257
Vinay Kalia3766b1e2012-01-11 18:58:41 -0800258void *msm_smem_new_client(enum smem_type mtype)
259{
260 struct smem_client *client = NULL;
261 void *clnt = NULL;
262 switch (mtype) {
263 case SMEM_ION:
264 clnt = ion_new_client();
265 break;
266 default:
267 pr_err("Mem type not supported\n");
268 break;
269 }
270 if (clnt) {
271 client = kzalloc(sizeof(*client), GFP_KERNEL);
272 if (client) {
273 client->mem_type = mtype;
274 client->clnt = clnt;
275 }
276 } else {
277 pr_err("Failed to create new client: mtype = %d\n", mtype);
278 }
279 return client;
280};
281
Vinay Kalia68398a42012-06-22 18:36:12 -0700282struct msm_smem *msm_smem_alloc(void *clt, size_t size, u32 align, u32 flags,
Vinay Kaliae38c55f2012-08-16 19:37:28 -0700283 int domain, int partition, int map_kernel)
Vinay Kalia3766b1e2012-01-11 18:58:41 -0800284{
285 struct smem_client *client;
286 int rc = 0;
287 struct msm_smem *mem;
Vinay Kalia3766b1e2012-01-11 18:58:41 -0800288 client = clt;
289 if (!client) {
290 pr_err("Invalid client passed\n");
291 return NULL;
292 }
Vinay Kaliac2a557c2012-08-03 11:39:47 -0700293 if (!size) {
294 pr_err("No need to allocate memory of size: %d\n", size);
295 return NULL;
296 }
Vinay Kalia3766b1e2012-01-11 18:58:41 -0800297 mem = kzalloc(sizeof(*mem), GFP_KERNEL);
298 if (!mem) {
299 pr_err("Failed to allocate shared mem\n");
300 return NULL;
301 }
302 switch (client->mem_type) {
303 case SMEM_ION:
Vinay Kalia68398a42012-06-22 18:36:12 -0700304 rc = alloc_ion_mem(client, size, align, flags,
Vinay Kaliae38c55f2012-08-16 19:37:28 -0700305 domain, partition, mem, map_kernel);
Vinay Kalia3766b1e2012-01-11 18:58:41 -0800306 break;
307 default:
308 pr_err("Mem type not supported\n");
309 rc = -EINVAL;
310 break;
311 }
312 if (rc) {
313 pr_err("Failed to allocate shared memory\n");
314 kfree(mem);
315 mem = NULL;
316 }
317 return mem;
318}
319
320void msm_smem_free(void *clt, struct msm_smem *mem)
321{
322 struct smem_client *client = clt;
323 if (!client || !mem) {
324 pr_err("Invalid client/handle passed\n");
325 return;
326 }
327 switch (client->mem_type) {
328 case SMEM_ION:
329 free_ion_mem(client, mem);
330 break;
331 default:
332 pr_err("Mem type not supported\n");
333 break;
334 }
335 kfree(mem);
336};
337
338void msm_smem_delete_client(void *clt)
339{
340 struct smem_client *client = clt;
341 if (!client) {
342 pr_err("Invalid client passed\n");
343 return;
344 }
345 switch (client->mem_type) {
346 case SMEM_ION:
347 ion_delete_client(client);
348 break;
349 default:
350 pr_err("Mem type not supported\n");
351 break;
352 }
353 kfree(client);
354}