Lines Matching full:iommu

14 #include <linux/iommu.h>
99 struct iommu_device iommu; member
101 /* Lock to modify the IOMMU registers */
123 struct sun50i_iommu *iommu; member
136 static u32 iommu_read(struct sun50i_iommu *iommu, u32 offset) in iommu_read() argument
138 return readl(iommu->base + offset); in iommu_read()
141 static void iommu_write(struct sun50i_iommu *iommu, u32 offset, u32 value) in iommu_write() argument
143 writel(value, iommu->base + offset); in iommu_write()
147 * The Allwinner H6 IOMMU uses a 2-level page table.
156 * The IOMMU supports a single DT, pointed by the IOMMU_TTB_REG
223 * The way permissions work is that the IOMMU has 16 "domains" that
234 * In order to make it work with the IOMMU framework, we will be using
237 * have each master setup in the same way, since the IOMMU framework
292 struct sun50i_iommu *iommu = sun50i_domain->iommu; in sun50i_table_flush() local
296 dma_sync_single_for_device(iommu->dev, dma, size, DMA_TO_DEVICE); in sun50i_table_flush()
299 static void sun50i_iommu_zap_iova(struct sun50i_iommu *iommu, in sun50i_iommu_zap_iova() argument
305 iommu_write(iommu, IOMMU_TLB_IVLD_ADDR_REG, iova); in sun50i_iommu_zap_iova()
306 iommu_write(iommu, IOMMU_TLB_IVLD_ADDR_MASK_REG, GENMASK(31, 12)); in sun50i_iommu_zap_iova()
307 iommu_write(iommu, IOMMU_TLB_IVLD_ENABLE_REG, in sun50i_iommu_zap_iova()
310 ret = readl_poll_timeout_atomic(iommu->base + IOMMU_TLB_IVLD_ENABLE_REG, in sun50i_iommu_zap_iova()
313 dev_warn(iommu->dev, "TLB invalidation timed out!\n"); in sun50i_iommu_zap_iova()
316 static void sun50i_iommu_zap_ptw_cache(struct sun50i_iommu *iommu, in sun50i_iommu_zap_ptw_cache() argument
322 iommu_write(iommu, IOMMU_PC_IVLD_ADDR_REG, iova); in sun50i_iommu_zap_ptw_cache()
323 iommu_write(iommu, IOMMU_PC_IVLD_ENABLE_REG, in sun50i_iommu_zap_ptw_cache()
326 ret = readl_poll_timeout_atomic(iommu->base + IOMMU_PC_IVLD_ENABLE_REG, in sun50i_iommu_zap_ptw_cache()
329 dev_warn(iommu->dev, "PTW cache invalidation timed out!\n"); in sun50i_iommu_zap_ptw_cache()
332 static void sun50i_iommu_zap_range(struct sun50i_iommu *iommu, in sun50i_iommu_zap_range() argument
335 assert_spin_locked(&iommu->iommu_lock); in sun50i_iommu_zap_range()
337 iommu_write(iommu, IOMMU_AUTO_GATING_REG, 0); in sun50i_iommu_zap_range()
339 sun50i_iommu_zap_iova(iommu, iova); in sun50i_iommu_zap_range()
340 sun50i_iommu_zap_iova(iommu, iova + SPAGE_SIZE); in sun50i_iommu_zap_range()
342 sun50i_iommu_zap_iova(iommu, iova + size); in sun50i_iommu_zap_range()
343 sun50i_iommu_zap_iova(iommu, iova + size + SPAGE_SIZE); in sun50i_iommu_zap_range()
345 sun50i_iommu_zap_ptw_cache(iommu, iova); in sun50i_iommu_zap_range()
346 sun50i_iommu_zap_ptw_cache(iommu, iova + SZ_1M); in sun50i_iommu_zap_range()
348 sun50i_iommu_zap_ptw_cache(iommu, iova + size); in sun50i_iommu_zap_range()
349 sun50i_iommu_zap_ptw_cache(iommu, iova + size + SZ_1M); in sun50i_iommu_zap_range()
352 iommu_write(iommu, IOMMU_AUTO_GATING_REG, IOMMU_AUTO_GATING_ENABLE); in sun50i_iommu_zap_range()
355 static int sun50i_iommu_flush_all_tlb(struct sun50i_iommu *iommu) in sun50i_iommu_flush_all_tlb() argument
360 assert_spin_locked(&iommu->iommu_lock); in sun50i_iommu_flush_all_tlb()
362 iommu_write(iommu, in sun50i_iommu_flush_all_tlb()
373 ret = readl_poll_timeout_atomic(iommu->base + IOMMU_TLB_FLUSH_REG, in sun50i_iommu_flush_all_tlb()
377 dev_warn(iommu->dev, "TLB Flush timed out!\n"); in sun50i_iommu_flush_all_tlb()
385 struct sun50i_iommu *iommu = sun50i_domain->iommu; in sun50i_iommu_flush_iotlb_all() local
390 * .probe_device, and since we link our (single) domain to our iommu in in sun50i_iommu_flush_iotlb_all()
396 if (!iommu) in sun50i_iommu_flush_iotlb_all()
399 spin_lock_irqsave(&iommu->iommu_lock, flags); in sun50i_iommu_flush_iotlb_all()
400 sun50i_iommu_flush_all_tlb(iommu); in sun50i_iommu_flush_iotlb_all()
401 spin_unlock_irqrestore(&iommu->iommu_lock, flags); in sun50i_iommu_flush_iotlb_all()
408 struct sun50i_iommu *iommu = sun50i_domain->iommu; in sun50i_iommu_iotlb_sync_map() local
411 spin_lock_irqsave(&iommu->iommu_lock, flags); in sun50i_iommu_iotlb_sync_map()
412 sun50i_iommu_zap_range(iommu, iova, size); in sun50i_iommu_iotlb_sync_map()
413 spin_unlock_irqrestore(&iommu->iommu_lock, flags); in sun50i_iommu_iotlb_sync_map()
424 static int sun50i_iommu_enable(struct sun50i_iommu *iommu) in sun50i_iommu_enable() argument
430 if (!iommu->domain) in sun50i_iommu_enable()
433 sun50i_domain = to_sun50i_domain(iommu->domain); in sun50i_iommu_enable()
435 ret = reset_control_deassert(iommu->reset); in sun50i_iommu_enable()
439 ret = clk_prepare_enable(iommu->clk); in sun50i_iommu_enable()
443 spin_lock_irqsave(&iommu->iommu_lock, flags); in sun50i_iommu_enable()
445 iommu_write(iommu, IOMMU_TTB_REG, sun50i_domain->dt_dma); in sun50i_iommu_enable()
446 iommu_write(iommu, IOMMU_TLB_PREFETCH_REG, in sun50i_iommu_enable()
453 iommu_write(iommu, IOMMU_INT_ENABLE_REG, IOMMU_INT_MASK); in sun50i_iommu_enable()
454 iommu_write(iommu, IOMMU_DM_AUT_CTRL_REG(SUN50I_IOMMU_ACI_NONE), in sun50i_iommu_enable()
468 iommu_write(iommu, IOMMU_DM_AUT_CTRL_REG(SUN50I_IOMMU_ACI_RD), in sun50i_iommu_enable()
476 iommu_write(iommu, IOMMU_DM_AUT_CTRL_REG(SUN50I_IOMMU_ACI_WR), in sun50i_iommu_enable()
484 ret = sun50i_iommu_flush_all_tlb(iommu); in sun50i_iommu_enable()
486 spin_unlock_irqrestore(&iommu->iommu_lock, flags); in sun50i_iommu_enable()
490 iommu_write(iommu, IOMMU_AUTO_GATING_REG, IOMMU_AUTO_GATING_ENABLE); in sun50i_iommu_enable()
491 iommu_write(iommu, IOMMU_ENABLE_REG, IOMMU_ENABLE_ENABLE); in sun50i_iommu_enable()
493 spin_unlock_irqrestore(&iommu->iommu_lock, flags); in sun50i_iommu_enable()
498 clk_disable_unprepare(iommu->clk); in sun50i_iommu_enable()
501 reset_control_assert(iommu->reset); in sun50i_iommu_enable()
506 static void sun50i_iommu_disable(struct sun50i_iommu *iommu) in sun50i_iommu_disable() argument
510 spin_lock_irqsave(&iommu->iommu_lock, flags); in sun50i_iommu_disable()
512 iommu_write(iommu, IOMMU_ENABLE_REG, 0); in sun50i_iommu_disable()
513 iommu_write(iommu, IOMMU_TTB_REG, 0); in sun50i_iommu_disable()
515 spin_unlock_irqrestore(&iommu->iommu_lock, flags); in sun50i_iommu_disable()
517 clk_disable_unprepare(iommu->clk); in sun50i_iommu_disable()
518 reset_control_assert(iommu->reset); in sun50i_iommu_disable()
521 static void *sun50i_iommu_alloc_page_table(struct sun50i_iommu *iommu, in sun50i_iommu_alloc_page_table() argument
527 page_table = kmem_cache_zalloc(iommu->pt_pool, gfp); in sun50i_iommu_alloc_page_table()
531 pt_dma = dma_map_single(iommu->dev, page_table, PT_SIZE, DMA_TO_DEVICE); in sun50i_iommu_alloc_page_table()
532 if (dma_mapping_error(iommu->dev, pt_dma)) { in sun50i_iommu_alloc_page_table()
533 dev_err(iommu->dev, "Couldn't map L2 Page Table\n"); in sun50i_iommu_alloc_page_table()
534 kmem_cache_free(iommu->pt_pool, page_table); in sun50i_iommu_alloc_page_table()
544 static void sun50i_iommu_free_page_table(struct sun50i_iommu *iommu, in sun50i_iommu_free_page_table() argument
549 dma_unmap_single(iommu->dev, pt_phys, PT_SIZE, DMA_TO_DEVICE); in sun50i_iommu_free_page_table()
550 kmem_cache_free(iommu->pt_pool, page_table); in sun50i_iommu_free_page_table()
556 struct sun50i_iommu *iommu = sun50i_domain->iommu; in sun50i_dte_get_page_table() local
569 page_table = sun50i_iommu_alloc_page_table(iommu, gfp); in sun50i_dte_get_page_table()
583 sun50i_iommu_free_page_table(iommu, drop_pt); in sun50i_dte_get_page_table()
597 struct sun50i_iommu *iommu = sun50i_domain->iommu; in sun50i_iommu_map() local
612 dev_err(iommu->dev, in sun50i_iommu_map()
711 static int sun50i_iommu_attach_domain(struct sun50i_iommu *iommu, in sun50i_iommu_attach_domain() argument
714 iommu->domain = &sun50i_domain->domain; in sun50i_iommu_attach_domain()
715 sun50i_domain->iommu = iommu; in sun50i_iommu_attach_domain()
717 sun50i_domain->dt_dma = dma_map_single(iommu->dev, sun50i_domain->dt, in sun50i_iommu_attach_domain()
719 if (dma_mapping_error(iommu->dev, sun50i_domain->dt_dma)) { in sun50i_iommu_attach_domain()
720 dev_err(iommu->dev, "Couldn't map L1 Page Table\n"); in sun50i_iommu_attach_domain()
724 return sun50i_iommu_enable(iommu); in sun50i_iommu_attach_domain()
727 static void sun50i_iommu_detach_domain(struct sun50i_iommu *iommu, in sun50i_iommu_detach_domain() argument
748 sun50i_iommu_free_page_table(iommu, page_table); in sun50i_iommu_detach_domain()
752 sun50i_iommu_disable(iommu); in sun50i_iommu_detach_domain()
754 dma_unmap_single(iommu->dev, virt_to_phys(sun50i_domain->dt), in sun50i_iommu_detach_domain()
757 iommu->domain = NULL; in sun50i_iommu_detach_domain()
763 struct sun50i_iommu *iommu = dev_iommu_priv_get(dev); in sun50i_iommu_identity_attach() local
766 dev_dbg(dev, "Detaching from IOMMU domain\n"); in sun50i_iommu_identity_attach()
768 if (iommu->domain == identity_domain) in sun50i_iommu_identity_attach()
771 sun50i_domain = to_sun50i_domain(iommu->domain); in sun50i_iommu_identity_attach()
773 sun50i_iommu_detach_domain(iommu, sun50i_domain); in sun50i_iommu_identity_attach()
790 struct sun50i_iommu *iommu; in sun50i_iommu_attach_device() local
792 iommu = sun50i_iommu_from_dev(dev); in sun50i_iommu_attach_device()
793 if (!iommu) in sun50i_iommu_attach_device()
796 dev_dbg(dev, "Attaching to IOMMU domain\n"); in sun50i_iommu_attach_device()
800 if (iommu->domain == domain) in sun50i_iommu_attach_device()
805 sun50i_iommu_attach_domain(iommu, sun50i_domain); in sun50i_iommu_attach_device()
812 struct sun50i_iommu *iommu; in sun50i_iommu_probe_device() local
814 iommu = sun50i_iommu_from_dev(dev); in sun50i_iommu_probe_device()
815 if (!iommu) in sun50i_iommu_probe_device()
818 return &iommu->iommu; in sun50i_iommu_probe_device()
851 static void sun50i_iommu_report_fault(struct sun50i_iommu *iommu, in sun50i_iommu_report_fault() argument
855 dev_err(iommu->dev, "Page fault for %pad (master %d, dir %s)\n", in sun50i_iommu_report_fault()
858 if (iommu->domain) in sun50i_iommu_report_fault()
859 report_iommu_fault(iommu->domain, iommu->dev, iova, prot); in sun50i_iommu_report_fault()
861 dev_err(iommu->dev, "Page fault while iommu not attached to any domain?\n"); in sun50i_iommu_report_fault()
863 sun50i_iommu_zap_range(iommu, iova, SPAGE_SIZE); in sun50i_iommu_report_fault()
866 static phys_addr_t sun50i_iommu_handle_pt_irq(struct sun50i_iommu *iommu, in sun50i_iommu_handle_pt_irq() argument
874 assert_spin_locked(&iommu->iommu_lock); in sun50i_iommu_handle_pt_irq()
876 iova = iommu_read(iommu, addr_reg); in sun50i_iommu_handle_pt_irq()
877 blame = iommu_read(iommu, blame_reg); in sun50i_iommu_handle_pt_irq()
885 sun50i_iommu_report_fault(iommu, master, iova, IOMMU_FAULT_READ); in sun50i_iommu_handle_pt_irq()
890 static phys_addr_t sun50i_iommu_handle_perm_irq(struct sun50i_iommu *iommu) in sun50i_iommu_handle_perm_irq() argument
898 assert_spin_locked(&iommu->iommu_lock); in sun50i_iommu_handle_perm_irq()
900 blame = iommu_read(iommu, IOMMU_INT_STA_REG); in sun50i_iommu_handle_perm_irq()
902 iova = iommu_read(iommu, IOMMU_INT_ERR_ADDR_REG(master)); in sun50i_iommu_handle_perm_irq()
903 aci = sun50i_get_pte_aci(iommu_read(iommu, in sun50i_iommu_handle_perm_irq()
940 sun50i_iommu_report_fault(iommu, master, iova, dir); in sun50i_iommu_handle_perm_irq()
948 struct sun50i_iommu *iommu = dev_id; in sun50i_iommu_irq() local
950 spin_lock(&iommu->iommu_lock); in sun50i_iommu_irq()
952 status = iommu_read(iommu, IOMMU_INT_STA_REG); in sun50i_iommu_irq()
954 spin_unlock(&iommu->iommu_lock); in sun50i_iommu_irq()
958 l1_status = iommu_read(iommu, IOMMU_L1PG_INT_REG); in sun50i_iommu_irq()
959 l2_status = iommu_read(iommu, IOMMU_L2PG_INT_REG); in sun50i_iommu_irq()
962 sun50i_iommu_handle_pt_irq(iommu, in sun50i_iommu_irq()
966 sun50i_iommu_handle_pt_irq(iommu, in sun50i_iommu_irq()
970 sun50i_iommu_handle_perm_irq(iommu); in sun50i_iommu_irq()
972 iommu_write(iommu, IOMMU_INT_CLR_REG, status); in sun50i_iommu_irq()
975 iommu_write(iommu, IOMMU_RESET_REG, ~resets); in sun50i_iommu_irq()
976 iommu_write(iommu, IOMMU_RESET_REG, IOMMU_RESET_RELEASE_ALL); in sun50i_iommu_irq()
978 spin_unlock(&iommu->iommu_lock); in sun50i_iommu_irq()
985 struct sun50i_iommu *iommu; in sun50i_iommu_probe() local
988 iommu = devm_kzalloc(&pdev->dev, sizeof(*iommu), GFP_KERNEL); in sun50i_iommu_probe()
989 if (!iommu) in sun50i_iommu_probe()
991 spin_lock_init(&iommu->iommu_lock); in sun50i_iommu_probe()
992 iommu->domain = &sun50i_iommu_identity_domain; in sun50i_iommu_probe()
993 platform_set_drvdata(pdev, iommu); in sun50i_iommu_probe()
994 iommu->dev = &pdev->dev; in sun50i_iommu_probe()
996 iommu->pt_pool = kmem_cache_create(dev_name(&pdev->dev), in sun50i_iommu_probe()
1000 if (!iommu->pt_pool) in sun50i_iommu_probe()
1003 iommu->base = devm_platform_ioremap_resource(pdev, 0); in sun50i_iommu_probe()
1004 if (IS_ERR(iommu->base)) { in sun50i_iommu_probe()
1005 ret = PTR_ERR(iommu->base); in sun50i_iommu_probe()
1015 iommu->clk = devm_clk_get(&pdev->dev, NULL); in sun50i_iommu_probe()
1016 if (IS_ERR(iommu->clk)) { in sun50i_iommu_probe()
1018 ret = PTR_ERR(iommu->clk); in sun50i_iommu_probe()
1022 iommu->reset = devm_reset_control_get(&pdev->dev, NULL); in sun50i_iommu_probe()
1023 if (IS_ERR(iommu->reset)) { in sun50i_iommu_probe()
1025 ret = PTR_ERR(iommu->reset); in sun50i_iommu_probe()
1029 ret = iommu_device_sysfs_add(&iommu->iommu, &pdev->dev, in sun50i_iommu_probe()
1034 ret = iommu_device_register(&iommu->iommu, &sun50i_iommu_ops, &pdev->dev); in sun50i_iommu_probe()
1039 dev_name(&pdev->dev), iommu); in sun50i_iommu_probe()
1046 iommu_device_unregister(&iommu->iommu); in sun50i_iommu_probe()
1049 iommu_device_sysfs_remove(&iommu->iommu); in sun50i_iommu_probe()
1052 kmem_cache_destroy(iommu->pt_pool); in sun50i_iommu_probe()
1058 { .compatible = "allwinner,sun50i-h6-iommu", },
1065 .name = "sun50i-iommu",
1072 MODULE_DESCRIPTION("Allwinner H6 IOMMU driver");