drivers/vfio/pci/pds/dirty.c

Source file repositories/reference/linux-study-clean/drivers/vfio/pci/pds/dirty.c

File Facts

System
Linux kernel
Corpus path
drivers/vfio/pci/pds/dirty.c
Extension
.c
Size
17370 bytes
Lines
646
Domain
Driver Families
Bucket
drivers/vfio
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 (err) {
			dev_err(&pdev->dev, "Failed to alloc dirty bitmaps: %pe\n",
				ERR_PTR(err));
			goto out_free_regions;
		}

		err = pds_vfio_dirty_alloc_sgl(pds_vfio, region, page_count);
		if (err) {
			dev_err(&pdev->dev, "Failed to alloc dirty sg lists: %pe\n",
				ERR_PTR(err));
			goto out_free_regions;
		}

		region->size = region_size;
		region->start = region_start;
		region->page_size = region_page_size;
		region->dev_bmp_offset_start_byte = dev_bmp_offset_byte;

		dev_bmp_offset_byte += page_count / BITS_PER_BYTE;
		if (dev_bmp_offset_byte % BITS_PER_BYTE) {
			dev_err(&pdev->dev, "Device bitmap offset is mis-aligned\n");
			err = -EINVAL;
			goto out_free_regions;
		}
	}

	return 0;

out_free_regions:
	pds_vfio_dirty_free_bitmaps(dirty);
	pds_vfio_dirty_free_sgl(pds_vfio);
	pds_vfio_dirty_free_regions(dirty);

	return err;
}

static int pds_vfio_dirty_enable(struct pds_vfio_pci_device *pds_vfio,
				 struct rb_root_cached *ranges, u32 nnodes,
				 u64 *page_size)
{
	struct pci_dev *pdev = pds_vfio->vfio_coredev.pdev;
	struct device *pdsc_dev = &pci_physfn(pdev)->dev;
	struct pds_lm_dirty_region_info *region_info;
	struct interval_tree_node *node = NULL;
	u64 region_page_size = *page_size;
	u8 max_regions = 0, num_regions;
	dma_addr_t regions_dma = 0;
	u32 num_ranges = nnodes;
	int err;
	u16 len;

	dev_dbg(&pdev->dev, "vf%u: Start dirty page tracking\n",
		pds_vfio->vf_id);

	if (pds_vfio_dirty_is_enabled(pds_vfio))
		return -EINVAL;

	/* find if dirty tracking is disabled, i.e. num_regions == 0 */
	err = pds_vfio_dirty_status_cmd(pds_vfio, 0, &max_regions,
					&num_regions);
	if (err < 0) {
		dev_err(&pdev->dev, "Failed to get dirty status, err %pe\n",
			ERR_PTR(err));
		return err;
	} else if (num_regions) {
		dev_err(&pdev->dev,
			"Dirty tracking already enabled for %d regions\n",
			num_regions);
		return -EEXIST;
	} else if (!max_regions) {
		dev_err(&pdev->dev,
			"Device doesn't support dirty tracking, max_regions %d\n",
			max_regions);
		return -EOPNOTSUPP;
	}

	if (num_ranges > max_regions) {
		vfio_combine_iova_ranges(ranges, nnodes, max_regions);
		num_ranges = max_regions;
	}

	region_info = kzalloc_objs(*region_info, num_ranges);
	if (!region_info)
		return -ENOMEM;
	len = num_ranges * sizeof(*region_info);

	node = interval_tree_iter_first(ranges, 0, ULONG_MAX);
	if (!node) {
		err = -EINVAL;
		goto out_free_region_info;

Annotation

Implementation Notes