blob: 25b5c5c7fd75d9f8e85317448b0bb088249d1af8 [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;
72 flags = flags | ION_HEAP(ION_CP_MM_HEAP_ID);
73 hndl = ion_alloc(client->clnt, size, align, flags);
74 if (IS_ERR_OR_NULL(hndl)) {
75 pr_err("Failed to allocate shared memory = %p, %d, %d, 0x%x\n",
76 client, size, align, flags);
77 rc = -ENOMEM;
78 goto fail_shared_mem_alloc;
79 }
80 mem->mem_type = client->mem_type;
81 mem->smem_priv = hndl;
82 if (ion_phys(client->clnt, hndl, &mem->paddr, &len)) {
83 pr_err("Failed to get physical address\n");
84 rc = -EIO;
85 goto fail_map;
86 }
87 mem->device_addr = mem->paddr;
88 mem->size = size;
89 mem->kvaddr = ion_map_kernel(client->clnt, hndl, 0);
90 if (!mem->kvaddr) {
91 pr_err("Failed to map shared mem in kernel\n");
92 rc = -EIO;
93 goto fail_map;
94 }
95 return rc;
96fail_map:
97 ion_free(client->clnt, hndl);
98fail_shared_mem_alloc:
99 return rc;
100}
101
102static void free_ion_mem(struct smem_client *client, struct msm_smem *mem)
103{
104 ion_unmap_kernel(client->clnt, mem->smem_priv);
105 ion_free(client->clnt, mem->smem_priv);
106}
107
108static void *ion_new_client(void)
109{
110 struct ion_client *client = NULL;
111 client = msm_ion_client_create(-1, "video_client");
112 if (!client)
113 pr_err("Failed to create smem client\n");
114 return client;
115};
116
117static void ion_delete_client(struct smem_client *client)
118{
119 ion_client_destroy(client->clnt);
120}
121
122struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 offset)
123{
124 struct smem_client *client = clt;
125 int rc = 0;
126 struct msm_smem *mem;
127 if (fd < 0) {
128 pr_err("Invalid fd: %d\n", fd);
129 return NULL;
130 }
131 mem = kzalloc(sizeof(*mem), GFP_KERNEL);
132 if (!mem) {
133 pr_err("Failed to allocte shared mem\n");
134 return NULL;
135 }
136 switch (client->mem_type) {
137 case SMEM_ION:
138 rc = ion_user_to_kernel(clt, fd, offset, mem);
139 break;
140 default:
141 pr_err("Mem type not supported\n");
142 rc = -EINVAL;
143 break;
144 }
145 if (rc) {
146 pr_err("Failed to allocate shared memory\n");
147 kfree(mem);
148 mem = NULL;
149 }
150 return mem;
151}
152
153void *msm_smem_new_client(enum smem_type mtype)
154{
155 struct smem_client *client = NULL;
156 void *clnt = NULL;
157 switch (mtype) {
158 case SMEM_ION:
159 clnt = ion_new_client();
160 break;
161 default:
162 pr_err("Mem type not supported\n");
163 break;
164 }
165 if (clnt) {
166 client = kzalloc(sizeof(*client), GFP_KERNEL);
167 if (client) {
168 client->mem_type = mtype;
169 client->clnt = clnt;
170 }
171 } else {
172 pr_err("Failed to create new client: mtype = %d\n", mtype);
173 }
174 return client;
175};
176
177struct msm_smem *msm_smem_alloc(void *clt, size_t size, u32 align, u32 flags)
178{
179 struct smem_client *client;
180 int rc = 0;
181 struct msm_smem *mem;
182
183 client = clt;
184 if (!client) {
185 pr_err("Invalid client passed\n");
186 return NULL;
187 }
188 mem = kzalloc(sizeof(*mem), GFP_KERNEL);
189 if (!mem) {
190 pr_err("Failed to allocate shared mem\n");
191 return NULL;
192 }
193 switch (client->mem_type) {
194 case SMEM_ION:
195 rc = alloc_ion_mem(client, size, align, flags, mem);
196 break;
197 default:
198 pr_err("Mem type not supported\n");
199 rc = -EINVAL;
200 break;
201 }
202 if (rc) {
203 pr_err("Failed to allocate shared memory\n");
204 kfree(mem);
205 mem = NULL;
206 }
207 return mem;
208}
209
210void msm_smem_free(void *clt, struct msm_smem *mem)
211{
212 struct smem_client *client = clt;
213 if (!client || !mem) {
214 pr_err("Invalid client/handle passed\n");
215 return;
216 }
217 switch (client->mem_type) {
218 case SMEM_ION:
219 free_ion_mem(client, mem);
220 break;
221 default:
222 pr_err("Mem type not supported\n");
223 break;
224 }
225 kfree(mem);
226};
227
228void msm_smem_delete_client(void *clt)
229{
230 struct smem_client *client = clt;
231 if (!client) {
232 pr_err("Invalid client passed\n");
233 return;
234 }
235 switch (client->mem_type) {
236 case SMEM_ION:
237 ion_delete_client(client);
238 break;
239 default:
240 pr_err("Mem type not supported\n");
241 break;
242 }
243 kfree(client);
244}