in dfl-afu-dma-region.c [301:370]
int afu_dma_map_region(struct dfl_feature_platform_data *pdata,
u64 user_addr, u64 length, u64 *iova)
{
struct dfl_afu_dma_region *region;
int ret;
/*
* Check Inputs, only accept page-aligned user memory region with
* valid length.
*/
if (!PAGE_ALIGNED(user_addr) || !PAGE_ALIGNED(length) || !length)
return -EINVAL;
/* Check overflow */
if (user_addr + length < user_addr)
return -EINVAL;
region = kzalloc(sizeof(*region), GFP_KERNEL);
if (!region)
return -ENOMEM;
region->user_addr = user_addr;
region->length = length;
/* Pin the user memory region */
ret = afu_dma_pin_pages(pdata, region);
if (ret) {
dev_err(&pdata->dev->dev, "failed to pin memory region\n");
goto free_region;
}
/* Only accept continuous pages, return error else */
if (!afu_dma_check_continuous_pages(region)) {
dev_err(&pdata->dev->dev, "pages are not continuous\n");
ret = -EINVAL;
goto unpin_pages;
}
/* As pages are continuous then start to do DMA mapping */
region->iova = dma_map_page(dfl_fpga_pdata_to_parent(pdata),
region->pages[0], 0,
region->length,
DMA_BIDIRECTIONAL);
if (dma_mapping_error(dfl_fpga_pdata_to_parent(pdata), region->iova)) {
dev_err(&pdata->dev->dev, "failed to map for dma\n");
ret = -EFAULT;
goto unpin_pages;
}
*iova = region->iova;
mutex_lock(&pdata->lock);
ret = afu_dma_region_add(pdata, region);
mutex_unlock(&pdata->lock);
if (ret) {
dev_err(&pdata->dev->dev, "failed to add dma region\n");
goto unmap_dma;
}
return 0;
unmap_dma:
dma_unmap_page(dfl_fpga_pdata_to_parent(pdata),
region->iova, region->length, DMA_BIDIRECTIONAL);
unpin_pages:
afu_dma_unpin_pages(pdata, region);
free_region:
kfree(region);
return ret;
}