blob: 2c7a90be7d21a345cfbbb1fc23467968ff5619a8 [file] [log] [blame]
Prabhanjan Kandula96e92342016-03-24 21:03:35 +05301/*
Rohit Kulkarni3ac98392017-10-20 12:04:34 -07002 * Copyright (c) 2011-2018, The Linux Foundation. All rights reserved.
Prabhanjan Kandula96e92342016-03-24 21:03:35 +05303
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above
10 * copyright notice, this list of conditions and the following
11 * disclaimer in the documentation and/or other materials provided
12 * with the distribution.
13 * * Neither the name of The Linux Foundation nor the names of its
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#define DEBUG 0
31#define ATRACE_TAG (ATRACE_TAG_GRAPHICS | ATRACE_TAG_HAL)
32#include <sys/ioctl.h>
33#include <sys/mman.h>
Rohit Kulkarni3ac98392017-10-20 12:04:34 -070034#include <linux/msm_ion.h>
35#if TARGET_ION_ABI_VERSION >= 2
Rohit Kulkarni3ac98392017-10-20 12:04:34 -070036#include <linux/dma-buf.h>
Naseer Ahmede36f2242017-12-01 15:33:56 -050037#include <ion/ion.h>
Rohit Kulkarni3ac98392017-10-20 12:04:34 -070038#endif
Prabhanjan Kandula96e92342016-03-24 21:03:35 +053039#include <stdlib.h>
40#include <fcntl.h>
Naseer Ahmedfcad05e2018-03-06 20:41:14 -050041#include <log/log.h>
Naseer Ahmede36f2242017-12-01 15:33:56 -050042#include <cutils/trace.h>
Prabhanjan Kandula96e92342016-03-24 21:03:35 +053043#include <errno.h>
44#include <utils/Trace.h>
Naseer Ahmed7a2b09c2017-05-11 13:03:17 -040045#include <string>
Prabhanjan Kandula96e92342016-03-24 21:03:35 +053046
Prabhanjan Kandula96e92342016-03-24 21:03:35 +053047#include "gr_utils.h"
Naseer Ahmede36f2242017-12-01 15:33:56 -050048#include "gralloc_priv.h"
Prabhanjan Kandula96e92342016-03-24 21:03:35 +053049#include "gr_ion_alloc.h"
50
Naseer Ahmede36f2242017-12-01 15:33:56 -050051namespace gralloc {
Prabhanjan Kandula96e92342016-03-24 21:03:35 +053052
53bool IonAlloc::Init() {
54 if (ion_dev_fd_ == FD_INIT) {
Rohit Kulkarni3ac98392017-10-20 12:04:34 -070055 ion_dev_fd_ = OpenIonDevice();
Prabhanjan Kandula96e92342016-03-24 21:03:35 +053056 }
57
58 if (ion_dev_fd_ < 0) {
59 ALOGE("%s: Failed to open ion device - %s", __FUNCTION__, strerror(errno));
60 ion_dev_fd_ = FD_INIT;
61 return false;
62 }
63
64 return true;
65}
66
Rohit Kulkarni3ac98392017-10-20 12:04:34 -070067#if TARGET_ION_ABI_VERSION >= 2 // Use libion APIs for new ion
68
69int IonAlloc::OpenIonDevice() {
70 return ion_open();
71}
72
73void IonAlloc::CloseIonDevice() {
74 if (ion_dev_fd_ > FD_INIT) {
75 ion_close(ion_dev_fd_);
76 }
77
78 ion_dev_fd_ = FD_INIT;
79}
80
81int IonAlloc::AllocBuffer(AllocData *data) {
82 ATRACE_CALL();
83 int err = 0;
84 int fd = -1;
85 unsigned int flags = data->flags;
86
87 flags |= data->uncached ? 0 : ION_FLAG_CACHED;
88
89 std::string tag_name{};
90 if (ATRACE_ENABLED()) {
91 tag_name = "libion alloc size: " + std::to_string(data->size);
92 }
93
94 ATRACE_BEGIN(tag_name.c_str());
95 err = ion_alloc_fd(ion_dev_fd_, data->size, data->align, data->heap_id, flags, &fd);
96 ATRACE_END();
97 if (err) {
98 ALOGE("libion alloc failed");
99 return err;
100 }
101
102 data->fd = fd;
103 data->ion_handle = fd; // For new ion api ion_handle does not exists so reusing fd for now
104 ALOGD_IF(DEBUG, "libion: Allocated buffer size:%u fd:%d", data->size, data->fd);
105
106 return 0;
107}
108
109int IonAlloc::FreeBuffer(void *base, unsigned int size, unsigned int offset, int fd,
110 int /*ion_handle*/) {
111 ATRACE_CALL();
112 int err = 0;
113 ALOGD_IF(DEBUG, "libion: Freeing buffer base:%p size:%u fd:%d", base, size, fd);
114
115 if (base) {
116 err = UnmapBuffer(base, size, offset);
117 }
118
119 close(fd);
120 return err;
121}
122
123int IonAlloc::ImportBuffer(int fd) {
124 // For new ion api ion_handle does not exists so reusing fd for now
125 return fd;
126}
127
128int IonAlloc::CleanBuffer(void */*base*/, unsigned int /*size*/, unsigned int /*offset*/,
129 int /*handle*/, int op, int dma_buf_fd) {
130 ATRACE_CALL();
131 ATRACE_INT("operation id", op);
132
133 struct dma_buf_sync sync;
134 int err = 0;
135
136 switch (op) {
137 case CACHE_CLEAN:
138 sync.flags = DMA_BUF_SYNC_END | DMA_BUF_SYNC_RW;
139 break;
140 case CACHE_INVALIDATE:
141 sync.flags = DMA_BUF_SYNC_START | DMA_BUF_SYNC_RW;
142 break;
Rohit Kulkarnib20abe72018-03-13 16:55:10 -0700143 case CACHE_READ_DONE:
144 sync.flags = DMA_BUF_SYNC_END | DMA_BUF_SYNC_READ;
145 break;
Rohit Kulkarni3ac98392017-10-20 12:04:34 -0700146 default:
147 ALOGE("%s: Invalid operation %d", __FUNCTION__, op);
148 return -1;
149 }
150
151 if (ioctl(dma_buf_fd, INT(DMA_BUF_IOCTL_SYNC), &sync)) {
152 err = -errno;
153 ALOGE("%s: DMA_BUF_IOCTL_SYNC failed with error - %s", __FUNCTION__, strerror(errno));
154 return err;
155 }
156
157 return 0;
158}
159
160#else
161#ifndef TARGET_ION_ABI_VERSION // Use old ion apis directly
162
163int IonAlloc::OpenIonDevice() {
164 return open(kIonDevice, O_RDONLY);
165}
166
Prabhanjan Kandula96e92342016-03-24 21:03:35 +0530167void IonAlloc::CloseIonDevice() {
168 if (ion_dev_fd_ > FD_INIT) {
169 close(ion_dev_fd_);
170 }
171
172 ion_dev_fd_ = FD_INIT;
173}
174
175int IonAlloc::AllocBuffer(AllocData *data) {
176 ATRACE_CALL();
177 int err = 0;
178 struct ion_handle_data handle_data;
179 struct ion_fd_data fd_data;
180 struct ion_allocation_data ion_alloc_data;
Prabhanjan Kandula96e92342016-03-24 21:03:35 +0530181
182 ion_alloc_data.len = data->size;
183 ion_alloc_data.align = data->align;
184 ion_alloc_data.heap_id_mask = data->heap_id;
185 ion_alloc_data.flags = data->flags;
186 ion_alloc_data.flags |= data->uncached ? 0 : ION_FLAG_CACHED;
Naseer Ahmed7a2b09c2017-05-11 13:03:17 -0400187 std::string tag_name{};
188 if (ATRACE_ENABLED()) {
189 tag_name = "ION_IOC_ALLOC size: " + std::to_string(data->size);
190 }
Prabhanjan Kandula96e92342016-03-24 21:03:35 +0530191
Naseer Ahmed7a2b09c2017-05-11 13:03:17 -0400192 ATRACE_BEGIN(tag_name.c_str());
Prabhanjan Kandula96e92342016-03-24 21:03:35 +0530193 if (ioctl(ion_dev_fd_, INT(ION_IOC_ALLOC), &ion_alloc_data)) {
194 err = -errno;
195 ALOGE("ION_IOC_ALLOC failed with error - %s", strerror(errno));
196 return err;
197 }
Naseer Ahmed7a2b09c2017-05-11 13:03:17 -0400198 ATRACE_END();
Prabhanjan Kandula96e92342016-03-24 21:03:35 +0530199
200 fd_data.handle = ion_alloc_data.handle;
201 handle_data.handle = ion_alloc_data.handle;
Naseer Ahmed7a2b09c2017-05-11 13:03:17 -0400202 ATRACE_BEGIN("ION_IOC_MAP");
Prabhanjan Kandula96e92342016-03-24 21:03:35 +0530203 if (ioctl(ion_dev_fd_, INT(ION_IOC_MAP), &fd_data)) {
204 err = -errno;
205 ALOGE("%s: ION_IOC_MAP failed with error - %s", __FUNCTION__, strerror(errno));
206 ioctl(ion_dev_fd_, INT(ION_IOC_FREE), &handle_data);
207 return err;
208 }
Naseer Ahmed7a2b09c2017-05-11 13:03:17 -0400209 ATRACE_END();
Prabhanjan Kandula96e92342016-03-24 21:03:35 +0530210
Prabhanjan Kandula96e92342016-03-24 21:03:35 +0530211 data->fd = fd_data.fd;
Naseer Ahmede69031e2016-11-22 20:05:16 -0500212 data->ion_handle = handle_data.handle;
Naseer Ahmede36f2242017-12-01 15:33:56 -0500213 ALOGD_IF(DEBUG, "ion: Allocated buffer size:%zu fd:%d handle:0x%x", ion_alloc_data.len, data->fd,
214 data->ion_handle);
Prabhanjan Kandula96e92342016-03-24 21:03:35 +0530215
216 return 0;
217}
218
Naseer Ahmede69031e2016-11-22 20:05:16 -0500219int IonAlloc::FreeBuffer(void *base, unsigned int size, unsigned int offset, int fd,
220 int ion_handle) {
Prabhanjan Kandula96e92342016-03-24 21:03:35 +0530221 ATRACE_CALL();
222 int err = 0;
Naseer Ahmede69031e2016-11-22 20:05:16 -0500223 ALOGD_IF(DEBUG, "ion: Freeing buffer base:%p size:%u fd:%d handle:0x%x", base, size, fd,
224 ion_handle);
Prabhanjan Kandula96e92342016-03-24 21:03:35 +0530225
226 if (base) {
227 err = UnmapBuffer(base, size, offset);
228 }
Prabhanjan Kandula96e92342016-03-24 21:03:35 +0530229
Naseer Ahmed3a9d53a2017-03-15 19:21:40 -0400230 if (ion_handle > 0) {
231 struct ion_handle_data handle_data;
232 handle_data.handle = ion_handle;
233 ioctl(ion_dev_fd_, INT(ION_IOC_FREE), &handle_data);
234 }
235 close(fd);
Prabhanjan Kandula96e92342016-03-24 21:03:35 +0530236 return err;
237}
238
Naseer Ahmed3a9d53a2017-03-15 19:21:40 -0400239int IonAlloc::ImportBuffer(int fd) {
240 struct ion_fd_data fd_data;
241 int err = 0;
242 fd_data.fd = fd;
243 if (ioctl(ion_dev_fd_, INT(ION_IOC_IMPORT), &fd_data)) {
244 err = -errno;
245 ALOGE("%s: ION_IOC_IMPORT failed with error - %s", __FUNCTION__, strerror(errno));
246 return err;
247 }
248 return fd_data.handle;
249}
250
Rohit Kulkarni3ac98392017-10-20 12:04:34 -0700251int IonAlloc::CleanBuffer(void *base, unsigned int size, unsigned int offset, int handle, int op,
252 int /*fd*/) {
Rohit Kulkarnib20abe72018-03-13 16:55:10 -0700253 if (op == CACHE_READ_DONE) {
254 return 0;
255 }
256
Prabhanjan Kandula96e92342016-03-24 21:03:35 +0530257 ATRACE_CALL();
258 ATRACE_INT("operation id", op);
259 struct ion_flush_data flush_data;
Prabhanjan Kandula96e92342016-03-24 21:03:35 +0530260 int err = 0;
261
Naseer Ahmed3a9d53a2017-03-15 19:21:40 -0400262 flush_data.handle = handle;
Prabhanjan Kandula96e92342016-03-24 21:03:35 +0530263 flush_data.vaddr = base;
264 // offset and length are unsigned int
265 flush_data.offset = offset;
266 flush_data.length = size;
267
268 struct ion_custom_data d;
269 switch (op) {
270 case CACHE_CLEAN:
271 d.cmd = ION_IOC_CLEAN_CACHES;
272 break;
273 case CACHE_INVALIDATE:
274 d.cmd = ION_IOC_INV_CACHES;
275 break;
276 case CACHE_CLEAN_AND_INVALIDATE:
277 default:
278 d.cmd = ION_IOC_CLEAN_INV_CACHES;
279 }
280
281 d.arg = (unsigned long)(&flush_data); // NOLINT
282 if (ioctl(ion_dev_fd_, INT(ION_IOC_CUSTOM), &d)) {
283 err = -errno;
284 ALOGE("%s: ION_IOC_CLEAN_INV_CACHES failed with error - %s", __FUNCTION__, strerror(errno));
Prabhanjan Kandula96e92342016-03-24 21:03:35 +0530285 return err;
286 }
287
Prabhanjan Kandula96e92342016-03-24 21:03:35 +0530288 return 0;
289}
290
Rohit Kulkarni3ac98392017-10-20 12:04:34 -0700291#else // This ion version is not supported
292
293int IonAlloc::OpenIonDevice() {
294 return -EINVAL;
295}
296
297void IonAlloc::CloseIonDevice() {
298}
299
300int IonAlloc::AllocBuffer(AllocData * /*data*/) {
301 return -EINVAL;
302}
303
304int IonAlloc::FreeBuffer(void * /*base*/, unsigned int /*size*/, unsigned int /*offset*/,
305 int /*fd*/, int /*ion_handle*/) {
306 return -EINVAL;
307}
308
309int IonAlloc::ImportBuffer(int /*fd*/) {
310 return -EINVAL;
311}
312
313int IonAlloc::CleanBuffer(void * /*base*/, unsigned int /*size*/, unsigned int /*offset*/,
314 int /*handle*/, int /*op*/, int /*fd*/) {
315 return -EINVAL;
316}
317
318#endif
319#endif // TARGET_ION_ABI_VERSION
320
321
322int IonAlloc::MapBuffer(void **base, unsigned int size, unsigned int offset, int fd) {
323 ATRACE_CALL();
324 int err = 0;
325 void *addr = 0;
326
327 addr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
328 *base = addr;
329 if (addr == MAP_FAILED) {
330 err = -errno;
331 ALOGE("ion: Failed to map memory in the client: %s", strerror(errno));
332 } else {
333 ALOGD_IF(DEBUG, "ion: Mapped buffer base:%p size:%u offset:%u fd:%d", addr, size, offset, fd);
334 }
335
336 return err;
337}
338
339int IonAlloc::UnmapBuffer(void *base, unsigned int size, unsigned int /*offset*/) {
340 ATRACE_CALL();
341 ALOGD_IF(DEBUG, "ion: Unmapping buffer base:%p size:%u", base, size);
342
343 int err = 0;
344 if (munmap(base, size)) {
345 err = -errno;
346 ALOGE("ion: Failed to unmap memory at %p : %s", base, strerror(errno));
347 }
348
349 return err;
350}
351
Naseer Ahmede36f2242017-12-01 15:33:56 -0500352} // namespace gralloc