diff options
Diffstat (limited to 'drivers/char/s3c_mem.c')
-rw-r--r-- | drivers/char/s3c_mem.c | 310 |
1 files changed, 100 insertions, 210 deletions
diff --git a/drivers/char/s3c_mem.c b/drivers/char/s3c_mem.c index 7645dbe..3e09dda 100644 --- a/drivers/char/s3c_mem.c +++ b/drivers/char/s3c_mem.c @@ -43,9 +43,10 @@ #include "s3c_dma_mem.h" #endif -#ifdef CONFIG_S3C_MEM_CMA_ALLOC +#ifdef CONFIG_VIDEO_SAMSUNG_USE_DMA_MEM #include <linux/cma.h> #include <linux/platform_device.h> +#include <linux/backing-dev.h> #endif static int flag; @@ -56,99 +57,7 @@ static unsigned int physical_address; static unsigned int virtual_address; #endif -#ifdef CONFIG_S3C_MEM_CMA_ALLOC - #ifdef CONFIG_VIDEO_SAMSUNG_USE_DMA_MEM -struct device *s3c_mem_cma_dev; -static struct device *s3c_mem_get_dev(void) -{ - return s3c_mem_cma_dev; -} - -#else -struct s3c_slot_info *s3c_slot_info; -int s3c_cma_max_block_num; -int s3c_cma_block_size; - - -static void s3c_mem_log(struct s3c_dev_info *prv_data, bool mem_info) -{ - int i = 0; - for (i = 0; i < prv_data->dev_max_slot_num; i++) - printk(KERN_INFO - "s_slot_info[%d].s_start_addr=0x%x s_mapped=%d\n", i, - prv_data->s_slot_info[i].s_start_addr, - prv_data->s_slot_info[i].s_mapped); - if (mem_info) - printk(KERN_INFO - "s_cur_mem_info->paddr=0x%x s_mem_info->vaddr=0x%x s_mem_info->size=%d\n", - prv_data->s_cur_mem_info.paddr, - prv_data->s_cur_mem_info.vaddr, - prv_data->s_cur_mem_info.mapped_size); -} - -static unsigned long s3c_mapping_slot(struct s3c_dev_info *prv_data) -{ - int i, j, k, v_start_slot = 0; - unsigned long lv_ret = 0; - - for (i = 0; i < prv_data->dev_max_slot_num; i++) { - if (prv_data->s_slot_info[i].s_mapped == false) { - if (i + prv_data->s_cur_mem_info.req_memblock > - prv_data->dev_max_slot_num) { - printk(KERN_ERR "ERROR : not enough memory\n"); - return lv_ret; - } - v_start_slot = i; - for (j = i; - j < i + prv_data->s_cur_mem_info.req_memblock; - j++) { - if (prv_data->s_slot_info[j].s_mapped == true) - break; - } - if (j == i + prv_data->s_cur_mem_info.req_memblock) { - lv_ret = - __phys_to_pfn(prv_data->s_slot_info - [v_start_slot].s_start_addr); - physical_address = (unsigned int) - prv_data->s_slot_info[v_start_slot]. - s_start_addr; - for (k = v_start_slot; k < j; k++) { - prv_data->s_slot_info[k].s_mapped = - true; - printk(KERN_INFO - "prv_data->s_slot_info[%d].s_mapped=1\n", - k); - } - break; - } - } else - continue; - } - if (i == prv_data->dev_max_slot_num) - printk(KERN_ERR "ERROR :can not find the suitable slot\n"); - - return lv_ret; -} - -static int s3c_unmapping_slot(struct s3c_dev_info *prv_data) -{ - int i, j, lv_ret = 0; - for (i = 0; i < prv_data->dev_max_slot_num; i++) { - if (prv_data->s_slot_info[i].s_start_addr == - prv_data->s_cur_mem_info.paddr) { - for (j = i; - j < i + prv_data->s_cur_mem_info.req_memblock; - j++) { - prv_data->s_slot_info[j].s_mapped = false; - printk(KERN_INFO - "s_slot_info[%d].s_mapped = 0\n", j); - } - } - } - return lv_ret; -} -#endif int s3c_mem_open(struct inode *inode, struct file *filp) { @@ -158,22 +67,10 @@ int s3c_mem_open(struct inode *inode, struct file *filp) prv_data = kzalloc(sizeof(struct s3c_dev_info), GFP_KERNEL); if (!prv_data) { pr_err("%s: not enough memory\n", __func__); + mutex_unlock(&mem_open_lock); return -ENOMEM; } -#ifdef CONFIG_VIDEO_SAMSUNG_USE_DMA_MEM - prv_data->s3c_mem_cma_dev = s3c_mem_get_dev(); - prv_data->s_cur_mem_info.phy_addr = 0; - prv_data->s_cur_mem_info.vir_addr = 0; - prv_data->s_cur_mem_info.size = 0; -#else - prv_data->s_slot_info = s3c_slot_info; - prv_data->dev_slot_size = s3c_cma_block_size; - prv_data->dev_max_slot_num = s3c_cma_max_block_num; - prv_data->s_cur_mem_info.paddr = 0; - prv_data->s_cur_mem_info.vaddr = 0; - prv_data->s_cur_mem_info.mapped_size = 0; - prv_data->s_cur_mem_info.req_memblock = 0; -#endif + filp->private_data = prv_data; mutex_unlock(&mem_open_lock); @@ -186,47 +83,36 @@ int s3c_mem_release(struct inode *inode, struct file *filp) struct mm_struct *mm = current->mm; struct s3c_dev_info *prv_data = (struct s3c_dev_info *)filp->private_data; - + int i, err = 0; mutex_lock(&mem_release_lock); -#ifdef CONFIG_VIDEO_SAMSUNG_USE_DMA_MEM - if (prv_data->s_cur_mem_info.vir_addr) { - if (do_munmap - (mm, prv_data->s_cur_mem_info.vir_addr, - prv_data->s_cur_mem_info.size) < 0) { - printk(KERN_ERR "do_munmap() failed !!\n"); - mutex_unlock(&mem_free_lock); - return -EINVAL; + + for (i = 0; i < S3C_MEM_CMA_MAX_CTX_BUF; i++) { + if (prv_data->s_cur_mem_info[i].vir_addr) { + if (do_munmap + (mm, prv_data->s_cur_mem_info[i].vir_addr, + prv_data->s_cur_mem_info[i].size) < 0) { + printk(KERN_ERR "do_munmap() failed !!\n"); + err = -EINVAL; + } + if (prv_data->s_cur_mem_info[i].phy_addr) { + cma_free(prv_data->s_cur_mem_info[i].phy_addr); + + prv_data->s_cur_mem_info[i].vir_addr = 0; + prv_data->s_cur_mem_info[i].phy_addr = 0; + prv_data->s_cur_mem_info[i].size = 0; + prv_data->s3c_mem_ctx_buf_num--; + } + } - if (prv_data->s_cur_mem_info.phy_addr) - cma_free(prv_data->s_cur_mem_info.phy_addr); - prv_data->s_cur_mem_info.vir_addr = 0; - prv_data->s_cur_mem_info.size = 0; - prv_data->s_cur_mem_info.phy_addr = 0; - DEBUG("do_munmap() succeed !!\n"); } -#else - printk(KERN_INFO - "prv_data->s_cur_mem_info->paddr=0x%x vaddr=0x%x size=%d\n", - prv_data->s_cur_mem_info.paddr, prv_data->s_cur_mem_info.vaddr, - prv_data->s_cur_mem_info.mapped_size); - - if (prv_data->s_cur_mem_info.vaddr) { - s3c_unmapping_slot(prv_data); - if (do_munmap - (mm, prv_data->s_cur_mem_info.vaddr, - prv_data->s_cur_mem_info.mapped_size) < 0) { - printk(KERN_ERR "do_munmap() failed !!\n"); - mutex_unlock(&mem_release_lock); - return -EINVAL; - } + if (!err) { + kfree(filp->private_data); + filp->private_data = NULL; } -#endif - kfree(filp->private_data); - filp->private_data = NULL; mutex_unlock(&mem_release_lock); - return 0; + return err; } #endif @@ -285,15 +171,14 @@ long s3c_mem_ioctl(struct file *file, unsigned int cmd, unsigned long arg) mutex_unlock(&mem_alloc_lock); break; -#ifdef CONFIG_S3C_MEM_CMA_ALLOC +#ifdef CONFIG_VIDEO_SAMSUNG_USE_DMA_MEM case S3C_MEM_CMA_ALLOC: { -#ifdef CONFIG_VIDEO_SAMSUNG_USE_DMA_MEM struct cma_info mem_info; - int err; -#endif + int err, i = 0; struct s3c_dev_info *prv_data = (struct s3c_dev_info *)file->private_data; + struct device *dev; mutex_lock(&mem_alloc_lock); if (copy_from_user(¶m, (struct s3c_mem_alloc *)arg, @@ -303,9 +188,26 @@ long s3c_mem_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } flag = MEM_CMA_ALLOC; -#ifdef CONFIG_VIDEO_SAMSUNG_USE_DMA_MEM - err = cma_info(&mem_info, prv_data->s3c_mem_cma_dev, 0); - printk(KERN_DEBUG "%s : [cma_info] start_addr : 0x%x, end_addr : 0x%x, " + if (prv_data->s3c_mem_ctx_buf_num >= + S3C_MEM_CMA_MAX_CTX_BUF) { + printk(KERN_ERR "%s: exceed max_ctx\n", + __func__); + mutex_unlock(&mem_alloc_lock); + return -ENOMEM; + } + + if (file->f_mapping->backing_dev_info->dev) + dev = file->f_mapping->backing_dev_info->dev; + else { + printk(KERN_ERR "%s: get dev info failed\n", + __func__); + mutex_unlock(&mem_alloc_lock); + return -EFAULT; + } + + err = cma_info(&mem_info, dev, 0); + printk(KERN_DEBUG + "%s : [cma_info] start_addr : 0x%x, end_addr : 0x%x, " "total_size : 0x%x, free_size : 0x%x req_size : 0x%x\n", __func__, mem_info.lower_bound, mem_info.upper_bound, mem_info.total_size, @@ -317,8 +219,8 @@ long s3c_mem_ioctl(struct file *file, unsigned int cmd, unsigned long arg) mutex_unlock(&mem_alloc_lock); return -ENOMEM; } - param.phy_addr = (dma_addr_t) cma_alloc - (prv_data->s3c_mem_cma_dev, "dma", + physical_address = param.phy_addr = + (dma_addr_t) cma_alloc(dev, "dma", (size_t) param.size, 0); printk(KERN_INFO "param.phy_addr = 0x%x\n", @@ -330,9 +232,6 @@ long s3c_mem_ioctl(struct file *file, unsigned int cmd, unsigned long arg) mutex_unlock(&mem_alloc_lock); return -ENOMEM; } - prv_data->s_cur_mem_info.size = param.size; - prv_data->s_cur_mem_info.phy_addr = param.phy_addr; -#endif param.vir_addr = do_mmap(file, 0, param.size, @@ -342,27 +241,40 @@ long s3c_mem_ioctl(struct file *file, unsigned int cmd, unsigned long arg) if (param.vir_addr == -EINVAL) { printk(KERN_ERR "S3C_MEM_ALLOC FAILED\n"); + if (param.phy_addr) + cma_free(param.phy_addr); flag = 0; mutex_unlock(&mem_alloc_lock); return -EFAULT; } -#ifdef CONFIG_VIDEO_SAMSUNG_USE_DMA_MEM - prv_data->s_cur_mem_info.vir_addr = param.vir_addr; -#else - param.phy_addr = physical_address; - printk(KERN_INFO "physical_address=0x%x\n", - physical_address); - prv_data->s_cur_mem_info.paddr = param.phy_addr; - prv_data->s_cur_mem_info.vaddr = param.vir_addr; - prv_data->s_cur_mem_info.mapped_size = - PAGE_ALIGN(param.size); -#endif + if (copy_to_user((struct s3c_mem_alloc *)arg, ¶m, sizeof(struct s3c_mem_alloc))) { + if (param.vir_addr) + do_munmap(mm, param.vir_addr, + param.size); + if (param.phy_addr) + cma_free(param.phy_addr); + flag = 0; mutex_unlock(&mem_alloc_lock); return -EFAULT; } + + for (i = 0; i < S3C_MEM_CMA_MAX_CTX_BUF; i++) { + if (!prv_data->s_cur_mem_info[i].vir_addr + && !prv_data->s_cur_mem_info[i].phy_addr) { + prv_data->s_cur_mem_info[i].vir_addr = + param.vir_addr; + prv_data->s_cur_mem_info[i].phy_addr = + param.phy_addr; + prv_data->s_cur_mem_info[i].size = + param.size; + break; + } + } + prv_data->s3c_mem_ctx_buf_num++; + flag = 0; mutex_unlock(&mem_alloc_lock); @@ -518,11 +430,12 @@ long s3c_mem_ioctl(struct file *file, unsigned int cmd, unsigned long arg) mutex_unlock(&mem_free_lock); break; -#ifdef CONFIG_S3C_MEM_CMA_ALLOC +#ifdef CONFIG_VIDEO_SAMSUNG_USE_DMA_MEM case S3C_MEM_CMA_FREE: { struct s3c_dev_info *prv_data = (struct s3c_dev_info *)file->private_data; + int i = 0; mutex_lock(&mem_free_lock); if (copy_from_user(¶m, (struct s3c_mem_alloc *)arg, @@ -539,7 +452,6 @@ long s3c_mem_ioctl(struct file *file, unsigned int cmd, unsigned long arg) printk ("FREE : pa = 0x%x size = %d va = 0x%x\n", param.phy_addr, param.size, param.vir_addr); -#ifdef CONFIG_VIDEO_SAMSUNG_USE_DMA_MEM if (param.vir_addr) { if (do_munmap(mm, param.vir_addr, param.size) < 0) { @@ -548,36 +460,31 @@ long s3c_mem_ioctl(struct file *file, unsigned int cmd, unsigned long arg) mutex_unlock(&mem_free_lock); return -EINVAL; } - if (prv_data->s_cur_mem_info.phy_addr) { - cma_free(prv_data-> - s_cur_mem_info.phy_addr); + if (param.phy_addr) + cma_free(param.phy_addr); + + for (i = 0; i < S3C_MEM_CMA_MAX_CTX_BUF; i++) { + if ((prv_data->s_cur_mem_info[i]. + phy_addr == param.phy_addr) + && (prv_data->s_cur_mem_info[i]. + vir_addr == param.vir_addr)) { + prv_data->s_cur_mem_info[i]. + phy_addr = 0; + prv_data->s_cur_mem_info[i]. + vir_addr = 0; + prv_data->s_cur_mem_info[i]. + size = 0; + if (prv_data-> + s3c_mem_ctx_buf_num > 0) + prv_data-> + s3c_mem_ctx_buf_num--; + break; + } } - param.size = 0; - prv_data->s_cur_mem_info.vir_addr = 0; - prv_data->s_cur_mem_info.size = 0; - prv_data->s_cur_mem_info.phy_addr = 0; DEBUG("do_munmap() succeed !!\n"); } -#else - if (param.vir_addr) { - s3c_unmapping_slot(prv_data); - if (do_munmap(mm, param.vir_addr, param.size) < - 0) { - printk(KERN_ERR - "do_munmap() failed !!\n"); - mutex_unlock(&mem_free_lock); - return -EINVAL; - } - param.size = 0; - prv_data->s_cur_mem_info.paddr = 0; - prv_data->s_cur_mem_info.vaddr = 0; - prv_data->s_cur_mem_info.mapped_size = 0; - prv_data->s_cur_mem_info.req_memblock = 0; - DEBUG("do_munmap() succeed !!\n"); - } -#endif if (copy_to_user((struct s3c_mem_alloc *)arg, ¶m, sizeof(struct s3c_mem_alloc))) { mutex_unlock(&mem_free_lock); @@ -714,29 +621,12 @@ int s3c_mem_mmap(struct file *filp, struct vm_area_struct *vma) #endif pageFrameNo = __phys_to_pfn(phys_addr); break; -#ifdef CONFIG_S3C_MEM_CMA_ALLOC +#ifdef CONFIG_VIDEO_SAMSUNG_USE_DMA_MEM case MEM_CMA_ALLOC: { - struct s3c_dev_info *prv_data = - (struct s3c_dev_info *)filp->private_data; vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); -#ifdef CONFIG_VIDEO_SAMSUNG_USE_DMA_MEM - pageFrameNo = - __phys_to_pfn(prv_data->s_cur_mem_info.phy_addr); -#else - prv_data->s_cur_mem_info.req_memblock = - PAGE_ALIGN(size) / prv_data->dev_slot_size; - - if (PAGE_ALIGN(size) % prv_data->dev_slot_size) - prv_data->s_cur_mem_info.req_memblock++; - - printk(KERN_INFO "required slot=%d size=%lu\n", - prv_data->s_cur_mem_info.req_memblock, size); - - - pageFrameNo = s3c_mapping_slot(prv_data); -#endif + pageFrameNo = __phys_to_pfn(physical_address); if (!pageFrameNo) { printk(KERN_ERR "mapping failed !\n"); return -EINVAL; |