From patchwork Thu May 25 11:37:24 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gabriele Paoloni X-Patchwork-Id: 100500 Delivered-To: patch@linaro.org Received: by 10.140.96.100 with SMTP id j91csp719665qge; Thu, 25 May 2017 04:40:35 -0700 (PDT) X-Received: by 10.84.231.199 with SMTP id g7mr49927820pln.70.1495712435450; Thu, 25 May 2017 04:40:35 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1495712435; cv=none; d=google.com; s=arc-20160816; b=1BpABIMtiBKJRtAuKHTUtX5ZfGte2S0ctijvJEo4HcI9LBV911S7Cd5Jzay/rB+EtR hmvS8yRh2MunPH2iebrCl1sfk30NbmY00k90yK5KDIH8OS6bVURymYXxUo3jOoOwVHNb mhlDsWyaOCl30tY+jI2eFIsfg6GkacPPnzIQtjDFNun8Wfk/0c2x3vaFCoM79jAW81WW 6ZWCgyY6Q88FewFRX8sLu+F5aLEx7TkON2DMk0WuDQeQOcUymmHeiyscm9XvknkoEzGX XFe7Hzordddpg91+EmfnmKJCLXRxs4QAIAs6DSsJNhzhLG4bF6oRam+Kv0Z3KXcjgIrS S1Fg== 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=dTPb+mDUaw07NLxMhdttJ9thi999dAeBSPoB/ac7VYk=; b=H6nTDSWmw7y7EU6EfaOEXK2udaVnwUoEFJJZAOzdTQLOeXC0TQc1L2loC6iEI4SUuF oU6pkl+dLuyaYmVlR4lfW6Xz3dYUyHI3gurHCeCzhHKSKkDh2s+xtIKeR+kUVCe0ZHkn yHSRYq6TFeCM1jopRs3UYyHUQ0g4rSEiqSKbNtPejmuNdpyIayUm2uSYSLsl6KnTdBw9 QayZaLpmPLJbCYeZnWrvvkq7u8G7E7GIPbsOgQ9QSCoseOA609IYfZezETTqnIGjhJUS NUsN6OUw4N9OSRfuDmac9Hxhhm6a+xLDpboMlww/Zj6cLxjSqxtChn0hiScd+37v9myM miOQ== 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 i35si19509770plg.96.2017.05.25.04.40.35; Thu, 25 May 2017 04:40:35 -0700 (PDT) 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 S1764163AbdEYLkV (ORCPT + 25 others); Thu, 25 May 2017 07:40:21 -0400 Received: from szxga02-in.huawei.com ([45.249.212.188]:6826 "EHLO szxga02-in.huawei.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751644AbdEYLjJ (ORCPT ); Thu, 25 May 2017 07:39:09 -0400 Received: from 172.30.72.55 (EHLO DGGEML401-HUB.china.huawei.com) ([172.30.72.55]) by dggrg02-dlp.huawei.com (MOS 4.4.6-GA FastPath queued) with ESMTP id AOF02102; Thu, 25 May 2017 19:38:51 +0800 (CST) Received: from G00308965-DELL1.china.huawei.com (10.203.181.156) by DGGEML401-HUB.china.huawei.com (10.3.17.32) with Microsoft SMTP Server id 14.3.301.0; Thu, 25 May 2017 19:38:44 +0800 From: Gabriele Paoloni To: , , , , , , , , CC: , , , , , , , , , , , , "zhichang.yuan" Subject: [PATCH v9 3/7] OF: Add missing I/O range exception for indirect-IO devices Date: Thu, 25 May 2017 12:37:24 +0100 Message-ID: <1495712248-5232-4-git-send-email-gabriele.paoloni@huawei.com> X-Mailer: git-send-email 2.7.1.windows.1 In-Reply-To: <1495712248-5232-1-git-send-email-gabriele.paoloni@huawei.com> References: <1495712248-5232-1-git-send-email-gabriele.paoloni@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.203.181.156] X-CFilter-Loop: Reflected X-Mirapoint-Virus-RAPID-Raw: score=unknown(0), refid=str=0001.0A020201.5926C24B.01C5, ss=1, re=0.000, recu=0.000, reip=0.000, cl=1, cld=1, fgs=0, ip=0.0.0.0, so=2014-11-16 11:51:01, dmn=2013-03-21 17:37:32 X-Mirapoint-Loop-Id: fc9478f547b05418191d424e89600ee2 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 handlings for this case. During the OF address translation, some checkings will be perfromed 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 --- drivers/of/address.c | 90 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 74 insertions(+), 16 deletions(-) -- 2.7.4 diff --git a/drivers/of/address.c b/drivers/of/address.c index 34a55e8..c51de70 100644 --- a/drivers/of/address.c +++ b/drivers/of/address.c @@ -552,9 +552,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; @@ -567,6 +572,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) @@ -587,6 +593,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; @@ -599,6 +607,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 != PIO_CPU_MMIO)) { + result = of_read_number(addr + 1, na - 1); + pr_debug("indirectIO matched(%s) 0x%llx\n", + of_node_full_name(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); @@ -631,13 +652,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); @@ -679,29 +719,47 @@ 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 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); + 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); + 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;