From fa8dda1edef9ebc3af467c644c5533ac97171e12 Mon Sep 17 00:00:00 2001 From: Wu Hao Date: Sat, 30 Jun 2018 08:53:35 +0800 Subject: fpga: dfl: afu: add DFL_FPGA_PORT_DMA_MAP/UNMAP ioctls support DMA memory regions are required for Accelerated Function Unit (AFU) usage. These two ioctls allow user space applications to map user memory regions for dma, and unmap them after use. Iova is returned from driver to user space application via DFL_FPGA_PORT_DMA_MAP ioctl. Application needs to unmap it after use, otherwise, driver will unmap them in device file release operation. Each AFU has its own rb tree to keep track of its mapped DMA regions. Ioctl interfaces: * DFL_FPGA_PORT_DMA_MAP Do the dma mapping per user_addr and length provided by user. Return iova in provided struct dfl_fpga_port_dma_map. * DFL_FPGA_PORT_DMA_UNMAP Unmap the dma region per iova provided by user. Signed-off-by: Tim Whisonant Signed-off-by: Enno Luebbers Signed-off-by: Shiva Rao Signed-off-by: Christopher Rauer Signed-off-by: Xiao Guangrong Signed-off-by: Wu Hao Acked-by: Alan Tull Signed-off-by: Greg Kroah-Hartman --- drivers/fpga/dfl-afu-main.c | 61 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) (limited to 'drivers/fpga/dfl-afu-main.c') diff --git a/drivers/fpga/dfl-afu-main.c b/drivers/fpga/dfl-afu-main.c index f67a78d7e9ad..02baa6a227c0 100644 --- a/drivers/fpga/dfl-afu-main.c +++ b/drivers/fpga/dfl-afu-main.c @@ -293,7 +293,11 @@ static int afu_release(struct inode *inode, struct file *filp) pdata = dev_get_platdata(&pdev->dev); - port_reset(pdev); + mutex_lock(&pdata->lock); + __port_reset(pdev); + afu_dma_region_destroy(pdata); + mutex_unlock(&pdata->lock); + dfl_feature_dev_use_end(pdata); return 0; @@ -364,6 +368,55 @@ static long afu_ioctl_get_region_info(struct dfl_feature_platform_data *pdata, return 0; } +static long +afu_ioctl_dma_map(struct dfl_feature_platform_data *pdata, void __user *arg) +{ + struct dfl_fpga_port_dma_map map; + unsigned long minsz; + long ret; + + minsz = offsetofend(struct dfl_fpga_port_dma_map, iova); + + if (copy_from_user(&map, arg, minsz)) + return -EFAULT; + + if (map.argsz < minsz || map.flags) + return -EINVAL; + + ret = afu_dma_map_region(pdata, map.user_addr, map.length, &map.iova); + if (ret) + return ret; + + if (copy_to_user(arg, &map, sizeof(map))) { + afu_dma_unmap_region(pdata, map.iova); + return -EFAULT; + } + + dev_dbg(&pdata->dev->dev, "dma map: ua=%llx, len=%llx, iova=%llx\n", + (unsigned long long)map.user_addr, + (unsigned long long)map.length, + (unsigned long long)map.iova); + + return 0; +} + +static long +afu_ioctl_dma_unmap(struct dfl_feature_platform_data *pdata, void __user *arg) +{ + struct dfl_fpga_port_dma_unmap unmap; + unsigned long minsz; + + minsz = offsetofend(struct dfl_fpga_port_dma_unmap, iova); + + if (copy_from_user(&unmap, arg, minsz)) + return -EFAULT; + + if (unmap.argsz < minsz || unmap.flags) + return -EINVAL; + + return afu_dma_unmap_region(pdata, unmap.iova); +} + static long afu_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct platform_device *pdev = filp->private_data; @@ -384,6 +437,10 @@ static long afu_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) return afu_ioctl_get_info(pdata, (void __user *)arg); case DFL_FPGA_PORT_GET_REGION_INFO: return afu_ioctl_get_region_info(pdata, (void __user *)arg); + case DFL_FPGA_PORT_DMA_MAP: + return afu_ioctl_dma_map(pdata, (void __user *)arg); + case DFL_FPGA_PORT_DMA_UNMAP: + return afu_ioctl_dma_unmap(pdata, (void __user *)arg); default: /* * Let sub-feature's ioctl function to handle the cmd @@ -460,6 +517,7 @@ static int afu_dev_init(struct platform_device *pdev) mutex_lock(&pdata->lock); dfl_fpga_pdata_set_private(pdata, afu); afu_mmio_region_init(pdata); + afu_dma_region_init(pdata); mutex_unlock(&pdata->lock); return 0; @@ -473,6 +531,7 @@ static int afu_dev_destroy(struct platform_device *pdev) mutex_lock(&pdata->lock); afu = dfl_fpga_pdata_get_private(pdata); afu_mmio_region_destroy(pdata); + afu_dma_region_destroy(pdata); dfl_fpga_pdata_set_private(pdata, NULL); mutex_unlock(&pdata->lock); -- cgit v1.2.3