#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/platform_device.h>
#include <linux/iommu.h>
#include <linux/omap-iommu.h>
#include <linux/mutex.h>
#include <linux/spinlock.h>
#include <linux/io.h>
#include <linux/pm_runtime.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/regmap.h>
#include <linux/mfd/syscon.h>
#include <linux/platform_data/iommu-omap.h>
#include "omap-iopgtable.h"
#include "omap-iommu.h"
static const struct iommu_ops omap_iommu_ops;
#define to_iommu(dev) …
#define OMAP_IOMMU_PGSIZES …
#define MMU_LOCK_BASE_SHIFT …
#define MMU_LOCK_BASE_MASK …
#define MMU_LOCK_BASE(x) …
#define MMU_LOCK_VICT_SHIFT …
#define MMU_LOCK_VICT_MASK …
#define MMU_LOCK_VICT(x) …
static struct platform_driver omap_iommu_driver;
static struct kmem_cache *iopte_cachep;
static struct omap_iommu_domain *to_omap_domain(struct iommu_domain *dom)
{ … }
void omap_iommu_save_ctx(struct device *dev)
{ … }
EXPORT_SYMBOL_GPL(…);
void omap_iommu_restore_ctx(struct device *dev)
{ … }
EXPORT_SYMBOL_GPL(…);
static void dra7_cfg_dspsys_mmu(struct omap_iommu *obj, bool enable)
{ … }
static void __iommu_set_twl(struct omap_iommu *obj, bool on)
{ … }
static int omap2_iommu_enable(struct omap_iommu *obj)
{ … }
static void omap2_iommu_disable(struct omap_iommu *obj)
{ … }
static int iommu_enable(struct omap_iommu *obj)
{ … }
static void iommu_disable(struct omap_iommu *obj)
{ … }
static u32 iotlb_cr_to_virt(struct cr_regs *cr)
{ … }
static u32 get_iopte_attr(struct iotlb_entry *e)
{ … }
static u32 iommu_report_fault(struct omap_iommu *obj, u32 *da)
{ … }
void iotlb_lock_get(struct omap_iommu *obj, struct iotlb_lock *l)
{ … }
void iotlb_lock_set(struct omap_iommu *obj, struct iotlb_lock *l)
{ … }
static void iotlb_read_cr(struct omap_iommu *obj, struct cr_regs *cr)
{ … }
static void iotlb_load_cr(struct omap_iommu *obj, struct cr_regs *cr)
{ … }
struct cr_regs __iotlb_read_cr(struct omap_iommu *obj, int n)
{ … }
#ifdef PREFETCH_IOTLB
static struct cr_regs *iotlb_alloc_cr(struct omap_iommu *obj,
struct iotlb_entry *e)
{
struct cr_regs *cr;
if (!e)
return NULL;
if (e->da & ~(get_cam_va_mask(e->pgsz))) {
dev_err(obj->dev, "%s:\twrong alignment: %08x\n", __func__,
e->da);
return ERR_PTR(-EINVAL);
}
cr = kmalloc(sizeof(*cr), GFP_KERNEL);
if (!cr)
return ERR_PTR(-ENOMEM);
cr->cam = (e->da & MMU_CAM_VATAG_MASK) | e->prsvd | e->pgsz | e->valid;
cr->ram = e->pa | e->endian | e->elsz | e->mixed;
return cr;
}
static int load_iotlb_entry(struct omap_iommu *obj, struct iotlb_entry *e)
{
int err = 0;
struct iotlb_lock l;
struct cr_regs *cr;
if (!obj || !obj->nr_tlb_entries || !e)
return -EINVAL;
pm_runtime_get_sync(obj->dev);
iotlb_lock_get(obj, &l);
if (l.base == obj->nr_tlb_entries) {
dev_warn(obj->dev, "%s: preserve entries full\n", __func__);
err = -EBUSY;
goto out;
}
if (!e->prsvd) {
int i;
struct cr_regs tmp;
for_each_iotlb_cr(obj, obj->nr_tlb_entries, i, tmp)
if (!iotlb_cr_valid(&tmp))
break;
if (i == obj->nr_tlb_entries) {
dev_dbg(obj->dev, "%s: full: no entry\n", __func__);
err = -EBUSY;
goto out;
}
iotlb_lock_get(obj, &l);
} else {
l.vict = l.base;
iotlb_lock_set(obj, &l);
}
cr = iotlb_alloc_cr(obj, e);
if (IS_ERR(cr)) {
pm_runtime_put_sync(obj->dev);
return PTR_ERR(cr);
}
iotlb_load_cr(obj, cr);
kfree(cr);
if (e->prsvd)
l.base++;
if (++l.vict == obj->nr_tlb_entries)
l.vict = l.base;
iotlb_lock_set(obj, &l);
out:
pm_runtime_put_sync(obj->dev);
return err;
}
#else
static int load_iotlb_entry(struct omap_iommu *obj, struct iotlb_entry *e)
{ … }
#endif
static int prefetch_iotlb_entry(struct omap_iommu *obj, struct iotlb_entry *e)
{ … }
static void flush_iotlb_page(struct omap_iommu *obj, u32 da)
{ … }
static void flush_iotlb_all(struct omap_iommu *obj)
{ … }
static void flush_iopte_range(struct device *dev, dma_addr_t dma,
unsigned long offset, int num_entries)
{ … }
static void iopte_free(struct omap_iommu *obj, u32 *iopte, bool dma_valid)
{ … }
static u32 *iopte_alloc(struct omap_iommu *obj, u32 *iopgd,
dma_addr_t *pt_dma, u32 da)
{ … }
static int iopgd_alloc_section(struct omap_iommu *obj, u32 da, u32 pa, u32 prot)
{ … }
static int iopgd_alloc_super(struct omap_iommu *obj, u32 da, u32 pa, u32 prot)
{ … }
static int iopte_alloc_page(struct omap_iommu *obj, u32 da, u32 pa, u32 prot)
{ … }
static int iopte_alloc_large(struct omap_iommu *obj, u32 da, u32 pa, u32 prot)
{ … }
static int
iopgtable_store_entry_core(struct omap_iommu *obj, struct iotlb_entry *e)
{ … }
static int
omap_iopgtable_store_entry(struct omap_iommu *obj, struct iotlb_entry *e)
{ … }
static void
iopgtable_lookup_entry(struct omap_iommu *obj, u32 da, u32 **ppgd, u32 **ppte)
{ … }
static size_t iopgtable_clear_entry_core(struct omap_iommu *obj, u32 da)
{ … }
static size_t iopgtable_clear_entry(struct omap_iommu *obj, u32 da)
{ … }
static void iopgtable_clear_entry_all(struct omap_iommu *obj)
{ … }
static irqreturn_t iommu_fault_handler(int irq, void *data)
{ … }
static int omap_iommu_attach(struct omap_iommu *obj, u32 *iopgd)
{ … }
static void omap_iommu_detach(struct omap_iommu *obj)
{ … }
static void omap_iommu_save_tlb_entries(struct omap_iommu *obj)
{ … }
static void omap_iommu_restore_tlb_entries(struct omap_iommu *obj)
{ … }
int omap_iommu_domain_deactivate(struct iommu_domain *domain)
{ … }
EXPORT_SYMBOL_GPL(…);
int omap_iommu_domain_activate(struct iommu_domain *domain)
{ … }
EXPORT_SYMBOL_GPL(…);
static __maybe_unused int omap_iommu_runtime_suspend(struct device *dev)
{ … }
static __maybe_unused int omap_iommu_runtime_resume(struct device *dev)
{ … }
static int omap_iommu_prepare(struct device *dev)
{ … }
static bool omap_iommu_can_register(struct platform_device *pdev)
{ … }
static int omap_iommu_dra7_get_dsp_system_cfg(struct platform_device *pdev,
struct omap_iommu *obj)
{ … }
static int omap_iommu_probe(struct platform_device *pdev)
{ … }
static void omap_iommu_remove(struct platform_device *pdev)
{ … }
static const struct dev_pm_ops omap_iommu_pm_ops = …;
static const struct of_device_id omap_iommu_of_match[] = …;
static struct platform_driver omap_iommu_driver = …;
static u32 iotlb_init_entry(struct iotlb_entry *e, u32 da, u32 pa, int pgsz)
{ … }
static int omap_iommu_map(struct iommu_domain *domain, unsigned long da,
phys_addr_t pa, size_t bytes, size_t count,
int prot, gfp_t gfp, size_t *mapped)
{ … }
static size_t omap_iommu_unmap(struct iommu_domain *domain, unsigned long da,
size_t size, size_t count, struct iommu_iotlb_gather *gather)
{ … }
static int omap_iommu_count(struct device *dev)
{ … }
static int omap_iommu_attach_init(struct device *dev,
struct omap_iommu_domain *odomain)
{ … }
static void omap_iommu_detach_fini(struct omap_iommu_domain *odomain)
{ … }
static int
omap_iommu_attach_dev(struct iommu_domain *domain, struct device *dev)
{ … }
static void _omap_iommu_detach_dev(struct omap_iommu_domain *omap_domain,
struct device *dev)
{ … }
static int omap_iommu_identity_attach(struct iommu_domain *identity_domain,
struct device *dev)
{ … }
static struct iommu_domain_ops omap_iommu_identity_ops = …;
static struct iommu_domain omap_iommu_identity_domain = …;
static struct iommu_domain *omap_iommu_domain_alloc_paging(struct device *dev)
{ … }
static void omap_iommu_domain_free(struct iommu_domain *domain)
{ … }
static phys_addr_t omap_iommu_iova_to_phys(struct iommu_domain *domain,
dma_addr_t da)
{ … }
static struct iommu_device *omap_iommu_probe_device(struct device *dev)
{ … }
static void omap_iommu_release_device(struct device *dev)
{ … }
static const struct iommu_ops omap_iommu_ops = …;
static int __init omap_iommu_init(void)
{ … }
subsys_initcall(omap_iommu_init);