drivers/iommu/iommufd/io_pagetable.c

Source file repositories/reference/linux-study-clean/drivers/iommu/iommufd/io_pagetable.c

File Facts

System
Linux kernel
Corpus path
drivers/iommu/iommufd/io_pagetable.c
Extension
.c
Size
40810 bytes
Lines
1552
Domain
Driver Families
Bucket
drivers/iommu
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

struct iopt_pages_list {
	struct iopt_pages *pages;
	struct iopt_area *area;
	struct list_head next;
	unsigned long start_byte;
	unsigned long length;
};

struct iopt_area *iopt_area_contig_init(struct iopt_area_contig_iter *iter,
					struct io_pagetable *iopt,
					unsigned long iova,
					unsigned long last_iova)
{
	lockdep_assert_held(&iopt->iova_rwsem);

	iter->cur_iova = iova;
	iter->last_iova = last_iova;
	iter->area = iopt_area_iter_first(iopt, iova, iova);
	if (!iter->area)
		return NULL;
	if (!iter->area->pages) {
		iter->area = NULL;
		return NULL;
	}
	return iter->area;
}

struct iopt_area *iopt_area_contig_next(struct iopt_area_contig_iter *iter)
{
	unsigned long last_iova;

	if (!iter->area)
		return NULL;
	last_iova = iopt_area_last_iova(iter->area);
	if (iter->last_iova <= last_iova)
		return NULL;

	iter->cur_iova = last_iova + 1;
	iter->area = iopt_area_iter_next(iter->area, iter->cur_iova,
					 iter->last_iova);
	if (!iter->area)
		return NULL;
	if (iter->cur_iova != iopt_area_iova(iter->area) ||
	    !iter->area->pages) {
		iter->area = NULL;
		return NULL;
	}
	return iter->area;
}

static bool __alloc_iova_check_range(unsigned long *start, unsigned long last,
				     unsigned long length,
				     unsigned long iova_alignment,
				     unsigned long page_offset)
{
	unsigned long aligned_start;

	/* ALIGN_UP() */
	if (check_add_overflow(*start, iova_alignment - 1, &aligned_start))
		return false;
	aligned_start &= ~(iova_alignment - 1);
	aligned_start |= page_offset;

	if (aligned_start >= last || last - aligned_start < length - 1)
		return false;
	*start = aligned_start;
	return true;
}

static bool __alloc_iova_check_hole(struct interval_tree_double_span_iter *span,
				    unsigned long length,
				    unsigned long iova_alignment,
				    unsigned long page_offset)
{
	if (span->is_used)
		return false;
	return __alloc_iova_check_range(&span->start_hole, span->last_hole,
					length, iova_alignment, page_offset);
}

static bool __alloc_iova_check_used(struct interval_tree_span_iter *span,
				    unsigned long length,
				    unsigned long iova_alignment,
				    unsigned long page_offset)
{
	if (span->is_hole)
		return false;
	return __alloc_iova_check_range(&span->start_used, span->last_used,
					length, iova_alignment, page_offset);
}

Annotation

Implementation Notes