| /* |
| * Copyright (c) 2019, The Linux Foundation. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are |
| * met: |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * Redistributions in binary form must reproduce the above |
| * copyright notice, this list of conditions and the following |
| * disclaimer in the documentation and/or other materials provided |
| * with the distribution. |
| * * Neither the name of The Linux Foundation nor the names of its |
| * contributors may be used to endorse or promote products derived |
| * from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS |
| * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
| * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
| * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE |
| * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN |
| * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "rpcmem.h" |
| #include "verify.h" |
| #include "fastrpc_internal.h" |
| #include "AEEQList.h" |
| #include "AEEstd.h" |
| #include "apps_std.h" |
| |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <pthread.h> |
| #include <fcntl.h> |
| #include <string.h> |
| #include <unistd.h> |
| #include <sys/ioctl.h> |
| #include <sys/mman.h> |
| #include <errno.h> |
| |
| #define PAGE_SIZE 4096 |
| #define PAGE_MASK ~((uintptr_t)PAGE_SIZE - 1) |
| |
| static QList rpclst; |
| static pthread_mutex_t rpcmt; |
| struct rpc_info |
| { |
| QNode qn; |
| void *buf; |
| void *aligned_buf; |
| int size; |
| int fd; |
| }; |
| |
| extern int open_device_node(int domain); |
| static int rpcmem_open_dev() |
| { |
| return open_device_node(3); |
| } |
| |
| void rpcmem_init() |
| { |
| int fd; |
| QList_Ctor(&rpclst); |
| pthread_mutex_init(&rpcmt, 0); |
| } |
| |
| void rpcmem_deinit() |
| { |
| pthread_mutex_destroy(&rpcmt); |
| } |
| |
| int rpcmem_to_fd_internal(void *po) { |
| struct rpc_info *rinfo, *rfree = 0; |
| QNode *pn, *pnn; |
| |
| pthread_mutex_lock(&rpcmt); |
| QLIST_NEXTSAFE_FOR_ALL(&rpclst, pn, pnn) |
| { |
| rinfo = STD_RECOVER_REC(struct rpc_info, qn, pn); |
| if (rinfo->aligned_buf == po) |
| { |
| rfree = rinfo; |
| break; |
| } |
| } |
| pthread_mutex_unlock(&rpcmt); |
| |
| if (rfree) |
| return rfree->fd; |
| |
| return -1; |
| } |
| |
| int rpcmem_to_fd(void *po) { |
| return rpcmem_to_fd_internal(po); |
| } |
| |
| |
| void *rpcmem_alloc_internal(int heapid, uint32 flags, int size) |
| { |
| struct rpc_info *rinfo; |
| struct fastrpc_alloc_dma_buf buf; |
| int nErr = 0; |
| (void)heapid; |
| (void)flags; |
| int dev = rpcmem_open_dev(); |
| |
| VERIFY(0 != (rinfo = calloc(1, sizeof(*rinfo)))); |
| |
| buf.size = size + PAGE_SIZE; |
| buf.fd = -1; |
| buf.flags = 0; |
| |
| VERIFY((0 == ioctl(dev, FASTRPC_IOCTL_ALLOC_DMA_BUFF, (unsigned long)&buf)) || errno == ENOTTY); |
| VERIFY(0 != (rinfo->buf = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, buf.fd, 0))); |
| rinfo->fd = buf.fd; |
| rinfo->aligned_buf = (void *)(((uintptr_t)rinfo->buf /*+ PAGE_SIZE*/) & PAGE_MASK); |
| rinfo->aligned_buf = rinfo->buf; |
| rinfo->size = size; |
| pthread_mutex_lock(&rpcmt); |
| QList_AppendNode(&rpclst, &rinfo->qn); |
| pthread_mutex_unlock(&rpcmt); |
| |
| return rinfo->aligned_buf; |
| bail: |
| if (nErr) |
| { |
| if (rinfo) |
| { |
| if (rinfo->buf) |
| { |
| free(rinfo->buf); |
| } |
| free(rinfo); |
| } |
| } |
| return 0; |
| } |
| |
| void rpcmem_free_internal(void *po) |
| { |
| struct rpc_info *rinfo, *rfree = 0; |
| QNode *pn, *pnn; |
| int nErr = 0; |
| |
| pthread_mutex_lock(&rpcmt); |
| QLIST_NEXTSAFE_FOR_ALL(&rpclst, pn, pnn) |
| { |
| rinfo = STD_RECOVER_REC(struct rpc_info, qn, pn); |
| if (rinfo->aligned_buf == po) |
| { |
| rfree = rinfo; |
| QNode_Dequeue(&rinfo->qn); |
| break; |
| } |
| } |
| pthread_mutex_unlock(&rpcmt); |
| if (rfree) |
| { |
| int dev = rpcmem_open_dev(); |
| |
| munmap(rfree->buf, rfree->size); |
| free(rfree); |
| } |
| bail: |
| return; |
| |
| } |
| |
| void rpcmem_free(void* po) { |
| rpcmem_free_internal(po); |
| } |
| |
| void* rpcmem_alloc(int heapid, uint32 flags, int size) { |
| return rpcmem_alloc_internal(heapid, flags, size); |
| } |