blob: c9a74cea977b61615eb72b6b9fb23f3f39f6a519 [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>
Naseer Ahmedf4753692019-09-17 13:51:36 -040034#include <linux/ion.h>
35#ifndef QMAA
Rohit Kulkarni3ac98392017-10-20 12:04:34 -070036#include <linux/msm_ion.h>
Naseer Ahmedf4753692019-09-17 13:51:36 -040037#endif
38
Rohit Kulkarni3ac98392017-10-20 12:04:34 -070039#if TARGET_ION_ABI_VERSION >= 2
Rohit Kulkarni3ac98392017-10-20 12:04:34 -070040#include <linux/dma-buf.h>
Naseer Ahmede36f2242017-12-01 15:33:56 -050041#include <ion/ion.h>
Rohit Kulkarni3ac98392017-10-20 12:04:34 -070042#endif
Prabhanjan Kandula96e92342016-03-24 21:03:35 +053043#include <stdlib.h>
44#include <fcntl.h>
Naseer Ahmedfcad05e2018-03-06 20:41:14 -050045#include <log/log.h>
Naseer Ahmede36f2242017-12-01 15:33:56 -050046#include <cutils/trace.h>
Prabhanjan Kandula96e92342016-03-24 21:03:35 +053047#include <errno.h>
48#include <utils/Trace.h>
Naseer Ahmed7a2b09c2017-05-11 13:03:17 -040049#include <string>
Prabhanjan Kandula96e92342016-03-24 21:03:35 +053050
Prabhanjan Kandula96e92342016-03-24 21:03:35 +053051#include "gr_utils.h"
Naseer Ahmede36f2242017-12-01 15:33:56 -050052#include "gralloc_priv.h"
Prabhanjan Kandula96e92342016-03-24 21:03:35 +053053#include "gr_ion_alloc.h"
54
Naseer Ahmede36f2242017-12-01 15:33:56 -050055namespace gralloc {
Prabhanjan Kandula96e92342016-03-24 21:03:35 +053056
57bool IonAlloc::Init() {
58 if (ion_dev_fd_ == FD_INIT) {
Rohit Kulkarni3ac98392017-10-20 12:04:34 -070059 ion_dev_fd_ = OpenIonDevice();
Prabhanjan Kandula96e92342016-03-24 21:03:35 +053060 }
61
62 if (ion_dev_fd_ < 0) {
63 ALOGE("%s: Failed to open ion device - %s", __FUNCTION__, strerror(errno));
64 ion_dev_fd_ = FD_INIT;
65 return false;
66 }
67
68 return true;
69}
70
Rohit Kulkarni3ac98392017-10-20 12:04:34 -070071#if TARGET_ION_ABI_VERSION >= 2 // Use libion APIs for new ion
72
73int IonAlloc::OpenIonDevice() {
74 return ion_open();
75}
76
77void IonAlloc::CloseIonDevice() {
78 if (ion_dev_fd_ > FD_INIT) {
79 ion_close(ion_dev_fd_);
80 }
81
82 ion_dev_fd_ = FD_INIT;
83}
84
85int IonAlloc::AllocBuffer(AllocData *data) {
86 ATRACE_CALL();
87 int err = 0;
88 int fd = -1;
89 unsigned int flags = data->flags;
90
91 flags |= data->uncached ? 0 : ION_FLAG_CACHED;
92
93 std::string tag_name{};
94 if (ATRACE_ENABLED()) {
95 tag_name = "libion alloc size: " + std::to_string(data->size);
96 }
97
98 ATRACE_BEGIN(tag_name.c_str());
99 err = ion_alloc_fd(ion_dev_fd_, data->size, data->align, data->heap_id, flags, &fd);
100 ATRACE_END();
101 if (err) {
Ramkumar Radhakrishnan30ea0f02018-10-11 19:25:10 -0700102 ALOGE("libion alloc failed ion_fd %d size %d align %d heap_id %x flags %x",
103 ion_dev_fd_, data->size, data->align, data->heap_id, flags);
Rohit Kulkarni3ac98392017-10-20 12:04:34 -0700104 return err;
105 }
106
107 data->fd = fd;
108 data->ion_handle = fd; // For new ion api ion_handle does not exists so reusing fd for now
109 ALOGD_IF(DEBUG, "libion: Allocated buffer size:%u fd:%d", data->size, data->fd);
110
111 return 0;
112}
113
114int IonAlloc::FreeBuffer(void *base, unsigned int size, unsigned int offset, int fd,
115 int /*ion_handle*/) {
116 ATRACE_CALL();
117 int err = 0;
118 ALOGD_IF(DEBUG, "libion: Freeing buffer base:%p size:%u fd:%d", base, size, fd);
119
120 if (base) {
121 err = UnmapBuffer(base, size, offset);
122 }
123
124 close(fd);
125 return err;
126}
127
128int IonAlloc::ImportBuffer(int fd) {
129 // For new ion api ion_handle does not exists so reusing fd for now
130 return fd;
131}
132
133int IonAlloc::CleanBuffer(void */*base*/, unsigned int /*size*/, unsigned int /*offset*/,
134 int /*handle*/, int op, int dma_buf_fd) {
135 ATRACE_CALL();
136 ATRACE_INT("operation id", op);
137
138 struct dma_buf_sync sync;
139 int err = 0;
140
141 switch (op) {
142 case CACHE_CLEAN:
143 sync.flags = DMA_BUF_SYNC_END | DMA_BUF_SYNC_RW;
144 break;
145 case CACHE_INVALIDATE:
146 sync.flags = DMA_BUF_SYNC_START | DMA_BUF_SYNC_RW;
147 break;
Rohit Kulkarnib20abe72018-03-13 16:55:10 -0700148 case CACHE_READ_DONE:
149 sync.flags = DMA_BUF_SYNC_END | DMA_BUF_SYNC_READ;
150 break;
Rohit Kulkarni3ac98392017-10-20 12:04:34 -0700151 default:
152 ALOGE("%s: Invalid operation %d", __FUNCTION__, op);
153 return -1;
154 }
155
156 if (ioctl(dma_buf_fd, INT(DMA_BUF_IOCTL_SYNC), &sync)) {
157 err = -errno;
158 ALOGE("%s: DMA_BUF_IOCTL_SYNC failed with error - %s", __FUNCTION__, strerror(errno));
159 return err;
160 }
161
162 return 0;
163}
164
165#else
166#ifndef TARGET_ION_ABI_VERSION // Use old ion apis directly
167
168int IonAlloc::OpenIonDevice() {
169 return open(kIonDevice, O_RDONLY);
170}
171
Prabhanjan Kandula96e92342016-03-24 21:03:35 +0530172void IonAlloc::CloseIonDevice() {
173 if (ion_dev_fd_ > FD_INIT) {
174 close(ion_dev_fd_);
175 }
176
177 ion_dev_fd_ = FD_INIT;
178}
179
180int IonAlloc::AllocBuffer(AllocData *data) {
181 ATRACE_CALL();
182 int err = 0;
183 struct ion_handle_data handle_data;
184 struct ion_fd_data fd_data;
185 struct ion_allocation_data ion_alloc_data;
Prabhanjan Kandula96e92342016-03-24 21:03:35 +0530186
187 ion_alloc_data.len = data->size;
188 ion_alloc_data.align = data->align;
189 ion_alloc_data.heap_id_mask = data->heap_id;
190 ion_alloc_data.flags = data->flags;
191 ion_alloc_data.flags |= data->uncached ? 0 : ION_FLAG_CACHED;
Naseer Ahmed7a2b09c2017-05-11 13:03:17 -0400192 std::string tag_name{};
193 if (ATRACE_ENABLED()) {
194 tag_name = "ION_IOC_ALLOC size: " + std::to_string(data->size);
195 }
Prabhanjan Kandula96e92342016-03-24 21:03:35 +0530196
Naseer Ahmed7a2b09c2017-05-11 13:03:17 -0400197 ATRACE_BEGIN(tag_name.c_str());
Prabhanjan Kandula96e92342016-03-24 21:03:35 +0530198 if (ioctl(ion_dev_fd_, INT(ION_IOC_ALLOC), &ion_alloc_data)) {
199 err = -errno;
200 ALOGE("ION_IOC_ALLOC failed with error - %s", strerror(errno));
201 return err;
202 }
Naseer Ahmed7a2b09c2017-05-11 13:03:17 -0400203 ATRACE_END();
Prabhanjan Kandula96e92342016-03-24 21:03:35 +0530204
205 fd_data.handle = ion_alloc_data.handle;
206 handle_data.handle = ion_alloc_data.handle;
Naseer Ahmed7a2b09c2017-05-11 13:03:17 -0400207 ATRACE_BEGIN("ION_IOC_MAP");
Prabhanjan Kandula96e92342016-03-24 21:03:35 +0530208 if (ioctl(ion_dev_fd_, INT(ION_IOC_MAP), &fd_data)) {
209 err = -errno;
210 ALOGE("%s: ION_IOC_MAP failed with error - %s", __FUNCTION__, strerror(errno));
211 ioctl(ion_dev_fd_, INT(ION_IOC_FREE), &handle_data);
212 return err;
213 }
Naseer Ahmed7a2b09c2017-05-11 13:03:17 -0400214 ATRACE_END();
Prabhanjan Kandula96e92342016-03-24 21:03:35 +0530215
Prabhanjan Kandula96e92342016-03-24 21:03:35 +0530216 data->fd = fd_data.fd;
Naseer Ahmede69031e2016-11-22 20:05:16 -0500217 data->ion_handle = handle_data.handle;
Naseer Ahmede36f2242017-12-01 15:33:56 -0500218 ALOGD_IF(DEBUG, "ion: Allocated buffer size:%zu fd:%d handle:0x%x", ion_alloc_data.len, data->fd,
219 data->ion_handle);
Prabhanjan Kandula96e92342016-03-24 21:03:35 +0530220
221 return 0;
222}
223
Naseer Ahmede69031e2016-11-22 20:05:16 -0500224int IonAlloc::FreeBuffer(void *base, unsigned int size, unsigned int offset, int fd,
225 int ion_handle) {
Prabhanjan Kandula96e92342016-03-24 21:03:35 +0530226 ATRACE_CALL();
227 int err = 0;
Naseer Ahmede69031e2016-11-22 20:05:16 -0500228 ALOGD_IF(DEBUG, "ion: Freeing buffer base:%p size:%u fd:%d handle:0x%x", base, size, fd,
229 ion_handle);
Prabhanjan Kandula96e92342016-03-24 21:03:35 +0530230
231 if (base) {
232 err = UnmapBuffer(base, size, offset);
233 }
Prabhanjan Kandula96e92342016-03-24 21:03:35 +0530234
Naseer Ahmed3a9d53a2017-03-15 19:21:40 -0400235 if (ion_handle > 0) {
236 struct ion_handle_data handle_data;
237 handle_data.handle = ion_handle;
238 ioctl(ion_dev_fd_, INT(ION_IOC_FREE), &handle_data);
239 }
240 close(fd);
Prabhanjan Kandula96e92342016-03-24 21:03:35 +0530241 return err;
242}
243
Naseer Ahmed3a9d53a2017-03-15 19:21:40 -0400244int IonAlloc::ImportBuffer(int fd) {
245 struct ion_fd_data fd_data;
246 int err = 0;
247 fd_data.fd = fd;
248 if (ioctl(ion_dev_fd_, INT(ION_IOC_IMPORT), &fd_data)) {
249 err = -errno;
250 ALOGE("%s: ION_IOC_IMPORT failed with error - %s", __FUNCTION__, strerror(errno));
251 return err;
252 }
253 return fd_data.handle;
254}
255
Rohit Kulkarni3ac98392017-10-20 12:04:34 -0700256int IonAlloc::CleanBuffer(void *base, unsigned int size, unsigned int offset, int handle, int op,
257 int /*fd*/) {
Rohit Kulkarnib20abe72018-03-13 16:55:10 -0700258 if (op == CACHE_READ_DONE) {
259 return 0;
260 }
261
Naseer Ahmedf4753692019-09-17 13:51:36 -0400262#ifndef QMAA
Prabhanjan Kandula96e92342016-03-24 21:03:35 +0530263 ATRACE_CALL();
264 ATRACE_INT("operation id", op);
265 struct ion_flush_data flush_data;
Prabhanjan Kandula96e92342016-03-24 21:03:35 +0530266 int err = 0;
267
Naseer Ahmed3a9d53a2017-03-15 19:21:40 -0400268 flush_data.handle = handle;
Prabhanjan Kandula96e92342016-03-24 21:03:35 +0530269 flush_data.vaddr = base;
270 // offset and length are unsigned int
271 flush_data.offset = offset;
272 flush_data.length = size;
273
274 struct ion_custom_data d;
275 switch (op) {
276 case CACHE_CLEAN:
277 d.cmd = ION_IOC_CLEAN_CACHES;
278 break;
279 case CACHE_INVALIDATE:
280 d.cmd = ION_IOC_INV_CACHES;
281 break;
282 case CACHE_CLEAN_AND_INVALIDATE:
283 default:
284 d.cmd = ION_IOC_CLEAN_INV_CACHES;
285 }
286
287 d.arg = (unsigned long)(&flush_data); // NOLINT
288 if (ioctl(ion_dev_fd_, INT(ION_IOC_CUSTOM), &d)) {
289 err = -errno;
290 ALOGE("%s: ION_IOC_CLEAN_INV_CACHES failed with error - %s", __FUNCTION__, strerror(errno));
Prabhanjan Kandula96e92342016-03-24 21:03:35 +0530291 return err;
292 }
Naseer Ahmedf4753692019-09-17 13:51:36 -0400293#endif
Prabhanjan Kandula96e92342016-03-24 21:03:35 +0530294 return 0;
295}
296
Rohit Kulkarni3ac98392017-10-20 12:04:34 -0700297#else // This ion version is not supported
298
299int IonAlloc::OpenIonDevice() {
300 return -EINVAL;
301}
302
303void IonAlloc::CloseIonDevice() {
304}
305
306int IonAlloc::AllocBuffer(AllocData * /*data*/) {
307 return -EINVAL;
308}
309
310int IonAlloc::FreeBuffer(void * /*base*/, unsigned int /*size*/, unsigned int /*offset*/,
311 int /*fd*/, int /*ion_handle*/) {
312 return -EINVAL;
313}
314
315int IonAlloc::ImportBuffer(int /*fd*/) {
316 return -EINVAL;
317}
318
319int IonAlloc::CleanBuffer(void * /*base*/, unsigned int /*size*/, unsigned int /*offset*/,
320 int /*handle*/, int /*op*/, int /*fd*/) {
321 return -EINVAL;
322}
323
324#endif
325#endif // TARGET_ION_ABI_VERSION
326
327
328int IonAlloc::MapBuffer(void **base, unsigned int size, unsigned int offset, int fd) {
329 ATRACE_CALL();
330 int err = 0;
331 void *addr = 0;
332
333 addr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
334 *base = addr;
335 if (addr == MAP_FAILED) {
336 err = -errno;
337 ALOGE("ion: Failed to map memory in the client: %s", strerror(errno));
338 } else {
339 ALOGD_IF(DEBUG, "ion: Mapped buffer base:%p size:%u offset:%u fd:%d", addr, size, offset, fd);
340 }
341
342 return err;
343}
344
345int IonAlloc::UnmapBuffer(void *base, unsigned int size, unsigned int /*offset*/) {
346 ATRACE_CALL();
347 ALOGD_IF(DEBUG, "ion: Unmapping buffer base:%p size:%u", base, size);
348
349 int err = 0;
350 if (munmap(base, size)) {
351 err = -errno;
352 ALOGE("ion: Failed to unmap memory at %p : %s", base, strerror(errno));
353 }
354
355 return err;
356}
357
Naseer Ahmede36f2242017-12-01 15:33:56 -0500358} // namespace gralloc