drivers/media/platform/nvidia/tegra-vde/iommu.c

Source file repositories/reference/linux-study-clean/drivers/media/platform/nvidia/tegra-vde/iommu.c

File Facts

System
Linux kernel
Corpus path
drivers/media/platform/nvidia/tegra-vde/iommu.c
Extension
.c
Size
3532 bytes
Lines
159
Domain
Driver Families
Bucket
drivers/media
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

// SPDX-License-Identifier: GPL-2.0+
/*
 * NVIDIA Tegra Video decoder driver
 *
 * Copyright (C) 2016-2019 GRATE-DRIVER project
 */

#include <linux/iommu.h>
#include <linux/iova.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>

#if IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)
#include <asm/dma-iommu.h>
#endif

#include "vde.h"

int tegra_vde_iommu_map(struct tegra_vde *vde,
			struct sg_table *sgt,
			struct iova **iovap,
			size_t size)
{
	struct iova *iova;
	unsigned long shift;
	unsigned long end;
	dma_addr_t addr;

	end = vde->domain->geometry.aperture_end;
	size = iova_align(&vde->iova, size);
	shift = iova_shift(&vde->iova);

	iova = alloc_iova(&vde->iova, size >> shift, end >> shift, true);
	if (!iova)
		return -ENOMEM;

	addr = iova_dma_addr(&vde->iova, iova);

	size = iommu_map_sgtable(vde->domain, addr, sgt,
				 IOMMU_READ | IOMMU_WRITE);
	if (!size) {
		__free_iova(&vde->iova, iova);
		return -ENXIO;
	}

	*iovap = iova;

	return 0;
}

void tegra_vde_iommu_unmap(struct tegra_vde *vde, struct iova *iova)
{
	unsigned long shift = iova_shift(&vde->iova);
	unsigned long size = iova_size(iova) << shift;
	dma_addr_t addr = iova_dma_addr(&vde->iova, iova);

	iommu_unmap(vde->domain, addr, size);
	__free_iova(&vde->iova, iova);
}

int tegra_vde_iommu_init(struct tegra_vde *vde)
{
	struct device *dev = vde->dev;
	struct iova *iova;
	unsigned long order;
	unsigned long shift;
	int err;

	vde->group = iommu_group_get(dev);
	if (!vde->group)
		return 0;

#if IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)
	if (dev->archdata.mapping) {
		struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev);

		arm_iommu_detach_device(dev);
		arm_iommu_release_mapping(mapping);
	}
#endif
	vde->domain = iommu_paging_domain_alloc(dev);
	if (IS_ERR(vde->domain)) {
		err = PTR_ERR(vde->domain);
		vde->domain = NULL;
		goto put_group;
	}

	err = iova_cache_get();
	if (err)
		goto free_domain;

Annotation

Implementation Notes