From patchwork Tue Mar 6 10:47:44 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Garry X-Patchwork-Id: 130766 Delivered-To: patch@linaro.org Received: by 10.46.66.2 with SMTP id p2csp3782745lja; Tue, 6 Mar 2018 02:48:43 -0800 (PST) X-Google-Smtp-Source: AG47ELs5qNw/lV8Th8JzJswJolBOwebzI/cFBCF7qGAbTTzpx4a2IDAstAj6Q+8KY6qSjOVVnkIg X-Received: by 2002:a17:902:f44:: with SMTP id 62-v6mr16000468ply.27.1520333323413; Tue, 06 Mar 2018 02:48:43 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1520333323; cv=none; d=google.com; s=arc-20160816; b=KzDv4+ReDO190zL4wHtZGc6JYx5IQZw9ET6C1bFT6StMU18LKRWIckBBSZRuRM1+vQ AYvtMrC57LJujK3467rBwA8fKwkg6dU9ygrC/SHfQr9IAu098D75jDzXq9VaQbPHzsS7 2apa3M1mgMa+Rl+sSZE0TBpcuCrX4gZkmQ8HPifzVoXgqnkFWBzBXD2ZmJ5crOXcT5Hk uosdpyW0lTZMll/6rUhxUedEtXscm7CdhxQs93lNJS8fhX7cF3yhTUgjSj2zbSPT+kej C+qtXODtuCWYccMjNi7NJl/8M0ApZbr13bGdTjGbBdhLLwvWy7KwNy/IydA5NyT906eb Jebw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:arc-authentication-results; bh=Z0uXAtNDkj72As2awn2LlidDV/LGt+pVLAUtK030rNc=; b=dPwjSwmWxpR6ZRvgSOtiFAUv79HJg6Y2g61aRT12ObbP1UU7R96whZ/fuxkDnChs++ vViyM3c3VlGbd5rJFLglo+g1JxyoRcaykdZtiGoGBxLfLSCFEjrD8limKN/jr108zgVz 9hmx+9JytMq5gFxgNc8DQfirxVQIBpb5TGIEb6EWVLCRukgn4CoSIQ7WyXjDWOp1R7kv vtGmUbIYzwijXmv8NKw3W6BducyQwWjVJygQoLxLMX7+LMRBiY9i4lZzS6qiWlVNzbza rPForwxHmYu2vYeUUEuXI32glGfI6Yuk1LIC6O1lcYhLXZgwsDFC9AN+VKalwLYLGO1S a7BQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id s62si9714450pgc.184.2018.03.06.02.48.43; Tue, 06 Mar 2018 02:48:43 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753541AbeCFKsj (ORCPT + 28 others); Tue, 6 Mar 2018 05:48:39 -0500 Received: from szxga04-in.huawei.com ([45.249.212.190]:6157 "EHLO huawei.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1753433AbeCFKsd (ORCPT ); Tue, 6 Mar 2018 05:48:33 -0500 Received: from DGGEMS404-HUB.china.huawei.com (unknown [172.30.72.59]) by Forcepoint Email with ESMTP id 60194703C77F8; Tue, 6 Mar 2018 18:48:14 +0800 (CST) Received: from localhost.localdomain (10.67.212.75) by DGGEMS404-HUB.china.huawei.com (10.3.19.204) with Microsoft SMTP Server id 14.3.361.1; Tue, 6 Mar 2018 18:48:07 +0800 From: John Garry To: , , , , , , , , , , , , , CC: , , , , , , , , , , , , , Subject: [PATCH v16 5/9] OF: Add missing I/O range exception for indirect-IO devices Date: Tue, 6 Mar 2018 18:47:44 +0800 Message-ID: <1520333268-82754-6-git-send-email-john.garry@huawei.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1520333268-82754-1-git-send-email-john.garry@huawei.com> References: <1520333268-82754-1-git-send-email-john.garry@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.67.212.75] X-CFilter-Loop: Reflected Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Zhichang Yuan There are some special ISA/LPC devices that work on a specific I/O range where it is not correct to specify a 'ranges' property in DTS parent node as CPU addresses translated from DTS node are only for memory space on some architectures, such as Arm64. Without the parent 'ranges' property, current of_translate_address() return an error. Here we add special handling for this case. During the OF address translation, some checking will be performed to identify whether the device node is registered as indirect-IO. If yes, the I/O translation will be done in a different way from that one of PCI MMIO. In this way, the I/O 'reg' property of the special ISA/LPC devices will be parsed correctly. Signed-off-by: Zhichang Yuan Signed-off-by: Gabriele Paoloni Signed-off-by: Arnd Bergmann #earlier draft Acked-by: Rob Herring Reviewed-by: Andy Shevchenko Tested-by: dann frazier --- drivers/of/address.c | 92 +++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 76 insertions(+), 16 deletions(-) -- 1.9.1 diff --git a/drivers/of/address.c b/drivers/of/address.c index cdf047b..c434f659 100644 --- a/drivers/of/address.c +++ b/drivers/of/address.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -562,9 +563,14 @@ static int of_translate_one(struct device_node *parent, struct of_bus *bus, * that translation is impossible (that is we are not dealing with a value * that can be mapped to a cpu physical address). This is not really specified * that way, but this is traditionally the way IBM at least do things + * + * Whenever the translation fails, the *host pointer will be set to the + * device that had registered logical PIO mapping, and the return code is + * relative to that node. */ static u64 __of_translate_address(struct device_node *dev, - const __be32 *in_addr, const char *rprop) + const __be32 *in_addr, const char *rprop, + struct device_node **host) { struct device_node *parent = NULL; struct of_bus *bus, *pbus; @@ -577,6 +583,7 @@ static u64 __of_translate_address(struct device_node *dev, /* Increase refcount at current level */ of_node_get(dev); + *host = NULL; /* Get parent & match bus type */ parent = of_get_parent(dev); if (parent == NULL) @@ -597,6 +604,8 @@ static u64 __of_translate_address(struct device_node *dev, /* Translate */ for (;;) { + struct logic_pio_hwaddr *iorange; + /* Switch to parent bus */ of_node_put(dev); dev = parent; @@ -609,6 +618,19 @@ static u64 __of_translate_address(struct device_node *dev, break; } + /* + * For indirectIO device which has no ranges property, get + * the address from reg directly. + */ + iorange = find_io_range_by_fwnode(&dev->fwnode); + if (iorange && (iorange->flags != LOGIC_PIO_CPU_MMIO)) { + result = of_read_number(addr + 1, na - 1); + pr_debug("indirectIO matched(%pOF) 0x%llx\n", + dev, result); + *host = of_node_get(dev); + break; + } + /* Get new parent bus and counts */ pbus = of_match_bus(parent); pbus->count_cells(dev, &pna, &pns); @@ -640,13 +662,32 @@ static u64 __of_translate_address(struct device_node *dev, u64 of_translate_address(struct device_node *dev, const __be32 *in_addr) { - return __of_translate_address(dev, in_addr, "ranges"); + struct device_node *host; + u64 ret; + + ret = __of_translate_address(dev, in_addr, "ranges", &host); + if (host) { + of_node_put(host); + return OF_BAD_ADDR; + } + + return ret; } EXPORT_SYMBOL(of_translate_address); u64 of_translate_dma_address(struct device_node *dev, const __be32 *in_addr) { - return __of_translate_address(dev, in_addr, "dma-ranges"); + struct device_node *host; + u64 ret; + + ret = __of_translate_address(dev, in_addr, "dma-ranges", &host); + + if (host) { + of_node_put(host); + return OF_BAD_ADDR; + } + + return ret; } EXPORT_SYMBOL(of_translate_dma_address); @@ -688,29 +729,48 @@ const __be32 *of_get_address(struct device_node *dev, int index, u64 *size, } EXPORT_SYMBOL(of_get_address); +static u64 of_translate_ioport(struct device_node *dev, const __be32 *in_addr, + u64 size) +{ + u64 taddr; + unsigned long port; + struct device_node *host; + + taddr = __of_translate_address(dev, in_addr, "ranges", &host); + if (host) { + /* host specific port access */ + port = logic_pio_trans_hwaddr(&host->fwnode, taddr, size); + of_node_put(host); + } else { + /* memory mapped I/O range */ + port = pci_address_to_pio(taddr); + } + + if (port == (unsigned long)-1) + return OF_BAD_ADDR; + + return port; +} + static int __of_address_to_resource(struct device_node *dev, const __be32 *addrp, u64 size, unsigned int flags, const char *name, struct resource *r) { u64 taddr; - if ((flags & (IORESOURCE_IO | IORESOURCE_MEM)) == 0) + if (flags & IORESOURCE_MEM) + taddr = of_translate_address(dev, addrp); + else if (flags & IORESOURCE_IO) + taddr = of_translate_ioport(dev, addrp, size); + else return -EINVAL; - taddr = of_translate_address(dev, addrp); + if (taddr == OF_BAD_ADDR) return -EINVAL; memset(r, 0, sizeof(struct resource)); - if (flags & IORESOURCE_IO) { - unsigned long port; - port = pci_address_to_pio(taddr); - if (port == (unsigned long)-1) - return -EINVAL; - r->start = port; - r->end = port + size - 1; - } else { - r->start = taddr; - r->end = taddr + size - 1; - } + + r->start = taddr; + r->end = taddr + size - 1; r->flags = flags; r->name = name ? name : dev->full_name;