Lines Matching +full:smmu +full:- +full:v1
2 * IOMMU API for QCOM secure IOMMUs. Somewhat based on arm-smmu.c
23 #include <linux/dma-iommu.h>
24 #include <linux/dma-mapping.h>
28 #include <linux/io-64-nonatomic-hi-lo.h>
45 #include "io-pgtable.h"
46 #include "arm-smmu-regs.h"
61 struct qcom_iommu_ctx *ctxs[0]; /* indexed by asid-1 */
89 if (!fwspec || fwspec->ops != &qcom_iommu_ops) in to_iommu()
91 return fwspec->iommu_priv; in to_iommu()
99 return qcom_iommu->ctxs[asid - 1]; in to_ctx()
105 writel_relaxed(val, ctx->base + reg); in iommu_writel()
111 writeq_relaxed(val, ctx->base + reg); in iommu_writeq()
117 return readl_relaxed(ctx->base + reg); in iommu_readl()
123 return readq_relaxed(ctx->base + reg); in iommu_readq()
131 for (i = 0; i < fwspec->num_ids; i++) { in qcom_iommu_tlb_sync()
132 struct qcom_iommu_ctx *ctx = to_ctx(fwspec, fwspec->ids[i]); in qcom_iommu_tlb_sync()
137 ret = readl_poll_timeout(ctx->base + ARM_SMMU_CB_TLBSTATUS, val, in qcom_iommu_tlb_sync()
140 dev_err(ctx->dev, "timeout waiting for TLB SYNC\n"); in qcom_iommu_tlb_sync()
149 for (i = 0; i < fwspec->num_ids; i++) { in qcom_iommu_tlb_inv_context()
150 struct qcom_iommu_ctx *ctx = to_ctx(fwspec, 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()
165 for (i = 0; i < fwspec->num_ids; i++) { in qcom_iommu_tlb_inv_range_nosync()
166 struct qcom_iommu_ctx *ctx = to_ctx(fwspec, fwspec->ids[i]); in qcom_iommu_tlb_inv_range_nosync()
170 iova |= ctx->asid; in qcom_iommu_tlb_inv_range_nosync()
174 } while (s -= granule); in qcom_iommu_tlb_inv_range_nosync()
198 if (!report_iommu_fault(ctx->domain, ctx->dev, iova, 0)) { in qcom_iommu_fault()
199 dev_err_ratelimited(ctx->dev, in qcom_iommu_fault()
202 fsr, iova, fsynr, ctx->asid); in qcom_iommu_fault()
221 mutex_lock(&qcom_domain->init_mutex); in qcom_iommu_init_domain()
222 if (qcom_domain->iommu) in qcom_iommu_init_domain()
230 .iommu_dev = qcom_iommu->dev, in qcom_iommu_init_domain()
233 qcom_domain->iommu = qcom_iommu; in qcom_iommu_init_domain()
236 dev_err(qcom_iommu->dev, "failed to allocate pagetable ops\n"); in qcom_iommu_init_domain()
237 ret = -ENOMEM; in qcom_iommu_init_domain()
242 domain->pgsize_bitmap = pgtbl_cfg.pgsize_bitmap; in qcom_iommu_init_domain()
243 domain->geometry.aperture_end = (1ULL << pgtbl_cfg.ias) - 1; in qcom_iommu_init_domain()
244 domain->geometry.force_aperture = true; in qcom_iommu_init_domain()
246 for (i = 0; i < fwspec->num_ids; i++) { in qcom_iommu_init_domain()
247 struct qcom_iommu_ctx *ctx = to_ctx(fwspec, fwspec->ids[i]); in qcom_iommu_init_domain()
249 if (!ctx->secure_init) { in qcom_iommu_init_domain()
250 ret = qcom_scm_restore_sec_cfg(qcom_iommu->sec_id, ctx->asid); in qcom_iommu_init_domain()
252 dev_err(qcom_iommu->dev, "secure init failed: %d\n", ret); in qcom_iommu_init_domain()
255 ctx->secure_init = true; in qcom_iommu_init_domain()
261 ((u64)ctx->asid << TTBRn_ASID_SHIFT)); in qcom_iommu_init_domain()
264 ((u64)ctx->asid << TTBRn_ASID_SHIFT)); in qcom_iommu_init_domain()
273 /* MAIRs (stage-1 only) */ in qcom_iommu_init_domain()
288 ctx->domain = domain; in qcom_iommu_init_domain()
291 mutex_unlock(&qcom_domain->init_mutex); in qcom_iommu_init_domain()
294 qcom_domain->pgtbl_ops = pgtbl_ops; in qcom_iommu_init_domain()
299 qcom_domain->iommu = NULL; in qcom_iommu_init_domain()
301 mutex_unlock(&qcom_domain->init_mutex); in qcom_iommu_init_domain()
321 iommu_get_dma_cookie(&qcom_domain->domain)) { in qcom_iommu_domain_alloc()
326 mutex_init(&qcom_domain->init_mutex); in qcom_iommu_domain_alloc()
327 spin_lock_init(&qcom_domain->pgtbl_lock); in qcom_iommu_domain_alloc()
329 return &qcom_domain->domain; in qcom_iommu_domain_alloc()
338 if (qcom_domain->iommu) { in qcom_iommu_domain_free()
341 * off, for example, with GPUs or anything involving dma-buf. in qcom_iommu_domain_free()
345 pm_runtime_get_sync(qcom_domain->iommu->dev); in qcom_iommu_domain_free()
346 free_io_pgtable_ops(qcom_domain->pgtbl_ops); in qcom_iommu_domain_free()
347 pm_runtime_put_sync(qcom_domain->iommu->dev); in qcom_iommu_domain_free()
355 struct qcom_iommu_dev *qcom_iommu = to_iommu(dev->iommu_fwspec); in qcom_iommu_attach_dev()
361 return -ENXIO; in qcom_iommu_attach_dev()
365 pm_runtime_get_sync(qcom_iommu->dev); in qcom_iommu_attach_dev()
366 ret = qcom_iommu_init_domain(domain, qcom_iommu, dev->iommu_fwspec); in qcom_iommu_attach_dev()
367 pm_runtime_put_sync(qcom_iommu->dev); in qcom_iommu_attach_dev()
375 if (qcom_domain->iommu != qcom_iommu) { in qcom_iommu_attach_dev()
378 dev_name(qcom_domain->iommu->dev), in qcom_iommu_attach_dev()
379 dev_name(qcom_iommu->dev)); in qcom_iommu_attach_dev()
380 return -EINVAL; in qcom_iommu_attach_dev()
388 struct iommu_fwspec *fwspec = dev->iommu_fwspec; in qcom_iommu_detach_dev()
393 if (WARN_ON(!qcom_domain->iommu)) in qcom_iommu_detach_dev()
396 pm_runtime_get_sync(qcom_iommu->dev); in qcom_iommu_detach_dev()
397 for (i = 0; i < fwspec->num_ids; i++) { in qcom_iommu_detach_dev()
398 struct qcom_iommu_ctx *ctx = to_ctx(fwspec, fwspec->ids[i]); in qcom_iommu_detach_dev()
403 ctx->domain = NULL; in qcom_iommu_detach_dev()
405 pm_runtime_put_sync(qcom_iommu->dev); in qcom_iommu_detach_dev()
414 struct io_pgtable_ops *ops = qcom_domain->pgtbl_ops; in qcom_iommu_map()
417 return -ENODEV; in qcom_iommu_map()
419 spin_lock_irqsave(&qcom_domain->pgtbl_lock, flags); in qcom_iommu_map()
420 ret = ops->map(ops, iova, paddr, size, prot); in qcom_iommu_map()
421 spin_unlock_irqrestore(&qcom_domain->pgtbl_lock, flags); in qcom_iommu_map()
431 struct io_pgtable_ops *ops = qcom_domain->pgtbl_ops; in qcom_iommu_unmap()
437 * for example, with GPUs or anything involving dma-buf. So we in qcom_iommu_unmap()
441 pm_runtime_get_sync(qcom_domain->iommu->dev); in qcom_iommu_unmap()
442 spin_lock_irqsave(&qcom_domain->pgtbl_lock, flags); in qcom_iommu_unmap()
443 ret = ops->unmap(ops, iova, size); in qcom_iommu_unmap()
444 spin_unlock_irqrestore(&qcom_domain->pgtbl_lock, flags); in qcom_iommu_unmap()
445 pm_runtime_put_sync(qcom_domain->iommu->dev); in qcom_iommu_unmap()
453 struct io_pgtable *pgtable = container_of(qcom_domain->pgtbl_ops, in qcom_iommu_iotlb_sync()
455 if (!qcom_domain->pgtbl_ops) in qcom_iommu_iotlb_sync()
458 pm_runtime_get_sync(qcom_domain->iommu->dev); in qcom_iommu_iotlb_sync()
459 qcom_iommu_tlb_sync(pgtable->cookie); in qcom_iommu_iotlb_sync()
460 pm_runtime_put_sync(qcom_domain->iommu->dev); in qcom_iommu_iotlb_sync()
469 struct io_pgtable_ops *ops = qcom_domain->pgtbl_ops; in qcom_iommu_iova_to_phys()
474 spin_lock_irqsave(&qcom_domain->pgtbl_lock, flags); in qcom_iommu_iova_to_phys()
475 ret = ops->iova_to_phys(ops, iova); in qcom_iommu_iova_to_phys()
476 spin_unlock_irqrestore(&qcom_domain->pgtbl_lock, flags); in qcom_iommu_iova_to_phys()
486 * Return true here as the SMMU can always send out coherent in qcom_iommu_capable()
499 struct qcom_iommu_dev *qcom_iommu = to_iommu(dev->iommu_fwspec); in qcom_iommu_add_device()
504 return -ENODEV; in qcom_iommu_add_device()
511 link = device_link_add(dev, qcom_iommu->dev, DL_FLAG_PM_RUNTIME); in qcom_iommu_add_device()
513 dev_err(qcom_iommu->dev, "Unable to create device link between %s and %s\n", in qcom_iommu_add_device()
514 dev_name(qcom_iommu->dev), dev_name(dev)); in qcom_iommu_add_device()
515 return -ENODEV; in qcom_iommu_add_device()
523 iommu_device_link(&qcom_iommu->iommu, dev); in qcom_iommu_add_device()
530 struct qcom_iommu_dev *qcom_iommu = to_iommu(dev->iommu_fwspec); in qcom_iommu_remove_device()
535 iommu_device_unlink(&qcom_iommu->iommu, dev); in qcom_iommu_remove_device()
544 unsigned asid = args->args[0]; in qcom_iommu_of_xlate()
546 if (args->args_count != 1) { in qcom_iommu_of_xlate()
549 args->np->full_name, args->args_count); in qcom_iommu_of_xlate()
550 return -EINVAL; in qcom_iommu_of_xlate()
553 iommu_pdev = of_find_device_by_node(args->np); in qcom_iommu_of_xlate()
555 return -EINVAL; in qcom_iommu_of_xlate()
560 * to sanity check this elsewhere, since 'asid - 1' is used to in qcom_iommu_of_xlate()
561 * index into qcom_iommu->ctxs: in qcom_iommu_of_xlate()
564 WARN_ON(asid > qcom_iommu->num_ctxs)) in qcom_iommu_of_xlate()
565 return -EINVAL; in qcom_iommu_of_xlate()
567 if (!dev->iommu_fwspec->iommu_priv) { in qcom_iommu_of_xlate()
568 dev->iommu_fwspec->iommu_priv = qcom_iommu; in qcom_iommu_of_xlate()
574 if (WARN_ON(qcom_iommu != dev->iommu_fwspec->iommu_priv)) in qcom_iommu_of_xlate()
575 return -EINVAL; in qcom_iommu_of_xlate()
603 ret = clk_prepare_enable(qcom_iommu->iface_clk); in qcom_iommu_enable_clocks()
605 dev_err(qcom_iommu->dev, "Couldn't enable iface_clk\n"); in qcom_iommu_enable_clocks()
609 ret = clk_prepare_enable(qcom_iommu->bus_clk); in qcom_iommu_enable_clocks()
611 dev_err(qcom_iommu->dev, "Couldn't enable bus_clk\n"); in qcom_iommu_enable_clocks()
612 clk_disable_unprepare(qcom_iommu->iface_clk); in qcom_iommu_enable_clocks()
621 clk_disable_unprepare(qcom_iommu->bus_clk); in qcom_iommu_disable_clocks()
622 clk_disable_unprepare(qcom_iommu->iface_clk); in qcom_iommu_disable_clocks()
653 return -ENOMEM; in qcom_iommu_sec_ptbl_init()
678 return -ENODEV; in get_asid()
686 struct device *dev = &pdev->dev; in qcom_iommu_ctx_probe()
687 struct qcom_iommu_dev *qcom_iommu = dev_get_drvdata(dev->parent); in qcom_iommu_ctx_probe()
693 return -ENOMEM; in qcom_iommu_ctx_probe()
695 ctx->dev = dev; in qcom_iommu_ctx_probe()
699 ctx->base = devm_ioremap_resource(dev, res); in qcom_iommu_ctx_probe()
700 if (IS_ERR(ctx->base)) in qcom_iommu_ctx_probe()
701 return PTR_ERR(ctx->base); in qcom_iommu_ctx_probe()
706 return -ENODEV; in qcom_iommu_ctx_probe()
710 * boot-loader left us a surprise: in qcom_iommu_ctx_probe()
717 "qcom-iommu-fault", in qcom_iommu_ctx_probe()
724 ret = get_asid(dev->of_node); in qcom_iommu_ctx_probe()
730 ctx->asid = ret; in qcom_iommu_ctx_probe()
732 dev_dbg(dev, "found asid %u\n", ctx->asid); in qcom_iommu_ctx_probe()
734 qcom_iommu->ctxs[ctx->asid - 1] = ctx; in qcom_iommu_ctx_probe()
741 struct qcom_iommu_dev *qcom_iommu = dev_get_drvdata(pdev->dev.parent); in qcom_iommu_ctx_remove()
746 qcom_iommu->ctxs[ctx->asid - 1] = NULL; in qcom_iommu_ctx_remove()
752 { .compatible = "qcom,msm-iommu-v1-ns" },
753 { .compatible = "qcom,msm-iommu-v1-sec" },
759 .name = "qcom-iommu-ctx",
770 for_each_child_of_node(qcom_iommu->dev->of_node, child) in qcom_iommu_has_secure_context()
771 if (of_device_is_compatible(child, "qcom,msm-iommu-v1-sec")) in qcom_iommu_has_secure_context()
781 struct device *dev = &pdev->dev; in qcom_iommu_device_probe()
788 for_each_child_of_node(dev->of_node, child) in qcom_iommu_device_probe()
791 sz = sizeof(*qcom_iommu) + (max_asid * sizeof(qcom_iommu->ctxs[0])); in qcom_iommu_device_probe()
795 return -ENOMEM; in qcom_iommu_device_probe()
796 qcom_iommu->num_ctxs = max_asid; in qcom_iommu_device_probe()
797 qcom_iommu->dev = dev; in qcom_iommu_device_probe()
801 qcom_iommu->local_base = devm_ioremap_resource(dev, res); in qcom_iommu_device_probe()
802 if (IS_ERR(qcom_iommu->local_base)) in qcom_iommu_device_probe()
803 return PTR_ERR(qcom_iommu->local_base); in qcom_iommu_device_probe()
806 qcom_iommu->iface_clk = devm_clk_get(dev, "iface"); in qcom_iommu_device_probe()
807 if (IS_ERR(qcom_iommu->iface_clk)) { in qcom_iommu_device_probe()
809 return PTR_ERR(qcom_iommu->iface_clk); in qcom_iommu_device_probe()
812 qcom_iommu->bus_clk = devm_clk_get(dev, "bus"); in qcom_iommu_device_probe()
813 if (IS_ERR(qcom_iommu->bus_clk)) { in qcom_iommu_device_probe()
815 return PTR_ERR(qcom_iommu->bus_clk); in qcom_iommu_device_probe()
818 if (of_property_read_u32(dev->of_node, "qcom,iommu-secure-id", in qcom_iommu_device_probe()
819 &qcom_iommu->sec_id)) { in qcom_iommu_device_probe()
820 dev_err(dev, "missing qcom,iommu-secure-id property\n"); in qcom_iommu_device_probe()
821 return -ENODEV; in qcom_iommu_device_probe()
843 ret = iommu_device_sysfs_add(&qcom_iommu->iommu, dev, NULL, in qcom_iommu_device_probe()
850 iommu_device_set_ops(&qcom_iommu->iommu, &qcom_iommu_ops); in qcom_iommu_device_probe()
851 iommu_device_set_fwnode(&qcom_iommu->iommu, dev->fwnode); in qcom_iommu_device_probe()
853 ret = iommu_device_register(&qcom_iommu->iommu); in qcom_iommu_device_probe()
861 if (qcom_iommu->local_base) { in qcom_iommu_device_probe()
863 writel_relaxed(0xffffffff, qcom_iommu->local_base + SMMU_INTR_SEL_NS); in qcom_iommu_device_probe()
876 pm_runtime_force_suspend(&pdev->dev); in qcom_iommu_device_remove()
878 iommu_device_sysfs_remove(&qcom_iommu->iommu); in qcom_iommu_device_remove()
879 iommu_device_unregister(&qcom_iommu->iommu); in qcom_iommu_device_remove()
907 { .compatible = "qcom,msm-iommu-v1" },
914 .name = "qcom-iommu",
946 MODULE_DESCRIPTION("IOMMU API for QCOM IOMMU v1 implementations");