From patchwork Fri Oct 27 16:11:23 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gabriele Paoloni X-Patchwork-Id: 117365 Delivered-To: patch@linaro.org Received: by 10.140.22.164 with SMTP id 33csp947920qgn; Fri, 27 Oct 2017 09:14:49 -0700 (PDT) X-Google-Smtp-Source: ABhQp+TGmzHq/eAt2NiUtlK1MwT5PcLV/PdZ1hKgWAtjwJ6fCre/BV8IjSt8NKoMTvQ9T2j7PpQ5 X-Received: by 10.99.3.21 with SMTP id 21mr684824pgd.77.1509120889151; Fri, 27 Oct 2017 09:14:49 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1509120889; cv=none; d=google.com; s=arc-20160816; b=l/aHExF1X3ZhT7pmcF1kjhpX6OzgyHADtB1eGVdxYNY+5bF9nW1akYhNiexpBRDumH OPP28Ntspvw/V8JQAkHghUL7/FI+rFd1LZBg8yi6tPT5vkqTr5g7RxbRmxaiI97Grj8b ji2nkrrI3JGvI5jZPPrawyO6L8SE77PByOaGHnWjnhjBiqW4l5Iwqr5QK3gCtPjrwpGY 625WvzG7Mop1j0/UwJC913e9+gG7XipRqI2DREYsgtFOxq4bWZCRF0GMH9gX6Y3XQ6PF nmFOgyspx9GBXR2Wj3PSz6bpoZlESIJsYSt80DfKWwD8eHXZpruIR5Fz7U2sJdv7oz4l 0RYw== 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=XgN4sff3weY1OPp9FA5XUX3t+02iEjlfJYe5Mp/xn6E=; b=Pl2MsoNrir7JP1+3BinysxTWbvWkYPMgskBYgsbMcMu83xSZR6wiBouqvkrTEzTms2 861CJMHGk6RnZdnG7mKccU5txa6M6+fOFDqXrDchuhBo3B+lCi3rVJ/y6YnY4cATEJdl 5okKrnf80bvPAuauyIQiTecVx5CCOBQYe8/qsNFTwWTBfMr9rk0vowvOz+yJbSmJFcdM 1kTopgrC6nXDEEiZ0ZvQO4uJtFWxh1M7M7mbJH0ASF/mBRmHrazD0PWFvgBYzdSQA1dH TcOuLmnkS+kHeivqHQ77xTPyuw0CUQueKRJgYLJvv8lVHp+x144yNZExf4HmOrEpvqNt zZag== 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 14si4581727ple.239.2017.10.27.09.14.48; Fri, 27 Oct 2017 09:14:49 -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 S1752624AbdJ0QOs (ORCPT + 27 others); Fri, 27 Oct 2017 12:14:48 -0400 Received: from szxga04-in.huawei.com ([45.249.212.190]:9448 "EHLO szxga04-in.huawei.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752530AbdJ0QOp (ORCPT ); Fri, 27 Oct 2017 12:14:45 -0400 Received: from 172.30.72.58 (EHLO DGGEMS414-HUB.china.huawei.com) ([172.30.72.58]) by dggrg04-dlp.huawei.com (MOS 4.4.6-GA FastPath queued) with ESMTP id DJX16565; Sat, 28 Oct 2017 00:14:39 +0800 (CST) Received: from G00308965-DELL1.china.huawei.com (10.202.226.113) by DGGEMS414-HUB.china.huawei.com (10.3.19.214) with Microsoft SMTP Server id 14.3.361.1; Sat, 28 Oct 2017 00:12:48 +0800 From: Gabriele Paoloni To: , , , , , , , , CC: , , , , , , , , , , , , "zhichang.yuan" Subject: [PATCH v10 5/9] OF: Add missing I/O range exception for indirect-IO devices Date: Fri, 27 Oct 2017 17:11:23 +0100 Message-ID: <1509120687-7352-6-git-send-email-gabriele.paoloni@huawei.com> X-Mailer: git-send-email 2.7.1.windows.1 In-Reply-To: <1509120687-7352-1-git-send-email-gabriele.paoloni@huawei.com> References: <1509120687-7352-1-git-send-email-gabriele.paoloni@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.202.226.113] X-CFilter-Loop: Reflected X-Mirapoint-Virus-RAPID-Raw: score=unknown(0), refid=str=0001.0A020203.59F35B6F.0144, 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: d3057f1d5ea9f59b20f45be4aa1c4bdb 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 | 91 +++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 75 insertions(+), 16 deletions(-) -- 2.7.4 diff --git a/drivers/of/address.c b/drivers/of/address.c index 9d3ba07..323ee56 100644 --- a/drivers/of/address.c +++ b/drivers/of/address.c @@ -551,9 +551,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; @@ -566,6 +571,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) @@ -586,6 +592,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; @@ -598,6 +606,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); @@ -630,13 +651,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); @@ -678,29 +718,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;