15 #include <linux/module.h>
16 #include <linux/slab.h>
25 #include <asm/cacheflush.h>
31 #define for_each_iotlb_cr(obj, n, __i, cr) \
33 (__i < (n)) && (cr = __iotlb_read_cr((obj), __i), true); \
37 #define OMAP_IOMMU_PGSIZES (SZ_4K | SZ_64K | SZ_1M | SZ_16M)
85 if (arch_iommu != ops)
86 pr_err(
"%s: not your arch\n", __func__);
98 struct omap_iommu *obj = dev_to_omap_iommu(dev);
110 struct omap_iommu *obj = dev_to_omap_iommu(dev);
125 static int iommu_enable(
struct omap_iommu *obj)
137 err = arch_iommu->
enable(obj);
143 static void iommu_disable(
struct omap_iommu *obj)
166 static inline int iotlb_cr_valid(
struct cr_regs *
cr)
180 return arch_iommu->
alloc_cr(obj, e);
183 static u32 iotlb_cr_to_virt(
struct cr_regs *cr)
202 val = iommu_read_reg(obj,
MMU_LOCK);
216 iommu_write_reg(obj, val,
MMU_LOCK);
243 return arch_iommu->
dump_cr(obj, cr, buf);
252 iotlb_lock_get(obj, &
l);
254 iotlb_lock_set(obj, &
l);
255 iotlb_read_cr(obj, &cr);
265 #ifdef PREFETCH_IOTLB
277 iotlb_lock_get(obj, &
l);
279 dev_warn(obj->
dev,
"%s: preserve entries full\n", __func__);
288 if (!iotlb_cr_valid(&
tmp))
291 if (i == obj->nr_tlb_entries) {
292 dev_dbg(obj->
dev,
"%s: full: no entry\n", __func__);
297 iotlb_lock_get(obj, &
l);
300 iotlb_lock_set(obj, &
l);
303 cr = iotlb_alloc_cr(obj, e);
309 iotlb_load_cr(obj, cr);
317 iotlb_lock_set(obj, &
l);
334 return load_iotlb_entry(obj, e);
355 if (!iotlb_cr_valid(&cr))
358 start = iotlb_cr_to_virt(&cr);
361 if ((start <= da) && (da < start + bytes)) {
363 __func__, start, da, bytes);
364 iotlb_load_cr(obj, &cr);
371 dev_dbg(obj->
dev,
"%s: no page for %08x\n", __func__, da);
378 static void flush_iotlb_all(
struct omap_iommu *obj)
386 iotlb_lock_set(obj, &
l);
393 #if defined(CONFIG_OMAP_IOMMU_DEBUG) || defined(CONFIG_OMAP_IOMMU_DEBUG_MODULE)
402 bytes = arch_iommu->
dump_ctx(obj, buf, bytes);
419 iotlb_lock_get(obj, &saved);
422 if (!iotlb_cr_valid(&
tmp))
427 iotlb_lock_set(obj, &saved);
444 num = bytes /
sizeof(*cr);
451 num = __dump_tlb_entries(obj, cr, num);
452 for (i = 0; i < num; i++)
453 p += iotlb_dump_cr(obj, cr + i, p);
472 static void flush_iopgd_range(
u32 *
first,
u32 *last)
476 asm(
"mcr p15, 0, %0, c7, c10, 1 @ flush_pgd"
479 }
while (first <= last);
482 static void flush_iopte_range(
u32 *first,
u32 *last)
486 asm(
"mcr p15, 0, %0, c7, c10, 1 @ flush_pte"
489 }
while (first <= last);
492 static void iopte_free(
u32 *iopte)
510 iopte = kmem_cache_zalloc(iopte_cachep,
GFP_KERNEL);
518 flush_iopgd_range(iopgd, iopgd);
520 dev_vdbg(obj->
dev,
"%s: a new pte:%p\n", __func__, iopte);
530 "%s: da:%08x pgd:%p *pgd:%08x pte:%p *pte:%08x\n",
531 __func__, da, iopgd, *iopgd, iopte, *iopte);
541 dev_err(obj->
dev,
"%s: %08x:%08x should aligned on %08lx\n",
547 flush_iopgd_range(iopgd, iopgd);
557 dev_err(obj->
dev,
"%s: %08x:%08x should aligned on %08lx\n",
562 for (i = 0; i < 16; i++)
564 flush_iopgd_range(iopgd, iopgd + 15);
571 u32 *iopte = iopte_alloc(obj, iopgd, da);
574 return PTR_ERR(iopte);
577 flush_iopte_range(iopte, iopte);
579 dev_vdbg(obj->
dev,
"%s: da:%08x pa:%08x pte:%p *pte:%08x\n",
580 __func__, da, pa, iopte, *iopte);
588 u32 *iopte = iopte_alloc(obj, iopgd, da);
592 dev_err(obj->
dev,
"%s: %08x:%08x should aligned on %08lx\n",
598 return PTR_ERR(iopte);
600 for (i = 0; i < 16; i++)
602 flush_iopte_range(iopte, iopte + 15);
618 fn = iopgd_alloc_super;
621 fn = iopgd_alloc_section;
624 fn = iopte_alloc_large;
627 fn = iopte_alloc_page;
635 prot = get_iopte_attr(e);
638 err =
fn(obj, e->
da, e->
pa, prot);
653 flush_iotlb_page(obj, e->
da);
654 err = iopgtable_store_entry_core(obj, e);
656 prefetch_iotlb_entry(obj, e);
669 iopgtable_lookup_entry(
struct omap_iommu *obj, u32 da, u32 **ppgd, u32 **ppte)
684 static size_t iopgtable_clear_entry_core(
struct omap_iommu *obj, u32 da)
704 memset(iopte, 0, nent *
sizeof(*iopte));
705 flush_iopte_range(iopte, iopte + (nent - 1) *
sizeof(*iopte));
726 memset(iopgd, 0, nent *
sizeof(*iopgd));
727 flush_iopgd_range(iopgd, iopgd + (nent - 1) *
sizeof(*iopgd));
737 static size_t iopgtable_clear_entry(
struct omap_iommu *obj, u32 da)
743 bytes = iopgtable_clear_entry_core(obj, da);
744 flush_iotlb_page(obj, da);
751 static void iopgtable_clear_entry_all(
struct omap_iommu *obj)
771 flush_iopgd_range(iopgd, iopgd);
774 flush_iotlb_all(obj);
782 static irqreturn_t iommu_fault_handler(
int irq,
void *data)
793 errs = iommu_report_fault(obj, &da);
799 if (!report_iommu_fault(domain, obj->
dev, da, 0))
807 dev_err(obj->
dev,
"%s: errs:0x%08x da:0x%08x pgd:0x%p "
808 "*pgd:px%08x\n", obj->
name, errs, da, iopgd, *iopgd);
814 dev_err(obj->
dev,
"%s: errs:0x%08x da:0x%08x pgd:0x%p *pgd:0x%08x "
815 "pte:0x%p *pte:0x%08x\n", obj->
name, errs, da, iopgd, *iopgd,
821 static int device_match_by_alias(
struct device *
dev,
void *data)
836 static struct omap_iommu *omap_iommu_attach(
const char *
name, u32 *iopgd)
844 device_match_by_alias);
854 dev_err(dev,
"%s: already attached!\n", obj->
name);
860 err = iommu_enable(obj);
863 flush_iotlb_all(obj);
865 if (!try_module_get(obj->
owner))
886 static void omap_iommu_detach(
struct omap_iommu *obj)
888 if (!obj || IS_ERR(obj))
896 module_put(obj->
owner);
924 if (IS_ERR(obj->
clk))
930 obj->
ctx = (
void *)obj +
sizeof(*obj);
937 INIT_LIST_HEAD(&obj->
mmap);
946 dev_name(&pdev->
dev));
964 dev_name(&pdev->
dev), obj);
967 platform_set_drvdata(pdev, obj);
987 struct omap_iommu *obj = platform_get_drvdata(pdev);
989 platform_set_drvdata(pdev,
NULL);
991 iopgtable_clear_entry_all(obj);
1006 .probe = omap_iommu_probe,
1009 .name =
"omap-iommu",
1013 static void iopte_cachep_ctor(
void *iopte)
1018 static int omap_iommu_map(
struct iommu_domain *domain,
unsigned long da,
1030 if (omap_pgsz < 0) {
1031 dev_err(dev,
"invalid size to map: %d\n", bytes);
1035 dev_dbg(dev,
"mapping da 0x%lx to pa 0x%x size 0x%x\n", da, pa, bytes);
1037 flags = omap_pgsz | prot;
1039 iotlb_init_entry(&e, da, pa, flags);
1043 dev_err(dev,
"omap_iopgtable_store_entry failed: %d\n", ret);
1048 static size_t omap_iommu_unmap(
struct iommu_domain *domain,
unsigned long da,
1055 dev_dbg(dev,
"unmapping da 0x%lx size %u\n", da, size);
1057 return iopgtable_clear_entry(oiommu, da);
1068 spin_lock(&omap_domain->
lock);
1072 dev_err(dev,
"iommu domain is already attached\n");
1078 oiommu = omap_iommu_attach(arch_data->
name, omap_domain->
pgtable);
1079 if (IS_ERR(oiommu)) {
1080 ret = PTR_ERR(oiommu);
1081 dev_err(dev,
"can't get omap iommu: %d\n", ret);
1090 spin_unlock(&omap_domain->
lock);
1097 struct omap_iommu *oiommu = dev_to_omap_iommu(dev);
1102 dev_err(dev,
"invalid iommu device\n");
1106 iopgtable_clear_entry_all(oiommu);
1108 omap_iommu_detach(oiommu);
1114 static void omap_iommu_detach_dev(
struct iommu_domain *domain,
1119 spin_lock(&omap_domain->
lock);
1120 _omap_iommu_detach_dev(omap_domain, dev);
1121 spin_unlock(&omap_domain->
lock);
1124 static int omap_iommu_domain_init(
struct iommu_domain *domain)
1128 omap_domain = kzalloc(
sizeof(*omap_domain),
GFP_KERNEL);
1130 pr_err(
"kzalloc failed\n");
1136 pr_err(
"kzalloc failed\n");
1149 domain->
priv = omap_domain;
1151 domain->
geometry.aperture_start = 0;
1152 domain->
geometry.aperture_end = (1ULL << 32) - 1;
1153 domain->
geometry.force_aperture =
true;
1163 static void omap_iommu_domain_destroy(
struct iommu_domain *domain)
1174 _omap_iommu_detach_dev(omap_domain, omap_domain->
dev);
1189 iopgtable_lookup_entry(oiommu, da, &pgd, &pte);
1193 ret = omap_iommu_translate(*pte, da,
IOPTE_MASK);
1197 dev_err(dev,
"bogus pte 0x%x, da 0x%lx", *pte, da);
1204 dev_err(dev,
"bogus pgd 0x%x, da 0x%lx", *pgd, da);
1210 static int omap_iommu_domain_has_cap(
struct iommu_domain *domain,
1216 static struct iommu_ops omap_iommu_ops = {
1217 .domain_init = omap_iommu_domain_init,
1218 .domain_destroy = omap_iommu_domain_destroy,
1219 .attach_dev = omap_iommu_attach_dev,
1220 .detach_dev = omap_iommu_detach_dev,
1221 .map = omap_iommu_map,
1222 .unmap = omap_iommu_unmap,
1223 .iova_to_phys = omap_iommu_iova_to_phys,
1224 .domain_has_cap = omap_iommu_domain_has_cap,
1228 static int __init omap_iommu_init(
void)
1232 size_t align = 1 << 10;
1247 static void __exit omap_iommu_exit(
void)
1257 MODULE_AUTHOR(
"Hiroshi DOYU, Paul Mundt and Toshihiro Kobayashi");