drivers/fpga/dfl-afu-dma-region.c

Source file repositories/reference/linux-study-clean/drivers/fpga/dfl-afu-dma-region.c

File Facts

System
Linux kernel
Corpus path
drivers/fpga/dfl-afu-dma-region.c
Extension
.c
Size
10355 bytes
Lines
407
Domain
Driver Families
Bucket
drivers/fpga
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (dma_region_check_iova(region, iova, size)) {
			dev_dbg(dev, "find region (iova = %llx)\n",
				(unsigned long long)region->iova);
			return region;
		}

		if (iova < region->iova)
			node = node->rb_left;
		else if (iova > region->iova)
			node = node->rb_right;
		else
			/* the iova region is not fully covered. */
			break;
	}

	dev_dbg(dev, "region with iova %llx and size %llx is not found\n",
		(unsigned long long)iova, (unsigned long long)size);

	return NULL;
}

/**
 * afu_dma_region_find_iova - find the dma region from rbtree by iova
 * @fdata: feature dev data
 * @iova: address of the dma region
 *
 * Needs to be called with fdata->lock held.
 */
static struct dfl_afu_dma_region *
afu_dma_region_find_iova(struct dfl_feature_dev_data *fdata, u64 iova)
{
	return afu_dma_region_find(fdata, iova, 0);
}

/**
 * afu_dma_map_region - map memory region for dma
 * @fdata: feature dev data
 * @user_addr: address of the memory region
 * @length: size of the memory region
 * @iova: pointer of iova address
 *
 * Map memory region defined by @user_addr and @length, and return dma address
 * of the memory region via @iova.
 * Return 0 for success, otherwise error code.
 */
int afu_dma_map_region(struct dfl_feature_dev_data *fdata,
		       u64 user_addr, u64 length, u64 *iova)
{
	struct device *dev = &fdata->dev->dev;
	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(fdata, region);
	if (ret) {
		dev_err(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(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_fdata_to_parent(fdata),
				    region->pages[0], 0,
				    region->length,
				    DMA_BIDIRECTIONAL);
	if (dma_mapping_error(dfl_fpga_fdata_to_parent(fdata), region->iova)) {

Annotation

Implementation Notes