summaryrefslogtreecommitdiff
path: root/arch/arm/plat-omap/dmm_user.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/plat-omap/dmm_user.c')
-rw-r--r--arch/arm/plat-omap/dmm_user.c187
1 files changed, 43 insertions, 144 deletions
diff --git a/arch/arm/plat-omap/dmm_user.c b/arch/arm/plat-omap/dmm_user.c
index 3afa28db3d2d..6137ebf22354 100644
--- a/arch/arm/plat-omap/dmm_user.c
+++ b/arch/arm/plat-omap/dmm_user.c
@@ -30,12 +30,10 @@
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
-#include <linux/eventfd.h>
#include <plat/iommu.h>
#include <plat/iovmm.h>
#include <plat/dmm_user.h>
-#include "iopgtable.h"
#define OMAP_DMM_NAME "iovmm-omap"
@@ -59,161 +57,46 @@ static int omap_dmm_ioctl(struct inode *inode, struct file *filp,
switch (cmd) {
case DMM_IOCSETTLBENT:
- {
- struct iotlb_entry e;
- int size;
- size = copy_from_user(&e, (void __user *)args,
- sizeof(struct iotlb_entry));
- if (size) {
- ret = -EINVAL;
- goto err_user_buf;
- }
- load_iotlb_entry(obj->iovmm->iommu, &e);
+ /* FIXME: re-visit this check to perform
+ proper permission checks */
+ /* if (!capable(CAP_SYS_ADMIN))
+ return -EPERM; */
+ ret = program_tlb_entry(obj, (const void __user *)args);
break;
- }
case DMM_IOCCREATEPOOL:
- {
- struct iovmm_pool_info pool_info;
- int size;
-
- size = copy_from_user(&pool_info, (void __user *)args,
- sizeof(struct iovmm_pool_info));
- if (size) {
- ret = -EINVAL;
- goto err_user_buf;
- }
- omap_create_dmm_pool(obj, pool_info.pool_id, pool_info.size,
- pool_info.da_begin);
+ /* FIXME: re-visit this check to perform
+ proper permission checks */
+ /* if (!capable(CAP_SYS_ADMIN))
+ return -EPERM; */
+ ret = omap_create_dmm_pool(obj, (const void __user *)args);
break;
- }
- case DMM_IOCDELETEPOOL:
- {
- int pool_id;
- int size;
-
- size = copy_from_user(&pool_id, (void __user *)args,
- sizeof(int));
- if (size) {
- ret = -EINVAL;
- goto err_user_buf;
- }
- ret = omap_delete_dmm_pool(obj, pool_id);
- break;
- }
case DMM_IOCMEMMAP:
- {
- struct dmm_map_info map_info;
- int size;
- int status;
-
- size = copy_from_user(&map_info, (void __user *)args,
- sizeof(struct dmm_map_info));
-
- status = dmm_user(obj, map_info.mem_pool_id,
- map_info.da, map_info.mpu_addr,
- map_info.size, map_info.flags);
- ret = copy_to_user((void __user *)args, &map_info,
- sizeof(struct dmm_map_info));
+ ret = dmm_user(obj, (void __user *)args);
break;
- }
case DMM_IOCMEMUNMAP:
- {
- u32 da;
- int size;
- int status = 0;
-
- size = copy_from_user(&da, (void __user *)args, sizeof(u32));
- if (size) {
- ret = -EINVAL;
- goto err_user_buf;
- }
- status = user_un_map(obj, da);
- ret = status;
+ ret = user_un_map(obj, (const void __user *)args);
break;
- }
case IOMMU_IOCEVENTREG:
- {
- int fd;
- int size;
- struct iommu_event_ntfy *fd_reg;
-
- size = copy_from_user(&fd, (void __user *)args, sizeof(int));
- if (size) {
- ret = -EINVAL;
- goto err_user_buf;
- }
-
- fd_reg = kzalloc(sizeof(struct iommu_event_ntfy), GFP_KERNEL);
- fd_reg->fd = fd;
- fd_reg->evt_ctx = eventfd_ctx_fdget(fd);
- INIT_LIST_HEAD(&fd_reg->list);
- spin_lock_irq(&obj->iovmm->iommu->event_lock);
- list_add_tail(&fd_reg->list, &obj->iovmm->iommu->event_list);
- spin_unlock_irq(&obj->iovmm->iommu->event_lock);
+ ret = register_mmufault(obj, (const void __user *)args);
break;
- }
case IOMMU_IOCEVENTUNREG:
- {
- int fd;
- int size;
- struct iommu_event_ntfy *fd_reg, *temp_reg;
-
- size = copy_from_user(&fd, (void __user *)args, sizeof(int));
- if (size) {
- ret = -EINVAL;
- goto err_user_buf;
- }
- /* Free DMM mapped memory resources */
- spin_lock_irq(&obj->iovmm->iommu->event_lock);
- list_for_each_entry_safe(fd_reg, temp_reg,
- &obj->iovmm->iommu->event_list, list) {
- if (fd_reg->fd == fd) {
- list_del(&fd_reg->list);
- kfree(fd_reg);
- }
- }
- spin_unlock_irq(&obj->iovmm->iommu->event_lock);
+ ret = register_mmufault(obj, (const void __user *)args);
break;
- }
case DMM_IOCMEMFLUSH:
- {
- int size;
- int status;
- struct dmm_dma_info dma_info;
- size = copy_from_user(&dma_info, (void __user *)args,
- sizeof(struct dmm_dma_info));
- if (size) {
- ret = -EINVAL;
- goto err_user_buf;
- }
- status = proc_begin_dma(obj, dma_info.pva, dma_info.ul_size,
- dma_info.dir);
- ret = status;
+ ret = proc_begin_dma(obj, (void __user *)args);
break;
- }
case DMM_IOCMEMINV:
- {
- int size;
- int status;
- struct dmm_dma_info dma_info;
- size = copy_from_user(&dma_info, (void __user *)args,
- sizeof(struct dmm_dma_info));
- if (size) {
- ret = -EINVAL;
- goto err_user_buf;
- }
- status = proc_end_dma(obj, dma_info.pva, dma_info.ul_size,
- dma_info.dir);
- ret = status;
+ ret = proc_end_dma(obj, (void __user *)args);
+ break;
+ /* This ioctl can be deprecated */
+ case DMM_IOCDELETEPOOL:
break;
- }
case DMM_IOCDATOPA:
default:
return -ENOTTY;
}
-err_user_buf:
- return ret;
+ return ret;
}
static int omap_dmm_open(struct inode *inode, struct file *filp)
@@ -222,6 +105,7 @@ static int omap_dmm_open(struct inode *inode, struct file *filp)
struct iovmm_device *obj;
obj = container_of(inode->i_cdev, struct iovmm_device, cdev);
+ obj->refcount++;
iodmm = kzalloc(sizeof(struct iodmm_struct), GFP_KERNEL);
INIT_LIST_HEAD(&iodmm->map_list);
@@ -240,25 +124,41 @@ static int omap_dmm_release(struct inode *inode, struct file *filp)
if (!filp->private_data) {
status = -EIO;
- goto err;
+ goto err_out;
}
obj = filp->private_data;
+
flush_signals(current);
status = mutex_lock_interruptible(&obj->iovmm->dmm_map_lock);
if (status == 0) {
- iommu_notify_event(obj->iovmm->iommu, IOMMU_CLOSE, NULL);
+ /*
+ * Report to remote Processor of the cleanup of these
+ * resources before cleaning in order to avoid MMU fault
+ * type of behavior
+ */
+ if (!list_empty(&obj->map_list)) {
+ iommu_notify_event(obj->iovmm->iommu, IOMMU_CLOSE,
+ NULL);
+ }
mutex_unlock(&obj->iovmm->dmm_map_lock);
} else {
pr_err("%s mutex_lock_interruptible returned 0x%x\n",
__func__, status);
}
+
user_remove_resources(obj);
iommu_put(obj->iovmm->iommu);
+
+ /* Delete all the DMM pools after the reference count goes to zero */
+ if (--obj->iovmm->refcount == 0)
+ omap_delete_dmm_pools(obj);
+
kfree(obj);
+
filp->private_data = NULL;
-err:
+err_out:
return status;
}
@@ -316,6 +216,7 @@ static int __devinit omap_dmm_probe(struct platform_device *pdev)
mutex_init(&obj->dmm_map_lock);
platform_set_drvdata(pdev, obj);
return 0;
+
clean_cdev:
cdev_del(&obj->cdev);
err_cdev:
@@ -326,14 +227,12 @@ static int __devexit omap_dmm_remove(struct platform_device *pdev)
{
struct iovmm_device *obj = platform_get_drvdata(pdev);
int major = MAJOR(omap_dmm_dev);
+
device_destroy(omap_dmm_class, MKDEV(major, obj->minor));
cdev_del(&obj->cdev);
platform_set_drvdata(pdev, NULL);
- iopgtable_clear_entry_all(obj->iommu);
- iommu_put(obj->iommu);
- free_pages((unsigned long)obj->iommu->iopgd,
- get_order(IOPGD_TABLE_SIZE));
kfree(obj);
+
return 0;
}