Commit f626b52d authored by Ohad Ben-Cohen's avatar Ohad Ben-Cohen Committed by Joerg Roedel

omap: iommu: migrate to the generic IOMMU API

Migrate OMAP's iommu driver to the generic IOMMU API, so users can stay
generic, and any generic IOMMU functionality can be developed once
in the generic framework.

Migrate omap's iovmm (virtual memory manager) to the generic IOMMU API,
and adapt omap3isp as needed, so the latter won't break.

The plan is to eventually remove iovmm completely by replacing it
with the (upcoming) IOMMU-based DMA-API.

Tested on OMAP3 (with omap3isp) and OMAP4 (with rpmsg/remoteproc).
Signed-off-by: default avatarOhad Ben-Cohen <ohad@wizery.com>
Acked-by: default avatarLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: default avatarHiroshi DOYU <Hiroshi.DOYU@nokia.com>
Acked-by: default avatarTony Lindgren <tony@atomide.com>
Signed-off-by: default avatarJoerg Roedel <joerg.roedel@amd.com>
parent fcb8ce5c
......@@ -132,8 +132,10 @@ config OMAP_MBOX_KFIFO_SIZE
This can also be changed at runtime (via the mbox_kfifo_size
module parameter).
#can't be tristate; iommu api doesn't support un-registration
config OMAP_IOMMU
tristate
bool
select IOMMU_API
config OMAP_IOMMU_DEBUG
tristate "Export OMAP IOMMU internals in DebugFS"
......
......@@ -34,7 +34,7 @@ struct iommu {
void *isr_priv;
unsigned int refcount;
struct mutex iommu_lock; /* global for this whole object */
spinlock_t iommu_lock; /* global for this whole object */
/*
* We don't change iopgd for a situation like pgd for a task,
......@@ -167,8 +167,6 @@ extern void iopgtable_lookup_entry(struct iommu *obj, u32 da, u32 **ppgd,
extern size_t iopgtable_clear_entry(struct iommu *obj, u32 iova);
extern int iommu_set_da_range(struct iommu *obj, u32 start, u32 end);
extern struct iommu *iommu_get(const char *name);
extern void iommu_put(struct iommu *obj);
extern int iommu_set_isr(const char *name,
int (*isr)(struct iommu *obj, u32 da, u32 iommu_errs,
void *priv),
......@@ -185,5 +183,6 @@ extern int foreach_iommu_device(void *data,
extern ssize_t iommu_dump_ctx(struct iommu *obj, char *buf, ssize_t len);
extern size_t dump_tlb_entries(struct iommu *obj, char *buf, ssize_t len);
struct device *omap_find_iommu_device(const char *name);
#endif /* __MACH_IOMMU_H */
......@@ -13,6 +13,8 @@
#ifndef __IOMMU_MMAP_H
#define __IOMMU_MMAP_H
#include <linux/iommu.h>
struct iovm_struct {
struct iommu *iommu; /* iommu object which this belongs to */
u32 da_start; /* area definition */
......@@ -71,18 +73,21 @@ struct iovm_struct {
extern struct iovm_struct *find_iovm_area(struct iommu *obj, u32 da);
extern u32 iommu_vmap(struct iommu *obj, u32 da,
extern u32 iommu_vmap(struct iommu_domain *domain, struct iommu *obj, u32 da,
const struct sg_table *sgt, u32 flags);
extern struct sg_table *iommu_vunmap(struct iommu *obj, u32 da);
extern u32 iommu_vmalloc(struct iommu *obj, u32 da, size_t bytes,
u32 flags);
extern void iommu_vfree(struct iommu *obj, const u32 da);
extern u32 iommu_kmap(struct iommu *obj, u32 da, u32 pa, size_t bytes,
u32 flags);
extern void iommu_kunmap(struct iommu *obj, u32 da);
extern u32 iommu_kmalloc(struct iommu *obj, u32 da, size_t bytes,
u32 flags);
extern void iommu_kfree(struct iommu *obj, u32 da);
extern struct sg_table *iommu_vunmap(struct iommu_domain *domain,
struct iommu *obj, u32 da);
extern u32 iommu_vmalloc(struct iommu_domain *domain, struct iommu *obj,
u32 da, size_t bytes, u32 flags);
extern void iommu_vfree(struct iommu_domain *domain, struct iommu *obj,
const u32 da);
extern u32 iommu_kmap(struct iommu_domain *domain, struct iommu *obj, u32 da,
u32 pa, size_t bytes, u32 flags);
extern void iommu_kunmap(struct iommu_domain *domain, struct iommu *obj,
u32 da);
extern u32 iommu_kmalloc(struct iommu_domain *domain, struct iommu *obj,
u32 da, size_t bytes, u32 flags);
extern void iommu_kfree(struct iommu_domain *domain, struct iommu *obj, u32 da);
extern void *da_to_va(struct iommu *obj, u32 da);
......
This diff is collapsed.
......@@ -56,6 +56,19 @@
#define IOPAGE_MASK IOPTE_MASK
/**
* omap_iommu_translate() - va to pa translation
* @d: omap iommu descriptor
* @va: virtual address
* @mask: omap iommu descriptor mask
*
* va to pa translation
*/
static inline phys_addr_t omap_iommu_translate(u32 d, u32 va, u32 mask)
{
return (d & mask) | (va & (~mask));
}
/*
* some descriptor attributes.
*/
......@@ -64,10 +77,15 @@
#define IOPGD_SUPER (1 << 18 | 2 << 0)
#define iopgd_is_table(x) (((x) & 3) == IOPGD_TABLE)
#define iopgd_is_section(x) (((x) & (1 << 18 | 3)) == IOPGD_SECTION)
#define iopgd_is_super(x) (((x) & (1 << 18 | 3)) == IOPGD_SUPER)
#define IOPTE_SMALL (2 << 0)
#define IOPTE_LARGE (1 << 0)
#define iopte_is_small(x) (((x) & 2) == IOPTE_SMALL)
#define iopte_is_large(x) (((x) & 3) == IOPTE_LARGE)
/* to find an entry in a page-table-directory */
#define iopgd_index(da) (((da) >> IOPGD_SHIFT) & (PTRS_PER_IOPGD - 1))
#define iopgd_offset(obj, da) ((obj)->iopgd + iopgd_index(da))
......
This diff is collapsed.
......@@ -80,6 +80,13 @@
#include "isph3a.h"
#include "isphist.h"
/*
* this is provided as an interim solution until omap3isp doesn't need
* any omap-specific iommu API
*/
#define to_iommu(dev) \
(struct iommu *)platform_get_drvdata(to_platform_device(dev))
static unsigned int autoidle;
module_param(autoidle, int, 0444);
MODULE_PARM_DESC(autoidle, "Enable OMAP3ISP AUTOIDLE support");
......@@ -1975,7 +1982,8 @@ static int isp_remove(struct platform_device *pdev)
isp_cleanup_modules(isp);
omap3isp_get(isp);
iommu_put(isp->iommu);
iommu_detach_device(isp->domain, isp->iommu_dev);
iommu_domain_free(isp->domain);
omap3isp_put(isp);
free_irq(isp->irq_num, isp);
......@@ -2123,25 +2131,41 @@ static int isp_probe(struct platform_device *pdev)
}
/* IOMMU */
isp->iommu = iommu_get("isp");
if (IS_ERR_OR_NULL(isp->iommu)) {
isp->iommu = NULL;
isp->iommu_dev = omap_find_iommu_device("isp");
if (!isp->iommu_dev) {
dev_err(isp->dev, "omap_find_iommu_device failed\n");
ret = -ENODEV;
goto error_isp;
}
/* to be removed once iommu migration is complete */
isp->iommu = to_iommu(isp->iommu_dev);
isp->domain = iommu_domain_alloc();
if (!isp->domain) {
dev_err(isp->dev, "can't alloc iommu domain\n");
ret = -ENOMEM;
goto error_isp;
}
ret = iommu_attach_device(isp->domain, isp->iommu_dev);
if (ret) {
dev_err(&pdev->dev, "can't attach iommu device: %d\n", ret);
goto free_domain;
}
/* Interrupt */
isp->irq_num = platform_get_irq(pdev, 0);
if (isp->irq_num <= 0) {
dev_err(isp->dev, "No IRQ resource\n");
ret = -ENODEV;
goto error_isp;
goto detach_dev;
}
if (request_irq(isp->irq_num, isp_isr, IRQF_SHARED, "OMAP3 ISP", isp)) {
dev_err(isp->dev, "Unable to request IRQ\n");
ret = -EINVAL;
goto error_isp;
goto detach_dev;
}
/* Entities */
......@@ -2162,8 +2186,11 @@ static int isp_probe(struct platform_device *pdev)
isp_cleanup_modules(isp);
error_irq:
free_irq(isp->irq_num, isp);
detach_dev:
iommu_detach_device(isp->domain, isp->iommu_dev);
free_domain:
iommu_domain_free(isp->domain);
error_isp:
iommu_put(isp->iommu);
omap3isp_put(isp);
error:
isp_put_clocks(isp);
......
......@@ -32,6 +32,7 @@
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/wait.h>
#include <linux/iommu.h>
#include <plat/iommu.h>
#include <plat/iovmm.h>
......@@ -295,6 +296,8 @@ struct isp_device {
unsigned int subclk_resources;
struct iommu *iommu;
struct iommu_domain *domain;
struct device *iommu_dev;
struct isp_platform_callback platform_cb;
};
......
......@@ -365,7 +365,7 @@ static void ccdc_lsc_free_request(struct isp_ccdc_device *ccdc,
dma_unmap_sg(isp->dev, req->iovm->sgt->sgl,
req->iovm->sgt->nents, DMA_TO_DEVICE);
if (req->table)
iommu_vfree(isp->iommu, req->table);
iommu_vfree(isp->domain, isp->iommu, req->table);
kfree(req);
}
......@@ -437,8 +437,8 @@ static int ccdc_lsc_config(struct isp_ccdc_device *ccdc,
req->enable = 1;
req->table = iommu_vmalloc(isp->iommu, 0, req->config.size,
IOMMU_FLAG);
req->table = iommu_vmalloc(isp->domain, isp->iommu, 0,
req->config.size, IOMMU_FLAG);
if (IS_ERR_VALUE(req->table)) {
req->table = 0;
ret = -ENOMEM;
......@@ -733,15 +733,15 @@ static int ccdc_config(struct isp_ccdc_device *ccdc,
* already done by iommu_vmalloc().
*/
size = ccdc->fpc.fpnum * 4;
table_new = iommu_vmalloc(isp->iommu, 0, size,
IOMMU_FLAG);
table_new = iommu_vmalloc(isp->domain, isp->iommu, 0,
size, IOMMU_FLAG);
if (IS_ERR_VALUE(table_new))
return -ENOMEM;
if (copy_from_user(da_to_va(isp->iommu, table_new),
(__force void __user *)
ccdc->fpc.fpcaddr, size)) {
iommu_vfree(isp->iommu, table_new);
iommu_vfree(isp->domain, isp->iommu, table_new);
return -EFAULT;
}
......@@ -751,7 +751,7 @@ static int ccdc_config(struct isp_ccdc_device *ccdc,
ccdc_configure_fpc(ccdc);
if (table_old != 0)
iommu_vfree(isp->iommu, table_old);
iommu_vfree(isp->domain, isp->iommu, table_old);
}
return ccdc_lsc_config(ccdc, ccdc_struct);
......@@ -2286,5 +2286,5 @@ void omap3isp_ccdc_cleanup(struct isp_device *isp)
ccdc_lsc_free_queue(ccdc, &ccdc->lsc.free_queue);
if (ccdc->fpc.fpcaddr != 0)
iommu_vfree(isp->iommu, ccdc->fpc.fpcaddr);
iommu_vfree(isp->domain, isp->iommu, ccdc->fpc.fpcaddr);
}
......@@ -366,7 +366,7 @@ static void isp_stat_bufs_free(struct ispstat *stat)
dma_unmap_sg(isp->dev, buf->iovm->sgt->sgl,
buf->iovm->sgt->nents,
DMA_FROM_DEVICE);
iommu_vfree(isp->iommu, buf->iommu_addr);
iommu_vfree(isp->domain, isp->iommu, buf->iommu_addr);
} else {
if (!buf->virt_addr)
continue;
......@@ -399,8 +399,8 @@ static int isp_stat_bufs_alloc_iommu(struct ispstat *stat, unsigned int size)
struct iovm_struct *iovm;
WARN_ON(buf->dma_addr);
buf->iommu_addr = iommu_vmalloc(isp->iommu, 0, size,
IOMMU_FLAG);
buf->iommu_addr = iommu_vmalloc(isp->domain, isp->iommu, 0,
size, IOMMU_FLAG);
if (IS_ERR((void *)buf->iommu_addr)) {
dev_err(stat->isp->dev,
"%s: Can't acquire memory for "
......
......@@ -446,7 +446,7 @@ ispmmu_vmap(struct isp_device *isp, const struct scatterlist *sglist, int sglen)
sgt->nents = sglen;
sgt->orig_nents = sglen;
da = iommu_vmap(isp->iommu, 0, sgt, IOMMU_FLAG);
da = iommu_vmap(isp->domain, isp->iommu, 0, sgt, IOMMU_FLAG);
if (IS_ERR_VALUE(da))
kfree(sgt);
......@@ -462,7 +462,7 @@ static void ispmmu_vunmap(struct isp_device *isp, dma_addr_t da)
{
struct sg_table *sgt;
sgt = iommu_vunmap(isp->iommu, (u32)da);
sgt = iommu_vunmap(isp->domain, isp->iommu, (u32)da);
kfree(sgt);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment