drivers/accel/amdxdna/amdxdna_iommu.c

Source file repositories/reference/linux-study-clean/drivers/accel/amdxdna/amdxdna_iommu.c

File Facts

System
Linux kernel
Corpus path
drivers/accel/amdxdna/amdxdna_iommu.c
Extension
.c
Size
5132 bytes
Lines
211
Domain
Driver Families
Bucket
drivers/accel
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 (!sg_page(sgt->sgl)) {
			XDNA_ERR(xdna, "sgl is not page backed");
			return -EOPNOTSUPP;
		}

		iova = amdxdna_iommu_alloc_iova(xdna, abo->mem.size, &dma_addr,
						(abo->type == AMDXDNA_BO_DEV_HEAP));
		if (IS_ERR(iova)) {
			XDNA_ERR(xdna, "Alloc iova failed, ret %ld", PTR_ERR(iova));
			return PTR_ERR(iova);
		}

		size = iommu_map_sgtable(xdna->domain, dma_addr, sgt,
					 IOMMU_READ | IOMMU_WRITE);
		if (size < 0) {
			XDNA_ERR(xdna, "iommu_map_sgtable failed: %zd", size);
			__free_iova(&xdna->iovad, iova);
			return size;
		}
		if (size < abo->mem.size) {
			iommu_unmap(xdna->domain, dma_addr, size);
			__free_iova(&xdna->iovad, iova);
			return -ENXIO;
		}
		abo->mem.dma_addr = dma_addr;
	} else {
		/* Device doesn't support scatter/gather list, fail non-contiguous mapping. */
		contig_sz = drm_prime_get_contiguous_size(sgt);
		if (contig_sz < abo->mem.size) {
			XDNA_ERR(xdna,
				 "noncontiguous dma addr, contig size:%ld, expected size:%ld",
				 contig_sz, abo->mem.size);
			return -EINVAL;
		}
		abo->mem.dma_addr = sg_dma_address(sgt->sgl);
	}
	return 0;
}

void amdxdna_dma_unmap_bo(struct amdxdna_dev *xdna, struct amdxdna_gem_obj *abo)
{
	size_t size;

	if (abo->mem.dma_addr == AMDXDNA_INVALID_ADDR)
		return;

	if (amdxdna_iova_on(xdna)) {
		size = iova_align(&xdna->iovad, abo->mem.size);
		iommu_unmap(xdna->domain, abo->mem.dma_addr, size);
		free_iova(&xdna->iovad, iova_pfn(&xdna->iovad, abo->mem.dma_addr));
	}
	abo->mem.dma_addr = AMDXDNA_INVALID_ADDR;
}

void *amdxdna_iommu_alloc(struct amdxdna_dev *xdna, size_t size, dma_addr_t *dma_addr)
{
	struct iova *iova;
	void *cpu_addr;
	int ret;

	iova = amdxdna_iommu_alloc_iova(xdna, size, dma_addr, true);
	if (IS_ERR(iova)) {
		XDNA_ERR(xdna, "Alloc iova failed, ret %ld", PTR_ERR(iova));
		return iova;
	}

	cpu_addr = (void *)__get_free_pages(GFP_KERNEL, get_order(size));
	if (!cpu_addr) {
		ret = -ENOMEM;
		goto free_iova;
	}

	ret = iommu_map(xdna->domain, *dma_addr, virt_to_phys(cpu_addr),
			iova_align(&xdna->iovad, size),
			IOMMU_READ | IOMMU_WRITE, GFP_KERNEL);
	if (ret)
		goto free_cpu_addr;

	return cpu_addr;

free_cpu_addr:
	free_pages((unsigned long)cpu_addr, get_order(size));
free_iova:
	__free_iova(&xdna->iovad, iova);
	return ERR_PTR(ret);
}

void amdxdna_iommu_free(struct amdxdna_dev *xdna, size_t size,
			void *cpu_addr, dma_addr_t dma_addr)
{

Annotation

Implementation Notes