From patchwork Mon Nov 10 12:26:08 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lorenzo Pieralisi X-Patchwork-Id: 40483 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-wi0-f199.google.com (mail-wi0-f199.google.com [209.85.212.199]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 47E08203C0 for ; Mon, 10 Nov 2014 12:26:23 +0000 (UTC) Received: by mail-wi0-f199.google.com with SMTP id r20sf4003745wiv.2 for ; Mon, 10 Nov 2014 04:26:22 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:delivered-to:from:to:cc:subject :date:message-id:sender:precedence:list-id:x-original-sender :x-original-authentication-results:mailing-list:list-post:list-help :list-archive:list-unsubscribe; bh=X2yG5xzfGa+Tr4ax9ni7XfYtojLVo4sIjbN+nHiTXqw=; b=gQEDTt/OaiDTVayMxqr4Q8zVcBcNXm24COeagovFgsKtUdzyiyWfh6Gv/XXC/3RI3K EUP/E5+aiPxQW95t08o0ld2OQ662ePWZRZ4I+3epdoEDY5+iaGJiVbGpbV4nfz2gosfr uQqT0vNpurLvG9UB+ABwcO5zSghdeUSSx/hMLoDU2lMtEjKt3tvchQCz3SFFPqXlzBeI AFI3tdA3p/ObPSRAsGJUQ5/iLXWnEzLCkZK8DWhVakpkKqhB92GBM0lfqosnIgZM4j5W e43pNEhf0sOHcZlmq5vmAtfI1qZKbblGZrAX+/SSmEwF3LNFn1W0znE5/2/MKUEIXyrK RbTg== X-Gm-Message-State: ALoCoQkjrUACqxCohq/mjuLPsXfhhahptEUvkfXbuegihQ+2I9NLiEYp5wEBlPnanC76kHTTIZ9x X-Received: by 10.180.221.7 with SMTP id qa7mr3984355wic.6.1415622382341; Mon, 10 Nov 2014 04:26:22 -0800 (PST) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.152.36.169 with SMTP id r9ls348926laj.57.gmail; Mon, 10 Nov 2014 04:26:21 -0800 (PST) X-Received: by 10.112.140.135 with SMTP id rg7mr1744770lbb.100.1415622381852; Mon, 10 Nov 2014 04:26:21 -0800 (PST) Received: from mail-la0-f41.google.com (mail-la0-f41.google.com. [209.85.215.41]) by mx.google.com with ESMTPS id aq3si26865101lbc.78.2014.11.10.04.26.21 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Mon, 10 Nov 2014 04:26:21 -0800 (PST) Received-SPF: pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.215.41 as permitted sender) client-ip=209.85.215.41; Received: by mail-la0-f41.google.com with SMTP id s18so7687487lam.28 for ; Mon, 10 Nov 2014 04:26:21 -0800 (PST) X-Received: by 10.152.5.38 with SMTP id p6mr28872995lap.44.1415622381682; Mon, 10 Nov 2014 04:26:21 -0800 (PST) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patch@linaro.org Received: by 10.112.184.201 with SMTP id ew9csp78325lbc; Mon, 10 Nov 2014 04:26:20 -0800 (PST) X-Received: by 10.70.91.71 with SMTP id cc7mr1497926pdb.79.1415622380065; Mon, 10 Nov 2014 04:26:20 -0800 (PST) Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id sk4si16332103pab.163.2014.11.10.04.26.19 for ; Mon, 10 Nov 2014 04:26:20 -0800 (PST) Received-SPF: none (google.com: devicetree-owner@vger.kernel.org does not designate permitted sender hosts) client-ip=209.132.180.67; Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752504AbaKJM0S (ORCPT + 4 others); Mon, 10 Nov 2014 07:26:18 -0500 Received: from foss-mx-na.foss.arm.com ([217.140.108.86]:55448 "EHLO foss-mx-na.foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751926AbaKJM0R (ORCPT ); Mon, 10 Nov 2014 07:26:17 -0500 Received: from foss-smtp-na-1.foss.arm.com (unknown [10.80.61.8]) by foss-mx-na.foss.arm.com (Postfix) with ESMTP id 0864D66; Mon, 10 Nov 2014 06:26:08 -0600 (CST) Received: from collaborate-mta1.arm.com (highbank-bc01-b06.austin.arm.com [10.112.81.134]) by foss-smtp-na-1.foss.arm.com (Postfix) with ESMTP id AA8CB5FAD7; Mon, 10 Nov 2014 06:26:05 -0600 (CST) Received: from red-moon.cambridge.arm.com (red-moon.cambridge.arm.com [10.1.203.137]) by collaborate-mta1.arm.com (Postfix) with ESMTP id 35AC213F6EE; Mon, 10 Nov 2014 06:26:04 -0600 (CST) From: Lorenzo Pieralisi To: linux-arm-kernel@lists.infradead.org, linux-pci@vger.kernel.org, devicetree@vger.kernel.org Cc: Lorenzo Pieralisi , Arnd Bergmann , Liviu Dudau , Bjorn Helgaas , Rob Herring , Catalin Marinas Subject: [RFC PATCH] drivers: of: move PCI domain assignment to generic OF code Date: Mon, 10 Nov 2014 12:26:08 +0000 Message-Id: <1415622368-14612-1-git-send-email-lorenzo.pieralisi@arm.com> X-Mailer: git-send-email 2.1.2 Sender: devicetree-owner@vger.kernel.org Precedence: list List-ID: X-Mailing-List: devicetree@vger.kernel.org X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: lorenzo.pieralisi@arm.com X-Original-Authentication-Results: mx.google.com; spf=pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.215.41 as permitted sender) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , The current logic used for PCI domain assignment in arm64 pci_bus_assign_domain_nr() is flawed in that, depending on the host controllers configuration for a platform and the respective initialization sequence, core code may end up allocating PCI domain numbers from both DT and the core code generic domain counter, which would result in PCI domain allocation aliases/errors. This patch fixes the logic behind the PCI domain number assignment and move the resulting code to the generic OF layer so that other archs can reuse the same domain allocation logic instead of resorting to an arch specific implementation that might end up duplicating the PCI domain assignment logic wrongly. If OF is not configured for a platform, the code falls back to the generic domain numbering implementation through the pci_get_new_domain_nr() API. Cc: Arnd Bergmann Cc: Liviu Dudau Cc: Bjorn Helgaas Cc: Rob Herring Cc: Catalin Marinas Signed-off-by: Lorenzo Pieralisi --- arch/arm64/kernel/pci.c | 14 +++-------- drivers/of/of_pci.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++-- include/linux/of_pci.h | 7 +++--- 3 files changed, 71 insertions(+), 16 deletions(-) diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c index ce5836c..5e21c1c 100644 --- a/arch/arm64/kernel/pci.c +++ b/arch/arm64/kernel/pci.c @@ -49,20 +49,14 @@ int pcibios_add_device(struct pci_dev *dev) #ifdef CONFIG_PCI_DOMAINS_GENERIC -static bool dt_domain_found = false; void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent) { - int domain = of_get_pci_domain_nr(parent->of_node); + int domain = of_assign_pci_domain_nr(parent->of_node); - if (domain >= 0) { - dt_domain_found = true; - } else if (dt_domain_found == true) { - dev_err(parent, "Node %s is missing \"linux,pci-domain\" property in DT\n", - parent->of_node->full_name); - return; - } else { - domain = pci_get_new_domain_nr(); + if (domain < 0) { + dev_err(parent, "PCI domain assignment failed\n"); + domain = -1; } bus->domain_nr = domain; diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c index 8882b46..43bf591 100644 --- a/drivers/of/of_pci.c +++ b/drivers/of/of_pci.c @@ -100,7 +100,7 @@ EXPORT_SYMBOL_GPL(of_pci_parse_bus_range); * Returns the associated domain number from DT in the range [0-0xffff], or * a negative value if the required property is not found. */ -int of_get_pci_domain_nr(struct device_node *node) +static int of_get_pci_domain_nr(struct device_node *node) { const __be32 *value; int len; @@ -114,7 +114,69 @@ int of_get_pci_domain_nr(struct device_node *node) return domain; } -EXPORT_SYMBOL_GPL(of_get_pci_domain_nr); + +/** + * of_assign_pci_domain_nr() - Assign a PCI domain number + * + * @node: device tree node with the domain information + * + * This function assigns and returns the host bridge domain number by + * first parsing the device tree node to find the linux,pci-domain + * property and falling back to the generic domain number API if DT + * property is not present/valid. The function implements logic that prevents + * code from mixing domain numbers assignments from both DT and the + * generic domain number implementation and returns an error if such + * cases are detected at run-time. + * + * Returns the assigned domain number, or a negative value to signal an error + */ +int of_assign_pci_domain_nr(struct device_node *node) +{ + static int use_dt_domains = -1; + int domain = of_get_pci_domain_nr(node); + + /* + * Check DT domain and use_dt_domains values. + * + * If DT domain property is valid (domain >= 0) and + * use_dt_domains != 0, the DT assignment is valid since this means + * we have not previously allocated a domain number by using + * pci_get_new_domain_nr(). + * + * If use_dt_domains value is == 0 and the DT property provides a + * valid domain number (>=0), this means that we are assigning a + * domain number from DT but we have previously allocated a domain + * number by using pci_get_new_domain_nr() so we should bail out with + * an error. + * + * If DT domain property value is not valid, and we have not previously + * assigned a domain number from DT (use_dt_domains != 1) we + * should assign a domain number by using the + * + * pci_get_new_domain_nr() + * + * API and update the use_dt_domains value to keep track of method we + * are using to assign domain numbers (use_dt_domains = 0). + * + * All other combinations imply we have a platform that is trying + * to mix DT and generic domain number assignments, which is a recipe + * for domain mishandling and it is prevented by returning an error + * value to the caller. + */ + if (domain >= 0 && use_dt_domains) { + use_dt_domains = 1; + } else if (domain < 0 && use_dt_domains != 1) { + use_dt_domains = 0; + domain = pci_get_new_domain_nr(); + } else { + pr_err("Node %s has inconsistent \"linux,pci-domain\" property in DT\n", + node->full_name); + return -EINVAL; + } + + return domain; +} +EXPORT_SYMBOL_GPL(of_assign_pci_domain_nr); #if defined(CONFIG_OF_ADDRESS) /** diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h index 1fd207e..fbba966 100644 --- a/include/linux/of_pci.h +++ b/include/linux/of_pci.h @@ -15,7 +15,7 @@ struct device_node *of_pci_find_child_device(struct device_node *parent, int of_pci_get_devfn(struct device_node *np); int of_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 pin); int of_pci_parse_bus_range(struct device_node *node, struct resource *res); -int of_get_pci_domain_nr(struct device_node *node); +int of_assign_pci_domain_nr(struct device_node *node); #else static inline int of_irq_parse_pci(const struct pci_dev *pdev, struct of_phandle_args *out_irq) { @@ -45,10 +45,9 @@ of_pci_parse_bus_range(struct device_node *node, struct resource *res) return -EINVAL; } -static inline int -of_get_pci_domain_nr(struct device_node *node) +static inline int of_assign_pci_domain_nr(struct device_node *node) { - return -1; + return pci_get_new_domain_nr(); } #endif