From patchwork Sat Jan 24 21:13:50 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 5700271 X-Patchwork-Delegate: geert@linux-m68k.org Return-Path: X-Original-To: patchwork-linux-sh@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id A6BA59F305 for ; Sat, 24 Jan 2015 21:13:24 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id A00D020115 for ; Sat, 24 Jan 2015 21:13:23 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 5CCA420131 for ; Sat, 24 Jan 2015 21:13:22 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751403AbbAXVNV (ORCPT ); Sat, 24 Jan 2015 16:13:21 -0500 Received: from galahad.ideasonboard.com ([185.26.127.97]:34326 "EHLO galahad.ideasonboard.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751236AbbAXVNU (ORCPT ); Sat, 24 Jan 2015 16:13:20 -0500 Received: from avalon.ideasonboard.com (dsl-hkibrasgw3-50ddcc-40.dhcp.inet.fi [80.221.204.40]) by galahad.ideasonboard.com (Postfix) with ESMTPSA id 6D25620010; Sat, 24 Jan 2015 22:13:17 +0100 (CET) From: Laurent Pinchart To: iommu@lists.linux-foundation.org Cc: linux-sh@vger.kernel.org Subject: [PATCH] iommu/ipmmu-vmsa: Fix IOMMU lookup when multiple IOMMUs are registered Date: Sat, 24 Jan 2015 23:13:50 +0200 Message-Id: <1422134030-11121-1-git-send-email-laurent.pinchart+renesas@ideasonboard.com> X-Mailer: git-send-email 2.0.5 Sender: linux-sh-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-sh@vger.kernel.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP When adding a new device the driver loops over all registered IOMMUs and calls the ipmmu_find_utlbs() function to parse the DT iommus attribute. The function returns an error when the IOMMU referenced in DT doesn't match the current IOMMU. The caller incorrectly breaks from the loop immediately when the error is reported, resulting in only the first IOMMU being considered. Fix this, and while at it move code that isn't specific to an IOMMU instance out of the loop. Signed-off-by: Laurent Pinchart --- drivers/iommu/ipmmu-vmsa.c | 49 ++++++++++++++++++++-------------------------- 1 file changed, 21 insertions(+), 28 deletions(-) diff --git a/drivers/iommu/ipmmu-vmsa.c b/drivers/iommu/ipmmu-vmsa.c index 791c3daec7c0..407324132587 100644 --- a/drivers/iommu/ipmmu-vmsa.c +++ b/drivers/iommu/ipmmu-vmsa.c @@ -1007,45 +1007,28 @@ static phys_addr_t ipmmu_iova_to_phys(struct iommu_domain *io_domain, } static int ipmmu_find_utlbs(struct ipmmu_vmsa_device *mmu, struct device *dev, - unsigned int **_utlbs) + unsigned int *utlbs, unsigned int num_utlbs) { - unsigned int *utlbs; unsigned int i; - int count; - - count = of_count_phandle_with_args(dev->of_node, "iommus", - "#iommu-cells"); - if (count < 0) - return -EINVAL; - - utlbs = kcalloc(count, sizeof(*utlbs), GFP_KERNEL); - if (!utlbs) - return -ENOMEM; - for (i = 0; i < count; ++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) - goto error; + return ret; of_node_put(args.np); if (args.np != mmu->dev->of_node || args.args_count != 1) - goto error; + return -EINVAL; utlbs[i] = args.args[0]; } - *_utlbs = utlbs; - - return count; - -error: - kfree(utlbs); - return -EINVAL; + return 0; } static int ipmmu_add_device(struct device *dev) @@ -1053,10 +1036,10 @@ static int ipmmu_add_device(struct device *dev) struct ipmmu_vmsa_archdata *archdata; struct ipmmu_vmsa_device *mmu; struct iommu_group *group = NULL; - unsigned int *utlbs = NULL; + unsigned int *utlbs; unsigned int i; - int num_utlbs = 0; - int ret; + int num_utlbs; + int ret = -ENODEV; if (dev->archdata.iommu) { dev_warn(dev, "IOMMU driver already assigned to device %s\n", @@ -1065,11 +1048,21 @@ static int ipmmu_add_device(struct device *dev) } /* Find the master corresponding to the device. */ + + num_utlbs = of_count_phandle_with_args(dev->of_node, "iommus", + "#iommu-cells"); + if (num_utlbs < 0) + 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) { - num_utlbs = ipmmu_find_utlbs(mmu, dev, &utlbs); - if (num_utlbs) { + ret = ipmmu_find_utlbs(mmu, dev, utlbs, num_utlbs); + if (!ret) { /* * TODO Take a reference to the MMU to protect * against device removal. @@ -1080,7 +1073,7 @@ static int ipmmu_add_device(struct device *dev) spin_unlock(&ipmmu_devices_lock); - if (num_utlbs <= 0) + if (ret < 0) return -ENODEV; for (i = 0; i < num_utlbs; ++i) {