iommu: remove unused rk-iommu/iovmm driver
Signed-off-by: Tao Huang <huangtao@rock-chips.com> Change-Id: Ieca1544f10c294303d0d40c6b4c5e1a797e577a2
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -1,98 +0,0 @@
|
||||
/*
|
||||
* Data structure definition for Rockchip IOMMU driver
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef __ASM_PLAT_IOMMU_H
|
||||
#define __ASM_PLAT_IOMMU_H
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/genalloc.h>
|
||||
#include <linux/iommu.h>
|
||||
|
||||
#include <linux/rockchip-iovmm.h>
|
||||
|
||||
|
||||
struct rk_iovmm {
|
||||
struct iommu_domain *domain; /* iommu domain for this iovmm */
|
||||
struct gen_pool *vmm_pool;
|
||||
struct list_head regions_list; /* list of rk_vm_region */
|
||||
spinlock_t lock; /* lock for updating regions_list */
|
||||
};
|
||||
|
||||
struct iommu_drvdata {
|
||||
struct list_head node; /* entry of rk_iommu_domain.clients */
|
||||
struct device *iommu; /* IOMMU's device descriptor */
|
||||
struct device *master; /* IOMMU's master device descriptor */
|
||||
int num_res_mem;
|
||||
int num_res_irq;
|
||||
const char *dbgname;
|
||||
void __iomem **res_bases;
|
||||
int activations;
|
||||
spinlock_t data_lock;
|
||||
struct iommu_domain *domain; /* domain given to iommu_attach_device() */
|
||||
unsigned int pgtable;
|
||||
struct rk_iovmm vmm;
|
||||
rockchip_iommu_fault_handler_t fault_handler;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_RK_IOVMM
|
||||
|
||||
#define IOVA_START 0x10000000
|
||||
#define IOVM_SIZE (SZ_1G - SZ_4K) /* last 4K is for error values */
|
||||
|
||||
struct rk_vm_region {
|
||||
struct list_head node;
|
||||
unsigned int start;
|
||||
unsigned int size;
|
||||
};
|
||||
|
||||
static inline struct rk_iovmm *rockchip_get_iovmm(struct device *dev)
|
||||
{
|
||||
struct iommu_drvdata *data = dev_get_drvdata(dev->archdata.iommu);
|
||||
|
||||
BUG_ON(!dev->archdata.iommu || !data);
|
||||
|
||||
return &data->vmm;
|
||||
}
|
||||
|
||||
int rockchip_init_iovmm(struct device *iommu, struct rk_iovmm *vmm);
|
||||
#else
|
||||
static inline int rockchip_init_iovmm(struct device *iommu,
|
||||
struct rk_iovmm *vmm)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef CONFIG_RK_IOMMU
|
||||
|
||||
/**
|
||||
* rockchip_iommu_tlb_invalidate() - flush all TLB entry in iommu
|
||||
* @owner: The device whose IOMMU.
|
||||
*
|
||||
* This function flush all TLB entry in iommu
|
||||
*/
|
||||
int rockchip_iommu_tlb_invalidate(struct device *owner);
|
||||
int rockchip_iommu_tlb_invalidate_global(struct device *owner);
|
||||
|
||||
#else /* CONFIG_RK_IOMMU */
|
||||
static inline int rockchip_iommu_tlb_invalidate(struct device *owner)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
static int rockchip_iommu_tlb_invalidate_global(struct device *owner)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif /*__ASM_PLAT_IOMMU_H*/
|
||||
@@ -1,326 +0,0 @@
|
||||
/*
|
||||
* 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_ROCKCHIP_IOMMU_DEBUG
|
||||
#define DEBUG
|
||||
#endif
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/hardirq.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
|
||||
#include "rk-iommu.h"
|
||||
|
||||
#define IOMMU_REGION_GUARD (2<<PAGE_SHIFT)
|
||||
|
||||
static struct rk_vm_region *find_region(struct rk_iovmm *vmm, dma_addr_t iova)
|
||||
{
|
||||
struct rk_vm_region *region;
|
||||
|
||||
list_for_each_entry(region, &vmm->regions_list, node)
|
||||
if (region->start == iova)
|
||||
return region;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int rockchip_iovmm_invalidate_tlb(struct device *dev)
|
||||
{
|
||||
int ret = rockchip_iommu_tlb_invalidate_global(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(rockchip_iovmm_invalidate_tlb);
|
||||
|
||||
void rockchip_iovmm_set_fault_handler(struct device *dev,
|
||||
rockchip_iommu_fault_handler_t handler)
|
||||
{
|
||||
struct iommu_drvdata *data = dev_get_drvdata(dev->archdata.iommu);
|
||||
|
||||
data->fault_handler = handler;
|
||||
}
|
||||
EXPORT_SYMBOL(rockchip_iovmm_set_fault_handler);
|
||||
|
||||
int rockchip_iovmm_activate(struct device *dev)
|
||||
{
|
||||
struct rk_iovmm *vmm = rockchip_get_iovmm(dev);
|
||||
|
||||
return iommu_attach_device(vmm->domain, dev);
|
||||
}
|
||||
EXPORT_SYMBOL(rockchip_iovmm_activate);
|
||||
|
||||
void rockchip_iovmm_deactivate(struct device *dev)
|
||||
{
|
||||
struct rk_iovmm *vmm = rockchip_get_iovmm(dev);
|
||||
|
||||
iommu_detach_device(vmm->domain, dev);
|
||||
}
|
||||
EXPORT_SYMBOL(rockchip_iovmm_deactivate);
|
||||
|
||||
dma_addr_t rockchip_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 rk_vm_region *region;
|
||||
struct rk_iovmm *vmm = rockchip_get_iovmm(dev);
|
||||
int order;
|
||||
int ret;
|
||||
|
||||
for (; sg->length < offset; sg = sg_next(sg))
|
||||
offset -= sg->length;
|
||||
|
||||
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) {
|
||||
ret = -ENOMEM;
|
||||
goto err_map_nomem;
|
||||
}
|
||||
|
||||
start = (dma_addr_t)gen_pool_alloc(vmm->vmm_pool,
|
||||
size+IOMMU_REGION_GUARD);
|
||||
if (!start) {
|
||||
ret = -ENOMEM;
|
||||
goto err_map_noiomem;
|
||||
}
|
||||
|
||||
pr_debug("%s: size = %zx\n", __func__, size);
|
||||
|
||||
addr = start;
|
||||
do {
|
||||
phys_addr_t phys;
|
||||
size_t len;
|
||||
|
||||
phys = sg_phys(sg);
|
||||
len = sg->length;
|
||||
|
||||
/* if back to back sg entries are contiguous consolidate them */
|
||||
while (sg_next(sg) && sg_phys(sg) + sg->length == sg_phys(sg_next(sg))) {
|
||||
sg = sg_next(sg);
|
||||
len += sg->length;
|
||||
}
|
||||
|
||||
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;
|
||||
pr_debug("addr = %pad, phys = %pa, len = %zx\n", &addr, &phys, len);
|
||||
ret = iommu_map(vmm->domain, addr, phys, len, 0);
|
||||
if (ret)
|
||||
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;
|
||||
|
||||
region->start = start + start_off;
|
||||
region->size = size;
|
||||
|
||||
INIT_LIST_HEAD(®ion->node);
|
||||
|
||||
spin_lock(&vmm->lock);
|
||||
|
||||
list_add(®ion->node, &vmm->regions_list);
|
||||
|
||||
spin_unlock(&vmm->lock);
|
||||
|
||||
ret = rockchip_iommu_tlb_invalidate(dev);
|
||||
if (ret) {
|
||||
spin_lock(&vmm->lock);
|
||||
list_del(®ion->node);
|
||||
spin_unlock(&vmm->lock);
|
||||
goto err_map_map;
|
||||
}
|
||||
dev_dbg(dev->archdata.iommu, "IOVMM: Allocated VM region @ %p/%#X bytes.\n",
|
||||
®ion->start, region->size);
|
||||
|
||||
return region->start;
|
||||
|
||||
err_map_map:
|
||||
iommu_unmap(vmm->domain, start, mapped_size);
|
||||
gen_pool_free(vmm->vmm_pool, start, size);
|
||||
err_map_noiomem:
|
||||
kfree(region);
|
||||
err_map_nomem:
|
||||
dev_err(dev->archdata.iommu, "IOVMM: Failed to allocated VM region for %zx bytes.\n", size);
|
||||
return (dma_addr_t)ret;
|
||||
}
|
||||
|
||||
void rockchip_iovmm_unmap(struct device *dev, dma_addr_t iova)
|
||||
{
|
||||
struct rk_vm_region *region;
|
||||
struct rk_iovmm *vmm = rockchip_get_iovmm(dev);
|
||||
size_t unmapped_size;
|
||||
|
||||
/* This function must not be called in IRQ handlers */
|
||||
BUG_ON(in_irq());
|
||||
|
||||
spin_lock(&vmm->lock);
|
||||
|
||||
region = find_region(vmm, iova);
|
||||
if (WARN_ON(!region)) {
|
||||
spin_unlock(&vmm->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
list_del(®ion->node);
|
||||
|
||||
spin_unlock(&vmm->lock);
|
||||
|
||||
region->start = round_down(region->start, PAGE_SIZE);
|
||||
|
||||
unmapped_size = iommu_unmap(vmm->domain,
|
||||
region->start, region->size);
|
||||
/*
|
||||
rockchip_iommu_tlb_invalidate(dev);
|
||||
*/
|
||||
gen_pool_free(vmm->vmm_pool, region->start,
|
||||
region->size+IOMMU_REGION_GUARD);
|
||||
|
||||
WARN_ON(unmapped_size != region->size);
|
||||
|
||||
dev_dbg(dev->archdata.iommu, "IOVMM: Unmapped %zx bytes from %pad.\n",
|
||||
unmapped_size, ®ion->start);
|
||||
|
||||
kfree(region);
|
||||
}
|
||||
|
||||
int rockchip_iovmm_map_oto(struct device *dev, phys_addr_t phys, size_t size)
|
||||
{
|
||||
struct rk_vm_region *region;
|
||||
struct rk_iovmm *vmm = rockchip_get_iovmm(dev);
|
||||
int ret;
|
||||
|
||||
if (WARN_ON((phys + size) >= IOVA_START)) {
|
||||
dev_err(dev->archdata.iommu, "Unable to create one to one mapping for %zx @ %pa\n",
|
||||
size, &phys);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
region = kmalloc(sizeof(*region), GFP_KERNEL);
|
||||
if (!region)
|
||||
return -ENOMEM;
|
||||
|
||||
if (WARN_ON(phys & ~PAGE_MASK))
|
||||
phys = round_down(phys, PAGE_SIZE);
|
||||
|
||||
|
||||
ret = iommu_map(vmm->domain, (dma_addr_t)phys, phys, size, 0);
|
||||
if (ret < 0) {
|
||||
kfree(region);
|
||||
return ret;
|
||||
}
|
||||
|
||||
region->start = (dma_addr_t)phys;
|
||||
region->size = size;
|
||||
INIT_LIST_HEAD(®ion->node);
|
||||
|
||||
spin_lock(&vmm->lock);
|
||||
|
||||
list_add(®ion->node, &vmm->regions_list);
|
||||
|
||||
spin_unlock(&vmm->lock);
|
||||
|
||||
ret = rockchip_iommu_tlb_invalidate(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rockchip_iovmm_unmap_oto(struct device *dev, phys_addr_t phys)
|
||||
{
|
||||
struct rk_vm_region *region;
|
||||
struct rk_iovmm *vmm = rockchip_get_iovmm(dev);
|
||||
size_t unmapped_size;
|
||||
|
||||
/* This function must not be called in IRQ handlers */
|
||||
BUG_ON(in_irq());
|
||||
|
||||
if (WARN_ON(phys & ~PAGE_MASK))
|
||||
phys = round_down(phys, PAGE_SIZE);
|
||||
|
||||
spin_lock(&vmm->lock);
|
||||
|
||||
region = find_region(vmm, (dma_addr_t)phys);
|
||||
if (WARN_ON(!region)) {
|
||||
spin_unlock(&vmm->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
list_del(®ion->node);
|
||||
|
||||
spin_unlock(&vmm->lock);
|
||||
|
||||
unmapped_size = iommu_unmap(vmm->domain, region->start, region->size);
|
||||
WARN_ON(unmapped_size != region->size);
|
||||
dev_dbg(dev->archdata.iommu, "IOVMM: Unmapped %zx bytes from %pad.\n",
|
||||
unmapped_size, ®ion->start);
|
||||
|
||||
kfree(region);
|
||||
}
|
||||
|
||||
int rockchip_init_iovmm(struct device *iommu, struct rk_iovmm *vmm)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
vmm->vmm_pool = gen_pool_create(PAGE_SHIFT, -1);
|
||||
if (!vmm->vmm_pool) {
|
||||
ret = -ENOMEM;
|
||||
goto err_setup_genalloc;
|
||||
}
|
||||
|
||||
/* (1GB - 4KB) addr space from 0x10000000 */
|
||||
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;
|
||||
}
|
||||
|
||||
spin_lock_init(&vmm->lock);
|
||||
|
||||
INIT_LIST_HEAD(&vmm->regions_list);
|
||||
|
||||
dev_info(iommu, "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:
|
||||
dev_err(iommu, "IOVMM: Failed to create IOVMM (%d)\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -50,69 +50,6 @@ typedef int (*rockchip_iommu_fault_handler_t)(struct device *dev,
|
||||
struct scatterlist;
|
||||
struct device;
|
||||
|
||||
#ifdef CONFIG_RK_IOVMM
|
||||
|
||||
int rockchip_iovmm_activate(struct device *dev);
|
||||
void rockchip_iovmm_deactivate(struct device *dev);
|
||||
|
||||
/* rockchip_iovmm_map() - Maps a list of physical memory chunks
|
||||
* @dev: the owner of the IO address space where the mapping is created
|
||||
* @sg: list of physical memory chunks to map
|
||||
* @offset: length in bytes where the mapping starts
|
||||
* @size: how much memory to map in bytes. @offset + @size must not exceed
|
||||
* total size of @sg
|
||||
*
|
||||
* This function returns mapped IO address in the address space of @dev.
|
||||
* Returns minus error number if mapping fails.
|
||||
* Caller must check its return code with IS_ERROR_VALUE() if the function
|
||||
* succeeded.
|
||||
*
|
||||
* The caller of this function must ensure that iovmm_cleanup() is not called
|
||||
* while this function is called.
|
||||
*
|
||||
*/
|
||||
dma_addr_t rockchip_iovmm_map(struct device *dev, struct scatterlist *sg,
|
||||
off_t offset, size_t size);
|
||||
|
||||
/* rockchip_iovmm_unmap() - unmaps the given IO address
|
||||
* @dev: the owner of the IO address space where @iova belongs
|
||||
* @iova: IO address that needs to be unmapped and freed.
|
||||
*
|
||||
* The caller of this function must ensure that iovmm_cleanup() is not called
|
||||
* while this function is called.
|
||||
*/
|
||||
void rockchip_iovmm_unmap(struct device *dev, dma_addr_t iova);
|
||||
|
||||
/* rockchip_iovmm_map_oto - create one to one mapping for the given physical address
|
||||
* @dev: the owner of the IO address space to map
|
||||
* @phys: physical address to map
|
||||
* @size: size of the mapping to create
|
||||
*
|
||||
* This function return 0 if mapping is successful. Otherwise, minus error
|
||||
* value.
|
||||
*/
|
||||
int rockchip_iovmm_map_oto(struct device *dev, phys_addr_t phys, size_t size);
|
||||
|
||||
/* rockchip_iovmm_unmap_oto - remove one to one mapping
|
||||
* @dev: the owner ofthe IO address space
|
||||
* @phys: physical address to remove mapping
|
||||
*/
|
||||
void rockchip_iovmm_unmap_oto(struct device *dev, phys_addr_t phys);
|
||||
|
||||
void rockchip_iovmm_set_fault_handler(struct device *dev,
|
||||
rockchip_iommu_fault_handler_t handler);
|
||||
/** rockchip_iovmm_set_fault_handler() - Fault handler for IOMMUs
|
||||
* Called when interrupt occurred by the IOMMUs
|
||||
* The device drivers of peripheral devices that has a IOMMU can implement
|
||||
* a fault handler to resolve address translation fault by IOMMU.
|
||||
* The meanings of return value and parameters are described below.
|
||||
*
|
||||
* return value: non-zero if the fault is correctly resolved.
|
||||
* zero if the fault is not handled.
|
||||
*/
|
||||
|
||||
int rockchip_iovmm_invalidate_tlb(struct device *dev);
|
||||
#else
|
||||
static inline int rockchip_iovmm_activate(struct device *dev)
|
||||
{
|
||||
return -ENOSYS;
|
||||
@@ -151,6 +88,4 @@ static inline int rockchip_iovmm_invalidate_tlb(struct device *dev)
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_RK_IOVMM */
|
||||
|
||||
#endif /*__ASM_PLAT_IOVMM_H*/
|
||||
|
||||
Reference in New Issue
Block a user