blob: 76e3592563f75b8beeb4e7b494d4ca54b0aef0a3 [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;
29
30 if (!iova || !buffer_size || !hndl || !clnt) {
31 pr_err("Invalid params: %p, %p, %p, %p\n",
32 clnt, hndl, iova, buffer_size);
33 return -EINVAL;
34 }
35 if (align < 4096)
36 align = 4096;
37 flags |= UNCACHED;
38 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,
48 struct ion_handle *hndl, int domain_num)
49{
50 ion_unmap_iommu(clnt, hndl, domain_num, 0);
51}
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 Kalia3766b1e2012-01-11 18:58:41 -080074 mem->kvaddr = ion_map_kernel(client->clnt, hndl, ionflag);
75 if (!mem->kvaddr) {
76 pr_err("Failed to map shared mem in kernel\n");
77 rc = -EIO;
78 goto fail_map;
79 }
Vinay Kalia68398a42012-06-22 18:36:12 -070080 mem->domain = domain;
81 mem->partition_num = partition;
82 rc = get_device_address(client->clnt, hndl, mem->domain,
83 mem->partition_num, 4096, &iova, &buffer_size, UNCACHED);
84 if (rc) {
85 pr_err("Failed to get device address: %d\n", rc);
86 goto fail_device_address;
87 }
Vinay Kalia3766b1e2012-01-11 18:58:41 -080088
89 mem->kvaddr += offset;
Vinay Kalia3766b1e2012-01-11 18:58:41 -080090 mem->mem_type = client->mem_type;
91 mem->smem_priv = hndl;
Vinay Kalia68398a42012-06-22 18:36:12 -070092 mem->device_addr = iova + offset;
93 mem->size = buffer_size;
Vinay Kalia3766b1e2012-01-11 18:58:41 -080094 return rc;
Vinay Kalia68398a42012-06-22 18:36:12 -070095fail_device_address:
96 ion_unmap_kernel(client->clnt, hndl);
Vinay Kalia3766b1e2012-01-11 18:58:41 -080097fail_map:
98 ion_free(client->clnt, hndl);
99fail_import_fd:
100 return rc;
101}
102
103static int alloc_ion_mem(struct smem_client *client, size_t size,
Vinay Kalia68398a42012-06-22 18:36:12 -0700104 u32 align, u32 flags, int domain, int partition,
105 struct msm_smem *mem)
Vinay Kalia3766b1e2012-01-11 18:58:41 -0800106{
107 struct ion_handle *hndl;
Vinay Kalia68398a42012-06-22 18:36:12 -0700108 unsigned long iova = 0;
109 unsigned long buffer_size = 0;
Vinay Kalia3766b1e2012-01-11 18:58:41 -0800110 int rc = 0;
Praneeth Paladugu24036812012-06-14 00:26:25 -0700111 if (size == 0)
112 goto skip_mem_alloc;
Vinay Kalia3766b1e2012-01-11 18:58:41 -0800113 flags = flags | ION_HEAP(ION_CP_MM_HEAP_ID);
Vinay Kalia68398a42012-06-22 18:36:12 -0700114 if (align < 4096)
115 align = 4096;
116 size = (size + 4095) & (~4095);
Vinay Kalia3766b1e2012-01-11 18:58:41 -0800117 hndl = ion_alloc(client->clnt, size, align, flags);
118 if (IS_ERR_OR_NULL(hndl)) {
119 pr_err("Failed to allocate shared memory = %p, %d, %d, 0x%x\n",
120 client, size, align, flags);
121 rc = -ENOMEM;
122 goto fail_shared_mem_alloc;
123 }
124 mem->mem_type = client->mem_type;
125 mem->smem_priv = hndl;
Vinay Kalia68398a42012-06-22 18:36:12 -0700126 mem->domain = domain;
127 mem->partition_num = partition;
Vinay Kalia3766b1e2012-01-11 18:58:41 -0800128 mem->kvaddr = ion_map_kernel(client->clnt, hndl, 0);
129 if (!mem->kvaddr) {
130 pr_err("Failed to map shared mem in kernel\n");
131 rc = -EIO;
132 goto fail_map;
133 }
Vinay Kalia68398a42012-06-22 18:36:12 -0700134 rc = get_device_address(client->clnt, hndl, mem->domain,
135 mem->partition_num, align, &iova, &buffer_size, UNCACHED);
136 if (rc) {
137 pr_err("Failed to get device address: %d\n", rc);
138 goto fail_device_address;
139 }
140 mem->device_addr = iova;
141 pr_err("device_address = 0x%lx, kvaddr = 0x%p\n",
142 mem->device_addr, mem->kvaddr);
143 mem->size = size;
Vinay Kalia3766b1e2012-01-11 18:58:41 -0800144 return rc;
Vinay Kalia68398a42012-06-22 18:36:12 -0700145fail_device_address:
146 ion_unmap_kernel(client->clnt, hndl);
Vinay Kalia3766b1e2012-01-11 18:58:41 -0800147fail_map:
148 ion_free(client->clnt, hndl);
149fail_shared_mem_alloc:
Praneeth Paladugu24036812012-06-14 00:26:25 -0700150skip_mem_alloc:
Vinay Kalia3766b1e2012-01-11 18:58:41 -0800151 return rc;
152}
153
154static void free_ion_mem(struct smem_client *client, struct msm_smem *mem)
155{
Vinay Kalia68398a42012-06-22 18:36:12 -0700156 put_device_address(client->clnt,
157 mem->smem_priv, mem->domain);
Vinay Kalia3766b1e2012-01-11 18:58:41 -0800158 ion_unmap_kernel(client->clnt, mem->smem_priv);
159 ion_free(client->clnt, mem->smem_priv);
160}
161
162static void *ion_new_client(void)
163{
164 struct ion_client *client = NULL;
165 client = msm_ion_client_create(-1, "video_client");
166 if (!client)
167 pr_err("Failed to create smem client\n");
168 return client;
169};
170
171static void ion_delete_client(struct smem_client *client)
172{
173 ion_client_destroy(client->clnt);
174}
175
Vinay Kalia68398a42012-06-22 18:36:12 -0700176struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 offset,
177 int domain, int partition)
Vinay Kalia3766b1e2012-01-11 18:58:41 -0800178{
179 struct smem_client *client = clt;
180 int rc = 0;
181 struct msm_smem *mem;
182 if (fd < 0) {
183 pr_err("Invalid fd: %d\n", fd);
184 return NULL;
185 }
186 mem = kzalloc(sizeof(*mem), GFP_KERNEL);
187 if (!mem) {
188 pr_err("Failed to allocte shared mem\n");
189 return NULL;
190 }
191 switch (client->mem_type) {
192 case SMEM_ION:
Vinay Kalia68398a42012-06-22 18:36:12 -0700193 rc = ion_user_to_kernel(clt, fd, offset,
194 domain, partition, mem);
Vinay Kalia3766b1e2012-01-11 18:58:41 -0800195 break;
196 default:
197 pr_err("Mem type not supported\n");
198 rc = -EINVAL;
199 break;
200 }
201 if (rc) {
202 pr_err("Failed to allocate shared memory\n");
203 kfree(mem);
204 mem = NULL;
205 }
206 return mem;
207}
208
209void *msm_smem_new_client(enum smem_type mtype)
210{
211 struct smem_client *client = NULL;
212 void *clnt = NULL;
213 switch (mtype) {
214 case SMEM_ION:
215 clnt = ion_new_client();
216 break;
217 default:
218 pr_err("Mem type not supported\n");
219 break;
220 }
221 if (clnt) {
222 client = kzalloc(sizeof(*client), GFP_KERNEL);
223 if (client) {
224 client->mem_type = mtype;
225 client->clnt = clnt;
226 }
227 } else {
228 pr_err("Failed to create new client: mtype = %d\n", mtype);
229 }
230 return client;
231};
232
Vinay Kalia68398a42012-06-22 18:36:12 -0700233struct msm_smem *msm_smem_alloc(void *clt, size_t size, u32 align, u32 flags,
234 int domain, int partition)
Vinay Kalia3766b1e2012-01-11 18:58:41 -0800235{
236 struct smem_client *client;
237 int rc = 0;
238 struct msm_smem *mem;
239
240 client = clt;
241 if (!client) {
242 pr_err("Invalid client passed\n");
243 return NULL;
244 }
245 mem = kzalloc(sizeof(*mem), GFP_KERNEL);
246 if (!mem) {
247 pr_err("Failed to allocate shared mem\n");
248 return NULL;
249 }
250 switch (client->mem_type) {
251 case SMEM_ION:
Vinay Kalia68398a42012-06-22 18:36:12 -0700252 rc = alloc_ion_mem(client, size, align, flags,
253 domain, partition, mem);
Vinay Kalia3766b1e2012-01-11 18:58:41 -0800254 break;
255 default:
256 pr_err("Mem type not supported\n");
257 rc = -EINVAL;
258 break;
259 }
260 if (rc) {
261 pr_err("Failed to allocate shared memory\n");
262 kfree(mem);
263 mem = NULL;
264 }
265 return mem;
266}
267
268void msm_smem_free(void *clt, struct msm_smem *mem)
269{
270 struct smem_client *client = clt;
271 if (!client || !mem) {
272 pr_err("Invalid client/handle passed\n");
273 return;
274 }
275 switch (client->mem_type) {
276 case SMEM_ION:
277 free_ion_mem(client, mem);
278 break;
279 default:
280 pr_err("Mem type not supported\n");
281 break;
282 }
283 kfree(mem);
284};
285
286void msm_smem_delete_client(void *clt)
287{
288 struct smem_client *client = clt;
289 if (!client) {
290 pr_err("Invalid client passed\n");
291 return;
292 }
293 switch (client->mem_type) {
294 case SMEM_ION:
295 ion_delete_client(client);
296 break;
297 default:
298 pr_err("Mem type not supported\n");
299 break;
300 }
301 kfree(client);
302}