aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/samsung/mfc5x/mfc_buf.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/samsung/mfc5x/mfc_buf.c')
-rw-r--r--drivers/media/video/samsung/mfc5x/mfc_buf.c1037
1 files changed, 1037 insertions, 0 deletions
diff --git a/drivers/media/video/samsung/mfc5x/mfc_buf.c b/drivers/media/video/samsung/mfc5x/mfc_buf.c
new file mode 100644
index 0000000..e0e243d
--- /dev/null
+++ b/drivers/media/video/samsung/mfc5x/mfc_buf.c
@@ -0,0 +1,1037 @@
+/*
+ * linux/drivers/media/video/samsung/mfc5x/mfc_buf.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Buffer manager for Samsung MFC (Multi Function Codec - FIMV) driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/err.h>
+
+#include "mfc.h"
+#include "mfc_mem.h"
+#include "mfc_buf.h"
+#include "mfc_log.h"
+#include "mfc_errno.h"
+
+#ifdef CONFIG_VIDEO_MFC_VCM_UMP
+#include <plat/s5p-vcm.h>
+
+#include "ump_kernel_interface.h"
+#include "ump_kernel_interface_ref_drv.h"
+#include "ump_kernel_interface_vcm.h"
+#endif
+
+#define PRINT_BUF
+#undef DEBUG_ALLOC_FREE
+
+static struct list_head mfc_alloc_head[MFC_MAX_MEM_PORT_NUM];
+/* The free node list sorted by real address */
+static struct list_head mfc_free_head[MFC_MAX_MEM_PORT_NUM];
+
+#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
+static enum MFC_BUF_ALLOC_SCHEME buf_alloc_scheme = MBS_FIRST_FIT;
+#else
+static enum MFC_BUF_ALLOC_SCHEME buf_alloc_scheme = MBS_BEST_FIT;
+#endif
+
+/* FIXME: test locking, add locking mechanisim */
+/*
+static spinlock_t lock;
+*/
+
+
+void mfc_print_buf(void)
+{
+#ifdef PRINT_BUF
+ struct list_head *pos;
+ struct mfc_alloc_buffer *alloc = NULL;
+ struct mfc_free_buffer *free = NULL;
+ int port, i;
+
+ for (port = 0; port < mfc_mem_count(); port++) {
+ mfc_dbg("---- port %d buffer list ----", port);
+
+ i = 0;
+ list_for_each(pos, &mfc_alloc_head[port]) {
+ alloc = list_entry(pos, struct mfc_alloc_buffer, list);
+ mfc_dbg("[A #%04d] addr: 0x%08x, size: %d",
+ i, (unsigned int)alloc->addr, alloc->size);
+ mfc_dbg("\t real: 0x%08lx", alloc->real);
+ mfc_dbg("\t type: 0x%08x, owner: %d",
+ alloc->type, alloc->owner);
+#if defined(CONFIG_VIDEO_MFC_VCM_UMP)
+ mfc_dbg("\t* vcm sysmmu");
+ if (alloc->vcm_s) {
+ mfc_dbg("\t start: 0x%08x, res_size : 0x%08x\n",
+ (unsigned int)alloc->vcm_s->res.start,
+ (unsigned int)alloc->vcm_s->res.res_size);
+ mfc_dbg("\t bound_size: 0x%08x\n",
+ (unsigned int)alloc->vcm_s->res.bound_size);
+ }
+
+ mfc_dbg("\t* vcm kernel");
+ if (alloc->vcm_k) {
+ mfc_dbg("\t start: 0x%08x, res_size : 0x%08x\n",
+ (unsigned int)alloc->vcm_k->start,
+ (unsigned int)alloc->vcm_k->res_size);
+ mfc_dbg("\t bound_size: 0x%08x\n",
+ (unsigned int)alloc->vcm_k->bound_size);
+ }
+
+ mfc_dbg("\t* ump");
+ if (alloc->ump_handle) {
+ mfc_dbg("\t secure id: 0x%08x",
+ mfc_ump_get_id(alloc->ump_handle));
+ }
+#elif defined(CONFIG_S5P_VMEM)
+ mfc_dbg("\t vmem cookie: 0x%08x addr: 0x%08lx, size: %d",
+ alloc->vmem_cookie, alloc->vmem_addr,
+ alloc->vmem_size);
+#else
+ mfc_dbg("\t offset: 0x%08x", alloc->ofs);
+#endif
+ i++;
+ }
+
+ i = 0;
+ list_for_each(pos, &mfc_free_head[port]) {
+ free = list_entry(pos, struct mfc_free_buffer, list);
+ mfc_dbg("[F #%04d] addr: 0x%08lx, size: %d",
+ i, free->real, free->size);
+ i++;
+ }
+ }
+#endif
+}
+
+static int mfc_put_free_buf(unsigned long addr, unsigned int size, int port)
+{
+ struct list_head *pos, *nxt;
+ struct mfc_free_buffer *free;
+ struct mfc_free_buffer *next = NULL;
+ struct mfc_free_buffer *prev;
+ /* 0x00: not merged, 0x01: prev merged, 0x02: next merged */
+ int merged = 0x00;
+
+ if (!size)
+ return -EINVAL;
+
+ mfc_dbg("addr: 0x%08lx, size: %d, port: %d\n", addr, size, port);
+
+ list_for_each_safe(pos, nxt, &mfc_free_head[port]) {
+ next = list_entry(pos, struct mfc_free_buffer, list);
+
+ /*
+ * When the allocated address must be align without VMEM,
+ * the free buffer can be overlap
+ * previous free buffer temporaily
+ * Target buffer will be shrink after this operation
+ */
+ if (addr <= next->real) {
+ prev = list_entry(pos->prev, struct mfc_free_buffer, list);
+
+ mfc_dbg("prev->addr: 0x%08lx, size: %d", prev->real, prev->size);
+ /* merge previous free buffer */
+ if (prev && ((prev->real + prev->size) == addr)) {
+ addr = prev->real;
+ size += prev->size;
+
+ prev->size = size;
+
+ merged |= 0x01;
+ mfc_dbg("auto merge free buffer[p]: addr: 0x%08lx, size: %d",
+ prev->real, prev->size);
+ }
+
+ mfc_dbg("next->addr: 0x%08lx, size: %d", next->real, next->size);
+ /* merge next free buffer */
+ if ((addr + size) == next->real) {
+ next->real = addr;
+ next->size += size;
+
+ if (merged)
+ prev->size = next->size;
+
+ merged |= 0x02;
+ mfc_dbg("auto merge free buffer[n]: addr: 0x%08lx, size: %d",
+ next->real, next->size);
+ }
+
+ break;
+ }
+ }
+
+ if (!merged) {
+ free = (struct mfc_free_buffer *)
+ kzalloc(sizeof(struct mfc_free_buffer), GFP_KERNEL);
+
+ if (unlikely(free == NULL))
+ return -ENOMEM;
+
+ free->real = addr;
+ free->size = size;
+
+ list_add_tail(&free->list, pos);
+ }
+
+ /* bi-directional merged */
+ else if ((merged & 0x03) == 0x03) {
+ list_del(&next->list);
+ kfree(next);
+ }
+
+ return 0;
+}
+
+static unsigned long mfc_get_free_buf(unsigned int size, int align, int port)
+{
+ struct list_head *pos, *nxt;
+ struct mfc_free_buffer *free;
+ struct mfc_free_buffer *match = NULL;
+ int align_size = 0;
+ unsigned long addr = 0;
+
+ mfc_dbg("size: %d, align: %d, port: %d\n",
+ size, align, port);
+
+ if (list_empty(&mfc_free_head[port])) {
+ mfc_err("no free node in mfc buffer\n");
+
+ return 0;
+ }
+
+ /* find best fit area */
+ list_for_each_safe(pos, nxt, &mfc_free_head[port]) {
+ free = list_entry(pos, struct mfc_free_buffer, list);
+
+#if (defined(CONFIG_VIDEO_MFC_VCM_UMP) || defined(CONFIG_S5P_VMEM))
+ /*
+ * Align the start address.
+ * We assume the start address of free buffer aligned with 4KB
+ */
+ align_size = ALIGN(align_size + size, PAGE_SIZE) - size;
+
+ if (align > PAGE_SIZE) {
+ align_size = ALIGN(free->real, align) - free->real;
+ align_size += ALIGN(align_size + size, PAGE_SIZE) - size;
+ } else {
+ align_size = ALIGN(align_size + size, PAGE_SIZE) - size;
+ }
+#else
+ align_size = ALIGN(free->real, align) - free->real;
+#endif
+ if (free->size >= (size + align_size)) {
+ if (buf_alloc_scheme == MBS_BEST_FIT) {
+ if (match != NULL) {
+ if (free->size < match->size)
+ match = free;
+ } else {
+ match = free;
+ }
+ } else if (buf_alloc_scheme == MBS_FIRST_FIT) {
+ match = free;
+ break;
+ }
+ }
+ }
+
+ if (match != NULL) {
+ addr = match->real;
+ align_size = ALIGN(addr, align) - addr;
+
+#if !(defined(CONFIG_VIDEO_MFC_VCM_UMP) || defined(CONFIG_S5P_VMEM))
+ if (align_size > 0) {
+ /*
+ * When the allocated address must be align without VMEM,
+ * the free buffer can be overlap
+ * previous free buffer temporaily
+ */
+ if (mfc_put_free_buf(match->real, align_size, port) < 0)
+ return 0;
+ }
+#endif
+ /* change allocated buffer address & size */
+ match->real += (size + align_size);
+ match->size -= (size + align_size);
+
+ if (match->size == 0) {
+ list_del(&match->list);
+ kfree(match);
+ }
+ } else {
+ mfc_err("no suitable free node in mfc buffer\n");
+
+ return 0;
+ }
+
+ return addr;
+}
+
+int mfc_init_buf(void)
+{
+#ifndef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
+ int port;
+#endif
+ int ret = 0;
+
+#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
+ INIT_LIST_HEAD(&mfc_alloc_head[0]);
+ INIT_LIST_HEAD(&mfc_free_head[0]);
+
+ if (mfc_put_free_buf(mfc_mem_data_base(0),
+ mfc_mem_data_size(0), 0) < 0)
+ mfc_err("failed to add free buffer: [0x%08lx: %d]\n",
+ mfc_mem_data_base(0), mfc_mem_data_size(0));
+
+ if (mfc_put_free_buf(mfc_mem_data_base(1),
+ mfc_mem_data_size(1), 0) < 0)
+ mfc_dbg("failed to add free buffer: [0x%08lx: %d]\n",
+ mfc_mem_data_base(1), mfc_mem_data_size(1));
+
+ if (list_empty(&mfc_free_head[0]))
+ ret = -1;
+
+#else
+ for (port = 0; port < mfc_mem_count(); port++) {
+ INIT_LIST_HEAD(&mfc_alloc_head[port]);
+ INIT_LIST_HEAD(&mfc_free_head[port]);
+
+ if (mfc_put_free_buf(mfc_mem_data_base(port),
+ mfc_mem_data_size(port), port) < 0)
+ mfc_err("failed to add free buffer: [0x%08lx: %d]\n",
+ mfc_mem_data_base(port),
+ mfc_mem_data_size(port));
+ }
+
+ for (port = 0; port < mfc_mem_count(); port++) {
+ if (list_empty(&mfc_free_head[port]))
+ ret = -1;
+ }
+#endif
+
+ /*
+ spin_lock_init(&lock);
+ */
+
+ mfc_print_buf();
+
+ return ret;
+}
+
+void mfc_final_buf(void)
+{
+ struct list_head *pos, *nxt;
+ struct mfc_alloc_buffer *alloc;
+ struct mfc_free_buffer *free;
+ int port;
+ /*
+ unsigned long flags;
+ */
+
+ /*
+ spin_lock_irqsave(&lock, flags);
+ */
+
+ for (port = 0; port < mfc_mem_count(); port++) {
+ list_for_each_safe(pos, nxt, &mfc_alloc_head[port]) {
+ alloc = list_entry(pos, struct mfc_alloc_buffer, list);
+#if defined(CONFIG_VIDEO_MFC_VCM_UMP)
+ if (alloc->ump_handle)
+ mfc_ump_unmap(alloc->ump_handle);
+
+ if (alloc->vcm_k)
+ mfc_vcm_unmap(alloc->vcm_k);
+
+ if (alloc->vcm_s)
+ mfc_vcm_unbind(alloc->vcm_s,
+ alloc->type & MBT_OTHER);
+
+ if (mfc_put_free_buf(alloc->vcm_addr,
+ alloc->vcm_size, port) < 0) {
+
+ mfc_err("failed to add free buffer\n");
+ } else {
+ list_del(&alloc->list);
+ kfree(alloc);
+ }
+#elif defined(CONFIG_S5P_VMEM)
+ if (alloc->vmem_cookie)
+ s5p_vfree(alloc->vmem_cookie);
+
+ if (mfc_put_free_buf(alloc->vmem_addr,
+ alloc->vmem_size, port) < 0) {
+
+ mfc_err("failed to add free buffer\n");
+ } else {
+ list_del(&alloc->list);
+ kfree(alloc);
+ }
+#else
+ if (mfc_put_free_buf(alloc->real,
+ alloc->size, port) < 0) {
+
+ mfc_err("failed to add free buffer\n");
+ } else {
+ list_del(&alloc->list);
+ kfree(alloc);
+ }
+#endif
+ }
+ }
+
+ /*
+ spin_unlock_irqrestore(&lock, flags);
+ */
+
+ mfc_print_buf();
+
+ /*
+ spin_lock_irqsave(&lock, flags);
+ */
+
+ for (port = 0; port < mfc_mem_count(); port++) {
+ list_for_each_safe(pos, nxt, &mfc_free_head[port]) {
+ free = list_entry(pos, struct mfc_free_buffer, list);
+ list_del(&free->list);
+ kfree(free);
+ }
+ }
+
+ /*
+ spin_unlock_irqrestore(&lock, flags);
+ */
+
+ mfc_print_buf();
+}
+
+void mfc_set_buf_alloc_scheme(enum MFC_BUF_ALLOC_SCHEME scheme)
+{
+ buf_alloc_scheme = scheme;
+}
+
+void mfc_merge_buf(void)
+{
+ struct list_head *pos, *nxt;
+ struct mfc_free_buffer *n1;
+ struct mfc_free_buffer *n2;
+ int port;
+
+ for (port = 0; port < mfc_mem_count(); port++) {
+ list_for_each_safe(pos, nxt, &mfc_free_head[port]) {
+ n1 = list_entry(pos, struct mfc_free_buffer, list);
+ n2 = list_entry(nxt, struct mfc_free_buffer, list);
+
+ mfc_dbg("merge pre: n1: 0x%08lx, n2: 0x%08lx",
+ n1->real, n2->real);
+
+ if (!list_is_last(pos, &mfc_free_head[port])) {
+ if ((n1->real + n1->size) == n2->real) {
+ n2->real = n1->real;
+ n2->size += n1->size;
+ list_del(&n1->list);
+ kfree(n1);
+ }
+ }
+
+ mfc_dbg("merge aft: n1: 0x%08lx, n2: 0x%08lx, last: %d",
+ n1->real, n2->real,
+ list_is_last(pos, &mfc_free_head[port]));
+ }
+ }
+
+#ifdef DEBUG_ALLOC_FREE
+ mfc_print_buf();
+#endif
+}
+
+/* FIXME: port auto select, return values */
+struct mfc_alloc_buffer *_mfc_alloc_buf(
+ struct mfc_inst_ctx *ctx, unsigned int size, int align, int flag)
+{
+ unsigned long addr;
+ struct mfc_alloc_buffer *alloc;
+ int port = flag & 0xFFFF;
+#if defined(CONFIG_VIDEO_MFC_VCM_UMP)
+ int align_size = 0;
+ struct ump_vcm ump_vcm;
+#elif defined(CONFIG_S5P_VMEM)
+ int align_size = 0;
+#endif
+ /*
+ unsigned long flags;
+ */
+
+ if (!size)
+ return NULL;
+
+ alloc = (struct mfc_alloc_buffer *)
+ kzalloc(sizeof(struct mfc_alloc_buffer), GFP_KERNEL);
+
+ if (unlikely(alloc == NULL))
+ return NULL;
+
+ /* FIXME: right position? */
+ if (port > (mfc_mem_count() - 1))
+ port = mfc_mem_count() - 1;
+
+ /*
+ spin_lock_irqsave(&lock, flags);
+ */
+
+ addr = mfc_get_free_buf(size, align, port);
+
+ mfc_dbg("mfc_get_free_buf: 0x%08lx\n", addr);
+
+ if (!addr) {
+ mfc_dbg("cannot get suitable free buffer\n");
+ /* FIXME: is it need?
+ mfc_put_free_buf(addr, size, port);
+ */
+ kfree(alloc);
+ /*
+ spin_unlock_irqrestore(&lock, flags);
+ */
+
+ return NULL;
+ }
+
+#if defined(CONFIG_VIDEO_MFC_VCM_UMP)
+ if (align > PAGE_SIZE) {
+ align_size = ALIGN(addr, align) - addr;
+ align_size += ALIGN(align_size + size, PAGE_SIZE) - size;
+ } else {
+ align_size = ALIGN(align_size + size, PAGE_SIZE) - size;
+ }
+
+ alloc->vcm_s = mfc_vcm_bind(addr, size + align_size);
+ if (IS_ERR(alloc->vcm_s)) {
+ mfc_put_free_buf(addr, size, port);
+ kfree(alloc);
+
+ return NULL;
+ /*
+ return PTR_ERR(alloc->vcm_s);
+ */
+ }
+
+ if (flag & MBT_KERNEL) {
+ alloc->vcm_k = mfc_vcm_map(alloc->vcm_s->res.phys);
+ if (IS_ERR(alloc->vcm_k)) {
+ mfc_vcm_unbind(alloc->vcm_s,
+ alloc->type & MBT_OTHER);
+ mfc_put_free_buf(addr, size, port);
+ kfree(alloc);
+
+ return NULL;
+ /*
+ return PTR_ERR(alloc->vcm_k);
+ */
+ }
+ }
+
+ if (flag & MBT_USER) {
+ ump_vcm.vcm = alloc->vcm_s->res.vcm;
+ ump_vcm.vcm_res = &(alloc->vcm_s->res);
+ ump_vcm.dev_id = VCM_DEV_MFC;
+
+ alloc->ump_handle = mfc_ump_map(alloc->vcm_s->res.phys, (unsigned long)&ump_vcm);
+ if (IS_ERR(alloc->ump_handle)) {
+ mfc_vcm_unmap(alloc->vcm_k);
+ mfc_vcm_unbind(alloc->vcm_s,
+ alloc->type & MBT_OTHER);
+ mfc_put_free_buf(addr, size, port);
+ kfree(alloc);
+
+ return NULL;
+ /*
+ return PTR_ERR(alloc->vcm_k);
+ */
+ }
+ }
+
+ alloc->vcm_addr = addr;
+ alloc->vcm_size = size + align_size;
+#elif defined(CONFIG_S5P_VMEM)
+ if (align > PAGE_SIZE) {
+ align_size = ALIGN(addr, align) - addr;
+ align_size += ALIGN(align_size + size, PAGE_SIZE) - size;
+ } else {
+ align_size = ALIGN(align_size + size, PAGE_SIZE) - size;
+ }
+
+ alloc->vmem_cookie = s5p_vmem_vmemmap(size + align_size,
+ addr, addr + (size + align_size));
+
+ if (!alloc->vmem_cookie) {
+ mfc_dbg("cannot map free buffer to memory\n");
+ mfc_put_free_buf(addr, size, port);
+ kfree(alloc);
+
+ return NULL;
+ }
+
+ alloc->vmem_addr = addr;
+ alloc->vmem_size = size + align_size;
+#endif
+ alloc->real = ALIGN(addr, align);
+ alloc->size = size;
+
+#if defined(CONFIG_VIDEO_MFC_VCM_UMP)
+ if (alloc->vcm_k)
+ alloc->addr = (unsigned char *)alloc->vcm_k->start;
+ else
+ alloc->addr = NULL;
+#elif defined(CONFIG_S5P_VMEM)
+ alloc->addr = (unsigned char *)(mfc_mem_addr(port) +
+ mfc_mem_base_ofs(alloc->real));
+#else
+ alloc->addr = (unsigned char *)(mfc_mem_addr(port) +
+ mfc_mem_base_ofs(alloc->real));
+ /*
+ alloc->user = (unsigned char *)(ctx->userbase +
+ mfc_mem_data_ofs(alloc->real, 1));
+ */
+ alloc->ofs = mfc_mem_data_ofs(alloc->real, 1);
+#endif
+ alloc->type = flag & 0xFFFF0000;
+ alloc->owner = ctx->id;
+
+ list_add(&alloc->list, &mfc_alloc_head[port]);
+
+ /*
+ spin_unlock_irqrestore(&lock, flags);
+ */
+
+#ifdef DEBUG_ALLOC_FREE
+ mfc_print_buf();
+#endif
+
+ return alloc;
+}
+
+#if defined(CONFIG_VIDEO_MFC_VCM_UMP)
+unsigned int mfc_vcm_bind_from_others(struct mfc_inst_ctx *ctx,
+ struct mfc_buf_alloc_arg *args, int flag)
+{
+ int ret;
+ unsigned long addr;
+ unsigned int size;
+ unsigned int secure_id = args->secure_id;
+ int port = flag & 0xFFFF;
+
+ struct vcm_res *vcm_res;
+ struct vcm_mmu_res *s_res;
+ struct mfc_alloc_buffer *alloc;
+
+ ump_dd_handle ump_mem;
+
+ /* FIXME: right position? */
+ if (port > (mfc_mem_count() - 1))
+ port = mfc_mem_count() - 1;
+
+ ump_mem = ump_dd_handle_create_from_secure_id(secure_id);
+ ump_dd_reference_add(ump_mem);
+
+ vcm_res = (struct vcm_res *)
+ ump_dd_meminfo_get(secure_id, (void*)VCM_DEV_MFC);
+ if (!vcm_res) {
+ mfc_dbg("%s: Failed to get vcm_res\n", __func__);
+ goto err_ret;
+ }
+
+ size = vcm_res->bound_size;
+
+ alloc = (struct mfc_alloc_buffer *)
+ kzalloc(sizeof(struct mfc_alloc_buffer), GFP_KERNEL);
+ if(!alloc) {
+ mfc_dbg("%s: Failed to get mfc_alloc_buffer\n", __func__);
+ goto err_ret;
+ }
+
+ addr = mfc_get_free_buf(size, ALIGN_2KB, port);
+ if (!addr) {
+ mfc_dbg("cannot get suitable free buffer\n");
+ goto err_ret_alloc;
+ }
+ mfc_dbg("mfc_get_free_buf: 0x%08lx\n", addr);
+
+ s_res = kzalloc(sizeof(struct vcm_mmu_res), GFP_KERNEL);
+ if (!s_res) {
+ mfc_dbg("%s: Failed to get vcm_mmu_res\n", __func__);
+ goto err_ret_alloc;
+ }
+
+ s_res->res.start = addr;
+ s_res->res.res_size = size;
+ s_res->res.vcm = ctx->dev->vcm_info.sysmmu_vcm;
+ INIT_LIST_HEAD(&s_res->bound);
+
+ ret = vcm_bind(&s_res->res, vcm_res->phys);
+ if (ret < 0) {
+ mfc_dbg("%s: Failed to vcm_bind\n", __func__);
+ goto err_ret_s_res;
+ }
+
+ alloc->vcm_s = s_res;
+ alloc->vcm_addr = addr;
+ alloc->ump_handle = ump_mem;
+ alloc->vcm_size = size;
+ alloc->real = addr;
+ alloc->size = size;
+ alloc->type = flag & 0xFFFF0000;
+ alloc->owner = ctx->id;
+
+ list_add(&alloc->list, &mfc_alloc_head[port]);
+
+ mfc_print_buf();
+
+ return 0;
+
+err_ret_s_res:
+ kfree(s_res);
+err_ret_alloc:
+ kfree(alloc);
+err_ret:
+ return -1;
+}
+#endif
+
+int
+mfc_alloc_buf(struct mfc_inst_ctx *ctx, struct mfc_buf_alloc_arg *args, int flag)
+{
+ struct mfc_alloc_buffer *alloc;
+
+ alloc = _mfc_alloc_buf(ctx, args->size, args->align, flag);
+
+ if (unlikely(alloc == NULL))
+ return MFC_MEM_ALLOC_FAIL;
+ /*
+ args->phys = (unsigned int)alloc->real;
+ */
+ args->addr = (unsigned int)alloc->addr;
+#if defined(CONFIG_VIDEO_MFC_VCM_UMP)
+ if (alloc->ump_handle)
+ args->secure_id = mfc_ump_get_id(alloc->ump_handle);
+#elif defined(CONFIG_S5P_VMEM)
+ args->cookie = (unsigned int)alloc->vmem_cookie;
+#else
+ args->offset = alloc->ofs;
+#endif
+ return MFC_OK;
+}
+
+int _mfc_free_buf(unsigned long real)
+{
+ struct list_head *pos, *nxt;
+ struct mfc_alloc_buffer *alloc;
+ int port;
+ int found = 0;
+ /*
+ unsigned long flags;
+ */
+
+ mfc_dbg("addr: 0x%08lx\n", real);
+
+ /*
+ spin_lock_irqsave(&lock, flags);
+ */
+
+ for (port = 0; port < mfc_mem_count(); port++) {
+ list_for_each_safe(pos, nxt, &mfc_alloc_head[port]) {
+ alloc = list_entry(pos, struct mfc_alloc_buffer, list);
+
+ if (alloc->real == real) {
+ found = 1;
+#if defined(CONFIG_VIDEO_MFC_VCM_UMP)
+ if (alloc->ump_handle)
+ mfc_ump_unmap(alloc->ump_handle);
+
+ if (alloc->vcm_k)
+ mfc_vcm_unmap(alloc->vcm_k);
+
+ if (alloc->vcm_s)
+ mfc_vcm_unbind(alloc->vcm_s,
+ alloc->type & MBT_OTHER);
+
+ if (mfc_put_free_buf(alloc->vcm_addr,
+ alloc->vcm_size, port) < 0) {
+
+ mfc_err("failed to add free buffer\n");
+ } else {
+ list_del(&alloc->list);
+ kfree(alloc);
+ }
+#elif defined(CONFIG_S5P_VMEM)
+ if (alloc->vmem_cookie)
+ s5p_vfree(alloc->vmem_cookie);
+
+ if (mfc_put_free_buf(alloc->vmem_addr,
+ alloc->vmem_size, port) < 0) {
+
+ mfc_err("failed to add free buffer\n");
+ } else {
+ list_del(&alloc->list);
+ kfree(alloc);
+ }
+#else
+ if (mfc_put_free_buf(alloc->real,
+ alloc->size, port) < 0) {
+
+ mfc_err("failed to add free buffer\n");
+ } else {
+ list_del(&alloc->list);
+ kfree(alloc);
+ }
+#endif
+ break;
+ }
+ }
+
+ if (found)
+ break;
+ }
+
+ /*
+ spin_unlock_irqrestore(&lock, flags);
+ */
+
+#ifdef DEBUG_ALLOC_FREE
+ mfc_print_buf();
+#endif
+
+ if (found)
+ return 0;
+
+ return -1;
+}
+
+int mfc_free_buf(struct mfc_inst_ctx *ctx, unsigned int key)
+{
+ unsigned long real;
+
+ real = mfc_get_buf_real(ctx->id, key);
+ if (unlikely(real == 0))
+ return MFC_MEM_INVALID_ADDR_FAIL;
+
+ if (_mfc_free_buf(real) < 0)
+ return MFC_MEM_INVALID_ADDR_FAIL;
+
+ return MFC_OK;
+}
+
+void mfc_free_buf_type(int owner, int type)
+{
+ int port;
+ struct list_head *pos, *nxt;
+ struct mfc_alloc_buffer *alloc;
+
+ for (port = 0; port < mfc_mem_count(); port++) {
+ list_for_each_safe(pos, nxt, &mfc_alloc_head[port]) {
+ alloc = list_entry(pos, struct mfc_alloc_buffer, list);
+
+ if ((alloc->owner == owner) && (alloc->type == type)) {
+ if (mfc_put_free_buf(alloc->real,
+ alloc->size, port) < 0) {
+
+ mfc_err("failed to add free buffer\n");
+ } else {
+ list_del(&alloc->list);
+ kfree(alloc);
+ }
+ }
+ }
+ }
+}
+
+/* FIXME: add MFC Buffer Type */
+void mfc_free_buf_inst(int owner)
+{
+ struct list_head *pos, *nxt;
+ int port;
+ struct mfc_alloc_buffer *alloc;
+ /*
+ unsigned long flags;
+ */
+
+ mfc_dbg("owner: %d\n", owner);
+
+ /*
+ spin_lock_irqsave(&lock, flags);
+ */
+
+ for (port = 0; port < mfc_mem_count(); port++) {
+ list_for_each_safe(pos, nxt, &mfc_alloc_head[port]) {
+ alloc = list_entry(pos, struct mfc_alloc_buffer, list);
+
+ if (alloc->owner == owner) {
+#if defined(CONFIG_VIDEO_MFC_VCM_UMP)
+ if (alloc->ump_handle)
+ mfc_ump_unmap(alloc->ump_handle);
+
+ if (alloc->vcm_k)
+ mfc_vcm_unmap(alloc->vcm_k);
+
+ if (alloc->vcm_s)
+ mfc_vcm_unbind(alloc->vcm_s,
+ alloc->type & MBT_OTHER);
+
+ if (mfc_put_free_buf(alloc->vcm_addr,
+ alloc->vcm_size, port) < 0) {
+
+ mfc_err("failed to add free buffer\n");
+ } else {
+ list_del(&alloc->list);
+ kfree(alloc);
+ }
+#elif defined(CONFIG_S5P_VMEM)
+ if (alloc->vmem_cookie)
+ s5p_vfree(alloc->vmem_cookie);
+
+ if (mfc_put_free_buf(alloc->vmem_addr,
+ alloc->vmem_size, port) < 0) {
+
+ mfc_err("failed to add free buffer\n");
+ } else {
+ list_del(&alloc->list);
+ kfree(alloc);
+ }
+#else
+ if (mfc_put_free_buf(alloc->real,
+ alloc->size, port) < 0) {
+
+ mfc_err("failed to add free buffer\n");
+ } else {
+ list_del(&alloc->list);
+ kfree(alloc);
+ }
+#endif
+ }
+ }
+ }
+
+ /*
+ spin_unlock_irqrestore(&lock, flags);
+ */
+
+#ifdef DEBUG_ALLOC_FREE
+ mfc_print_buf();
+#endif
+}
+
+unsigned long mfc_get_buf_real(int owner, unsigned int key)
+{
+ struct list_head *pos, *nxt;
+ int port;
+ struct mfc_alloc_buffer *alloc;
+
+#if defined(CONFIG_VIDEO_MFC_VCM_UMP)
+ mfc_dbg("owner: %d, secure id: 0x%08x\n", owner, key);
+#elif defined(CONFIG_S5P_VMEM)
+ mfc_dbg("owner: %d, cookie: 0x%08x\n", owner, key);
+#else
+ mfc_dbg("owner: %d, offset: 0x%08x\n", owner, key);
+#endif
+
+ for (port = 0; port < mfc_mem_count(); port++) {
+ list_for_each_safe(pos, nxt, &mfc_alloc_head[port]) {
+ alloc = list_entry(pos, struct mfc_alloc_buffer, list);
+
+ if (alloc->owner == owner) {
+#if defined(CONFIG_VIDEO_MFC_VCM_UMP)
+ if (alloc->ump_handle) {
+ if (mfc_ump_get_id(alloc->ump_handle) == key)
+ return alloc->real;
+ }
+#elif defined(CONFIG_S5P_VMEM)
+ if (alloc->vmem_cookie == key)
+ return alloc->real;
+#else
+ if (alloc->ofs == key)
+ return alloc->real;
+#endif
+ }
+ }
+ }
+
+ return 0;
+}
+
+#if 0
+unsigned char *mfc_get_buf_addr(int owner, unsigned char *user)
+{
+ struct list_head *pos, *nxt;
+ int port;
+ struct mfc_alloc_buffer *alloc;
+
+ mfc_dbg("owner: %d, user: 0x%08x\n", owner, (unsigned int)user);
+
+ for (port = 0; port < mfc_mem_count(); port++) {
+ list_for_each_safe(pos, nxt, &mfc_alloc_head[port]) {
+ alloc = list_entry(pos, struct mfc_alloc_buffer, list);
+
+ if ((alloc->owner == owner)
+ && (alloc->user == user)){
+
+ return alloc->addr;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+unsigned char *_mfc_get_buf_addr(int owner, unsigned char *user)
+{
+ struct list_head *pos, *nxt;
+ int port;
+ struct mfc_alloc_buffer *alloc;
+
+ mfc_dbg("owner: %d, user: 0x%08x\n", owner, (unsigned int)user);
+
+ for (port = 0; port < mfc_mem_count(); port++) {
+ list_for_each_safe(pos, nxt, &mfc_alloc_head[port]) {
+ alloc = list_entry(pos, struct mfc_alloc_buffer, list);
+
+ if ((alloc->owner == owner)
+ && ((alloc->user <= user) || ((alloc->user + alloc->size) > user))){
+
+ return alloc->addr;
+ }
+ }
+ }
+
+ return NULL;
+}
+#endif
+
+#ifdef CONFIG_VIDEO_MFC_VCM_UMP
+void *mfc_get_buf_ump_handle(unsigned long real)
+{
+ struct list_head *pos, *nxt;
+ int port;
+ struct mfc_alloc_buffer *alloc;
+
+ mfc_dbg("real: 0x%08lx\n", real);
+
+ for (port = 0; port < mfc_mem_count(); port++) {
+ list_for_each_safe(pos, nxt, &mfc_alloc_head[port]) {
+ alloc = list_entry(pos, struct mfc_alloc_buffer, list);
+
+ if (alloc->real == real)
+ return alloc->ump_handle;
+ }
+ }
+
+ return NULL;
+}
+#endif
+