initial GL libraries for msm8960

Change-Id: I16451c70a079894ac326d3564d96f1fbafcd4f1b
Signed-off-by: Iliyan Malchev <malchev@google.com>
diff --git a/libgralloc/pmemalloc.cpp b/libgralloc/pmemalloc.cpp
new file mode 100644
index 0000000..ccbf127
--- /dev/null
+++ b/libgralloc/pmemalloc.cpp
@@ -0,0 +1,388 @@
+/*
+ * 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.
+ *
+ * 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 <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <stdlib.h>
+#include <cutils/log.h>
+#include <errno.h>
+#include <linux/android_pmem.h>
+#include "gralloc_priv.h"
+#include "pmemalloc.h"
+#include "pmem_bestfit_alloc.h"
+
+using namespace gralloc;
+using android::sp;
+
+// Common functions between userspace
+// and kernel allocators
+static int getPmemTotalSize(int fd, size_t* size)
+{
+    //XXX: 7x27
+    int err = 0;
+    pmem_region region;
+    if (ioctl(fd, PMEM_GET_TOTAL_SIZE, &region)) {
+        err = -errno;
+    } else {
+        *size = region.len;
+    }
+    return err;
+}
+
+static int getOpenFlags(bool uncached)
+{
+    if(uncached)
+        return O_RDWR | O_SYNC;
+    else
+        return O_RDWR;
+}
+
+static int connectPmem(int fd, int master_fd) {
+    if (ioctl(fd, PMEM_CONNECT, master_fd))
+        return -errno;
+    return 0;
+}
+
+static int mapSubRegion(int fd, int offset, size_t size) {
+    struct pmem_region sub = { offset, size };
+    if (ioctl(fd, PMEM_MAP, &sub))
+        return -errno;
+    return 0;
+}
+
+static int unmapSubRegion(int fd, int offset, size_t size) {
+    struct pmem_region sub = { offset, size };
+    if (ioctl(fd, PMEM_UNMAP, &sub))
+        return -errno;
+    return 0;
+}
+
+static int alignPmem(int fd, size_t size, int align) {
+    struct pmem_allocation allocation;
+    allocation.size = size;
+    allocation.align = align;
+    if (ioctl(fd, PMEM_ALLOCATE_ALIGNED, &allocation))
+        return -errno;
+    return 0;
+}
+
+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;
+    if (ioctl(fd, PMEM_CLEAN_INV_CACHES, &pmem_addr))
+        return -errno;
+    return 0;
+}
+
+//-------------- 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()
+{
+    ALOGD("%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);
+        ALOGD("%s: Total pmem size: %d", __FUNCTION__, size);
+        if (err < 0) {
+            ALOGE("%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) {
+            err = -errno;
+            ALOGE("%s: Failed to map pmem master fd: %s", mPmemDev,
+                    strerror(errno));
+            base = 0;
+            close(fd);
+            fd = -1;
+        } else {
+            mMasterFd = fd;
+            mMasterBase = base;
+        }
+    } else {
+        err = -errno;
+        ALOGE("%s: Failed to open pmem device: %s", mPmemDev,
+                strerror(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
+        ALOGD("%s: Initializing pmem area", __FUNCTION__);
+        err = init_pmem_area_locked();
+        if (err) {
+            ALOGE("%s: failed to initialize pmem area", mPmemDev);
+            mMasterFd = err;
+        }
+    } else if (err < 0) {
+        // pmem couldn't be initialized, never use it
+    } else {
+        // pmem OK
+        err = 0;
+    }
+    pthread_mutex_unlock(&mLock);
+    return err;
+
+}
+
+int PmemUserspaceAlloc::alloc_buffer(alloc_data& data)
+{
+    int err = init_pmem_area();
+    if (err == 0) {
+        void* base = mMasterBase;
+        size_t size = data.size;
+        int offset = mAllocator->allocate(size);
+        if (offset < 0) {
+            // no more pmem memory
+            ALOGE("%s: No more pmem available", mPmemDev);
+            err = -ENOMEM;
+        } else {
+            int openFlags = getOpenFlags(data.uncached);
+
+            // now create the "sub-heap"
+            int fd = open(mPmemDev, openFlags, 0);
+            err = fd < 0 ? fd : 0;
+
+            // and connect to it
+            if (err == 0)
+                err = connectPmem(fd, mMasterFd);
+
+            // and make it available to the client process
+            if (err == 0)
+                err = mapSubRegion(fd, offset, size);
+
+            if (err < 0) {
+                ALOGE("%s: Failed to initialize pmem sub-heap: %d", mPmemDev,
+                        err);
+                close(fd);
+                mAllocator->deallocate(offset);
+                fd = -1;
+            } else {
+                ALOGD("%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 = clean_buffer((void*)((intptr_t) base + offset), size, offset, fd);
+                if (err < 0) {
+                    ALOGE("cleanPmem failed: (%s)", strerror(errno));
+                }
+                cacheflush(intptr_t(base) + offset, intptr_t(base) + offset + size, 0);
+                data.base = base;
+                data.offset = offset;
+                data.fd = fd;
+            }
+        }
+    }
+    return err;
+
+}
+
+int PmemUserspaceAlloc::free_buffer(void* base, size_t size, int offset, int fd)
+{
+    ALOGD("%s: Freeing buffer base:%p size:%d offset:%d fd:%d",
+            mPmemDev, base, size, offset, fd);
+    int err = 0;
+    if (fd >= 0) {
+        int err = unmapSubRegion(fd, offset, size);
+        ALOGE_IF(err<0, "PMEM_UNMAP failed (%s), fd=%d, sub.offset=%u, "
+                "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.
+            mAllocator->deallocate(offset);
+        }
+        close(fd);
+    }
+    return err;
+}
+
+int PmemUserspaceAlloc::map_buffer(void **pBase, size_t size, int offset, int fd)
+{
+    int err = 0;
+    size += offset;
+    void *base = mmap(0, size, PROT_READ| PROT_WRITE,
+            MAP_SHARED, fd, 0);
+    *pBase = base;
+    if(base == MAP_FAILED) {
+        err = -errno;
+        ALOGE("%s: Failed to map buffer size:%d offset:%d fd:%d Error: %s",
+                mPmemDev, size, offset, fd, strerror(errno));
+    } else {
+        ALOGD("%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;
+    ALOGD("%s: Unmapping buffer base:%p size:%d offset:%d",
+            mPmemDev , base, size, offset);
+    if (munmap(base, size) < 0) {
+
+        err = -errno;
+        ALOGE("%s: Failed to unmap memory at %p :%s",
+                   mPmemDev, base, strerror(errno));
+
+    }
+
+   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 = -errno;
+        ALOGE("%s: Error opening %s", __FUNCTION__, mPmemDev);
+        return err;
+    }
+
+    if (data.align == 8192) {
+        // Tile format buffers need physical alignment to 8K
+        // Default page size does not need this ioctl
+        err = alignPmem(fd, size, 8192);
+        if (err < 0) {
+            ALOGE("alignPmem failed");
+        }
+    }
+    void* base = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+    if (base == MAP_FAILED) {
+        err = -errno;
+        ALOGE("%s: failed to map pmem fd: %s", mPmemDev,
+                strerror(errno));
+        close(fd);
+        return err;
+    }
+    memset(base, 0, size);
+    clean_buffer((void*)((intptr_t) base + offset), size, offset, fd);
+    data.base = base;
+    data.offset = 0;
+    data.fd = fd;
+    ALOGD("%s: Allocated buffer base:%p size:%d fd:%d",
+                            mPmemDev, base, size, fd);
+    return 0;
+
+}
+
+int PmemKernelAlloc::free_buffer(void* base, size_t size, int offset, int fd)
+{
+    ALOGD("%s: Freeing buffer base:%p size:%d fd:%d",
+            mPmemDev, base, size, 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;
+    if(base == MAP_FAILED) {
+        err = -errno;
+        ALOGE("%s: Failed to map memory in the client: %s",
+                mPmemDev, strerror(errno));
+    } else {
+        ALOGD("%s: Mapped buffer base:%p size:%d, fd:%d",
+                                mPmemDev, base, size, fd);
+    }
+    return err;
+
+}
+
+int PmemKernelAlloc::unmap_buffer(void *base, size_t size, int offset)
+{
+    int err = 0;
+    if (munmap(base, size)) {
+        err = -errno;
+        ALOGW("%s: Error unmapping memory at %p: %s",
+                                mPmemDev, base, strerror(err));
+    }
+    return err;
+
+}
+int PmemKernelAlloc::clean_buffer(void *base, size_t size, int offset, int fd)
+{
+    return cleanPmem(base, size, offset, fd);
+}
+