diff options
author | Wolfgang Wiedmeyer <wolfgit@wiedmeyer.de> | 2015-10-25 15:09:20 +0100 |
---|---|---|
committer | Wolfgang Wiedmeyer <wolfgit@wiedmeyer.de> | 2015-10-25 15:09:20 +0100 |
commit | 9a5be153f580e9cb52b28d3f97ec744ed012b8af (patch) | |
tree | 0520e335e3ce998067e3594199482c3dedb02847 /drivers/iommu/exynos-iovmm.c | |
parent | f236331eca99eb2f3f0657cf16ed6a11ecc13aca (diff) | |
download | kernel_samsung_smdk4412-9a5be153f580e9cb52b28d3f97ec744ed012b8af.zip kernel_samsung_smdk4412-9a5be153f580e9cb52b28d3f97ec744ed012b8af.tar.gz kernel_samsung_smdk4412-9a5be153f580e9cb52b28d3f97ec744ed012b8af.tar.bz2 |
removed unneeded drivers
Diffstat (limited to 'drivers/iommu/exynos-iovmm.c')
-rw-r--r-- | drivers/iommu/exynos-iovmm.c | 510 |
1 files changed, 0 insertions, 510 deletions
diff --git a/drivers/iommu/exynos-iovmm.c b/drivers/iommu/exynos-iovmm.c deleted file mode 100644 index bc78722..0000000 --- a/drivers/iommu/exynos-iovmm.c +++ /dev/null @@ -1,510 +0,0 @@ -/* linux/arch/arm/plat-s5p/s5p_iovmm.c - * - * Copyright (c) 2011 Samsung Electronics Co., Ltd. - * http://www.samsung.com - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifdef CONFIG_EXYNOS_IOMMU_DEBUG -#define DEBUG -#endif - -#include <linux/slab.h> -#include <linux/scatterlist.h> -#include <linux/device.h> -#include <linux/list.h> -#include <linux/iommu.h> -#include <linux/genalloc.h> -#include <linux/err.h> -#include <linux/spinlock.h> -#include <linux/platform_device.h> -#include <linux/atomic.h> -#include <linux/rculist.h> - -#include <plat/iovmm.h> - -#define IOVA_START 0xC0000000 -#define IOVM_SIZE (SZ_1G - SZ_4K) /* last 4K is for error values */ - -struct s5p_vm_region { - struct list_head node; - dma_addr_t start; - size_t size; -}; - -struct s5p_iovmm { - struct list_head node; /* element of s5p_iovmm_list */ - struct rcu_head rcu; - struct iommu_domain *domain; - struct device *dev; - struct gen_pool *vmm_pool; - struct list_head regions_list; /* list of s5p_vm_region */ - atomic_t activations; - int num_setup; - spinlock_t lock; -}; - -static LIST_HEAD(s5p_iovmm_list); - -static struct s5p_iovmm *find_iovmm(struct device *dev) -{ - struct s5p_iovmm *vmm; - - list_for_each_entry(vmm, &s5p_iovmm_list, node) - if ((vmm->dev == dev) && (vmm->num_setup > 0)) - return vmm; - - return NULL; -} - -static struct s5p_vm_region *find_region(struct s5p_iovmm *vmm, dma_addr_t iova) -{ - struct s5p_vm_region *region; - - list_for_each_entry(region, &vmm->regions_list, node) - if (region->start == iova) - return region; - - return NULL; -} - -int iovmm_setup(struct device *dev) -{ - struct s5p_iovmm *vmm = NULL; - struct list_head *pos; - int ret; - - list_for_each(pos, &s5p_iovmm_list) { - vmm = list_entry(pos, struct s5p_iovmm, node); - if (vmm->dev == dev) { - struct s5p_iovmm *rcu_vmm; - - rcu_vmm = kmalloc(sizeof(*rcu_vmm), GFP_KERNEL); - if (rcu_vmm == NULL) - return -ENOMEM; - - memcpy(rcu_vmm, vmm, sizeof(*vmm)); - rcu_vmm->num_setup++; - list_replace_rcu(&vmm->node, &rcu_vmm->node); - - kfree(vmm); - - return 0; - } - } - - vmm = kzalloc(sizeof(*vmm), GFP_KERNEL); - if (!vmm) { - ret = -ENOMEM; - goto err_setup_alloc; - } - - vmm->vmm_pool = gen_pool_create(PAGE_SHIFT, -1); - if (!vmm->vmm_pool) { - ret = -ENOMEM; - goto err_setup_genalloc; - } - - /* (1GB - 4KB) addr space from 0xC0000000 */ - ret = gen_pool_add(vmm->vmm_pool, IOVA_START, IOVM_SIZE, -1); - if (ret) - goto err_setup_domain; - - vmm->domain = iommu_domain_alloc(&platform_bus_type); - if (!vmm->domain) { - ret = -ENOMEM; - goto err_setup_domain; - } - - vmm->dev = dev; - vmm->num_setup = 1; - - spin_lock_init(&vmm->lock); - - INIT_LIST_HEAD(&vmm->node); - INIT_LIST_HEAD(&vmm->regions_list); - atomic_set(&vmm->activations, 0); - - list_add_rcu(&vmm->node, &s5p_iovmm_list); - - dev_dbg(dev, "IOVMM: Created %#x B IOVMM from %#x.\n", - IOVM_SIZE, IOVA_START); - - return 0; -err_setup_domain: - gen_pool_destroy(vmm->vmm_pool); -err_setup_genalloc: - kfree(vmm); -err_setup_alloc: - dev_dbg(dev, "IOVMM: Failed to create IOVMM (%d)\n", ret); - return ret; -} - -static void iovmm_destroy(struct rcu_head *rcu) -{ - struct s5p_iovmm *vmm = container_of(rcu, struct s5p_iovmm, rcu); - struct list_head *pos, *tmp; - - while (WARN_ON(atomic_dec_return(&vmm->activations) > 0)) - iommu_detach_device(vmm->domain, vmm->dev); - - iommu_domain_free(vmm->domain); - - WARN_ON(!list_empty(&vmm->regions_list)); - - list_for_each_safe(pos, tmp, &vmm->regions_list) { - struct s5p_vm_region *region; - - region = list_entry(pos, struct s5p_vm_region, node); - - /* No need to unmap the region because - * iommu_domain_free() frees the page table */ - gen_pool_free(vmm->vmm_pool, region->start, - region->size); - - kfree(list_entry(pos, struct s5p_vm_region, node)); - } - - gen_pool_destroy(vmm->vmm_pool); - - dev_dbg(vmm->dev, "IOVMM: Removed IOVMM\n"); - - kfree(vmm); -} - -void iovmm_cleanup(struct device *dev) -{ - struct s5p_iovmm *vmm, *n; - - list_for_each_entry_safe(vmm, n, &s5p_iovmm_list, node) { - if (vmm->dev == dev) { - struct s5p_iovmm *rcu_vmm = NULL; - - while (rcu_vmm == NULL) /* should success */ - rcu_vmm = kmalloc(sizeof(*rcu_vmm), GFP_ATOMIC); - - memcpy(rcu_vmm, vmm, sizeof(*vmm)); - rcu_vmm->num_setup--; - list_replace_rcu(&vmm->node, &rcu_vmm->node); - - kfree(vmm); - - if (rcu_vmm->num_setup == 0) { - list_del_rcu(&rcu_vmm->node); - call_rcu(&rcu_vmm->rcu, iovmm_destroy); - } - - return; - } - } - - WARN(true, "%s: No IOVMM exist for %s\n", __func__, dev_name(dev)); -} - -int iovmm_activate(struct device *dev) -{ - struct s5p_iovmm *vmm; - int ret = 0; - - rcu_read_lock(); - - vmm = find_iovmm(dev); - if (WARN_ON(!vmm)) { - rcu_read_unlock(); - return -EINVAL; - } - - ret = iommu_attach_device(vmm->domain, vmm->dev); - if (!ret) - atomic_inc(&vmm->activations); - - rcu_read_unlock(); - - return ret; -} - -void iovmm_deactivate(struct device *dev) -{ - struct s5p_iovmm *vmm; - - rcu_read_lock(); - - vmm = find_iovmm(dev); - if (WARN_ON(!vmm)) { - rcu_read_unlock(); - return; - } - - iommu_detach_device(vmm->domain, vmm->dev); - - atomic_add_unless(&vmm->activations, -1, 0); - - rcu_read_unlock(); -} - -dma_addr_t iovmm_map(struct device *dev, struct scatterlist *sg, off_t offset, - size_t size) -{ - off_t start_off; - dma_addr_t addr, start = 0; - size_t mapped_size = 0; - struct s5p_vm_region *region; - struct s5p_iovmm *vmm; - int order; - unsigned long flags; -#ifdef CONFIG_EXYNOS_IOVMM_ALIGN64K - size_t iova_size = 0; -#endif - - rcu_read_lock(); - - vmm = find_iovmm(dev); - if (WARN_ON(!vmm)) - goto err_map_nomem; - - for (; sg_dma_len(sg) < offset; sg = sg_next(sg)) - offset -= sg_dma_len(sg); - - start_off = offset_in_page(sg_phys(sg) + offset); - size = PAGE_ALIGN(size + start_off); - - order = __fls(min_t(size_t, size, SZ_1M)); - - region = kmalloc(sizeof(*region), GFP_KERNEL); - if (!region) - goto err_map_nomem; - - INIT_LIST_HEAD(®ion->node); - - spin_lock_irqsave(&vmm->lock, flags); - -#ifdef CONFIG_EXYNOS_IOVMM_ALIGN64K - iova_size = ALIGN(size, SZ_64K); - start = (dma_addr_t)gen_pool_alloc_aligned(vmm->vmm_pool, iova_size, - order); -#else - start = (dma_addr_t)gen_pool_alloc_aligned(vmm->vmm_pool, size, order); -#endif - if (!start) - goto err_map_nomem_lock; - - addr = start; - do { - phys_addr_t phys; - size_t len; - - phys = sg_phys(sg); - len = sg_dma_len(sg); - - if (offset > 0) { - len -= offset; - phys += offset; - offset = 0; - } - - if (offset_in_page(phys)) { - len += offset_in_page(phys); - phys = round_down(phys, PAGE_SIZE); - } - - len = PAGE_ALIGN(len); - - if (len > (size - mapped_size)) - len = size - mapped_size; - - if (iommu_map(vmm->domain, addr, phys, len, 0)) - break; - - addr += len; - mapped_size += len; - } while ((sg = sg_next(sg)) && (mapped_size < size)); - - BUG_ON(mapped_size > size); - - if (mapped_size < size) - goto err_map_map; - -#ifdef CONFIG_EXYNOS_IOVMM_ALIGN64K - if (iova_size != size) { - addr = start + size; - size = iova_size; - - for (; addr < start + size; addr += PAGE_SIZE) { - if (iommu_map(vmm->domain, addr, - page_to_phys(ZERO_PAGE(0)), PAGE_SIZE, 0)) - goto err_map_map; - - mapped_size += PAGE_SIZE; - } - } -#endif - - region->start = start + start_off; - region->size = size; - - list_add(®ion->node, &vmm->regions_list); - - spin_unlock_irqrestore(&vmm->lock, flags); - - dev_dbg(dev, "IOVMM: Allocated VM region @ %#x/%#X bytes.\n", - region->start, region->size); - - rcu_read_unlock(); - - return region->start; - -err_map_map: - iommu_unmap(vmm->domain, start, mapped_size); - gen_pool_free(vmm->vmm_pool, start, size); -err_map_nomem_lock: - spin_unlock_irqrestore(&vmm->lock, flags); - kfree(region); -err_map_nomem: - dev_dbg(dev, "IOVMM: Failed to allocated VM region for %#x bytes.\n", - size); - rcu_read_unlock(); - - return (dma_addr_t)0; -} - -void iovmm_unmap(struct device *dev, dma_addr_t iova) -{ - struct s5p_vm_region *region; - struct s5p_iovmm *vmm; - unsigned long flags; - size_t unmapped_size; - - rcu_read_lock(); - - vmm = find_iovmm(dev); - - if (WARN_ON(!vmm)) { - rcu_read_unlock(); - return; - } - - spin_lock_irqsave(&vmm->lock, flags); - - region = find_region(vmm, iova); - if (WARN_ON(!region)) - goto err_region_not_found; - - region->start = round_down(region->start, PAGE_SIZE); - - gen_pool_free(vmm->vmm_pool, region->start, region->size); - list_del(®ion->node); - - unmapped_size = iommu_unmap(vmm->domain, region->start, region->size); - - WARN_ON(unmapped_size != region->size); - dev_dbg(dev, "IOVMM: Unmapped %#x bytes from %#x.\n", - unmapped_size, region->start); - - kfree(region); -err_region_not_found: - spin_unlock_irqrestore(&vmm->lock, flags); - - rcu_read_unlock(); -} - -int iovmm_map_oto(struct device *dev, phys_addr_t phys, size_t size) -{ - struct s5p_vm_region *region; - struct s5p_iovmm *vmm; - unsigned long flags; - int ret; - - rcu_read_lock(); - - vmm = find_iovmm(dev); - if (WARN_ON(!vmm)) { - ret = -EINVAL; - goto err_map_nomem; - } - - region = kmalloc(sizeof(*region), GFP_KERNEL); - if (!region) { - ret = -ENOMEM; - goto err_map_nomem; - } - - if (WARN_ON((phys + size) >= IOVA_START)) { - dev_err(dev, - "Unable to create one to one mapping for %#x @ %#x\n", - size, phys); - ret = -EINVAL; - goto err_out_of_memory; - } - - if (WARN_ON(phys & ~PAGE_MASK)) - phys = round_down(phys, PAGE_SIZE); - - spin_lock_irqsave(&vmm->lock, flags); - - ret = iommu_map(vmm->domain, (dma_addr_t)phys, phys, size, 0); - if (ret < 0) - goto err_map_failed; - - region->start = (dma_addr_t)phys; - region->size = size; - INIT_LIST_HEAD(®ion->node); - - list_add(®ion->node, &vmm->regions_list); - - spin_unlock_irqrestore(&vmm->lock, flags); - - rcu_read_unlock(); - - return 0; - -err_map_failed: - spin_unlock_irqrestore(&vmm->lock, flags); -err_out_of_memory: - kfree(region); -err_map_nomem: - rcu_read_unlock(); - - return ret; -} - -void iovmm_unmap_oto(struct device *dev, phys_addr_t phys) -{ - struct s5p_vm_region *region; - struct s5p_iovmm *vmm; - unsigned long flags; - size_t unmapped_size; - - rcu_read_lock(); - - vmm = find_iovmm(dev); - if (WARN_ON(!vmm)) { - rcu_read_unlock(); - return; - } - - if (WARN_ON(phys & ~PAGE_MASK)) - phys = round_down(phys, PAGE_SIZE); - - spin_lock_irqsave(&vmm->lock, flags); - - region = find_region(vmm, (dma_addr_t)phys); - if (WARN_ON(!region)) - goto err_region_not_found; - - list_del(®ion->node); - - unmapped_size = iommu_unmap(vmm->domain, region->start, region->size); - - WARN_ON(unmapped_size != region->size); - dev_dbg(dev, "IOVMM: Unmapped %#x bytes from %#x.\n", - unmapped_size, region->start); - - kfree(region); -err_region_not_found: - spin_unlock_irqrestore(&vmm->lock, flags); - - rcu_read_unlock(); -} |