drivers/iommu/iommu-pages.c

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

File Facts

System
Linux kernel
Corpus path
drivers/iommu/iommu-pages.c
Extension
.c
Size
7422 bytes
Lines
254
Domain
Driver Families
Bucket
drivers/iommu
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

if (WARN_ON(dma != virt_to_phys(virt))) {
			dma_unmap_single(dma_dev, dma, ioptdesc_mem_size(iopt),
					 DMA_TO_DEVICE);
			return -EOPNOTSUPP;
		}
	}

	iopt->incoherent = 1;
	return 0;
}
EXPORT_SYMBOL_GPL(iommu_pages_start_incoherent);

/**
 * iommu_pages_start_incoherent_list - Make a list of pages incoherent
 * @list: The list of pages to setup
 * @dma_dev: The iommu device
 *
 * Perform iommu_pages_start_incoherent() across all of list.
 *
 * If this fails the caller must call iommu_pages_stop_incoherent_list().
 */
int iommu_pages_start_incoherent_list(struct iommu_pages_list *list,
				      struct device *dma_dev)
{
	struct ioptdesc *cur;
	int ret;

	list_for_each_entry(cur, &list->pages, iopt_freelist_elm) {
		if (WARN_ON(cur->incoherent))
			continue;

		ret = iommu_pages_start_incoherent(
			folio_address(ioptdesc_folio(cur)), dma_dev);
		if (ret)
			return ret;
	}
	return 0;
}
EXPORT_SYMBOL_GPL(iommu_pages_start_incoherent_list);

/**
 * iommu_pages_stop_incoherent_list - Undo incoherence across a list
 * @list: The list of pages to release
 * @dma_dev: The iommu device
 *
 * Revert iommu_pages_start_incoherent() across all of the list. Pages that did
 * not call or succeed iommu_pages_start_incoherent() will be ignored.
 */
#if IOMMU_PAGES_USE_DMA_API
void iommu_pages_stop_incoherent_list(struct iommu_pages_list *list,
				      struct device *dma_dev)
{
	struct ioptdesc *cur;

	list_for_each_entry(cur, &list->pages, iopt_freelist_elm) {
		struct folio *folio = ioptdesc_folio(cur);

		if (!cur->incoherent)
			continue;
		dma_unmap_single(dma_dev, virt_to_phys(folio_address(folio)),
				 ioptdesc_mem_size(cur), DMA_TO_DEVICE);
		cur->incoherent = 0;
	}
}
EXPORT_SYMBOL_GPL(iommu_pages_stop_incoherent_list);

/**
 * iommu_pages_free_incoherent - Free an incoherent page
 * @virt: virtual address of the page to be freed.
 * @dma_dev: The iommu device
 *
 * If the page is incoherent it made coherent again then freed.
 */
void iommu_pages_free_incoherent(void *virt, struct device *dma_dev)
{
	struct ioptdesc *iopt = virt_to_ioptdesc(virt);

	if (iopt->incoherent) {
		dma_unmap_single(dma_dev, virt_to_phys(virt),
				 ioptdesc_mem_size(iopt), DMA_TO_DEVICE);
		iopt->incoherent = 0;
	}
	__iommu_free_desc(iopt);
}
EXPORT_SYMBOL_GPL(iommu_pages_free_incoherent);
#endif

Annotation

Implementation Notes