From: Kitae Kim Date: Fri, 10 May 2013 02:24:15 +0000 (+0900) Subject: new_codec: changed a way to copy data between guest and host. X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=1739fb2f290000e513124e2a7bd8374b574fbc50;p=sdk%2Femulator%2Femulator-kernel.git new_codec: changed a way to copy data between guest and host. Use mutex to reduce frequent context switching from user to kernel. And removed a routine that occupies device memory exclusively. Change-Id: I4cb8e0a255bafb3fec6b01307ad31ddc6666ce64 Signed-off-by: Kitae Kim --- diff --git a/drivers/maru/maru_new_codec.c b/drivers/maru/maru_new_codec.c index 855f5cf43dfa..043fe898a6f1 100644 --- a/drivers/maru/maru_new_codec.c +++ b/drivers/maru/maru_new_codec.c @@ -49,12 +49,17 @@ #include // #include -#define DEVICE_NAME "newcodec" MODULE_DESCRIPTION("Virtual New Codec Device Driver"); MODULE_AUTHOR("Kitae KIM ioaddr + CODEC_CMD_GET_SHARED_QUEUE); + value = readl(newcodec->ioaddr + CODEC_CMD_GET_QUEUE); CODEC_LOG("file value of head task: %x.\n", value); if (value) { newcodec_add_task(&newcodec->req_task, value); @@ -202,40 +188,17 @@ static void newcodec_shared_bh_func(struct work_struct *work) CODEC_LOG("there is no available task\n"); } } while (value); -} -static void newcodec_shared_bh(struct newcodec_device *dev) -{ - CODEC_LOG("request bottom-half operation.\n"); - queue_work(newcodec_bh_workqueue, &newcodec_shared_bh_work); + mutex_unlock(&newcodec_interrupt_mutex); } -static void newcodec_fixed_bh_func(struct work_struct *work) -{ - uint32_t value; - - CODEC_LOG("fixed_bh func.\n"); - - do { - value = readl(newcodec->ioaddr + CODEC_CMD_GET_FIXED_QUEUE); - CODEC_LOG("file value of head task: %x.\n", value); - if (value) { - newcodec_add_task(&newcodec->irq_task, value); - } else { - CODEC_LOG("there is no available task\n"); - } - } while (value); - - mutex_unlock(&newcodec_mutex); -} - -static void newcodec_fixed_bh(struct newcodec_device *dev) +static void newcodec_bh(struct newcodec_device *dev) { CODEC_LOG("request bottom-half operation.\n"); - queue_work(newcodec_bh_workqueue, &newcodec_fixed_bh_work); + queue_work(newcodec_bh_workqueue, &newcodec_bh_work); } -static void newcodec_add_task(struct list_head *head, int32_t file) +static void newcodec_add_task(struct list_head *head, uint32_t file) { struct newcodec_task *temp = NULL; @@ -247,7 +210,6 @@ static void newcodec_add_task(struct list_head *head, int32_t file) CODEC_LOG("add task. file: %x\n", file); temp->id = file; - INIT_LIST_HEAD(&temp->entry); mutex_lock(&newcodec_bh_mutex); @@ -270,54 +232,35 @@ static void newcodec_release_task_entry(struct list_head *head, int32_t value) } } -static uint32_t newcodec_manage_dev_mem(struct codec_mem_info *mem_info, int32_t file) +static int newcodec_manage_device_mem(uint32_t file) { - uint32_t req_mem_size = mem_info->index; - uint32_t used_mem_size = newcodec->used_mem_size; -// uint32_t mmapmgr_offset = newcodec->mmapmgr_offset; - struct newcodec_mmapmgr *mem_mgr; + struct device_mem_mgr *mem_mgr = NULL; + int index, ret = -1; - mem_mgr = &newcodec->mem_mgr[newcodec->mmapmgr_idx]; - CODEC_LOG("[file: %x] mem index: %d\n", - file, newcodec->mmapmgr_idx); + if (!newcodec->mem_mgr) { + printk(KERN_ERR "invalid access to mem_mgr variable.\n"); + return ret; + } - if ((used_mem_size + req_mem_size) < NEWCODEC_FIXED_DEV_MEM_MAX) { -#if 0 - if (used_mem_size == 0) { - newcodec->mem_mgr[0].id = file; - newcodec->mem_mgr[0].offset = 0; - newcodec->mmapmgr_offset = req_mem_size; - } else { -#endif - mem_mgr->id = file; - mem_mgr->offset = newcodec->mmapmgr_offset; - newcodec->mmapmgr_offset = mem_mgr->offset + req_mem_size; -// } + for (index = 0; index < CODEC_DEVICE_MEM_COUNT; index++) { + mem_mgr = &newcodec->mem_mgr[index]; - mutex_lock(&newcodec_mutex); - newcodec->used_mem_size += req_mem_size; - mutex_unlock(&newcodec_mutex); - - mem_info->type = CODEC_FIXED_DEVICE_MEM; - } else { - mem_mgr->id = file; - mem_mgr->offset = NEWCODEC_FIXED_DEV_MEM_MAX; - mem_info->type = CODEC_SHARED_DEVICE_MEM; + if (!mem_mgr->occupied) { + mem_mgr->occupied = true; + mem_mgr->context_id = file; + return ret; + } } - mem_info->index = newcodec->mmapmgr_idx; - mem_info->offset = mem_mgr->offset; + CODEC_LOG("all buffers are occupied. lock buffer_mutex.\n"); + // TODO: use another mutex. + newcodec->all_occupied = true; - newcodec->mmapmgr_idx++; - // TODO: twice size or return to 0 - if (newcodec->mmapmgr_idx == newcodec->mmapmgr_size) { - newcodec->mmapmgr_idx = 0; - } + mutex_lock(&newcodec_buffer_mutex); - return 0; + return ret; } - static long newcodec_ioctl(struct file *file, unsigned int cmd, unsigned long arg) @@ -327,10 +270,11 @@ static long newcodec_ioctl(struct file *file, switch (cmd) { case CODEC_CMD_ADD_TASK_QUEUE: CODEC_LOG("add task into req_task.\n"); - newcodec_add_task(&newcodec->req_task, (int32_t)file); + newcodec_add_task(&newcodec->req_task, (uint32_t)file); break; case CODEC_CMD_REMOVE_TASK_QUEUE: { +#if 0 struct newcodec_task *head_task = NULL; head_task = @@ -338,20 +282,42 @@ static long newcodec_ioctl(struct file *file, if (!head_task) { CODEC_LOG("[file: %p] head_task is NULL\n", file); } else { - CODEC_LOG("[file: %p] head_task of req: %x into old_task\n", + CODEC_LOG("[file: %p] head_task of req: %x into disuse_task\n", file, head_task->id); mutex_lock(&newcodec_mutex); - list_move_tail(&head_task->entry, &newcodec->old_task); + list_move_tail(&head_task->entry, &newcodec->disuse_task); mutex_unlock(&newcodec_mutex); - CODEC_LOG("release old_task resource.\n"); - newcodec_release_task_entry(&newcodec->old_task, (int32_t)file); + CODEC_LOG("release disuse_task resource.\n"); + newcodec_release_task_entry(&newcodec->disuse_task, (int32_t)file); } +#endif + struct device_mem_mgr *mem_mgr = NULL; + int index; + + for (index = 0; index < CODEC_DEVICE_MEM_COUNT; index++) { + mem_mgr = &newcodec->mem_mgr[index]; + if (mem_mgr->context_id == (uint32_t)file) { + mem_mgr->occupied = false; + mem_mgr->context_id = 0; + break; + } + } + + if (newcodec->all_occupied) { + CODEC_LOG("a buffer is available. unlock buffer_mutex.\n"); + // TODO: use another mutex. + newcodec->all_occupied = false; + mutex_unlock(&newcodec_buffer_mutex); + } + + mutex_unlock(&newcodec_interrupt_mutex); } break; case CODEC_CMD_COPY_TO_DEVICE_MEM: { +#if 0 struct newcodec_task *head_task = NULL; CODEC_LOG("[file: %p] COPY_TO_DEV_MEM\n", file); @@ -387,11 +353,49 @@ static long newcodec_ioctl(struct file *file, printk(KERN_ERR "ioctl: failed to copy data to user.\n"); ret = -EIO; } +#endif + int vacant_buffer_idx; + + vacant_buffer_idx = + newcodec_manage_device_mem((uint32_t)file); + + if (vacant_buffer_idx < 0) { + struct newcodec_task *head_task = NULL; + + CODEC_LOG("all buffers are occupied.\n"); + newcodec_add_task(&newcodec->req_task, (uint32_t)file); + + // wait until codec_buffer_mutex is unlocked. + mutex_lock(&newcodec_buffer_mutex); + + vacant_buffer_idx = + newcodec_manage_device_mem((uint32_t)file); + + head_task = + list_first_entry(&newcodec->req_task, + struct newcodec_task, entry); + if (!head_task) { + printk(KERN_ERR "head task is NULL.\n"); + } else { + CODEC_LOG("move the head task to disuse_task. %p\n", file); + mutex_lock(&newcodec_bh_mutex); + list_move_tail(&head_task->entry, &newcodec->disuse_task); + mutex_unlock(&newcodec_bh_mutex); + } + + } + + value = newcodec->mem_mgr[vacant_buffer_idx].mem_offset; + if (copy_to_user((void *)arg, &value, sizeof(uint32_t))) { + printk(KERN_ERR "ioctl: failed to copy data to user.\n"); + ret = -EIO; + } } break; case CODEC_CMD_COPY_FROM_DEVICE_MEM: { +#if 0 struct newcodec_task *head_task = NULL; CODEC_LOG("[file: %p] COPY_FROM_DEV_MEM\n", file); @@ -434,9 +438,69 @@ static long newcodec_ioctl(struct file *file, printk(KERN_ERR "ioctl: failed to copy data to user.\n"); ret = -EIO; } +#endif + +#if 0 + { + struct list_head *pos, *temp; + struct newcodec_task *node; + + list_for_each_safe(pos, temp, &newcodec->irq_task) { + node = list_entry(pos, struct newcodec_task, entry); + if (node->id == (uint32_t)file) { + CODEC_LOG("The task_id is done. %x\n", node->id); + list_del(pos); + kfree(node); + } + } + } +#endif + { + int vacant_buffer_idx; + + mutex_lock(&newcodec_interrupt_mutex); + + vacant_buffer_idx = + newcodec_manage_device_mem((uint32_t)file); + + if (vacant_buffer_idx < 0) { + struct newcodec_task *head_task = NULL; + + CODEC_LOG("all buffers are occupied.\n"); + + // wait until codec_buffer_mutex is unlocked. + mutex_lock(&newcodec_buffer_mutex); + + vacant_buffer_idx = + newcodec_manage_device_mem((uint32_t)file); + + head_task = + list_first_entry(&newcodec->req_task, + struct newcodec_task, entry); + if (!head_task) { + printk(KERN_ERR "head task is NULL.\n"); + } else { + CODEC_LOG("move the head task to disuse_task. %p\n", file); + mutex_lock(&newcodec_bh_mutex); + list_move_tail(&head_task->entry, &newcodec->disuse_task); + mutex_unlock(&newcodec_bh_mutex); + } + } + + // notify that codec device can copy data to memory region. + CODEC_LOG("[file: %p] pop data from codec_wq.\n", file); + writel((uint32_t)file, + newcodec->ioaddr + CODEC_CMD_POP_WRITE_QUEUE); + + value = newcodec->mem_mgr[vacant_buffer_idx].mem_offset; + if (copy_to_user((void *)arg, &value, sizeof(uint32_t))) { + printk(KERN_ERR "ioctl: failed to copy data to user.\n"); + ret = -EIO; + } + } } break; - case CODEC_CMD_GET_DEVICE_MEM_INFO: + case CODEC_CMD_ACQUIRE_DEVICE_MEM: { struct codec_mem_info mem_info; @@ -448,7 +512,7 @@ static long newcodec_ioctl(struct file *file, CODEC_LOG("request memory size: %d\n", mem_info.index); - newcodec_manage_dev_mem(&mem_info, (int32_t)file); + newcodec_manage_device_mem((int32_t)file); if (copy_to_user((void *)arg, &mem_info, sizeof(mem_info))) { printk(KERN_ERR "ioctl: failed to copy data to user.\n"); @@ -458,7 +522,7 @@ static long newcodec_ioctl(struct file *file, break; case CODEC_CMD_RELEASE_DEVICE_MEM: { - struct newcodec_mmapmgr *mem_mgr; + struct device_mem_mgr *mem_mgr; struct codec_mem_info mem_info; if (copy_from_user(&mem_info, (void *)arg, sizeof(mem_info))) { @@ -470,13 +534,13 @@ static long newcodec_ioctl(struct file *file, CODEC_LOG("release memory size: %d\n", mem_info.index); mem_mgr = &newcodec->mem_mgr[mem_info.index]; - if (mem_mgr->id == (int32_t)file && - mem_mgr->offset == mem_info.offset) { - memset(mem_mgr, 0x00, sizeof(struct newcodec_mmapmgr)); + if (mem_mgr->context_id == (uint32_t)file && + mem_mgr->mem_offset == mem_info.offset) { + memset(mem_mgr, 0x00, sizeof(struct device_mem_mgr)); } } break; -#if 0 +#if 0 case CODEC_CMD_WAIT_TASK_QUEUE: { value = CODEC_MEM_LOCK; @@ -528,7 +592,7 @@ static long newcodec_ioctl(struct file *file, } break; #endif -#if 1 +#if 0 case CODEC_CMD_WAIT_TASK_QUEUE: { // printk(KERN_INFO "wait_event\n"); @@ -571,9 +635,9 @@ static long newcodec_ioctl(struct file *file, } static ssize_t newcodec_read(struct file *file, char __user *buf, - size_t count, loff_t *fops) + size_t count, loff_t *fops) { - CODEC_LOG("do nothing in the read operation.\n"); + CODEC_LOG("do nothing.\n"); return 0; } @@ -594,39 +658,99 @@ static ssize_t newcodec_write(struct file *file, const char __user *buf, size_t return -EIO; } +#if 0 mutex_lock(&newcodec_mutex); if (param_info.api_index == CODEC_ELEMENT_QUERY) { writel((int32_t)param_info.api_index, newcodec->ioaddr + CODEC_CMD_API_INDEX); mutex_unlock(&newcodec_mutex); } else { - writel((int32_t)file, + writel((uint32_t)file, newcodec->ioaddr + CODEC_CMD_FILE_INDEX); writel((uint32_t)param_info.mem_offset, newcodec->ioaddr + CODEC_CMD_DEVICE_MEM_OFFSET); - writel((uint32_t)param_info.mem_type, - newcodec->ioaddr + CODEC_CMD_DEVICE_MEM_TYPE); writel((int32_t)param_info.ctx_index, newcodec->ioaddr + CODEC_CMD_CONTEXT_INDEX); writel((int32_t)param_info.api_index, newcodec->ioaddr + CODEC_CMD_API_INDEX); - if (param_info.mem_type == CODEC_SHARED_DEVICE_MEM) { - if (param_info.api_index > CODEC_ELEMENT_QUERY && - param_info.api_index < CODEC_DEINIT) { - struct newcodec_task *head_task = NULL; + if (param_info.api_index > CODEC_ELEMENT_QUERY && + param_info.api_index < CODEC_DEINIT) { + struct newcodec_task *head_task = NULL; - head_task = - list_first_entry(&newcodec->req_task, struct newcodec_task, entry); - if (!head_task) { - CODEC_LOG("[file: %p] head_task is NULL\n", file); - } else { - CODEC_LOG("move head_task: %x into old_task\n", head_task->id); - list_move_tail(&head_task->entry, &newcodec->old_task); + head_task = + list_first_entry(&newcodec->req_task, struct newcodec_task, entry); + if (!head_task) { + CODEC_LOG("[file: %p] head_task is NULL\n", file); + } else { + CODEC_LOG("move head_task: %x into disuse task\n", head_task->id); + list_move_tail(&head_task->entry, &newcodec->disuse_task); + } + } + + + CODEC_LOG("A buffer is avaiable. unlock buffer_mutex.\n"); + mutex_unlock(&codec_buffer_mutex); + } +#endif + int api_index; + + api_index = param_info.api_index; + switch (api_index) { + case CODEC_QUERY: + writel((int32_t)param_info.api_index, + newcodec->ioaddr + CODEC_CMD_API_INDEX); + break; + case CODEC_INIT ... CODEC_PICTURE_COPY: + { + writel((uint32_t)file, + newcodec->ioaddr + CODEC_CMD_FILE_INDEX); + writel((uint32_t)param_info.mem_offset, + newcodec->ioaddr + CODEC_CMD_DEVICE_MEM_OFFSET); + writel((int32_t)param_info.ctx_index, + newcodec->ioaddr + CODEC_CMD_CONTEXT_INDEX); + writel((int32_t)param_info.api_index, + newcodec->ioaddr + CODEC_CMD_API_INDEX); + + { + struct device_mem_mgr *mem_mgr = NULL; + int index; + + for (index = 0; index < CODEC_DEVICE_MEM_COUNT; index++) { + mem_mgr = &newcodec->mem_mgr[index]; + if (mem_mgr->context_id == (uint32_t)file) { + mem_mgr->occupied = false; + mem_mgr->context_id = 0; + break; + } + } + + if (newcodec->all_occupied) { + CODEC_LOG("a buffer is available. unlock buffer_mutex.\n"); + // TODO: use another mutex. + newcodec->all_occupied = false; + mutex_unlock(&newcodec_buffer_mutex); } } + + // acquire mutex to make the current context wait. + mutex_lock(&newcodec_interrupt_mutex); } + break; + case CODEC_DEINIT: + writel((uint32_t)file, + newcodec->ioaddr + CODEC_CMD_FILE_INDEX); + writel((uint32_t)param_info.mem_offset, + newcodec->ioaddr + CODEC_CMD_DEVICE_MEM_OFFSET); + writel((int32_t)param_info.ctx_index, + newcodec->ioaddr + CODEC_CMD_CONTEXT_INDEX); + writel((int32_t)param_info.api_index, + newcodec->ioaddr + CODEC_CMD_API_INDEX); + break; + default: + printk(KERN_ERR "wrong api_index %d", api_index); } + // mutex_unlock(&newcodec_mutex); return 0; @@ -667,20 +791,14 @@ static irqreturn_t newcodec_irq_handler(int irq, void *dev_id) int val = 0; val = readl(dev->ioaddr + CODEC_CMD_GET_THREAD_STATE); - if (!(val & NEWCODEC_IRQ_SHARED_TASK || - val & NEWCODEC_IRQ_FIXED_TASK)) { + if (!(val & CODEC_IRQ_TASK)) { return IRQ_NONE; } spin_lock_irqsave(&dev->lock, flags); - if (val == NEWCODEC_IRQ_SHARED_TASK) { - CODEC_LOG("handle shared_task irq\n"); - newcodec_shared_bh(dev); - } else if (val == NEWCODEC_IRQ_FIXED_TASK) { - CODEC_LOG("handle fixed_task irq\n"); - newcodec_fixed_bh(dev); - } + CODEC_LOG("handle shared_task irq\n"); + newcodec_bh(dev); spin_unlock_irqrestore(&dev->lock, flags); @@ -691,6 +809,29 @@ static int newcodec_open(struct inode *inode, struct file *file) { CODEC_LOG("open! struct file:%p\n", file); +#if 0 + struct newcodec_task *temp = NULL; + struct mutex *io_lock = NULL; + + temp = kzalloc(sizeof(struct newcodec_task), GFP_KERNEL); + if (!temp) { + return -ENOMEM; + } + temp->id = (int32_t)file; + + io_lock = kzalloc(sizeof(struct mutex), GFP_KERNEL); + if (!io_lock) { + kfree(temp); + return -ENOMEM; + } + mutex_init(io_lock); + + temp->id = (int32_t)file; + temp->data = io_lock; + + list_add_tail(&temp->entry, &newcodec->io_task); +#endif + /* register interrupt handler */ if (request_irq(newcodec->dev->irq, newcodec_irq_handler, IRQF_SHARED, DEVICE_NAME, newcodec)) { @@ -711,16 +852,14 @@ static int newcodec_release(struct inode *inode, struct file *file) free_irq(newcodec->dev->irq, newcodec); } - /* free old_task resource */ - CODEC_LOG("release old_task resource.\n"); - newcodec_release_task_entry(&newcodec->old_task, (int32_t)file); + /* free resource */ + CODEC_LOG("release disuse_task resource.\n"); + newcodec_release_task_entry(&newcodec->disuse_task, (int32_t)file); CODEC_LOG("release req_task resource.\n"); newcodec_release_task_entry(&newcodec->req_task, (int32_t)file); - CODEC_LOG("release irq_task resource.\n"); - newcodec_release_task_entry(&newcodec->irq_task, (int32_t)file); - +// newcodec_release_task_entry(&newcodec->io_task, (int32_t)file); #if 0 { struct list_head *pos, *temp; @@ -749,7 +888,7 @@ static int newcodec_release(struct inode *inode, struct file *file) /* notify closing codec device of qemu. */ if (file) { writel((int32_t)file, - newcodec->ioaddr + CODEC_CMD_RESET_CODEC_INFO); + newcodec->ioaddr + CODEC_CMD_RESET_AVCONTEXT); } module_put(THIS_MODULE); @@ -780,34 +919,34 @@ static int __devinit newcodec_probe(struct pci_dev *pci_dev, { int ret = 0; + printk(KERN_INFO "%s: driver is probed.\n", DEVICE_NAME); + newcodec = kzalloc(sizeof(struct newcodec_device), GFP_KERNEL); if (!newcodec) { printk(KERN_ERR "Failed to allocate memory for codec.\n"); - return -EIO; + return -ENOMEM; } + newcodec->dev = pci_dev; - newcodec->mmapmgr_size = 32; + newcodec->mem_mgr_size = 1; newcodec->mem_mgr = - kzalloc(sizeof(struct newcodec_mmapmgr) * - newcodec->mmapmgr_size, GFP_KERNEL); + kzalloc(sizeof(struct device_mem_mgr) * + newcodec->mem_mgr_size, GFP_KERNEL); if (!newcodec->mem_mgr) { printk(KERN_ERR "Failed to allocate memory.\n"); - return -EIO; + return -ENOMEM; } INIT_LIST_HEAD(&newcodec->req_task); - INIT_LIST_HEAD(&newcodec->old_task); - INIT_LIST_HEAD(&newcodec->irq_task); + INIT_LIST_HEAD(&newcodec->disuse_task); -// init_waitqueue_head(&newcodec->codec_wq); spin_lock_init(&newcodec->lock); if ((ret = pci_enable_device(pci_dev))) { printk(KERN_ERR "pci_enable_device failed\n"); return ret; } - pci_set_master(pci_dev); newcodec->mem_start = pci_resource_start(pci_dev, 0); @@ -853,8 +992,7 @@ static int __devinit newcodec_probe(struct pci_dev *pci_dev, return -EINVAL; } - ret = misc_register(&codec_dev); - if (ret) { + if ((ret = misc_register(&codec_dev))) { printk(KERN_ERR "cannot register codec as misc\n"); iounmap(newcodec->ioaddr); release_mem_region(newcodec->io_start, newcodec->io_size); @@ -893,9 +1031,6 @@ static void __devinit newcodec_remove(struct pci_dev *pci_dev) pci_disable_device(pci_dev); } -#define PCI_VENDOR_ID_TIZEN_EMUL 0xC9B5 -#define PCI_DEVICE_ID_VIRTUAL_NEW_CODEC 0x1024 - static struct pci_device_id newcodec_pci_table[] __devinitdata = { { .vendor = PCI_VENDOR_ID_TIZEN_EMUL, @@ -907,7 +1042,6 @@ static struct pci_device_id newcodec_pci_table[] __devinitdata = { }; MODULE_DEVICE_TABLE(pci, newcodec_pci_table); -/* define PCI Driver for CODEC */ static struct pci_driver driver = { .name = DEVICE_NAME, .id_table = newcodec_pci_table, @@ -917,7 +1051,7 @@ static struct pci_driver driver = { static int __init newcodec_init(void) { - printk(KERN_INFO "device is initialized.\n"); + printk(KERN_INFO "%s: driver is initialized.\n", DEVICE_NAME); newcodec_bh_workqueue = create_workqueue ("newcodec"); if (!newcodec_bh_workqueue) {