Lines Matching +full:msm +full:- +full:iommu +full:- +full:v1
1 // SPDX-License-Identifier: GPL-2.0-only
3 * IOMMU API for QCOM secure IOMMUs. Somewhat based on arm-smmu.c
13 #include <linux/dma-mapping.h>
17 #include <linux/io-64-nonatomic-hi-lo.h>
18 #include <linux/io-pgtable.h>
19 #include <linux/iommu.h>
33 #include "arm-smmu.h"
47 /* IOMMU core code handle */
48 struct iommu_device iommu; member
69 struct mutex init_mutex; /* Protects iommu pointer */
71 struct qcom_iommu_dev *iommu; member
86 if (!fwspec || fwspec->ops != &qcom_iommu_ops) in to_iommu()
94 struct qcom_iommu_dev *qcom_iommu = d->iommu; in to_ctx()
97 return qcom_iommu->ctxs[asid]; in to_ctx()
103 writel_relaxed(val, ctx->base + reg); in iommu_writel()
109 writeq_relaxed(val, ctx->base + reg); in iommu_writeq()
115 return readl_relaxed(ctx->base + reg); in iommu_readl()
121 return readq_relaxed(ctx->base + reg); in iommu_readq()
127 struct iommu_fwspec *fwspec = qcom_domain->fwspec; in qcom_iommu_tlb_sync()
130 for (i = 0; i < fwspec->num_ids; i++) { in qcom_iommu_tlb_sync()
131 struct qcom_iommu_ctx *ctx = to_ctx(qcom_domain, fwspec->ids[i]); in qcom_iommu_tlb_sync()
136 ret = readl_poll_timeout(ctx->base + ARM_SMMU_CB_TLBSTATUS, val, in qcom_iommu_tlb_sync()
139 dev_err(ctx->dev, "timeout waiting for TLB SYNC\n"); in qcom_iommu_tlb_sync()
146 struct iommu_fwspec *fwspec = qcom_domain->fwspec; in qcom_iommu_tlb_inv_context()
149 for (i = 0; i < fwspec->num_ids; i++) { in qcom_iommu_tlb_inv_context()
150 struct qcom_iommu_ctx *ctx = to_ctx(qcom_domain, fwspec->ids[i]); in qcom_iommu_tlb_inv_context()
151 iommu_writel(ctx, ARM_SMMU_CB_S1_TLBIASID, ctx->asid); in qcom_iommu_tlb_inv_context()
161 struct iommu_fwspec *fwspec = qcom_domain->fwspec; in qcom_iommu_tlb_inv_range_nosync()
166 for (i = 0; i < fwspec->num_ids; i++) { in qcom_iommu_tlb_inv_range_nosync()
167 struct qcom_iommu_ctx *ctx = to_ctx(qcom_domain, fwspec->ids[i]); in qcom_iommu_tlb_inv_range_nosync()
171 iova |= ctx->asid; in qcom_iommu_tlb_inv_range_nosync()
175 } while (s -= granule); in qcom_iommu_tlb_inv_range_nosync()
213 if (!report_iommu_fault(ctx->domain, ctx->dev, iova, 0)) { in qcom_iommu_fault()
214 dev_err_ratelimited(ctx->dev, in qcom_iommu_fault()
217 fsr, iova, fsynr, ctx->asid); in qcom_iommu_fault()
237 mutex_lock(&qcom_domain->init_mutex); in qcom_iommu_init_domain()
238 if (qcom_domain->iommu) in qcom_iommu_init_domain()
246 .iommu_dev = qcom_iommu->dev, in qcom_iommu_init_domain()
249 qcom_domain->iommu = qcom_iommu; in qcom_iommu_init_domain()
250 qcom_domain->fwspec = fwspec; in qcom_iommu_init_domain()
254 dev_err(qcom_iommu->dev, "failed to allocate pagetable ops\n"); in qcom_iommu_init_domain()
255 ret = -ENOMEM; in qcom_iommu_init_domain()
260 domain->pgsize_bitmap = pgtbl_cfg.pgsize_bitmap; in qcom_iommu_init_domain()
261 domain->geometry.aperture_end = (1ULL << pgtbl_cfg.ias) - 1; in qcom_iommu_init_domain()
262 domain->geometry.force_aperture = true; in qcom_iommu_init_domain()
264 for (i = 0; i < fwspec->num_ids; i++) { in qcom_iommu_init_domain()
265 struct qcom_iommu_ctx *ctx = to_ctx(qcom_domain, fwspec->ids[i]); in qcom_iommu_init_domain()
267 if (!ctx->secure_init) { in qcom_iommu_init_domain()
268 ret = qcom_scm_restore_sec_cfg(qcom_iommu->sec_id, ctx->asid); in qcom_iommu_init_domain()
270 dev_err(qcom_iommu->dev, "secure init failed: %d\n", ret); in qcom_iommu_init_domain()
273 ctx->secure_init = true; in qcom_iommu_init_domain()
276 /* Secured QSMMU-500/QSMMU-v2 contexts cannot be programmed */ in qcom_iommu_init_domain()
277 if (ctx->secured_ctx) { in qcom_iommu_init_domain()
278 ctx->domain = domain; in qcom_iommu_init_domain()
292 FIELD_PREP(ARM_SMMU_TTBRn_ASID, ctx->asid)); in qcom_iommu_init_domain()
301 /* MAIRs (stage-1 only) */ in qcom_iommu_init_domain()
318 ctx->domain = domain; in qcom_iommu_init_domain()
321 mutex_unlock(&qcom_domain->init_mutex); in qcom_iommu_init_domain()
324 qcom_domain->pgtbl_ops = pgtbl_ops; in qcom_iommu_init_domain()
329 qcom_domain->iommu = NULL; in qcom_iommu_init_domain()
331 mutex_unlock(&qcom_domain->init_mutex); in qcom_iommu_init_domain()
350 mutex_init(&qcom_domain->init_mutex); in qcom_iommu_domain_alloc()
351 spin_lock_init(&qcom_domain->pgtbl_lock); in qcom_iommu_domain_alloc()
353 return &qcom_domain->domain; in qcom_iommu_domain_alloc()
360 if (qcom_domain->iommu) { in qcom_iommu_domain_free()
363 * off, for example, with GPUs or anything involving dma-buf. in qcom_iommu_domain_free()
364 * So we cannot rely on the device_link. Make sure the IOMMU in qcom_iommu_domain_free()
367 pm_runtime_get_sync(qcom_domain->iommu->dev); in qcom_iommu_domain_free()
368 free_io_pgtable_ops(qcom_domain->pgtbl_ops); in qcom_iommu_domain_free()
369 pm_runtime_put_sync(qcom_domain->iommu->dev); in qcom_iommu_domain_free()
382 dev_err(dev, "cannot attach to IOMMU, is it on the same bus?\n"); in qcom_iommu_attach_dev()
383 return -ENXIO; in qcom_iommu_attach_dev()
387 pm_runtime_get_sync(qcom_iommu->dev); in qcom_iommu_attach_dev()
389 pm_runtime_put_sync(qcom_iommu->dev); in qcom_iommu_attach_dev()
397 if (qcom_domain->iommu != qcom_iommu) in qcom_iommu_attach_dev()
398 return -EINVAL; in qcom_iommu_attach_dev()
410 struct io_pgtable_ops *ops = qcom_domain->pgtbl_ops; in qcom_iommu_map()
413 return -ENODEV; in qcom_iommu_map()
415 spin_lock_irqsave(&qcom_domain->pgtbl_lock, flags); in qcom_iommu_map()
416 ret = ops->map_pages(ops, iova, paddr, pgsize, pgcount, prot, GFP_ATOMIC, mapped); in qcom_iommu_map()
417 spin_unlock_irqrestore(&qcom_domain->pgtbl_lock, flags); in qcom_iommu_map()
428 struct io_pgtable_ops *ops = qcom_domain->pgtbl_ops; in qcom_iommu_unmap()
434 * for example, with GPUs or anything involving dma-buf. So we in qcom_iommu_unmap()
435 * cannot rely on the device_link. Make sure the IOMMU is on to in qcom_iommu_unmap()
438 pm_runtime_get_sync(qcom_domain->iommu->dev); in qcom_iommu_unmap()
439 spin_lock_irqsave(&qcom_domain->pgtbl_lock, flags); in qcom_iommu_unmap()
440 ret = ops->unmap_pages(ops, iova, pgsize, pgcount, gather); in qcom_iommu_unmap()
441 spin_unlock_irqrestore(&qcom_domain->pgtbl_lock, flags); in qcom_iommu_unmap()
442 pm_runtime_put_sync(qcom_domain->iommu->dev); in qcom_iommu_unmap()
450 struct io_pgtable *pgtable = container_of(qcom_domain->pgtbl_ops, in qcom_iommu_flush_iotlb_all()
452 if (!qcom_domain->pgtbl_ops) in qcom_iommu_flush_iotlb_all()
455 pm_runtime_get_sync(qcom_domain->iommu->dev); in qcom_iommu_flush_iotlb_all()
456 qcom_iommu_tlb_sync(pgtable->cookie); in qcom_iommu_flush_iotlb_all()
457 pm_runtime_put_sync(qcom_domain->iommu->dev); in qcom_iommu_flush_iotlb_all()
472 struct io_pgtable_ops *ops = qcom_domain->pgtbl_ops; in qcom_iommu_iova_to_phys()
477 spin_lock_irqsave(&qcom_domain->pgtbl_lock, flags); in qcom_iommu_iova_to_phys()
478 ret = ops->iova_to_phys(ops, iova); in qcom_iommu_iova_to_phys()
479 spin_unlock_irqrestore(&qcom_domain->pgtbl_lock, flags); in qcom_iommu_iova_to_phys()
506 return ERR_PTR(-ENODEV); in qcom_iommu_probe_device()
509 * Establish the link between iommu and master, so that the in qcom_iommu_probe_device()
510 * iommu gets runtime enabled/disabled as per the master's in qcom_iommu_probe_device()
513 link = device_link_add(dev, qcom_iommu->dev, DL_FLAG_PM_RUNTIME); in qcom_iommu_probe_device()
515 dev_err(qcom_iommu->dev, "Unable to create device link between %s and %s\n", in qcom_iommu_probe_device()
516 dev_name(qcom_iommu->dev), dev_name(dev)); in qcom_iommu_probe_device()
517 return ERR_PTR(-ENODEV); in qcom_iommu_probe_device()
520 return &qcom_iommu->iommu; in qcom_iommu_probe_device()
527 unsigned asid = args->args[0]; in qcom_iommu_of_xlate()
529 if (args->args_count != 1) { in qcom_iommu_of_xlate()
530 dev_err(dev, "incorrect number of iommu params found for %s " in qcom_iommu_of_xlate()
532 args->np->full_name, args->args_count); in qcom_iommu_of_xlate()
533 return -EINVAL; in qcom_iommu_of_xlate()
536 iommu_pdev = of_find_device_by_node(args->np); in qcom_iommu_of_xlate()
538 return -EINVAL; in qcom_iommu_of_xlate()
545 if (WARN_ON(asid > qcom_iommu->max_asid) || in qcom_iommu_of_xlate()
546 WARN_ON(qcom_iommu->ctxs[asid] == NULL)) { in qcom_iommu_of_xlate()
547 put_device(&iommu_pdev->dev); in qcom_iommu_of_xlate()
548 return -EINVAL; in qcom_iommu_of_xlate()
555 * multiple different iommu devices. Multiple context in qcom_iommu_of_xlate()
559 put_device(&iommu_pdev->dev); in qcom_iommu_of_xlate()
560 return -EINVAL; in qcom_iommu_of_xlate()
600 dev_err(dev, "failed to get iommu secure pgtable size (%d)\n", in qcom_iommu_sec_ptbl_init()
605 dev_info(dev, "iommu sec: pgtable size: %zu\n", psize); in qcom_iommu_sec_ptbl_init()
613 return -ENOMEM; in qcom_iommu_sec_ptbl_init()
618 dev_err(dev, "failed to init iommu pgtable (%d)\n", ret); in qcom_iommu_sec_ptbl_init()
639 return -ENODEV; in get_asid()
646 if (!of_property_read_u32(np, "qcom,ctx-asid", &val)) in get_asid()
657 struct device *dev = &pdev->dev; in qcom_iommu_ctx_probe()
658 struct qcom_iommu_dev *qcom_iommu = dev_get_drvdata(dev->parent); in qcom_iommu_ctx_probe()
663 return -ENOMEM; in qcom_iommu_ctx_probe()
665 ctx->dev = dev; in qcom_iommu_ctx_probe()
668 ctx->base = devm_platform_ioremap_resource(pdev, 0); in qcom_iommu_ctx_probe()
669 if (IS_ERR(ctx->base)) in qcom_iommu_ctx_probe()
670 return PTR_ERR(ctx->base); in qcom_iommu_ctx_probe()
676 if (of_device_is_compatible(dev->of_node, "qcom,msm-iommu-v2-sec")) in qcom_iommu_ctx_probe()
677 ctx->secured_ctx = true; in qcom_iommu_ctx_probe()
680 * boot-loader left us a surprise: in qcom_iommu_ctx_probe()
682 if (!ctx->secured_ctx) in qcom_iommu_ctx_probe()
688 "qcom-iommu-fault", in qcom_iommu_ctx_probe()
695 ret = get_asid(dev->of_node); in qcom_iommu_ctx_probe()
701 ctx->asid = ret; in qcom_iommu_ctx_probe()
703 dev_dbg(dev, "found asid %u\n", ctx->asid); in qcom_iommu_ctx_probe()
705 qcom_iommu->ctxs[ctx->asid] = ctx; in qcom_iommu_ctx_probe()
712 struct qcom_iommu_dev *qcom_iommu = dev_get_drvdata(pdev->dev.parent); in qcom_iommu_ctx_remove()
717 qcom_iommu->ctxs[ctx->asid] = NULL; in qcom_iommu_ctx_remove()
721 { .compatible = "qcom,msm-iommu-v1-ns" },
722 { .compatible = "qcom,msm-iommu-v1-sec" },
723 { .compatible = "qcom,msm-iommu-v2-ns" },
724 { .compatible = "qcom,msm-iommu-v2-sec" },
730 .name = "qcom-iommu-ctx",
741 for_each_child_of_node(qcom_iommu->dev->of_node, child) { in qcom_iommu_has_secure_context()
742 if (of_device_is_compatible(child, "qcom,msm-iommu-v1-sec") || in qcom_iommu_has_secure_context()
743 of_device_is_compatible(child, "qcom,msm-iommu-v2-sec")) { in qcom_iommu_has_secure_context()
756 struct device *dev = &pdev->dev; in qcom_iommu_device_probe()
764 for_each_child_of_node(dev->of_node, child) in qcom_iommu_device_probe()
770 return -ENOMEM; in qcom_iommu_device_probe()
771 qcom_iommu->max_asid = max_asid; in qcom_iommu_device_probe()
772 qcom_iommu->dev = dev; in qcom_iommu_device_probe()
776 qcom_iommu->local_base = devm_ioremap_resource(dev, res); in qcom_iommu_device_probe()
777 if (IS_ERR(qcom_iommu->local_base)) in qcom_iommu_device_probe()
778 return PTR_ERR(qcom_iommu->local_base); in qcom_iommu_device_probe()
786 qcom_iommu->clks[CLK_IFACE].clk = clk; in qcom_iommu_device_probe()
793 qcom_iommu->clks[CLK_BUS].clk = clk; in qcom_iommu_device_probe()
800 qcom_iommu->clks[CLK_TBU].clk = clk; in qcom_iommu_device_probe()
802 if (of_property_read_u32(dev->of_node, "qcom,iommu-secure-id", in qcom_iommu_device_probe()
803 &qcom_iommu->sec_id)) { in qcom_iommu_device_probe()
804 dev_err(dev, "missing qcom,iommu-secure-id property\n"); in qcom_iommu_device_probe()
805 return -ENODEV; in qcom_iommu_device_probe()
823 dev_err(dev, "Failed to populate iommu contexts\n"); in qcom_iommu_device_probe()
827 ret = iommu_device_sysfs_add(&qcom_iommu->iommu, dev, NULL, in qcom_iommu_device_probe()
830 dev_err(dev, "Failed to register iommu in sysfs\n"); in qcom_iommu_device_probe()
834 ret = iommu_device_register(&qcom_iommu->iommu, &qcom_iommu_ops, dev); in qcom_iommu_device_probe()
836 dev_err(dev, "Failed to register iommu\n"); in qcom_iommu_device_probe()
840 if (qcom_iommu->local_base) { in qcom_iommu_device_probe()
842 writel_relaxed(0xffffffff, qcom_iommu->local_base + SMMU_INTR_SEL_NS); in qcom_iommu_device_probe()
857 pm_runtime_force_suspend(&pdev->dev); in qcom_iommu_device_remove()
859 iommu_device_sysfs_remove(&qcom_iommu->iommu); in qcom_iommu_device_remove()
860 iommu_device_unregister(&qcom_iommu->iommu); in qcom_iommu_device_remove()
867 return clk_bulk_prepare_enable(CLK_NUM, qcom_iommu->clks); in qcom_iommu_resume()
874 clk_bulk_disable_unprepare(CLK_NUM, qcom_iommu->clks); in qcom_iommu_suspend()
886 { .compatible = "qcom,msm-iommu-v1" },
887 { .compatible = "qcom,msm-iommu-v2" },
893 .name = "qcom-iommu",