1/* 2 * Copyright (c) 2011-2012, 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#include <linux/ioctl.h> 32#include <sys/mman.h> 33#include <stdlib.h> 34#include <fcntl.h> 35#include <cutils/log.h> 36#include <errno.h> 37#include "gralloc_priv.h" 38#include "ionalloc.h" 39 40using gralloc::IonAlloc; 41 42#define ION_DEVICE "/dev/ion" 43 44int IonAlloc::open_device() 45{ 46 if(mIonFd == FD_INIT) 47 mIonFd = open(ION_DEVICE, O_RDONLY); 48 49 if(mIonFd < 0 ) { 50 ALOGE("%s: Failed to open ion device - %s", 51 __FUNCTION__, strerror(errno)); 52 mIonFd = FD_INIT; 53 return -errno; 54 } 55 return 0; 56} 57 58void IonAlloc::close_device() 59{ 60 if(mIonFd >= 0) 61 close(mIonFd); 62 mIonFd = FD_INIT; 63} 64 65int IonAlloc::alloc_buffer(alloc_data& data) 66{ 67 Locker::Autolock _l(mLock); 68 int err = 0; 69 struct ion_handle_data handle_data; 70 struct ion_fd_data fd_data; 71 struct ion_allocation_data ionAllocData; 72 void *base = 0; 73 74 ionAllocData.len = data.size; 75 ionAllocData.align = data.align; 76 ionAllocData.heap_mask = data.flags & ~ION_SECURE; 77 ionAllocData.flags = data.uncached ? 0 : ION_FLAG_CACHED; 78 // ToDo: replace usage of alloc data structure with 79 // ionallocdata structure. 80 if (data.flags & ION_SECURE) 81 ionAllocData.flags |= ION_SECURE; 82 83 // ToDo: replace usage of alloc data structure with 84 // ionallocdata structure. 85 if (data.flags & ION_SECURE) 86 ionAllocData.flags |= ION_SECURE; 87 88 err = open_device(); 89 if (err) 90 return err; 91 if(ioctl(mIonFd, ION_IOC_ALLOC, &ionAllocData)) { 92 err = -errno; 93 ALOGE("ION_IOC_ALLOC failed with error - %s", strerror(errno)); 94 return err; 95 } 96 97 fd_data.handle = ionAllocData.handle; 98 handle_data.handle = ionAllocData.handle; 99 if(ioctl(mIonFd, ION_IOC_MAP, &fd_data)) { 100 err = -errno; 101 ALOGE("%s: ION_IOC_MAP failed with error - %s", 102 __FUNCTION__, strerror(errno)); 103 ioctl(mIonFd, ION_IOC_FREE, &handle_data); 104 return err; 105 } 106 107 if(!(data.flags & ION_SECURE)) { 108 base = mmap(0, ionAllocData.len, PROT_READ|PROT_WRITE, 109 MAP_SHARED, fd_data.fd, 0); 110 if(base == MAP_FAILED) { 111 err = -errno; 112 ALOGE("%s: Failed to map the allocated memory: %s", 113 __FUNCTION__, strerror(errno)); 114 ioctl(mIonFd, ION_IOC_FREE, &handle_data); 115 return err; 116 } 117 } 118 119 data.base = base; 120 data.fd = fd_data.fd; 121 ioctl(mIonFd, ION_IOC_FREE, &handle_data); 122 ALOGD_IF(DEBUG, "ion: Allocated buffer base:%p size:%d fd:%d", 123 data.base, ionAllocData.len, data.fd); 124 return 0; 125} 126 127 128int IonAlloc::free_buffer(void* base, size_t size, int offset, int fd) 129{ 130 Locker::Autolock _l(mLock); 131 ALOGD_IF(DEBUG, "ion: Freeing buffer base:%p size:%d fd:%d", 132 base, size, fd); 133 int err = 0; 134 err = open_device(); 135 if (err) 136 return err; 137 138 if(base) 139 err = unmap_buffer(base, size, offset); 140 close(fd); 141 return err; 142} 143 144int IonAlloc::map_buffer(void **pBase, size_t size, int offset, int fd) 145{ 146 int err = 0; 147 void *base = 0; 148 // It is a (quirky) requirement of ION to have opened the 149 // ion fd in the process that is doing the mapping 150 err = open_device(); 151 if (err) 152 return err; 153 154 base = mmap(0, size, PROT_READ| PROT_WRITE, 155 MAP_SHARED, fd, 0); 156 *pBase = base; 157 if(base == MAP_FAILED) { 158 err = -errno; 159 ALOGE("ion: Failed to map memory in the client: %s", 160 strerror(errno)); 161 } else { 162 ALOGD_IF(DEBUG, "ion: Mapped buffer base:%p size:%d offset:%d fd:%d", 163 base, size, offset, fd); 164 } 165 return err; 166} 167 168int IonAlloc::unmap_buffer(void *base, size_t size, int offset) 169{ 170 ALOGD_IF(DEBUG, "ion: Unmapping buffer base:%p size:%d", base, size); 171 int err = 0; 172 if(munmap(base, size)) { 173 err = -errno; 174 ALOGE("ion: Failed to unmap memory at %p : %s", 175 base, strerror(errno)); 176 } 177 return err; 178 179} 180int IonAlloc::clean_buffer(void *base, size_t size, int offset, int fd, int op) 181{ 182 struct ion_flush_data flush_data; 183 struct ion_fd_data fd_data; 184 struct ion_handle_data handle_data; 185 struct ion_handle* handle; 186 int err = 0; 187 188 err = open_device(); 189 if (err) 190 return err; 191 192 fd_data.fd = fd; 193 if (ioctl(mIonFd, ION_IOC_IMPORT, &fd_data)) { 194 err = -errno; 195 ALOGE("%s: ION_IOC_IMPORT failed with error - %s", 196 __FUNCTION__, strerror(errno)); 197 return err; 198 } 199 200 handle_data.handle = fd_data.handle; 201 flush_data.handle = fd_data.handle; 202 flush_data.vaddr = base; 203 flush_data.offset = offset; 204 flush_data.length = size; 205 206 struct ion_custom_data d; 207 switch(op) { 208 case CACHE_CLEAN: 209 d.cmd = ION_IOC_CLEAN_CACHES; 210 break; 211 case CACHE_INVALIDATE: 212 d.cmd = ION_IOC_INV_CACHES; 213 break; 214 case CACHE_CLEAN_AND_INVALIDATE: 215 default: 216 d.cmd = ION_IOC_CLEAN_INV_CACHES; 217 } 218 219 d.arg = (unsigned long int)&flush_data; 220 221 if(ioctl(mIonFd, ION_IOC_CUSTOM, &d)) { 222 err = -errno; 223 ALOGE("%s: ION_IOC_CLEAN_INV_CACHES failed with error - %s", 224 225 __FUNCTION__, strerror(errno)); 226 ioctl(mIonFd, ION_IOC_FREE, &handle_data); 227 return err; 228 } 229 ioctl(mIonFd, ION_IOC_FREE, &handle_data); 230 return 0; 231} 232 233