Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1423091AbbENXA2 (ORCPT ); Thu, 14 May 2015 19:00:28 -0400 Received: from galahad.ideasonboard.com ([185.26.127.97]:54050 "EHLO galahad.ideasonboard.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1422987AbbENXAO (ORCPT ); Thu, 14 May 2015 19:00:14 -0400 From: Laurent Pinchart To: linux-kernel@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org, iommu@lists.linux-foundation.org, Laura Abbott , Arnd Bergmann , Mitchel Humpherys , Joreg Roedel , Will Deacon , Grant Likely , Robin Murphy , Marek Szyprowski , Thierry Reding , Greg Kroah-Hartman Subject: [RFC/PATCH 9/9] iommu/ipmmu-vmsa: Use DT-based instantiation Date: Fri, 15 May 2015 02:00:10 +0300 Message-Id: <1431644410-2997-10-git-send-email-laurent.pinchart+renesas@ideasonboard.com> X-Mailer: git-send-email 2.3.6 In-Reply-To: <1431644410-2997-1-git-send-email-laurent.pinchart+renesas@ideasonboard.com> References: <1431644410-2997-1-git-send-email-laurent.pinchart+renesas@ideasonboard.com> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 8172 Lines: 310 Signed-off-by: Laurent Pinchart --- drivers/iommu/ipmmu-vmsa.c | 189 ++++++++++++++------------------------------- 1 file changed, 60 insertions(+), 129 deletions(-) diff --git a/drivers/iommu/ipmmu-vmsa.c b/drivers/iommu/ipmmu-vmsa.c index 24a950091458..7fa2afb5d7d1 100644 --- a/drivers/iommu/ipmmu-vmsa.c +++ b/drivers/iommu/ipmmu-vmsa.c @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include #include #include @@ -30,7 +32,6 @@ struct ipmmu_vmsa_device { struct device *dev; void __iomem *base; - struct list_head list; unsigned int num_utlbs; @@ -54,9 +55,6 @@ struct ipmmu_vmsa_archdata { unsigned int num_utlbs; }; -static DEFINE_SPINLOCK(ipmmu_devices_lock); -static LIST_HEAD(ipmmu_devices); - static struct ipmmu_vmsa_domain *to_vmsa_domain(struct iommu_domain *dom) { return container_of(dom, struct ipmmu_vmsa_domain, io_domain); @@ -578,110 +576,81 @@ static phys_addr_t ipmmu_iova_to_phys(struct iommu_domain *io_domain, return domain->iop->iova_to_phys(domain->iop, iova); } -static int ipmmu_find_utlbs(struct ipmmu_vmsa_device *mmu, struct device *dev, - unsigned int *utlbs, unsigned int num_utlbs) +static void ipmmu_remove_device(struct device *dev) { - unsigned int i; - - for (i = 0; i < num_utlbs; ++i) { - struct of_phandle_args args; - int ret; - - ret = of_parse_phandle_with_args(dev->of_node, "iommus", - "#iommu-cells", i, &args); - if (ret < 0) - return ret; + struct ipmmu_vmsa_archdata *archdata = dev->archdata.iommu; - of_node_put(args.np); + if (!archdata) + return; - if (args.np != mmu->dev->of_node || args.args_count != 1) - return -EINVAL; + arm_iommu_detach_device(dev); + iommu_group_remove_device(dev); - utlbs[i] = args.args[0]; - } + kfree(archdata->utlbs); + kfree(archdata); - return 0; + dev->archdata.iommu = NULL; } -static int ipmmu_add_device(struct device *dev) +static int ipmmu_of_xlate(struct device *dev, struct of_phandle_args *args) { struct ipmmu_vmsa_archdata *archdata; struct ipmmu_vmsa_device *mmu; - struct iommu_group *group = NULL; + struct platform_device *pdev; + unsigned int num_utlbs; unsigned int *utlbs; - unsigned int i; - int num_utlbs; - int ret = -ENODEV; - - if (dev->archdata.iommu) { - dev_warn(dev, "IOMMU driver already assigned to device %s\n", - dev_name(dev)); - return -EINVAL; - } + unsigned int utlb; + int ret; /* Find the master corresponding to the device. */ - - num_utlbs = of_count_phandle_with_args(dev->of_node, "iommus", - "#iommu-cells"); - if (num_utlbs < 0) + pdev = of_find_device_by_node(args->np); + if (!pdev) { + dev_dbg(dev, "%s: ipmmu pdev not found\n", __func__); return -ENODEV; - - utlbs = kcalloc(num_utlbs, sizeof(*utlbs), GFP_KERNEL); - if (!utlbs) - return -ENOMEM; - - spin_lock(&ipmmu_devices_lock); - - list_for_each_entry(mmu, &ipmmu_devices, list) { - ret = ipmmu_find_utlbs(mmu, dev, utlbs, num_utlbs); - if (!ret) { - /* - * TODO Take a reference to the MMU to protect - * against device removal. - */ - break; - } } - spin_unlock(&ipmmu_devices_lock); - - if (ret < 0) + mmu = platform_get_drvdata(pdev); + if (!mmu) { + dev_dbg(dev, "%s: ipmmu not found\n", __func__); return -ENODEV; - - for (i = 0; i < num_utlbs; ++i) { - if (utlbs[i] >= mmu->num_utlbs) { - ret = -EINVAL; - goto error; - } } - /* Create a device group and add the device to it. */ - group = iommu_group_alloc(); - if (IS_ERR(group)) { - dev_err(dev, "Failed to allocate IOMMU group\n"); - ret = PTR_ERR(group); - goto error; + /* Allocate arch data if not already done. */ + if (!dev->archdata.iommu) { + dev->archdata.iommu = kzalloc(sizeof(*archdata), GFP_KERNEL); + if (!dev->archdata.iommu) + return -ENOMEM; } - ret = iommu_group_add_device(group, dev); - iommu_group_put(group); + archdata = dev->archdata.iommu; + archdata->mmu = mmu; - if (ret < 0) { - dev_err(dev, "Failed to add device to IPMMU group\n"); - group = NULL; - goto error; + /* + * We don't support handling a device through different IOMMU + * instances. + */ + if (archdata->mmu && archdata->mmu != mmu) { + dev_warn(dev, "IOMMU driver already assigned to device %s\n", + dev_name(dev)); + return -EINVAL; } - archdata = kzalloc(sizeof(*archdata), GFP_KERNEL); - if (!archdata) { - ret = -ENOMEM; - goto error; + /* Validate and store the microTLB number. */ + utlb = args->args[0]; + if (utlb >= mmu->num_utlbs) { + dev_dbg(dev, "%s: invalid utlb %u\n", __func__, utlb); + return -EINVAL; } - archdata->mmu = mmu; + num_utlbs = archdata->num_utlbs + 1; + utlbs = krealloc(archdata->utlbs, num_utlbs * sizeof(*utlbs), + GFP_KERNEL); + if (utlbs == NULL) + return -ENOMEM; + utlbs[archdata->num_utlbs] = utlb; + archdata->utlbs = utlbs; archdata->num_utlbs = num_utlbs; - dev->archdata.iommu = archdata; /* * Create the ARM mapping, used by the ARM DMA mapping core to allocate @@ -699,50 +668,27 @@ static int ipmmu_add_device(struct device *dev) SZ_1G, SZ_2G); if (IS_ERR(mapping)) { dev_err(mmu->dev, "failed to create ARM IOMMU mapping\n"); - ret = PTR_ERR(mapping); - goto error; + return PTR_ERR(mapping); } mmu->mapping = mapping; } - /* Attach the ARM VA mapping to the device. */ + /* + * Detach the device from the default ARM VA mapping and attach it to + * our private mapping. + */ + arm_iommu_detach_device(dev); ret = arm_iommu_attach_device(dev, mmu->mapping); if (ret < 0) { dev_err(dev, "Failed to attach device to VA mapping\n"); - goto error; + return ret; } return 0; - -error: - arm_iommu_release_mapping(mmu->mapping); - - kfree(dev->archdata.iommu); - kfree(utlbs); - - dev->archdata.iommu = NULL; - - if (!IS_ERR_OR_NULL(group)) - iommu_group_remove_device(dev); - - return ret; } -static void ipmmu_remove_device(struct device *dev) -{ - struct ipmmu_vmsa_archdata *archdata = dev->archdata.iommu; - - arm_iommu_detach_device(dev); - iommu_group_remove_device(dev); - - kfree(archdata->utlbs); - kfree(archdata); - - dev->archdata.iommu = NULL; -} - -static const struct iommu_ops ipmmu_ops = { +static struct iommu_ops ipmmu_ops = { .domain_alloc = ipmmu_domain_alloc, .domain_free = ipmmu_domain_free, .attach_dev = ipmmu_attach_device, @@ -751,8 +697,8 @@ static const struct iommu_ops ipmmu_ops = { .unmap = ipmmu_unmap, .map_sg = default_iommu_map_sg, .iova_to_phys = ipmmu_iova_to_phys, - .add_device = ipmmu_add_device, .remove_device = ipmmu_remove_device, + .of_xlate = ipmmu_of_xlate, .pgsize_bitmap = SZ_1G | SZ_2M | SZ_4K, }; @@ -831,10 +777,7 @@ static int ipmmu_probe(struct platform_device *pdev) * ipmmu_init() after the probe function returns. */ - spin_lock(&ipmmu_devices_lock); - list_add(&mmu->list, &ipmmu_devices); - spin_unlock(&ipmmu_devices_lock); - + of_iommu_set_ops(mmu->dev->of_node, &ipmmu_ops); platform_set_drvdata(pdev, mmu); return 0; @@ -844,10 +787,6 @@ static int ipmmu_remove(struct platform_device *pdev) { struct ipmmu_vmsa_device *mmu = platform_get_drvdata(pdev); - spin_lock(&ipmmu_devices_lock); - list_del(&mmu->list); - spin_unlock(&ipmmu_devices_lock); - arm_iommu_release_mapping(mmu->mapping); ipmmu_device_reset(mmu); @@ -883,14 +822,6 @@ static int __init ipmmu_init(void) return 0; } -static void __exit ipmmu_exit(void) -{ - return platform_driver_unregister(&ipmmu_driver); -} - subsys_initcall(ipmmu_init); -module_exit(ipmmu_exit); -MODULE_DESCRIPTION("IOMMU API for Renesas VMSA-compatible IPMMU"); -MODULE_AUTHOR("Laurent Pinchart "); -MODULE_LICENSE("GPL v2"); +IOMMU_OF_DECLARE(ipmmu_vmsa_of, "renesas,ipmmu-vmsa", NULL); -- 2.3.6 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/