blob: bdace3c7d9ad5b4b9665895a5530d83db0d361ad [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>
15#include "msm_smem.h"
16
17struct smem_client {
18 int mem_type;
19 void *clnt;
20};
21
22static int ion_user_to_kernel(struct smem_client *client,
23 int fd, u32 offset, struct msm_smem *mem)
24{
25 struct ion_handle *hndl;
26 unsigned long ionflag;
27 size_t len;
28 int rc = 0;
29 hndl = ion_import_fd(client->clnt, fd);
30 if (IS_ERR_OR_NULL(hndl)) {
31 pr_err("Failed to get handle: %p, %d, %d, %p\n",
32 client, fd, offset, hndl);
33 rc = -ENOMEM;
34 goto fail_import_fd;
35 }
36 rc = ion_handle_get_flags(client->clnt, hndl, &ionflag);
37 if (rc) {
38 pr_err("Failed to get ion flags: %d", rc);
39 goto fail_map;
40 }
41 rc = ion_phys(client->clnt, hndl, &mem->paddr, &len);
42 if (rc) {
43 pr_err("Failed to get physical address\n");
44 goto fail_map;
45 }
46 mem->kvaddr = ion_map_kernel(client->clnt, hndl, ionflag);
47 if (!mem->kvaddr) {
48 pr_err("Failed to map shared mem in kernel\n");
49 rc = -EIO;
50 goto fail_map;
51 }
52
53 mem->kvaddr += offset;
54 mem->paddr += offset;
55 mem->mem_type = client->mem_type;
56 mem->smem_priv = hndl;
57 mem->device_addr = mem->paddr;
58 mem->size = len;
59 return rc;
60fail_map:
61 ion_free(client->clnt, hndl);
62fail_import_fd:
63 return rc;
64}
65
66static int alloc_ion_mem(struct smem_client *client, size_t size,
67 u32 align, u32 flags, struct msm_smem *mem)
68{
69 struct ion_handle *hndl;
70 size_t len;
71 int rc = 0;
Praneeth Paladugu24036812012-06-14 00:26:25 -070072 if (size == 0)
73 goto skip_mem_alloc;
Vinay Kalia3766b1e2012-01-11 18:58:41 -080074 flags = flags | ION_HEAP(ION_CP_MM_HEAP_ID);
75 hndl = ion_alloc(client->clnt, size, align, flags);
76 if (IS_ERR_OR_NULL(hndl)) {
77 pr_err("Failed to allocate shared memory = %p, %d, %d, 0x%x\n",
78 client, size, align, flags);
79 rc = -ENOMEM;
80 goto fail_shared_mem_alloc;
81 }
82 mem->mem_type = client->mem_type;
83 mem->smem_priv = hndl;
84 if (ion_phys(client->clnt, hndl, &mem->paddr, &len)) {
85 pr_err("Failed to get physical address\n");
86 rc = -EIO;
87 goto fail_map;
88 }
89 mem->device_addr = mem->paddr;
90 mem->size = size;
91 mem->kvaddr = ion_map_kernel(client->clnt, hndl, 0);
92 if (!mem->kvaddr) {
93 pr_err("Failed to map shared mem in kernel\n");
94 rc = -EIO;
95 goto fail_map;
96 }
97 return rc;
98fail_map:
99 ion_free(client->clnt, hndl);
100fail_shared_mem_alloc:
Praneeth Paladugu24036812012-06-14 00:26:25 -0700101skip_mem_alloc:
Vinay Kalia3766b1e2012-01-11 18:58:41 -0800102 return rc;
103}
104
105static void free_ion_mem(struct smem_client *client, struct msm_smem *mem)
106{
107 ion_unmap_kernel(client->clnt, mem->smem_priv);
108 ion_free(client->clnt, mem->smem_priv);
109}
110
111static void *ion_new_client(void)
112{
113 struct ion_client *client = NULL;
114 client = msm_ion_client_create(-1, "video_client");
115 if (!client)
116 pr_err("Failed to create smem client\n");
117 return client;
118};
119
120static void ion_delete_client(struct smem_client *client)
121{
122 ion_client_destroy(client->clnt);
123}
124
125struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 offset)
126{
127 struct smem_client *client = clt;
128 int rc = 0;
129 struct msm_smem *mem;
130 if (fd < 0) {
131 pr_err("Invalid fd: %d\n", fd);
132 return NULL;
133 }
134 mem = kzalloc(sizeof(*mem), GFP_KERNEL);
135 if (!mem) {
136 pr_err("Failed to allocte shared mem\n");
137 return NULL;
138 }
139 switch (client->mem_type) {
140 case SMEM_ION:
141 rc = ion_user_to_kernel(clt, fd, offset, mem);
142 break;
143 default:
144 pr_err("Mem type not supported\n");
145 rc = -EINVAL;
146 break;
147 }
148 if (rc) {
149 pr_err("Failed to allocate shared memory\n");
150 kfree(mem);
151 mem = NULL;
152 }
153 return mem;
154}
155
156void *msm_smem_new_client(enum smem_type mtype)
157{
158 struct smem_client *client = NULL;
159 void *clnt = NULL;
160 switch (mtype) {
161 case SMEM_ION:
162 clnt = ion_new_client();
163 break;
164 default:
165 pr_err("Mem type not supported\n");
166 break;
167 }
168 if (clnt) {
169 client = kzalloc(sizeof(*client), GFP_KERNEL);
170 if (client) {
171 client->mem_type = mtype;
172 client->clnt = clnt;
173 }
174 } else {
175 pr_err("Failed to create new client: mtype = %d\n", mtype);
176 }
177 return client;
178};
179
180struct msm_smem *msm_smem_alloc(void *clt, size_t size, u32 align, u32 flags)
181{
182 struct smem_client *client;
183 int rc = 0;
184 struct msm_smem *mem;
185
186 client = clt;
187 if (!client) {
188 pr_err("Invalid client passed\n");
189 return NULL;
190 }
191 mem = kzalloc(sizeof(*mem), GFP_KERNEL);
192 if (!mem) {
193 pr_err("Failed to allocate shared mem\n");
194 return NULL;
195 }
196 switch (client->mem_type) {
197 case SMEM_ION:
198 rc = alloc_ion_mem(client, size, align, flags, mem);
199 break;
200 default:
201 pr_err("Mem type not supported\n");
202 rc = -EINVAL;
203 break;
204 }
205 if (rc) {
206 pr_err("Failed to allocate shared memory\n");
207 kfree(mem);
208 mem = NULL;
209 }
210 return mem;
211}
212
213void msm_smem_free(void *clt, struct msm_smem *mem)
214{
215 struct smem_client *client = clt;
216 if (!client || !mem) {
217 pr_err("Invalid client/handle passed\n");
218 return;
219 }
220 switch (client->mem_type) {
221 case SMEM_ION:
222 free_ion_mem(client, mem);
223 break;
224 default:
225 pr_err("Mem type not supported\n");
226 break;
227 }
228 kfree(mem);
229};
230
231void msm_smem_delete_client(void *clt)
232{
233 struct smem_client *client = clt;
234 if (!client) {
235 pr_err("Invalid client passed\n");
236 return;
237 }
238 switch (client->mem_type) {
239 case SMEM_ION:
240 ion_delete_client(client);
241 break;
242 default:
243 pr_err("Mem type not supported\n");
244 break;
245 }
246 kfree(client);
247}