brintos

brintos / linux-shallow public Read only

0
0
Text · 3.4 KiB · 5521ed3 Raw
158 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * NVIDIA Tegra Video decoder driver4 *5 * Copyright (C) 2016-2019 GRATE-DRIVER project6 */7 8#include <linux/iommu.h>9#include <linux/iova.h>10#include <linux/kernel.h>11#include <linux/platform_device.h>12 13#if IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)14#include <asm/dma-iommu.h>15#endif16 17#include "vde.h"18 19int tegra_vde_iommu_map(struct tegra_vde *vde,20			struct sg_table *sgt,21			struct iova **iovap,22			size_t size)23{24	struct iova *iova;25	unsigned long shift;26	unsigned long end;27	dma_addr_t addr;28 29	end = vde->domain->geometry.aperture_end;30	size = iova_align(&vde->iova, size);31	shift = iova_shift(&vde->iova);32 33	iova = alloc_iova(&vde->iova, size >> shift, end >> shift, true);34	if (!iova)35		return -ENOMEM;36 37	addr = iova_dma_addr(&vde->iova, iova);38 39	size = iommu_map_sgtable(vde->domain, addr, sgt,40				 IOMMU_READ | IOMMU_WRITE);41	if (!size) {42		__free_iova(&vde->iova, iova);43		return -ENXIO;44	}45 46	*iovap = iova;47 48	return 0;49}50 51void tegra_vde_iommu_unmap(struct tegra_vde *vde, struct iova *iova)52{53	unsigned long shift = iova_shift(&vde->iova);54	unsigned long size = iova_size(iova) << shift;55	dma_addr_t addr = iova_dma_addr(&vde->iova, iova);56 57	iommu_unmap(vde->domain, addr, size);58	__free_iova(&vde->iova, iova);59}60 61int tegra_vde_iommu_init(struct tegra_vde *vde)62{63	struct device *dev = vde->dev;64	struct iova *iova;65	unsigned long order;66	unsigned long shift;67	int err;68 69	vde->group = iommu_group_get(dev);70	if (!vde->group)71		return 0;72 73#if IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)74	if (dev->archdata.mapping) {75		struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev);76 77		arm_iommu_detach_device(dev);78		arm_iommu_release_mapping(mapping);79	}80#endif81	vde->domain = iommu_domain_alloc(&platform_bus_type);82	if (!vde->domain) {83		err = -ENOMEM;84		goto put_group;85	}86 87	err = iova_cache_get();88	if (err)89		goto free_domain;90 91	order = __ffs(vde->domain->pgsize_bitmap);92	init_iova_domain(&vde->iova, 1UL << order, 0);93 94	err = iommu_attach_group(vde->domain, vde->group);95	if (err)96		goto put_iova;97 98	/*99	 * We're using some static addresses that are not accessible by VDE100	 * to trap invalid memory accesses.101	 */102	shift = iova_shift(&vde->iova);103	iova = reserve_iova(&vde->iova, 0x60000000 >> shift,104			    0x70000000 >> shift);105	if (!iova) {106		err = -ENOMEM;107		goto detach_group;108	}109 110	vde->iova_resv_static_addresses = iova;111 112	/*113	 * BSEV's end-address wraps around due to integer overflow during114	 * of hardware context preparation if IOVA is allocated at the end115	 * of address space and VDE can't handle that. Hence simply reserve116	 * the last page to avoid the problem.117	 */118	iova = reserve_iova(&vde->iova, 0xffffffff >> shift,119			    (0xffffffff >> shift) + 1);120	if (!iova) {121		err = -ENOMEM;122		goto unreserve_iova;123	}124 125	vde->iova_resv_last_page = iova;126 127	return 0;128 129unreserve_iova:130	__free_iova(&vde->iova, vde->iova_resv_static_addresses);131detach_group:132	iommu_detach_group(vde->domain, vde->group);133put_iova:134	put_iova_domain(&vde->iova);135	iova_cache_put();136free_domain:137	iommu_domain_free(vde->domain);138put_group:139	iommu_group_put(vde->group);140 141	return err;142}143 144void tegra_vde_iommu_deinit(struct tegra_vde *vde)145{146	if (vde->domain) {147		__free_iova(&vde->iova, vde->iova_resv_last_page);148		__free_iova(&vde->iova, vde->iova_resv_static_addresses);149		iommu_detach_group(vde->domain, vde->group);150		put_iova_domain(&vde->iova);151		iova_cache_put();152		iommu_domain_free(vde->domain);153		iommu_group_put(vde->group);154 155		vde->domain = NULL;156	}157}158