From patchwork Wed Feb 20 09:48:40 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Thomas Petazzoni X-Patchwork-Id: 10821777 X-Patchwork-Delegate: bhelgaas@google.com Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C22CF139A for ; Wed, 20 Feb 2019 09:48:56 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A5AF12D963 for ; Wed, 20 Feb 2019 09:48:56 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 924E82DA1D; Wed, 20 Feb 2019 09:48:56 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id DBD452D963 for ; Wed, 20 Feb 2019 09:48:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726317AbfBTJsz (ORCPT ); Wed, 20 Feb 2019 04:48:55 -0500 Received: from relay10.mail.gandi.net ([217.70.178.230]:37275 "EHLO relay10.mail.gandi.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725816AbfBTJsz (ORCPT ); Wed, 20 Feb 2019 04:48:55 -0500 Received: from localhost (aaubervilliers-681-1-81-190.w90-88.abo.wanadoo.fr [90.88.23.190]) (Authenticated sender: thomas.petazzoni@bootlin.com) by relay10.mail.gandi.net (Postfix) with ESMTPSA id 7EB3724001A; Wed, 20 Feb 2019 09:48:49 +0000 (UTC) From: Thomas Petazzoni To: Bjorn Helgaas , Lorenzo Pieralisi , linux-pci@vger.kernel.org Cc: Russell King , linux-arm-kernel@lists.infradead.org, Jason Cooper , Andrew Lunn , Sebastian Hesselbarth , Gregory Clement , =?utf-8?q?Lu=C3=ADs_Mendes?= , Leigh Brown , Thomas Petazzoni Subject: [PATCH 1/2] PCI: pci-bridge-emul: Create per-bridge copy of register behavior Date: Wed, 20 Feb 2019 10:48:40 +0100 Message-Id: <20190220094841.11129-2-thomas.petazzoni@bootlin.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190220094841.11129-1-thomas.petazzoni@bootlin.com> References: <20190220094841.11129-1-thomas.petazzoni@bootlin.com> MIME-Version: 1.0 Sender: linux-pci-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The behavior of the different registers of the PCI-to-PCI bridge is currently encoded in two global arrays, shared by all instances of PCI-to-PCI bridge emulation. However, we will need to tweak the behavior on a per-bridge basis, to accommodate for different capabilities of the platforms where this code is used. In preparation for this, this commit creates a per-bridge copy of the register behavior arrays, so that they can later be tweaked on a per-bridge basis. Reported-by: Luís Mendes Reported-by: Leigh Brown Cc: Luís Mendes Cc: Leigh Brown Fixes: 1f08673eef123 ("PCI: mvebu: Convert to PCI emulated bridge config space") Signed-off-by: Thomas Petazzoni Tested-by: Luis Mendes --- drivers/pci/pci-bridge-emul.c | 80 +++++++++++++++++++++++------------ drivers/pci/pci-bridge-emul.h | 8 +++- 2 files changed, 60 insertions(+), 28 deletions(-) diff --git a/drivers/pci/pci-bridge-emul.c b/drivers/pci/pci-bridge-emul.c index 129738362d90..dd8d8060317e 100644 --- a/drivers/pci/pci-bridge-emul.c +++ b/drivers/pci/pci-bridge-emul.c @@ -24,29 +24,6 @@ #define PCI_CAP_PCIE_START PCI_BRIDGE_CONF_END #define PCI_CAP_PCIE_END (PCI_CAP_PCIE_START + PCI_EXP_SLTSTA2 + 2) -/* - * Initialize a pci_bridge_emul structure to represent a fake PCI - * bridge configuration space. The caller needs to have initialized - * the PCI configuration space with whatever values make sense - * (typically at least vendor, device, revision), the ->ops pointer, - * and optionally ->data and ->has_pcie. - */ -void pci_bridge_emul_init(struct pci_bridge_emul *bridge) -{ - bridge->conf.class_revision |= PCI_CLASS_BRIDGE_PCI << 16; - bridge->conf.header_type = PCI_HEADER_TYPE_BRIDGE; - bridge->conf.cache_line_size = 0x10; - bridge->conf.status = PCI_STATUS_CAP_LIST; - - if (bridge->has_pcie) { - bridge->conf.capabilities_pointer = PCI_CAP_PCIE_START; - bridge->pcie_conf.cap_id = PCI_CAP_ID_EXP; - /* Set PCIe v2, root port, slot support */ - bridge->pcie_conf.cap = PCI_EXP_TYPE_ROOT_PORT << 4 | 2 | - PCI_EXP_FLAGS_SLOT; - } -} - struct pci_bridge_reg_behavior { /* Read-only bits */ u32 ro; @@ -283,6 +260,55 @@ const static struct pci_bridge_reg_behavior pcie_cap_regs_behavior[] = { }, }; +/* + * Initialize a pci_bridge_emul structure to represent a fake PCI + * bridge configuration space. The caller needs to have initialized + * the PCI configuration space with whatever values make sense + * (typically at least vendor, device, revision), the ->ops pointer, + * and optionally ->data and ->has_pcie. + */ +int pci_bridge_emul_init(struct pci_bridge_emul *bridge) +{ + bridge->conf.class_revision |= PCI_CLASS_BRIDGE_PCI << 16; + bridge->conf.header_type = PCI_HEADER_TYPE_BRIDGE; + bridge->conf.cache_line_size = 0x10; + bridge->conf.status = PCI_STATUS_CAP_LIST; + bridge->pci_regs_behavior = kmemdup(pci_regs_behavior, + sizeof(pci_regs_behavior), + GFP_KERNEL); + if (!bridge->pci_regs_behavior) + return -ENOMEM; + + if (bridge->has_pcie) { + bridge->conf.capabilities_pointer = PCI_CAP_PCIE_START; + bridge->pcie_conf.cap_id = PCI_CAP_ID_EXP; + /* Set PCIe v2, root port, slot support */ + bridge->pcie_conf.cap = PCI_EXP_TYPE_ROOT_PORT << 4 | 2 | + PCI_EXP_FLAGS_SLOT; + bridge->pcie_cap_regs_behavior = + kmemdup(pcie_cap_regs_behavior, + sizeof(pcie_cap_regs_behavior), + GFP_KERNEL); + if (!bridge->pcie_cap_regs_behavior) { + kfree(bridge->pci_regs_behavior); + return -ENOMEM; + } + } + + return 0; +} + +/* + * Cleanup a pci_bridge_emul structure that was previously initilized + * using pci_bridge_emul_init(). + */ +void pci_bridge_emul_cleanup(struct pci_bridge_emul *bridge) +{ + if (bridge->has_pcie) + kfree(bridge->pcie_cap_regs_behavior); + kfree(bridge->pci_regs_behavior); +} + /* * Should be called by the PCI controller driver when reading the PCI * configuration space of the fake bridge. It will call back the @@ -312,11 +338,11 @@ int pci_bridge_emul_conf_read(struct pci_bridge_emul *bridge, int where, reg -= PCI_CAP_PCIE_START; read_op = bridge->ops->read_pcie; cfgspace = (u32 *) &bridge->pcie_conf; - behavior = pcie_cap_regs_behavior; + behavior = bridge->pcie_cap_regs_behavior; } else { read_op = bridge->ops->read_base; cfgspace = (u32 *) &bridge->conf; - behavior = pci_regs_behavior; + behavior = bridge->pci_regs_behavior; } if (read_op) @@ -383,11 +409,11 @@ int pci_bridge_emul_conf_write(struct pci_bridge_emul *bridge, int where, reg -= PCI_CAP_PCIE_START; write_op = bridge->ops->write_pcie; cfgspace = (u32 *) &bridge->pcie_conf; - behavior = pcie_cap_regs_behavior; + behavior = bridge->pcie_cap_regs_behavior; } else { write_op = bridge->ops->write_base; cfgspace = (u32 *) &bridge->conf; - behavior = pci_regs_behavior; + behavior = bridge->pci_regs_behavior; } /* Keep all bits, except the RW bits */ diff --git a/drivers/pci/pci-bridge-emul.h b/drivers/pci/pci-bridge-emul.h index 9d510ccf738b..f04637bb3222 100644 --- a/drivers/pci/pci-bridge-emul.h +++ b/drivers/pci/pci-bridge-emul.h @@ -107,15 +107,21 @@ struct pci_bridge_emul_ops { u32 old, u32 new, u32 mask); }; +struct pci_bridge_reg_behavior; + struct pci_bridge_emul { struct pci_bridge_emul_conf conf; struct pci_bridge_emul_pcie_conf pcie_conf; struct pci_bridge_emul_ops *ops; + struct pci_bridge_reg_behavior *pci_regs_behavior; + struct pci_bridge_reg_behavior *pcie_cap_regs_behavior; void *data; bool has_pcie; }; -void pci_bridge_emul_init(struct pci_bridge_emul *bridge); +int pci_bridge_emul_init(struct pci_bridge_emul *bridge); +void pci_bridge_emul_cleanup(struct pci_bridge_emul *bridge); + int pci_bridge_emul_conf_read(struct pci_bridge_emul *bridge, int where, int size, u32 *value); int pci_bridge_emul_conf_write(struct pci_bridge_emul *bridge, int where, From patchwork Wed Feb 20 09:48:41 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Thomas Petazzoni X-Patchwork-Id: 10821787 X-Patchwork-Delegate: bhelgaas@google.com Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 5E22B1805 for ; Wed, 20 Feb 2019 10:00:50 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 468D32DA77 for ; Wed, 20 Feb 2019 10:00:50 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 3A1ED2DD36; Wed, 20 Feb 2019 10:00:50 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B0C9B2DD33 for ; Wed, 20 Feb 2019 10:00:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727139AbfBTKAs (ORCPT ); Wed, 20 Feb 2019 05:00:48 -0500 Received: from mslow2.mail.gandi.net ([217.70.178.242]:36166 "EHLO mslow2.mail.gandi.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726428AbfBTKAs (ORCPT ); Wed, 20 Feb 2019 05:00:48 -0500 Received: from relay12.mail.gandi.net (unknown [217.70.178.232]) by mslow2.mail.gandi.net (Postfix) with ESMTP id 1D7D83A71DA for ; Wed, 20 Feb 2019 09:48:56 +0000 (UTC) Received: from localhost (aaubervilliers-681-1-81-190.w90-88.abo.wanadoo.fr [90.88.23.190]) (Authenticated sender: thomas.petazzoni@bootlin.com) by relay12.mail.gandi.net (Postfix) with ESMTPSA id 77F8B200012; Wed, 20 Feb 2019 09:48:53 +0000 (UTC) From: Thomas Petazzoni To: Bjorn Helgaas , Lorenzo Pieralisi , linux-pci@vger.kernel.org Cc: Russell King , linux-arm-kernel@lists.infradead.org, Jason Cooper , Andrew Lunn , Sebastian Hesselbarth , Gregory Clement , =?utf-8?q?Lu=C3=ADs_Mendes?= , Leigh Brown , Thomas Petazzoni Subject: [PATCH 2/2] PCI: pci-bridge-emul: Extend pci_bridge_emul_init() with flags Date: Wed, 20 Feb 2019 10:48:41 +0100 Message-Id: <20190220094841.11129-3-thomas.petazzoni@bootlin.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190220094841.11129-1-thomas.petazzoni@bootlin.com> References: <20190220094841.11129-1-thomas.petazzoni@bootlin.com> MIME-Version: 1.0 Sender: linux-pci-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Depending on the capabilities of the PCI controller/platform, the PCI-to-PCI bridge emulation behavior might need to be different. For example, on platforms that use the pci-mvebu code, we currently don't support prefetchable memory BARs, so the corresponding fields in the PCI-to-PCI bridge configuration space should be read-only. To implement this, this commit extends pci_bridge_emul_init() to take a "flags" argument, with currently one flag supported: PCI_BRIDGE_EMUL_NO_PREFETCHABLE_BAR, that will make the prefetchable memory base and limit registers read-only. The pci-mvebu and pci-aardvark drivers are updated accordingly. Reported-by: Luís Mendes Reported-by: Leigh Brown Cc: Luís Mendes Cc: Leigh Brown Fixes: 1f08673eef123 ("PCI: mvebu: Convert to PCI emulated bridge config space") Signed-off-by: Thomas Petazzoni Tested-by: Luis Mendes --- drivers/pci/controller/pci-aardvark.c | 2 +- drivers/pci/controller/pci-mvebu.c | 2 +- drivers/pci/pci-bridge-emul.c | 8 +++++++- drivers/pci/pci-bridge-emul.h | 7 ++++++- 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/drivers/pci/controller/pci-aardvark.c b/drivers/pci/controller/pci-aardvark.c index 750081c1cb48..6eecae447af3 100644 --- a/drivers/pci/controller/pci-aardvark.c +++ b/drivers/pci/controller/pci-aardvark.c @@ -499,7 +499,7 @@ static void advk_sw_pci_bridge_init(struct advk_pcie *pcie) bridge->data = pcie; bridge->ops = &advk_pci_bridge_emul_ops; - pci_bridge_emul_init(bridge); + pci_bridge_emul_init(bridge, 0); } diff --git a/drivers/pci/controller/pci-mvebu.c b/drivers/pci/controller/pci-mvebu.c index fa0fc46edb0c..d3a0419e42f2 100644 --- a/drivers/pci/controller/pci-mvebu.c +++ b/drivers/pci/controller/pci-mvebu.c @@ -583,7 +583,7 @@ static void mvebu_pci_bridge_emul_init(struct mvebu_pcie_port *port) bridge->data = port; bridge->ops = &mvebu_pci_bridge_emul_ops; - pci_bridge_emul_init(bridge); + pci_bridge_emul_init(bridge, PCI_BRIDGE_EMUL_NO_PREFETCHABLE_BAR); } static inline struct mvebu_pcie *sys_to_pcie(struct pci_sys_data *sys) diff --git a/drivers/pci/pci-bridge-emul.c b/drivers/pci/pci-bridge-emul.c index dd8d8060317e..83fb077d0b41 100644 --- a/drivers/pci/pci-bridge-emul.c +++ b/drivers/pci/pci-bridge-emul.c @@ -267,7 +267,8 @@ const static struct pci_bridge_reg_behavior pcie_cap_regs_behavior[] = { * (typically at least vendor, device, revision), the ->ops pointer, * and optionally ->data and ->has_pcie. */ -int pci_bridge_emul_init(struct pci_bridge_emul *bridge) +int pci_bridge_emul_init(struct pci_bridge_emul *bridge, + unsigned int flags) { bridge->conf.class_revision |= PCI_CLASS_BRIDGE_PCI << 16; bridge->conf.header_type = PCI_HEADER_TYPE_BRIDGE; @@ -295,6 +296,11 @@ int pci_bridge_emul_init(struct pci_bridge_emul *bridge) } } + if (flags & PCI_BRIDGE_EMUL_NO_PREFETCHABLE_BAR) { + bridge->pci_regs_behavior[PCI_PREF_MEMORY_BASE / 4].ro = ~0; + bridge->pci_regs_behavior[PCI_PREF_MEMORY_BASE / 4].rw = 0; + } + return 0; } diff --git a/drivers/pci/pci-bridge-emul.h b/drivers/pci/pci-bridge-emul.h index f04637bb3222..e65b1b79899d 100644 --- a/drivers/pci/pci-bridge-emul.h +++ b/drivers/pci/pci-bridge-emul.h @@ -119,7 +119,12 @@ struct pci_bridge_emul { bool has_pcie; }; -int pci_bridge_emul_init(struct pci_bridge_emul *bridge); +enum { + PCI_BRIDGE_EMUL_NO_PREFETCHABLE_BAR = BIT(0), +}; + +int pci_bridge_emul_init(struct pci_bridge_emul *bridge, + unsigned int flags); void pci_bridge_emul_cleanup(struct pci_bridge_emul *bridge); int pci_bridge_emul_conf_read(struct pci_bridge_emul *bridge, int where,