drivers/media/pci/intel/ipu6/ipu6-dma.c

Source file repositories/reference/linux-study-clean/drivers/media/pci/intel/ipu6/ipu6-dma.c

File Facts

System
Linux kernel
Corpus path
drivers/media/pci/intel/ipu6/ipu6-dma.c
Extension
.c
Size
10847 bytes
Lines
460
Domain
Driver Families
Bucket
drivers/media
Inferred role
Driver Families: exported/initcall integration point
Status
integration 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 vm_info {
	struct list_head list;
	struct page **pages;
	dma_addr_t ipu6_iova;
	void *vaddr;
	unsigned long size;
};

static struct vm_info *get_vm_info(struct ipu6_mmu *mmu, dma_addr_t iova)
{
	struct vm_info *info, *save;

	list_for_each_entry_safe(info, save, &mmu->vma_list, list) {
		if (iova >= info->ipu6_iova &&
		    iova < (info->ipu6_iova + info->size))
			return info;
	}

	return NULL;
}

static void __clear_buffer(struct page *page, size_t size, unsigned long attrs)
{
	void *ptr;

	if (!page)
		return;
	/*
	 * Ensure that the allocated pages are zeroed, and that any data
	 * lurking in the kernel direct-mapped region is invalidated.
	 */
	ptr = page_address(page);
	memset(ptr, 0, size);
	if ((attrs & DMA_ATTR_SKIP_CPU_SYNC) == 0)
		clflush_cache_range(ptr, size);
}

static struct page **__alloc_buffer(size_t size, gfp_t gfp, unsigned long attrs)
{
	int count = PHYS_PFN(size);
	int array_size = count * sizeof(struct page *);
	struct page **pages;
	int i = 0;

	pages = kvzalloc(array_size, GFP_KERNEL);
	if (!pages)
		return NULL;

	gfp |= __GFP_NOWARN;

	while (count) {
		int j, order = __fls(count);

		pages[i] = alloc_pages(gfp, order);
		while (!pages[i] && order)
			pages[i] = alloc_pages(gfp, --order);
		if (!pages[i])
			goto error;

		if (order) {
			split_page(pages[i], order);
			j = 1 << order;
			while (j--)
				pages[i + j] = pages[i] + j;
		}

		__clear_buffer(pages[i], PAGE_SIZE << order, attrs);
		i += 1 << order;
		count -= 1 << order;
	}

	return pages;
error:
	while (i--)
		if (pages[i])
			__free_pages(pages[i], 0);
	kvfree(pages);
	return NULL;
}

static void __free_buffer(struct page **pages, size_t size, unsigned long attrs)
{
	int count = PHYS_PFN(size);
	unsigned int i;

	for (i = 0; i < count && pages[i]; i++) {
		__clear_buffer(pages[i], PAGE_SIZE, attrs);
		__free_pages(pages[i], 0);
	}

Annotation

Implementation Notes