1 /* 2 * Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. 3 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> 34 #include <stdlib.h> 35 #include <fcntl.h> 36 #include <cutils/log.h> 37 #include <errno.h> 38 #include <utils/Trace.h> 39 40 #include "gralloc_priv.h" 41 #include "gr_utils.h" 42 #include "gr_ion_alloc.h" 43 44 namespace gralloc1 { 45 46 bool IonAlloc::Init() { 47 if (ion_dev_fd_ == FD_INIT) { 48 ion_dev_fd_ = open(kIonDevice, O_RDONLY); 49 } 50 51 if (ion_dev_fd_ < 0) { 52 ALOGE("%s: Failed to open ion device - %s", __FUNCTION__, strerror(errno)); 53 ion_dev_fd_ = FD_INIT; 54 return false; 55 } 56 57 return true; 58 } 59 60 void IonAlloc::CloseIonDevice() { 61 if (ion_dev_fd_ > FD_INIT) { 62 close(ion_dev_fd_); 63 } 64 65 ion_dev_fd_ = FD_INIT; 66 } 67 68 int IonAlloc::AllocBuffer(AllocData *data) { 69 ATRACE_CALL(); 70 int err = 0; 71 struct ion_handle_data handle_data; 72 struct ion_fd_data fd_data; 73 struct ion_allocation_data ion_alloc_data; 74 75 ion_alloc_data.len = data->size; 76 ion_alloc_data.align = data->align; 77 ion_alloc_data.heap_id_mask = data->heap_id; 78 ion_alloc_data.flags = data->flags; 79 ion_alloc_data.flags |= data->uncached ? 0 : ION_FLAG_CACHED; 80 81 if (ioctl(ion_dev_fd_, INT(ION_IOC_ALLOC), &ion_alloc_data)) { 82 err = -errno; 83 ALOGE("ION_IOC_ALLOC failed with error - %s", strerror(errno)); 84 return err; 85 } 86 87 fd_data.handle = ion_alloc_data.handle; 88 handle_data.handle = ion_alloc_data.handle; 89 if (ioctl(ion_dev_fd_, INT(ION_IOC_MAP), &fd_data)) { 90 err = -errno; 91 ALOGE("%s: ION_IOC_MAP failed with error - %s", __FUNCTION__, strerror(errno)); 92 ioctl(ion_dev_fd_, INT(ION_IOC_FREE), &handle_data); 93 return err; 94 } 95 96 data->fd = fd_data.fd; 97 data->ion_handle = handle_data.handle; 98 ALOGD_IF(DEBUG, "ion: Allocated buffer size:%zu fd:%d handle:0x%x", 99 ion_alloc_data.len, data->fd, data->ion_handle); 100 101 return 0; 102 } 103 104 int IonAlloc::FreeBuffer(void *base, unsigned int size, unsigned int offset, int fd, 105 int ion_handle) { 106 ATRACE_CALL(); 107 int err = 0; 108 ALOGD_IF(DEBUG, "ion: Freeing buffer base:%p size:%u fd:%d handle:0x%x", base, size, fd, 109 ion_handle); 110 111 if (base) { 112 err = UnmapBuffer(base, size, offset); 113 } 114 115 if (ion_handle > 0) { 116 struct ion_handle_data handle_data; 117 handle_data.handle = ion_handle; 118 ioctl(ion_dev_fd_, INT(ION_IOC_FREE), &handle_data); 119 } 120 close(fd); 121 return err; 122 } 123 124 int IonAlloc::MapBuffer(void **base, unsigned int size, unsigned int offset, int fd) { 125 ATRACE_CALL(); 126 int err = 0; 127 void *addr = 0; 128 129 // It is a (quirky) requirement of ION to have opened the 130 // ion fd in the process that is doing the mapping 131 addr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 132 *base = addr; 133 if (addr == MAP_FAILED) { 134 err = -errno; 135 ALOGE("ion: Failed to map memory in the client: %s", strerror(errno)); 136 } else { 137 ALOGD_IF(DEBUG, "ion: Mapped buffer base:%p size:%u offset:%u fd:%d", addr, size, offset, fd); 138 } 139 140 return err; 141 } 142 143 int IonAlloc::ImportBuffer(int fd) { 144 struct ion_fd_data fd_data; 145 int err = 0; 146 fd_data.fd = fd; 147 if (ioctl(ion_dev_fd_, INT(ION_IOC_IMPORT), &fd_data)) { 148 err = -errno; 149 ALOGE("%s: ION_IOC_IMPORT failed with error - %s", __FUNCTION__, strerror(errno)); 150 return err; 151 } 152 return fd_data.handle; 153 } 154 155 int IonAlloc::UnmapBuffer(void *base, unsigned int size, unsigned int /*offset*/) { 156 ATRACE_CALL(); 157 ALOGD_IF(DEBUG, "ion: Unmapping buffer base:%p size:%u", base, size); 158 159 int err = 0; 160 if (munmap(base, size)) { 161 err = -errno; 162 ALOGE("ion: Failed to unmap memory at %p : %s", base, strerror(errno)); 163 } 164 165 return err; 166 } 167 168 int IonAlloc::CleanBuffer(void *base, unsigned int size, unsigned int offset, int handle, int op) { 169 ATRACE_CALL(); 170 ATRACE_INT("operation id", op); 171 struct ion_flush_data flush_data; 172 int err = 0; 173 174 flush_data.handle = handle; 175 flush_data.vaddr = base; 176 // offset and length are unsigned int 177 flush_data.offset = offset; 178 flush_data.length = size; 179 180 struct ion_custom_data d; 181 switch (op) { 182 case CACHE_CLEAN: 183 d.cmd = ION_IOC_CLEAN_CACHES; 184 break; 185 case CACHE_INVALIDATE: 186 d.cmd = ION_IOC_INV_CACHES; 187 break; 188 case CACHE_CLEAN_AND_INVALIDATE: 189 default: 190 d.cmd = ION_IOC_CLEAN_INV_CACHES; 191 } 192 193 d.arg = (unsigned long)(&flush_data); // NOLINT 194 if (ioctl(ion_dev_fd_, INT(ION_IOC_CUSTOM), &d)) { 195 err = -errno; 196 ALOGE("%s: ION_IOC_CLEAN_INV_CACHES failed with error - %s", __FUNCTION__, strerror(errno)); 197 return err; 198 } 199 200 return 0; 201 } 202 203 } // namespace gralloc1 204