Commit fa8dda1e authored by Wu Hao's avatar Wu Hao Committed by Greg Kroah-Hartman

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: default avatarTim Whisonant <tim.whisonant@intel.com>
Signed-off-by: default avatarEnno Luebbers <enno.luebbers@intel.com>
Signed-off-by: default avatarShiva Rao <shiva.rao@intel.com>
Signed-off-by: default avatarChristopher Rauer <christopher.rauer@intel.com>
Signed-off-by: default avatarXiao Guangrong <guangrong.xiao@linux.intel.com>
Signed-off-by: default avatarWu Hao <hao.wu@intel.com>
Acked-by: default avatarAlan Tull <atull@kernel.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 857a2622
......@@ -38,7 +38,7 @@ obj-$(CONFIG_FPGA_DFL_FME_REGION) += dfl-fme-region.o
obj-$(CONFIG_FPGA_DFL_AFU) += dfl-afu.o
dfl-fme-objs := dfl-fme-main.o dfl-fme-pr.o
dfl-afu-objs := dfl-afu-main.o dfl-afu-region.o
dfl-afu-objs := dfl-afu-main.o dfl-afu-region.o dfl-afu-dma-region.o
# Drivers for FPGAs which implement DFL
obj-$(CONFIG_FPGA_DFL_PCI) += dfl-pci.o
This diff is collapsed.
......@@ -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);
......
......@@ -40,12 +40,32 @@ struct dfl_afu_mmio_region {
struct list_head node;
};
/**
* struct fpga_afu_dma_region - afu DMA region data structure
*
* @user_addr: region userspace virtual address.
* @length: region length.
* @iova: region IO virtual address.
* @pages: ptr to pages of this region.
* @node: rb tree node.
* @in_use: flag to indicate if this region is in_use.
*/
struct dfl_afu_dma_region {
u64 user_addr;
u64 length;
u64 iova;
struct page **pages;
struct rb_node node;
bool in_use;
};
/**
* struct dfl_afu - afu device data structure
*
* @region_cur_offset: current region offset from start to the device fd.
* @num_regions: num of mmio regions.
* @regions: the mmio region linked list of this afu feature device.
* @dma_regions: root of dma regions rb tree.
* @num_umsgs: num of umsgs.
* @pdata: afu platform device's pdata.
*/
......@@ -54,6 +74,7 @@ struct dfl_afu {
int num_regions;
u8 num_umsgs;
struct list_head regions;
struct rb_root dma_regions;
struct dfl_feature_platform_data *pdata;
};
......@@ -68,4 +89,12 @@ int afu_mmio_region_get_by_index(struct dfl_feature_platform_data *pdata,
int afu_mmio_region_get_by_offset(struct dfl_feature_platform_data *pdata,
u64 offset, u64 size,
struct dfl_afu_mmio_region *pregion);
#endif
void afu_dma_region_init(struct dfl_feature_platform_data *pdata);
void afu_dma_region_destroy(struct dfl_feature_platform_data *pdata);
int afu_dma_map_region(struct dfl_feature_platform_data *pdata,
u64 user_addr, u64 length, u64 *iova);
int afu_dma_unmap_region(struct dfl_feature_platform_data *pdata, u64 iova);
struct dfl_afu_dma_region *
afu_dma_region_find(struct dfl_feature_platform_data *pdata,
u64 iova, u64 size);
#endif /* __DFL_AFU_H */
......@@ -114,6 +114,43 @@ struct dfl_fpga_port_region_info {
#define DFL_FPGA_PORT_GET_REGION_INFO _IO(DFL_FPGA_MAGIC, DFL_PORT_BASE + 2)
/**
* DFL_FPGA_PORT_DMA_MAP - _IOWR(DFL_FPGA_MAGIC, DFL_PORT_BASE + 3,
* struct dfl_fpga_port_dma_map)
*
* Map the dma memory per user_addr and length which are provided by caller.
* Driver fills the iova in provided struct afu_port_dma_map.
* This interface only accepts page-size aligned user memory for dma mapping.
* Return: 0 on success, -errno on failure.
*/
struct dfl_fpga_port_dma_map {
/* Input */
__u32 argsz; /* Structure length */
__u32 flags; /* Zero for now */
__u64 user_addr; /* Process virtual address */
__u64 length; /* Length of mapping (bytes)*/
/* Output */
__u64 iova; /* IO virtual address */
};
#define DFL_FPGA_PORT_DMA_MAP _IO(DFL_FPGA_MAGIC, DFL_PORT_BASE + 3)
/**
* DFL_FPGA_PORT_DMA_UNMAP - _IOW(FPGA_MAGIC, PORT_BASE + 4,
* struct dfl_fpga_port_dma_unmap)
*
* Unmap the dma memory per iova provided by caller.
* Return: 0 on success, -errno on failure.
*/
struct dfl_fpga_port_dma_unmap {
/* Input */
__u32 argsz; /* Structure length */
__u32 flags; /* Zero for now */
__u64 iova; /* IO virtual address */
};
#define DFL_FPGA_PORT_DMA_UNMAP _IO(DFL_FPGA_MAGIC, DFL_PORT_BASE + 4)
/* IOCTLs for FME file descriptor */
/**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment