diff --git a/Android.mk b/Android.mk index bb37c5c..bb38442 100644 --- a/Android.mk +++ b/Android.mk @@ -1,8 +1,4 @@ #Enables the listed display HAL modules -display-hals := libhwcomposer liboverlay -ifeq ($(TARGET_USES_ION),true) - display-hals += libgralloc - include $(call all-named-subdir-makefiles,$(display-hals)) -endif +display-hals := libhwcomposer liboverlay libgralloc include $(call all-named-subdir-makefiles,$(display-hals)) diff --git a/libgralloc/Android.mk b/libgralloc/Android.mk index 718baf1..e3a0f5e 100644 --- a/libgralloc/Android.mk +++ b/libgralloc/Android.mk @@ -13,7 +13,6 @@ # limitations under the License. # Use this flag until pmem/ashmem is implemented in the new gralloc -ifeq ($(TARGET_USES_ION),true) LOCAL_PATH := $(call my-dir) # HAL module implemenation, not prelinked and stored in @@ -28,13 +27,11 @@ LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr LOCAL_SRC_FILES := framebuffer.cpp \ gpu.cpp \ gralloc.cpp \ - mapper.cpp \ - pmemalloc.cpp \ - pmem_bestfit_alloc.cpp + mapper.cpp LOCAL_MODULE := gralloc.$(TARGET_BOARD_PLATFORM) LOCAL_MODULE_TAGS := optional -LOCAL_CFLAGS:= -DLOG_TAG=\"$(TARGET_BOARD_PLATFORM).gralloc\" -DHOST -DDEBUG_CALC_FPS -DUSE_ION +LOCAL_CFLAGS:= -DLOG_TAG=\"$(TARGET_BOARD_PLATFORM).gralloc\" -DHOST -DDEBUG_CALC_FPS ifeq ($(call is-board-platform,msm7627_surf msm7627_6x),true) LOCAL_CFLAGS += -DTARGET_MSM7x27 @@ -53,6 +50,7 @@ endif ifeq ($(TARGET_GRALLOC_USES_ASHMEM),true) LOCAL_CFLAGS += -DUSE_ASHMEM endif + include $(BUILD_SHARED_LIBRARY) #MemAlloc Library @@ -64,9 +62,15 @@ LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr LOCAL_SHARED_LIBRARIES := liblog libcutils libutils LOCAL_SRC_FILES := ionalloc.cpp \ ashmemalloc.cpp \ + pmemalloc.cpp \ + pmem_bestfit_alloc.cpp \ alloc_controller.cpp -LOCAL_CFLAGS:= -DLOG_TAG=\"memalloc\" -DLOG_NDDEBUG=0 -DUSE_ION +LOCAL_CFLAGS:= -DLOG_TAG=\"memalloc\" -DLOG_NDDEBUG=0 + +ifeq ($(TARGET_USES_ION),true) + LOCAL_CFLAGS += -DUSE_ION +endif + LOCAL_MODULE := libmemalloc LOCAL_MODULE_TAGS := optional include $(BUILD_SHARED_LIBRARY) -endif #TARGET_USES_ION diff --git a/libgralloc/alloc_controller.cpp b/libgralloc/alloc_controller.cpp index 5cd07d3..53f4354 100644 --- a/libgralloc/alloc_controller.cpp +++ b/libgralloc/alloc_controller.cpp @@ -29,33 +29,19 @@ #include #include +#include #include "gralloc_priv.h" #include "alloc_controller.h" #include "memalloc.h" #include "ionalloc.h" +#include "pmemalloc.h" +#include "ashmemalloc.h" using namespace gralloc; using android::sp; -sp IAllocController::sController = NULL; -sp IAllocController::getInstance(void) -{ - if(sController == NULL) { -#ifdef USE_ION - sController = new IonController(); -#else - // XXX: Return pmem/ashmem controller when completed -#endif - } - return sController; -} - -IonController::IonController() -{ - mIonAlloc = new IonAlloc(); -} - -static bool canFallback(int compositionType, int usage, int flags) +//Common functions +static bool canFallback(int compositionType, int usage, bool triedSystem) { // Fallback to system heap when alloc fails unless // 1. Composition type is MDP @@ -64,7 +50,7 @@ static bool canFallback(int compositionType, int usage, int flags) if(compositionType == MDP_COMPOSITION) return false; - if(flags & ION_HEAP_SYSTEM_ID) + if(triedSystem) return false; if(usage &(GRALLOC_USAGE_PRIVATE_ADSP_HEAP| GRALLOC_USAGE_PRIVATE_EBI_HEAP | @@ -74,6 +60,29 @@ static bool canFallback(int compositionType, int usage, int flags) return true; } +sp IAllocController::sController = NULL; +sp IAllocController::getInstance(bool useMasterHeap) +{ + if(sController == NULL) { +#ifdef USE_ION + sController = new IonController(); +#else + if(useMasterHeap) + sController = new PmemAshmemController(); + else + sController = new PmemKernelController(); +#endif + } + return sController; +} + + +//-------------- IonController-----------------------// +IonController::IonController() +{ + mIonAlloc = new IonAlloc(); +} + int IonController::allocate(alloc_data& data, int usage, int compositionType) { @@ -110,7 +119,10 @@ int IonController::allocate(alloc_data& data, int usage, ret = mIonAlloc->alloc_buffer(data); // Fallback - if(ret < 0 && canFallback(compositionType, usage, ionFlags)) { + if(ret < 0 && canFallback(compositionType, + usage, + (ionFlags & ION_HEAP_SYSTEM_ID))) + { LOGW("Falling back to system heap"); data.flags = 1 << ION_HEAP_SYSTEM_ID; ret = mIonAlloc->alloc_buffer(data); @@ -134,20 +146,144 @@ sp IonController::getAllocator(int flags) return memalloc; } +//-------------- PmemKernelController-----------------------// + +PmemKernelController::PmemKernelController() +{ + mPmemAdspAlloc = new PmemKernelAlloc(DEVICE_PMEM_ADSP); + // XXX: Right now, there is no need to maintain an instance + // of the SMI allocator as we need it only in a few cases +} + +PmemKernelController::~PmemKernelController() +{ +} + +int PmemKernelController::allocate(alloc_data& data, int usage, + int compositionType) +{ + int ret = 0; + bool adspFallback = false; + + // Try SMI first + if ((usage & GRALLOC_USAGE_PRIVATE_SMI_HEAP) || + (usage & GRALLOC_USAGE_EXTERNAL_DISP) || + (usage & GRALLOC_USAGE_PROTECTED)) + { + int tempFd = open(DEVICE_PMEM_SMIPOOL, O_RDWR, 0); + if(tempFd > 0) { + close(tempFd); + sp memalloc; + memalloc = new PmemKernelAlloc(DEVICE_PMEM_SMIPOOL); + ret = memalloc->alloc_buffer(data); + if(ret >= 0) + return ret; + else { + adspFallback = true; + LOGW("Allocation from SMI failed, trying ADSP"); + } + } + } + + if ((usage & GRALLOC_USAGE_PRIVATE_ADSP_HEAP) || adspFallback) { + ret = mPmemAdspAlloc->alloc_buffer(data); + } + return ret; +} + +sp PmemKernelController::getAllocator(int flags) +{ + sp memalloc; + if (flags & private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP) + memalloc = mPmemAdspAlloc; + else { + LOGE("%s: Invalid flags passed: 0x%x", __FUNCTION__, flags); + memalloc = NULL; + } + + return memalloc; +} + +//-------------- PmemAshmmemController-----------------------// + +PmemAshmemController::PmemAshmemController() +{ + mPmemUserspaceAlloc = new PmemUserspaceAlloc(); + mAshmemAlloc = new AshmemAlloc(); + mPmemKernelCtrl = new PmemKernelController(); +} + +PmemAshmemController::~PmemAshmemController() +{ +} + int PmemAshmemController::allocate(alloc_data& data, int usage, int compositionType) { - //XXX PMEM with ashmem fallback strategy - return 0; + int ret = 0; + + // Decide caching + // Decide based on usage + uint32_t uread = usage & GRALLOC_USAGE_SW_READ_MASK; + uint32_t uwrite = usage & GRALLOC_USAGE_SW_WRITE_MASK; + if (uread == GRALLOC_USAGE_SW_READ_OFTEN || + uwrite == GRALLOC_USAGE_SW_WRITE_OFTEN) { + data.uncached = false; + } else { + data.uncached = true; + } + + // Override if we explicitly need uncached buffers + if (usage & GRALLOC_USAGE_PRIVATE_UNCACHED) + data.uncached = true; + + // If ADSP or SMI is requested use the kernel controller + if(usage & (GRALLOC_USAGE_PRIVATE_ADSP_HEAP| + GRALLOC_USAGE_PRIVATE_SMI_HEAP)) { + ret = mPmemKernelCtrl->allocate(data, usage, compositionType); + if(ret < 0) + LOGE("%s: Failed to allocate ADSP/SMI memory", __func__); + else + data.allocType = private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP; + return ret; + } + + if(usage & GRALLOC_USAGE_PRIVATE_SYSTEM_HEAP) { + ret = mAshmemAlloc->alloc_buffer(data); + if(ret >= 0) + data.allocType = private_handle_t::PRIV_FLAGS_USES_ASHMEM; + return ret; + } + + // if no memory specific flags are set, + // default to EBI heap, so that bypass + // can work. We can fall back to system + // heap if we run out. + ret = mPmemUserspaceAlloc->alloc_buffer(data); + + // Fallback + if(ret >= 0 ) { + data.allocType = private_handle_t::PRIV_FLAGS_USES_PMEM; + } else if(ret < 0 && canFallback(compositionType, usage, false)) { + LOGW("Falling back to ashmem"); + ret = mAshmemAlloc->alloc_buffer(data); + if(ret >= 0) + data.allocType = private_handle_t::PRIV_FLAGS_USES_ASHMEM; + } + + return ret; } sp PmemAshmemController::getAllocator(int flags) { sp memalloc; - if (flags & private_handle_t::PRIV_FLAGS_USES_PMEM) { - // XXX Return right allocator based on flags - memalloc = NULL; - } else { + if (flags & private_handle_t::PRIV_FLAGS_USES_PMEM) + memalloc = mPmemUserspaceAlloc; + else if (flags & private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP) + memalloc = mPmemKernelCtrl->getAllocator(flags); + else if (flags & private_handle_t::PRIV_FLAGS_USES_ASHMEM) + memalloc = mAshmemAlloc; + else { LOGE("%s: Invalid flags passed: 0x%x", __FUNCTION__, flags); memalloc = NULL; } diff --git a/libgralloc/alloc_controller.h b/libgralloc/alloc_controller.h index fbdd401..6c907d1 100644 --- a/libgralloc/alloc_controller.h +++ b/libgralloc/alloc_controller.h @@ -50,7 +50,7 @@ namespace gralloc { virtual ~IAllocController() {}; - static android::sp getInstance(void); + static android::sp getInstance(bool useMasterHeap); private: static android::sp sController; @@ -72,6 +72,25 @@ namespace gralloc { }; + class PmemKernelController : public IAllocController { + + public: + virtual int allocate(alloc_data& data, int usage, + int compositionType); + + virtual android::sp getAllocator(int flags); + + PmemKernelController (); + + ~PmemKernelController (); + + private: + android::sp mPmemAdspAlloc; + + }; + + // Main pmem controller - this should only + // be used within gralloc class PmemAshmemController : public IAllocController { public: @@ -79,7 +98,15 @@ namespace gralloc { int compositionType); virtual android::sp getAllocator(int flags); - // XXX: Pmem and ashmem alloc objects + + PmemAshmemController(); + + ~PmemAshmemController(); + + private: + android::sp mPmemUserspaceAlloc; + android::sp mAshmemAlloc; + android::sp mPmemKernelCtrl; }; diff --git a/libgralloc/gpu.cpp b/libgralloc/gpu.cpp index ad3cb28..e0f3ebb 100644 --- a/libgralloc/gpu.cpp +++ b/libgralloc/gpu.cpp @@ -161,7 +161,6 @@ int gpu_context_t::gralloc_alloc_buffer(size_t size, int usage, else data.align = getpagesize(); data.pHandle = (unsigned int) pHandle; - data.bufferType = bufferType; err = mAllocCtrl->allocate(data, usage, compositionType); if (err == 0) { @@ -307,8 +306,8 @@ int gpu_context_t::free_impl(private_handle_t const* hnd) { hnd->offset, hnd->fd); if(err) return err; + terminateBuffer(&m->base, const_cast(hnd)); } - // XXX any additional cleanup. delete hnd; return 0; } diff --git a/libgralloc/gralloc.cpp b/libgralloc/gralloc.cpp index 640b255..a98baf8 100644 --- a/libgralloc/gralloc.cpp +++ b/libgralloc/gralloc.cpp @@ -102,7 +102,7 @@ int gralloc_device_open(const hw_module_t* module, const char* name, const private_module_t* m = reinterpret_cast( module); gpu_context_t *dev; - sp alloc_ctrl = IAllocController::getInstance(); + sp alloc_ctrl = IAllocController::getInstance(true); dev = new gpu_context_t(m, alloc_ctrl); *device = &dev->common; status = 0; diff --git a/libgralloc/gralloc_priv.h b/libgralloc/gralloc_priv.h index 9f305cc..0130b6e 100644 --- a/libgralloc/gralloc_priv.h +++ b/libgralloc/gralloc_priv.h @@ -69,6 +69,7 @@ enum { #define INTERLACE_MASK 0x80 #define S3D_FORMAT_MASK 0xFF000 #define COLOR_FORMAT(x) (x & 0xFFF) // Max range for colorFormats is 0 - FFF +#define DEVICE_PMEM "/dev/pmem" #define DEVICE_PMEM_ADSP "/dev/pmem_adsp" #define DEVICE_PMEM_SMIPOOL "/dev/pmem_smipool" /*****************************************************************************/ diff --git a/libgralloc/mapper.cpp b/libgralloc/mapper.cpp index e217b7c..d6024b0 100644 --- a/libgralloc/mapper.cpp +++ b/libgralloc/mapper.cpp @@ -39,12 +39,10 @@ #include "gralloc_priv.h" #include "gr.h" -#include "ionalloc.h" -#include "ashmemalloc.h" +#include "alloc_controller.h" +#include "memalloc.h" -using gralloc::IMemAlloc; -using gralloc::IonAlloc; -using gralloc::AshmemAlloc; +using namespace gralloc; using android::sp; /*****************************************************************************/ @@ -53,14 +51,8 @@ using android::sp; static sp getAllocator(int flags) { sp memalloc; - if (flags & private_handle_t::PRIV_FLAGS_USES_ION) { - memalloc = new IonAlloc(); - } - if (flags & private_handle_t::PRIV_FLAGS_USES_ASHMEM) { - memalloc = new AshmemAlloc(); - } - - // XXX Return allocator for pmem + sp alloc_ctrl = IAllocController::getInstance(true); + memalloc = alloc_ctrl->getAllocator(flags); return memalloc; } @@ -192,7 +184,8 @@ int terminateBuffer(gralloc_module_t const* module, // this buffer was mapped, unmap it now if (hnd->flags & (private_handle_t::PRIV_FLAGS_USES_PMEM | private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP | - private_handle_t::PRIV_FLAGS_USES_ASHMEM)) { + private_handle_t::PRIV_FLAGS_USES_ASHMEM | + private_handle_t::PRIV_FLAGS_USES_ION)) { if (hnd->pid != getpid()) { // ... unless it's a "master" pmem buffer, that is a buffer // mapped in the process it's been allocated. diff --git a/libgralloc/memalloc.h b/libgralloc/memalloc.h index 7b76d06..13a54e7 100644 --- a/libgralloc/memalloc.h +++ b/libgralloc/memalloc.h @@ -44,7 +44,6 @@ namespace gralloc { unsigned int pHandle; bool uncached; unsigned int flags; - int bufferType; int allocType; }; diff --git a/libgralloc/pmem_bestfit_alloc.h b/libgralloc/pmem_bestfit_alloc.h index 16ff58a..2ea8452 100644 --- a/libgralloc/pmem_bestfit_alloc.h +++ b/libgralloc/pmem_bestfit_alloc.h @@ -30,7 +30,6 @@ /* * A simple templatized doubly linked-list implementation */ - template class LinkedList { @@ -93,7 +92,7 @@ public: } }; -class SimpleBestFitAllocator : public PmemUserspaceAllocator::Deps::Allocator +class SimpleBestFitAllocator : public gralloc::PmemUserspaceAlloc::Allocator { public: @@ -127,5 +126,4 @@ private: LinkedList mList; size_t mHeapSize; }; - #endif /* GRALLOC_ALLOCATOR_H_ */ diff --git a/libgralloc/pmemalloc.cpp b/libgralloc/pmemalloc.cpp index 010734b..6f3118a 100644 --- a/libgralloc/pmemalloc.cpp +++ b/libgralloc/pmemalloc.cpp @@ -1,135 +1,157 @@ /* - * Copyright (C) 2010 The Android Open Source Project + * Copyright (c) 2011, Code Aurora Forum. 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 Code Aurora Forum, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * 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. */ - -//#define LOG_NDEBUG 0 - -#include #include #include -#include -#include -#include - #include - +#include #include -#include - +#include +#include #include "gralloc_priv.h" #include "pmemalloc.h" +#include "pmem_bestfit_alloc.h" +using namespace gralloc; +using android::sp; -#define BEGIN_FUNC LOGV("%s begin", __PRETTY_FUNCTION__) -#define END_FUNC LOGV("%s end", __PRETTY_FUNCTION__) - - -static int get_open_flags(int usage) { - int openFlags = O_RDWR | O_SYNC; - uint32_t uread = usage & GRALLOC_USAGE_SW_READ_MASK; - uint32_t uwrite = usage & GRALLOC_USAGE_SW_WRITE_MASK; - if (uread == GRALLOC_USAGE_SW_READ_OFTEN || - uwrite == GRALLOC_USAGE_SW_WRITE_OFTEN) { - openFlags &= ~O_SYNC; - } - return openFlags; -} - -PmemAllocator::~PmemAllocator() +// Common functions between userspace +// and kernel allocators +static int getPmemTotalSize(int fd, size_t* size) { - BEGIN_FUNC; - END_FUNC; -} - - -PmemUserspaceAllocator::PmemUserspaceAllocator(Deps& deps, - Deps::Allocator& allocator, const char* pmemdev): - deps(deps), - allocator(allocator), - pmemdev(pmemdev), - master_fd(MASTER_FD_INIT) -{ - BEGIN_FUNC; - pthread_mutex_init(&lock, NULL); - END_FUNC; -} - - -PmemUserspaceAllocator::~PmemUserspaceAllocator() -{ - BEGIN_FUNC; - END_FUNC; -} - - -void* PmemUserspaceAllocator::get_base_address() { - BEGIN_FUNC; - END_FUNC; - return master_base; -} - - -int PmemUserspaceAllocator::init_pmem_area_locked() -{ - BEGIN_FUNC; + //XXX: 7x27 int err = 0; - int fd = deps.open(pmemdev, O_RDWR, 0); - if (fd >= 0) { - size_t size = 0; - err = deps.getPmemTotalSize(fd, &size); - if (err < 0) { - LOGE("%s: PMEM_GET_TOTAL_SIZE failed (%d), limp mode", pmemdev, - err); - size = 8<<20; // 8 MiB - } - allocator.setSize(size); - - void* base = deps.mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, - 0); - if (base == MAP_FAILED) { - LOGE("%s: failed to map pmem master fd: %s", pmemdev, - strerror(deps.getErrno())); - err = -deps.getErrno(); - base = 0; - deps.close(fd); - fd = -1; - } else { - master_fd = fd; - master_base = base; - } - } else { - LOGE("%s: failed to open pmem device: %s", pmemdev, - strerror(deps.getErrno())); - err = -deps.getErrno(); + pmem_region region; + err = ioctl(fd, PMEM_GET_TOTAL_SIZE, ®ion); + if (err == 0) { + *size = region.len; } - END_FUNC; return err; } - -int PmemUserspaceAllocator::init_pmem_area() +static int getOpenFlags(bool uncached) { - BEGIN_FUNC; - pthread_mutex_lock(&lock); - int err = master_fd; - if (err == MASTER_FD_INIT) { + if(uncached) + return O_RDWR | O_SYNC; + else + return O_RDWR; +} + +static int connectPmem(int fd, int master_fd) { + return ioctl(fd, PMEM_CONNECT, master_fd); +} + +static int mapSubRegion(int fd, int offset, size_t size) { + struct pmem_region sub = { offset, size }; + return ioctl(fd, PMEM_MAP, &sub); +} + +static int unmapSubRegion(int fd, int offset, size_t size) { + struct pmem_region sub = { offset, size }; + return ioctl(fd, PMEM_UNMAP, &sub); +} + +static int alignPmem(int fd, size_t size, int align) { + struct pmem_allocation allocation; + allocation.size = size; + allocation.align = align; + return ioctl(fd, PMEM_ALLOCATE_ALIGNED, &allocation); +} + +static int cleanPmem(void *base, size_t size, int offset, int fd) { + struct pmem_addr pmem_addr; + pmem_addr.vaddr = (unsigned long) base; + pmem_addr.offset = offset; + pmem_addr.length = size; + return ioctl(fd, PMEM_CLEAN_INV_CACHES, &pmem_addr); +} + +//-------------- PmemUserspaceAlloc-----------------------// +PmemUserspaceAlloc::PmemUserspaceAlloc() +{ + mPmemDev = DEVICE_PMEM; + mMasterFd = FD_INIT; + mAllocator = new SimpleBestFitAllocator(); + pthread_mutex_init(&mLock, NULL); +} + +PmemUserspaceAlloc::~PmemUserspaceAlloc() +{ +} + +int PmemUserspaceAlloc::init_pmem_area_locked() +{ + LOGD("%s: Opening master pmem FD", __FUNCTION__); + int err = 0; + int fd = open(mPmemDev, O_RDWR, 0); + if (fd >= 0) { + size_t size = 0; + err = getPmemTotalSize(fd, &size); + LOGD("%s: Total pmem size: %d", __FUNCTION__, size); + if (err < 0) { + LOGE("%s: PMEM_GET_TOTAL_SIZE failed (%d), limp mode", mPmemDev, + err); + size = 8<<20; // 8 MiB + } + mAllocator->setSize(size); + + void* base = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, + 0); + if (base == MAP_FAILED) { + LOGE("%s: Failed to map pmem master fd: %s", mPmemDev, + strerror(errno)); + err = -errno; + base = 0; + close(fd); + fd = -1; + } else { + mMasterFd = fd; + mMasterBase = base; + } + } else { + LOGE("%s: Failed to open pmem device: %s", mPmemDev, + strerror(errno)); + err = -errno; + } + return err; +} + +int PmemUserspaceAlloc::init_pmem_area() +{ + pthread_mutex_lock(&mLock); + int err = mMasterFd; + if (err == FD_INIT) { // first time, try to initialize pmem + LOGD("%s: Initializing pmem area", __FUNCTION__); err = init_pmem_area_locked(); if (err) { - LOGE("%s: failed to initialize pmem area", pmemdev); - master_fd = err; + LOGE("%s: failed to initialize pmem area", mPmemDev); + mMasterFd = err; } } else if (err < 0) { // pmem couldn't be initialized, never use it @@ -137,227 +159,211 @@ int PmemUserspaceAllocator::init_pmem_area() // pmem OK err = 0; } - pthread_mutex_unlock(&lock); - END_FUNC; + pthread_mutex_unlock(&mLock); return err; + } - -int PmemUserspaceAllocator::alloc_pmem_buffer(size_t size, int usage, - void** pBase, int* pOffset, int* pFd, int format) +int PmemUserspaceAlloc::alloc_buffer(alloc_data& data) { - BEGIN_FUNC; int err = init_pmem_area(); if (err == 0) { - void* base = master_base; - int offset = allocator.allocate(size); + void* base = mMasterBase; + size_t size = data.size; + int offset = mAllocator->allocate(size); if (offset < 0) { // no more pmem memory - LOGE("%s: no more pmem available", pmemdev); + LOGE("%s: No more pmem available", mPmemDev); err = -ENOMEM; } else { - int openFlags = get_open_flags(usage); - - //LOGD("%s: allocating pmem at offset 0x%p", pmemdev, offset); + int openFlags = getOpenFlags(data.uncached); // now create the "sub-heap" - int fd = deps.open(pmemdev, openFlags, 0); + int fd = open(mPmemDev, openFlags, 0); err = fd < 0 ? fd : 0; // and connect to it if (err == 0) - err = deps.connectPmem(fd, master_fd); + err = connectPmem(fd, mMasterFd); // and make it available to the client process if (err == 0) - err = deps.mapPmem(fd, offset, size); + err = mapSubRegion(fd, offset, size); if (err < 0) { - LOGE("%s: failed to initialize pmem sub-heap: %d", pmemdev, + LOGE("%s: Failed to initialize pmem sub-heap: %d", mPmemDev, err); - err = -deps.getErrno(); - deps.close(fd); - allocator.deallocate(offset); + err = -errno; + close(fd); + mAllocator->deallocate(offset); fd = -1; } else { - LOGV("%s: mapped fd %d at offset %d, size %d", pmemdev, fd, offset, size); + LOGD("%s: Allocated buffer base:%p size:%d offset:%d fd:%d", + mPmemDev, base, size, offset, fd); memset((char*)base + offset, 0, size); //Clean cache before flushing to ensure pmem is properly flushed - err = deps.cleanPmem(fd, (unsigned long) base + offset, offset, size); + err = clean_buffer((void*)((intptr_t) base + offset), size, offset, fd); if (err < 0) { - LOGE("cleanPmem failed: (%s)", strerror(deps.getErrno())); + LOGE("cleanPmem failed: (%s)", strerror(errno)); } -#ifdef HOST - cacheflush(intptr_t(base) + offset, intptr_t(base) + offset + size, 0); -#endif - *pBase = base; - *pOffset = offset; - *pFd = fd; + cacheflush(intptr_t(base) + offset, intptr_t(base) + offset + size, 0); + data.base = base; + data.offset = offset; + data.fd = fd; } - //LOGD_IF(!err, "%s: allocating pmem size=%d, offset=%d", pmemdev, size, offset); } } - END_FUNC; return err; + } - -int PmemUserspaceAllocator::free_pmem_buffer(size_t size, void* base, - int offset, int fd) +int PmemUserspaceAlloc::free_buffer(void* base, size_t size, int offset, int fd) { - BEGIN_FUNC; + LOGD("%s: Freeing buffer base:%p size:%d offset:%d fd:%d", + mPmemDev, base, size, offset, fd); int err = 0; if (fd >= 0) { - int err = deps.unmapPmem(fd, offset, size); + int err = unmapSubRegion(fd, offset, size); LOGE_IF(err<0, "PMEM_UNMAP failed (%s), fd=%d, sub.offset=%u, " - "sub.size=%u", strerror(deps.getErrno()), fd, offset, size); + "sub.size=%u", strerror(errno), fd, offset, size); if (err == 0) { // we can't deallocate the memory in case of UNMAP failure // because it would give that process access to someone else's // surfaces, which would be a security breach. - allocator.deallocate(offset); + mAllocator->deallocate(offset); } + close(fd); } - END_FUNC; return err; } -PmemUserspaceAllocator::Deps::Allocator::~Allocator() +int PmemUserspaceAlloc::map_buffer(void **pBase, size_t size, int offset, int fd) { - BEGIN_FUNC; - END_FUNC; -} - -PmemUserspaceAllocator::Deps::~Deps() -{ - BEGIN_FUNC; - END_FUNC; -} - -PmemKernelAllocator::PmemKernelAllocator(Deps& deps): - deps(deps) -{ - BEGIN_FUNC; - END_FUNC; -} - - -PmemKernelAllocator::~PmemKernelAllocator() -{ - BEGIN_FUNC; - END_FUNC; -} - - -void* PmemKernelAllocator::get_base_address() { - BEGIN_FUNC; - END_FUNC; - return 0; -} - - -static unsigned clp2(unsigned x) { - x = x - 1; - x = x | (x >> 1); - x = x | (x >> 2); - x = x | (x >> 4); - x = x | (x >> 8); - x = x | (x >>16); - return x + 1; -} - - -int PmemKernelAllocator::alloc_pmem_buffer(size_t size, int usage, - void** pBase,int* pOffset, int* pFd, int format) -{ - BEGIN_FUNC; - - *pBase = 0; - *pOffset = 0; - *pFd = -1; - - int err, offset = 0; - int openFlags = get_open_flags(usage); - const char *device; - if (usage & GRALLOC_USAGE_PRIVATE_ADSP_HEAP) { - device = DEVICE_PMEM_ADSP; - } else if (usage & GRALLOC_USAGE_PRIVATE_SMI_HEAP) { - device = DEVICE_PMEM_SMIPOOL; - } else if ((usage & GRALLOC_USAGE_EXTERNAL_DISP) || - (usage & GRALLOC_USAGE_PROTECTED)) { - int tempFd = deps.open(DEVICE_PMEM_SMIPOOL, openFlags, 0); - if (tempFd < 0) { - device = DEVICE_PMEM_ADSP; - } else { - close(tempFd); - device = DEVICE_PMEM_SMIPOOL; - } + int err = 0; + size += offset; + void *base = mmap(0, size, PROT_READ| PROT_WRITE, + MAP_SHARED, fd, 0); + *pBase = base; + if(base == MAP_FAILED) { + LOGD("%s: Failed to map memory in the client: %s", + mPmemDev, strerror(errno)); + err = -errno; } else { - LOGE("Invalid device"); - return -EINVAL; + LOGD("%s: Mapped buffer base:%p size:%d offset:%d fd:%d", + mPmemDev, base, size, offset, fd); + } + return err; + +} + +int PmemUserspaceAlloc::unmap_buffer(void *base, size_t size, int offset) +{ + int err = 0; + //pmem hack + base = (void*)(intptr_t(base) - offset); + size += offset; + LOGD("%s: Unmapping buffer base:%p size:%d offset:%d", + mPmemDev , base, size, offset); + if (munmap(base, size) < 0) { + LOGE("Could not unmap %s", strerror(errno)); + err = -errno; } - int fd = deps.open(device, openFlags, 0); + return err; +} + +int PmemUserspaceAlloc::clean_buffer(void *base, size_t size, int offset, int fd) +{ + return cleanPmem(base, size, offset, fd); +} + + +//-------------- PmemKernelAlloc-----------------------// + +PmemKernelAlloc::PmemKernelAlloc(const char* pmemdev) : + mPmemDev(pmemdev) +{ +} + +PmemKernelAlloc::~PmemKernelAlloc() +{ +} + +int PmemKernelAlloc::alloc_buffer(alloc_data& data) +{ + int err, offset = 0; + int openFlags = getOpenFlags(data.uncached); + int size = data.size; + + int fd = open(mPmemDev, openFlags, 0); if (fd < 0) { - err = -deps.getErrno(); - END_FUNC; - LOGE("Error opening %s", device); + err = -errno; + LOGE("%s: Error opening %s", __FUNCTION__, mPmemDev); return err; } - // The size should already be page aligned, now round it up to a power of 2. - //size = clp2(size); - - if (format == HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED) { + if (data.align == 8192) { // Tile format buffers need physical alignment to 8K - err = deps.alignPmem(fd, size, 8192); + // Default page size does not need this ioctl + err = alignPmem(fd, size, 8192); if (err < 0) { LOGE("alignPmem failed"); } } - - void* base = deps.mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + void* base = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); if (base == MAP_FAILED) { - LOGE("%s: failed to map pmem fd: %s", device, - strerror(deps.getErrno())); - err = -deps.getErrno(); - deps.close(fd); - END_FUNC; + LOGE("%s: failed to map pmem fd: %s", mPmemDev, + strerror(errno)); + err = -errno; + close(fd); return err; } memset(base, 0, size); + //XXX: Flush here if cached + data.base = base; + data.offset = 0; + data.fd = fd; + return 0; +} + +int PmemKernelAlloc::free_buffer(void* base, size_t size, int offset, int fd) +{ + int err = unmap_buffer(base, size, offset); + close(fd); + return err; +} + +int PmemKernelAlloc::map_buffer(void **pBase, size_t size, int offset, int fd) +{ + int err = 0; + void *base = mmap(0, size, PROT_READ| PROT_WRITE, + MAP_SHARED, fd, 0); *pBase = base; - *pOffset = 0; - *pFd = fd; - - END_FUNC; - return 0; -} - - -int PmemKernelAllocator::free_pmem_buffer(size_t size, void* base, - int offset, int fd) -{ - BEGIN_FUNC; - // The size should already be page aligned, - // now round it up to a power of 2 - // like we did when allocating. - //size = clp2(size); - - int err = deps.munmap(base, size); - if (err < 0) { - err = deps.getErrno(); - LOGW("error unmapping pmem fd: %s", strerror(err)); - return -err; + if(base == MAP_FAILED) { + LOGD("%s: Failed to map memory in the client: %s", + __func__, strerror(errno)); + err = -errno; + } else { + LOGD("%s: Mapped %d bytes", __func__, size); } + return err; - END_FUNC; - return 0; } -PmemKernelAllocator::Deps::~Deps() +int PmemKernelAlloc::unmap_buffer(void *base, size_t size, int offset) { - BEGIN_FUNC; - END_FUNC; + int err = 0; + munmap(base, size); + if (err < 0) { + err = -errno; + LOGW("Error unmapping pmem fd: %s", strerror(err)); + } + return err; + } +int PmemKernelAlloc::clean_buffer(void *base, size_t size, int offset, int fd) +{ + return cleanPmem(base, size, offset, fd); +} + diff --git a/libgralloc/pmemalloc.h b/libgralloc/pmemalloc.h index 2a1c6fd..4aed0b1 100644 --- a/libgralloc/pmemalloc.h +++ b/libgralloc/pmemalloc.h @@ -1,161 +1,106 @@ /* - * Copyright (C) 2010 The Android Open Source Project + * Copyright (c) 2011, Code Aurora Forum. 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 Code Aurora Forum, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * 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. */ -#ifndef GRALLOC_QSD8K_PMEMALLOC_H -#define GRALLOC_QSD8K_PMEMALLOC_H +#ifndef GRALLOC_PMEMALLOC_H +#define GRALLOC_PMEMALLOC_H -#include -#include -#include -#include +#include +#include +#include "memalloc.h" +namespace gralloc { + class PmemUserspaceAlloc : public IMemAlloc { -/** - * An interface to the PMEM allocators. - */ -class PmemAllocator { + public: + class Allocator: public android::RefBase { + public: + virtual ~Allocator() {}; + virtual ssize_t setSize(size_t size) = 0; + virtual size_t size() const = 0; + virtual ssize_t allocate(size_t size, uint32_t flags = 0) = 0; + virtual ssize_t deallocate(size_t offset) = 0; + }; - public: + virtual int alloc_buffer(alloc_data& data); - virtual ~PmemAllocator(); + virtual int free_buffer(void *base, size_t size, + int offset, int fd); - // Only valid after init_pmem_area() has completed successfully. - virtual void* get_base_address() = 0; + virtual int map_buffer(void **pBase, size_t size, + int offset, int fd); - virtual int alloc_pmem_buffer(size_t size, int usage, void** pBase, - int* pOffset, int* pFd, int format) = 0; - virtual int free_pmem_buffer(size_t size, void* base, int offset, int fd) = 0; -}; + virtual int unmap_buffer(void *base, size_t size, + int offset); + virtual int clean_buffer(void*base, size_t size, + int offset, int fd); -/** - * A PMEM allocator that allocates the entire pmem memory from the kernel and - * then uses a user-space allocator to suballocate from that. This requires - * that the PMEM device driver have kernel allocation disabled. - */ -class PmemUserspaceAllocator: public PmemAllocator { + PmemUserspaceAlloc(); - public: + ~PmemUserspaceAlloc(); - class Deps { - public: + private: + int mMasterFd; + void* mMasterBase; + const char* mPmemDev; + android::sp mAllocator; + pthread_mutex_t mLock; + int init_pmem_area(); + int init_pmem_area_locked(); - class Allocator { - public: - virtual ~Allocator(); - virtual ssize_t setSize(size_t size) = 0; - virtual size_t size() const = 0; - virtual ssize_t allocate(size_t size, uint32_t flags = 0) = 0; - virtual ssize_t deallocate(size_t offset) = 0; - }; - - virtual ~Deps(); - - // pmem - virtual size_t getPmemTotalSize(int fd, size_t* size) = 0; - virtual int connectPmem(int fd, int master_fd) = 0; - virtual int mapPmem(int fd, int offset, size_t size) = 0; - virtual int unmapPmem(int fd, int offset, size_t size) = 0; - virtual int cleanPmem(int fd, unsigned long base, int offset, size_t size) = 0; - - // C99 - virtual int getErrno() = 0; - - // POSIX - virtual void* mmap(void* start, size_t length, int prot, int flags, int fd, - off_t offset) = 0; - virtual int open(const char* pathname, int flags, int mode) = 0; - virtual int close(int fd) = 0; }; - PmemUserspaceAllocator(Deps& deps, Deps::Allocator& allocator, const char* pmemdev); - virtual ~PmemUserspaceAllocator(); + class PmemKernelAlloc : public IMemAlloc { - // Only valid after init_pmem_area() has completed successfully. - virtual void* get_base_address(); + public: + virtual int alloc_buffer(alloc_data& data); - virtual int init_pmem_area_locked(); - virtual int init_pmem_area(); - virtual int alloc_pmem_buffer(size_t size, int usage, void** pBase, - int* pOffset, int* pFd, int format); - virtual int free_pmem_buffer(size_t size, void* base, int offset, int fd); + virtual int free_buffer(void *base, size_t size, + int offset, int fd); -#ifndef ANDROID_OS - // DO NOT USE: For testing purposes only. - void set_master_values(int fd, void* base) { - master_fd = fd; - master_base = base; - } -#endif // ANDROID_OS + virtual int map_buffer(void **pBase, size_t size, + int offset, int fd); + + virtual int unmap_buffer(void *base, size_t size, + int offset); + + virtual int clean_buffer(void*base, size_t size, + int offset, int fd); + + PmemKernelAlloc(const char* device); + + ~PmemKernelAlloc(); + private: + const char* mPmemDev; - private: - enum { - MASTER_FD_INIT = -1, }; - Deps& deps; - Deps::Allocator& allocator; - - pthread_mutex_t lock; - const char* pmemdev; - int master_fd; - void* master_base; -}; - - -/** - * A PMEM allocator that allocates each individual allocation from the kernel - * (using the kernel's allocator). This requires the kernel driver for the - * particular PMEM device being allocated from to support kernel allocation. - */ -class PmemKernelAllocator: public PmemAllocator { - - public: - - class Deps { - public: - - virtual ~Deps(); - - // C99 - virtual int getErrno() = 0; - - // POSIX - virtual void* mmap(void* start, size_t length, int prot, int flags, int fd, - off_t offset) = 0; - virtual int munmap(void* start, size_t length) = 0; - virtual int open(const char* pathname, int flags, int mode) = 0; - virtual int close(int fd) = 0; - virtual int alignPmem(int fd, size_t size, int align) = 0; - }; - - PmemKernelAllocator(Deps& deps); - virtual ~PmemKernelAllocator(); - - // Only valid after init_pmem_area() has completed successfully. - virtual void* get_base_address(); - - virtual int alloc_pmem_buffer(size_t size, int usage, void** pBase, - int* pOffset, int* pFd, int format); - virtual int free_pmem_buffer(size_t size, void* base, int offset, int fd); - - private: - - Deps& deps; -}; - -#endif // GRALLOC_QSD8K_PMEMALLOC_H +} +#endif /* GRALLOC_PMEMALLOC_H */