diff options
Diffstat (limited to 'drivers/video/tegra/nvmap')
-rw-r--r-- | drivers/video/tegra/nvmap/Makefile | 1 | ||||
-rw-r--r-- | drivers/video/tegra/nvmap/nvmap_iommu.c | 97 |
2 files changed, 98 insertions, 0 deletions
diff --git a/drivers/video/tegra/nvmap/Makefile b/drivers/video/tegra/nvmap/Makefile index 95d7f68836af..3da03af2b1eb 100644 --- a/drivers/video/tegra/nvmap/Makefile +++ b/drivers/video/tegra/nvmap/Makefile @@ -4,4 +4,5 @@ obj-y += nvmap_dev.o obj-y += nvmap_handle.o obj-y += nvmap_heap.o obj-y += nvmap_ioctl.o +obj-${CONFIG_IOMMU_API} += nvmap_iommu.o obj-${CONFIG_NVMAP_RECLAIM_UNPINNED_VM} += nvmap_mru.o
\ No newline at end of file diff --git a/drivers/video/tegra/nvmap/nvmap_iommu.c b/drivers/video/tegra/nvmap/nvmap_iommu.c new file mode 100644 index 000000000000..ca868032db3f --- /dev/null +++ b/drivers/video/tegra/nvmap/nvmap_iommu.c @@ -0,0 +1,97 @@ +/* + * IOMMU backend support for NVMAP + * + * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <linux/slab.h> +#include <mach/iomap.h> +#include <mach/iovmm.h> + +#include "nvmap.h" + +struct tegra_iovmm_area *tegra_iommu_create_vm(struct device *dev, + dma_addr_t req, size_t size, pgprot_t prot) +{ + struct tegra_iovmm_area *area; + dma_addr_t iova; + + area = kmalloc(sizeof(*area), GFP_KERNEL); + if (!area) + return NULL; + + if (!req) + req = DMA_ANON_ADDR; + + iova = arm_iommu_alloc_iova_at(dev, req, size); + if (iova == DMA_ERROR_CODE) + goto err_out; + area->iovm_start = iova; + area->iovm_length = size; + area->pgprot = prot; + area->dev = dev; + return area; + +err_out: + kfree(area); + return NULL; +} + +void tegra_iommu_free_vm(struct tegra_iovmm_area *area) +{ + int i; + size_t count = area->iovm_length >> PAGE_SHIFT; + + for (i = 0; i < count; i++) { + dma_addr_t iova; + + iova = area->iovm_start + i * PAGE_SIZE; + dma_unmap_page(area->dev, iova, PAGE_SIZE, DMA_NONE); + } + kfree(area); +} + +struct tegra_iovmm_client *tegra_iommu_alloc_client(struct device *dev) +{ + struct dma_iommu_mapping *map; + struct tegra_iovmm_client *client; + + client = kzalloc(sizeof(*client), GFP_KERNEL); + if (!client) + return NULL; + + map = arm_iommu_create_mapping(&platform_bus_type, + TEGRA_IOMMU_BASE, TEGRA_IOMMU_SIZE, 0); + if (IS_ERR(map)) + goto err_map; + + if (arm_iommu_attach_device(dev, map)) + goto err_attach; + client->dev = dev; + return client; + +err_attach: + arm_iommu_release_mapping(map); +err_map: + kfree(client); + return NULL; +} + +void tegra_iommu_free_client(struct tegra_iovmm_client *client) +{ + arm_iommu_release_mapping(client->dev->archdata.mapping); + kfree(client); +} |