From: Bjorn Helgaas <helgaas@kernel.org> To: Thomas Petazzoni <thomas.petazzoni@bootlin.com> Cc: "Lorenzo Pieralisi" <lorenzo.pieralisi@arm.com>, "Russell King" <linux@arm.linux.org.uk>, "Simon Horman" <horms@verge.net.au>, "Antoine Tenart" <antoine.tenart@bootlin.com>, linux-pci@vger.kernel.org, "Gregory Clement" <gregory.clement@bootlin.com>, "Maxime Chevallier" <maxime.chevallier@bootlin.com>, "Nadav Haklai" <nadavh@marvell.com>, "Victor Gu" <xigu@marvell.com>, "Ray Jui" <ray.jui@broadcom.com>, "Miquèl Raynal" <miquel.raynal@bootlin.com>, "Bjorn Helgaas" <bhelgaas@google.com>, "Ley Foon Tan" <lftan@altera.com>, "Zachary Zhang" <zhangzg@marvell.com>, "Wilson Ding" <dingwei@marvell.com>, linux-arm-kernel@lists.infradead.org Subject: Re: [PATCH 1/3] PCI: Introduce PCI software bridge common logic Date: Thu, 12 Jul 2018 14:58:02 -0500 [thread overview] Message-ID: <20180712195802.GC28466@bhelgaas-glaptop.roam.corp.google.com> (raw) In-Reply-To: <20180629092231.32207-2-thomas.petazzoni@bootlin.com> [+cc Ray since he's doing something similar for iProc, Ley Foon & Simon for a possible Altera & R-Car bug] On Fri, Jun 29, 2018 at 11:22:29AM +0200, Thomas Petazzoni wrote: > Some PCI host controllers do not expose at the hardware level a root > port PCI bridge. Due to this, the Marvell Armada 370/38x/XP PCI > controller driver (pci-mvebu) emulates a root port PCI bridge, and > uses that to (among other things=E0) dynamically create the memory > windows that correspond to the PCI MEM and I/O regions. > = > Since we now need to add a very similar logic for the Marvell Armada > 37xx PCI controller driver (pci-aardvark), instead of duplicating the > code, we create in this commit a common logic called pci-sw-bridge. > = > The idea of this logic is to emulate a root port PCI bridge by > providing configuration space read/write operations, and faking behind > the scenes the configuration space of a PCI bridge. A PCI host > controller driver simply has to call pci_sw_bridge_read() and > pci_sw_bridge_write() to read/write the configuration space of the > bridge. These systems must actually have a Root Port (there's obviously a Port that originates the link), but it's not visible in a spec-compliant way. So this is basically a wrapper that translates accesses to standard config space into the vendor-specific registers. Since there really *is* a hardware bridge but it just doesn't have the interface we expect, "sw_bridge" doesn't feel like quite the right name for it. Maybe something related to adapter/emulation/interface/...? There are several drivers that do this, and it would be really cool to have them all do it in a similar way. I found at least these: hv_pcifront_read_config() mvebu_pcie_rd_conf() thunder_ecam_config_read() thunder_pem_config_read() xgene_pcie_config_read32() iproc_pcie_config_read32() rcar_pcie_read_conf() I *really* like the fact that your accessors use the normal register names, e.g., PCI_EXP_DEVCAP instead of PCISWCAP_EXP_DEVCAP. That's huge for greppability. > By default, the PCI bridge configuration space is simply emulated by a > chunk of memory, but the PCI host controller can override the behavior > of the read and write operations on a per-register basis to do > additional actions if needed. > = > Signed-off-by: Thomas Petazzoni <thomas.petazzoni@bootlin.com> > --- > drivers/pci/Kconfig | 3 + > drivers/pci/Makefile | 1 + > drivers/pci/pci-sw-bridge.c | 149 ++++++++++++++++++++++++++++++++++++= ++++++ > include/linux/pci-sw-bridge.h | 125 +++++++++++++++++++++++++++++++++++ Could this go in drivers/pci instead of include/linux? I'd prefer to hide it inside the PCI core if that's possible. > + * Should be called by the PCI controller driver when reading the PCI > + * configuration space of the fake bridge. It will call back the > + * ->ops->read_base or ->ops->read_pcie operations. > + */ > +int pci_sw_bridge_read(struct pci_sw_bridge *bridge, int where, > + int size, u32 *value) We don't really have a strong convention about the names of config accessors: *_rd_conf(), *_read_config(), *config_read() are all used. Maybe we could at least include "conf" to connect this with config space as opposed to MMIO space. > +{ > + int ret; > + int reg =3D where & ~3; > + > + if (bridge->has_pcie && reg >=3D PCI_CAP_PCIE_END) { > + *value =3D 0; > + return PCIBIOS_SUCCESSFUL; > + } > + > + if (!bridge->has_pcie && reg >=3D PCI_BRIDGE_CONF_END) { > + *value =3D 0; > + return PCIBIOS_SUCCESSFUL; > + } > + > + if (bridge->has_pcie && reg >=3D PCI_CAP_PCIE_START) { > + reg -=3D PCI_CAP_PCIE_START; > + > + if (bridge->ops->read_pcie) > + ret =3D bridge->ops->read_pcie(bridge, reg, value); > + else > + ret =3D PCI_SW_BRIDGE_NOT_HANDLED; > + > + if (ret =3D=3D PCI_SW_BRIDGE_NOT_HANDLED) > + *value =3D *((u32*) &bridge->pcie_conf + reg / 4); > + } else { > + if (bridge->ops->read_base) > + ret =3D bridge->ops->read_base(bridge, reg, value); > + else > + ret =3D PCI_SW_BRIDGE_NOT_HANDLED; > + > + if (ret =3D=3D PCI_SW_BRIDGE_NOT_HANDLED) > + *value =3D *((u32*) &bridge->conf + reg / 4); I'm not sure about this part, where the config space that's not handled by the bridge's ops ends up just being RAM that's readable and writable with no effect on the hardware. That seems a little counter-intuitive. I think dropping writes and reading zeroes would simplify my mental model. > + } > + > + if (size =3D=3D 1) > + *value =3D (*value >> (8 * (where & 3))) & 0xff; > + else if (size =3D=3D 2) > + *value =3D (*value >> (8 * (where & 3))) & 0xffff; > + else if (size !=3D 4) > + return PCIBIOS_BAD_REGISTER_NUMBER; This isn't directly related to your patches, but this is a common pattern with some variations between drivers, which makes me wonder whether there are bugs lurking. These use "where & 3" for size 2: advk_pcie_rd_conf() mtk_pcie_hw_rd_cfg() pci_generic_config_read32() But these use "where & 2": _altera_pcie_cfg_read() rcar_pcie_read_conf() I *think* this means that unaligned 2-byte config reads on Altera and R-Car will return incorrect data. In both cases, the actual read seen by the hardware is a 32-bit read, but I think we extract the wrong 16 bits from that result. I wonder if there's a way to use a common helper function to do this. > + return PCIBIOS_SUCCESSFUL; > +} > + /* > + * Called when writing to the regular PCI bridge configuration > + * space. old is the current value, new is the new value being > + * written, and mask indicates which parts of the value are > + * being changed. > + */ > + void (*write_base)(struct pci_sw_bridge *bridge, int reg, > + u32 old, u32 new, u32 mask); > + > + /* > + * Same as ->read_base(), except it is for reading from the > + * PCIe capability configuration space. I think you mean "->write_base(), except it is for writing to" > + */ > + void (*write_pcie)(struct pci_sw_bridge *bridge, int reg, > + u32 old, u32 new, u32 mask); > +}; _______________________________________________ linux-arm-kernel mailing list linux-arm-kernel@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
WARNING: multiple messages have this Message-ID (diff)
From: helgaas@kernel.org (Bjorn Helgaas) To: linux-arm-kernel@lists.infradead.org Subject: [PATCH 1/3] PCI: Introduce PCI software bridge common logic Date: Thu, 12 Jul 2018 14:58:02 -0500 [thread overview] Message-ID: <20180712195802.GC28466@bhelgaas-glaptop.roam.corp.google.com> (raw) In-Reply-To: <20180629092231.32207-2-thomas.petazzoni@bootlin.com> [+cc Ray since he's doing something similar for iProc, Ley Foon & Simon for a possible Altera & R-Car bug] On Fri, Jun 29, 2018 at 11:22:29AM +0200, Thomas Petazzoni wrote: > Some PCI host controllers do not expose at the hardware level a root > port PCI bridge. Due to this, the Marvell Armada 370/38x/XP PCI > controller driver (pci-mvebu) emulates a root port PCI bridge, and > uses that to (among other things?) dynamically create the memory > windows that correspond to the PCI MEM and I/O regions. > > Since we now need to add a very similar logic for the Marvell Armada > 37xx PCI controller driver (pci-aardvark), instead of duplicating the > code, we create in this commit a common logic called pci-sw-bridge. > > The idea of this logic is to emulate a root port PCI bridge by > providing configuration space read/write operations, and faking behind > the scenes the configuration space of a PCI bridge. A PCI host > controller driver simply has to call pci_sw_bridge_read() and > pci_sw_bridge_write() to read/write the configuration space of the > bridge. These systems must actually have a Root Port (there's obviously a Port that originates the link), but it's not visible in a spec-compliant way. So this is basically a wrapper that translates accesses to standard config space into the vendor-specific registers. Since there really *is* a hardware bridge but it just doesn't have the interface we expect, "sw_bridge" doesn't feel like quite the right name for it. Maybe something related to adapter/emulation/interface/...? There are several drivers that do this, and it would be really cool to have them all do it in a similar way. I found at least these: hv_pcifront_read_config() mvebu_pcie_rd_conf() thunder_ecam_config_read() thunder_pem_config_read() xgene_pcie_config_read32() iproc_pcie_config_read32() rcar_pcie_read_conf() I *really* like the fact that your accessors use the normal register names, e.g., PCI_EXP_DEVCAP instead of PCISWCAP_EXP_DEVCAP. That's huge for greppability. > By default, the PCI bridge configuration space is simply emulated by a > chunk of memory, but the PCI host controller can override the behavior > of the read and write operations on a per-register basis to do > additional actions if needed. > > Signed-off-by: Thomas Petazzoni <thomas.petazzoni@bootlin.com> > --- > drivers/pci/Kconfig | 3 + > drivers/pci/Makefile | 1 + > drivers/pci/pci-sw-bridge.c | 149 ++++++++++++++++++++++++++++++++++++++++++ > include/linux/pci-sw-bridge.h | 125 +++++++++++++++++++++++++++++++++++ Could this go in drivers/pci instead of include/linux? I'd prefer to hide it inside the PCI core if that's possible. > + * Should be called by the PCI controller driver when reading the PCI > + * configuration space of the fake bridge. It will call back the > + * ->ops->read_base or ->ops->read_pcie operations. > + */ > +int pci_sw_bridge_read(struct pci_sw_bridge *bridge, int where, > + int size, u32 *value) We don't really have a strong convention about the names of config accessors: *_rd_conf(), *_read_config(), *config_read() are all used. Maybe we could at least include "conf" to connect this with config space as opposed to MMIO space. > +{ > + int ret; > + int reg = where & ~3; > + > + if (bridge->has_pcie && reg >= PCI_CAP_PCIE_END) { > + *value = 0; > + return PCIBIOS_SUCCESSFUL; > + } > + > + if (!bridge->has_pcie && reg >= PCI_BRIDGE_CONF_END) { > + *value = 0; > + return PCIBIOS_SUCCESSFUL; > + } > + > + if (bridge->has_pcie && reg >= PCI_CAP_PCIE_START) { > + reg -= PCI_CAP_PCIE_START; > + > + if (bridge->ops->read_pcie) > + ret = bridge->ops->read_pcie(bridge, reg, value); > + else > + ret = PCI_SW_BRIDGE_NOT_HANDLED; > + > + if (ret == PCI_SW_BRIDGE_NOT_HANDLED) > + *value = *((u32*) &bridge->pcie_conf + reg / 4); > + } else { > + if (bridge->ops->read_base) > + ret = bridge->ops->read_base(bridge, reg, value); > + else > + ret = PCI_SW_BRIDGE_NOT_HANDLED; > + > + if (ret == PCI_SW_BRIDGE_NOT_HANDLED) > + *value = *((u32*) &bridge->conf + reg / 4); I'm not sure about this part, where the config space that's not handled by the bridge's ops ends up just being RAM that's readable and writable with no effect on the hardware. That seems a little counter-intuitive. I think dropping writes and reading zeroes would simplify my mental model. > + } > + > + if (size == 1) > + *value = (*value >> (8 * (where & 3))) & 0xff; > + else if (size == 2) > + *value = (*value >> (8 * (where & 3))) & 0xffff; > + else if (size != 4) > + return PCIBIOS_BAD_REGISTER_NUMBER; This isn't directly related to your patches, but this is a common pattern with some variations between drivers, which makes me wonder whether there are bugs lurking. These use "where & 3" for size 2: advk_pcie_rd_conf() mtk_pcie_hw_rd_cfg() pci_generic_config_read32() But these use "where & 2": _altera_pcie_cfg_read() rcar_pcie_read_conf() I *think* this means that unaligned 2-byte config reads on Altera and R-Car will return incorrect data. In both cases, the actual read seen by the hardware is a 32-bit read, but I think we extract the wrong 16 bits from that result. I wonder if there's a way to use a common helper function to do this. > + return PCIBIOS_SUCCESSFUL; > +} > + /* > + * Called when writing to the regular PCI bridge configuration > + * space. old is the current value, new is the new value being > + * written, and mask indicates which parts of the value are > + * being changed. > + */ > + void (*write_base)(struct pci_sw_bridge *bridge, int reg, > + u32 old, u32 new, u32 mask); > + > + /* > + * Same as ->read_base(), except it is for reading from the > + * PCIe capability configuration space. I think you mean "->write_base(), except it is for writing to" > + */ > + void (*write_pcie)(struct pci_sw_bridge *bridge, int reg, > + u32 old, u32 new, u32 mask); > +};
next prev parent reply other threads:[~2018-07-12 19:58 UTC|newest] Thread overview: 30+ messages / expand[flat|nested] mbox.gz Atom feed top 2018-06-29 9:22 [PATCH 0/3] PCI: emulated PCI bridge common logic Thomas Petazzoni 2018-06-29 9:22 ` Thomas Petazzoni 2018-06-29 9:22 ` [PATCH 1/3] PCI: Introduce PCI software " Thomas Petazzoni 2018-06-29 9:22 ` Thomas Petazzoni 2018-07-12 19:58 ` Bjorn Helgaas [this message] 2018-07-12 19:58 ` Bjorn Helgaas 2018-08-01 8:49 ` Thomas Petazzoni 2018-08-01 8:49 ` Thomas Petazzoni 2018-08-01 9:21 ` Russell King - ARM Linux 2018-08-01 9:21 ` Russell King - ARM Linux 2018-08-01 9:37 ` Thomas Petazzoni 2018-08-01 9:37 ` Thomas Petazzoni 2018-08-01 9:54 ` Thomas Petazzoni 2018-08-01 9:54 ` Thomas Petazzoni 2018-08-01 11:13 ` Thomas Petazzoni 2018-08-01 11:13 ` Thomas Petazzoni 2018-06-29 9:22 ` [PATCH 2/3] PCI: mvebu: Convert to PCI software bridge Thomas Petazzoni 2018-06-29 9:22 ` Thomas Petazzoni 2018-06-29 9:22 ` [PATCH 3/3] PCI: aardvark: Implement emulated root PCI bridge Thomas Petazzoni 2018-06-29 9:22 ` Thomas Petazzoni 2022-01-07 21:27 ` Bjorn Helgaas 2022-01-07 21:27 ` Bjorn Helgaas 2022-01-07 23:17 ` Bjorn Helgaas 2022-01-07 23:17 ` Bjorn Helgaas 2022-01-10 9:17 ` Pali Rohár 2022-01-10 9:17 ` Pali Rohár 2022-01-10 2:21 ` Marek Behún 2022-01-10 2:21 ` Marek Behún 2018-07-12 9:24 ` [PATCH 0/3] PCI: emulated PCI bridge common logic Thomas Petazzoni 2018-07-12 9:24 ` Thomas Petazzoni
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20180712195802.GC28466@bhelgaas-glaptop.roam.corp.google.com \ --to=helgaas@kernel.org \ --cc=antoine.tenart@bootlin.com \ --cc=bhelgaas@google.com \ --cc=dingwei@marvell.com \ --cc=gregory.clement@bootlin.com \ --cc=horms@verge.net.au \ --cc=lftan@altera.com \ --cc=linux-arm-kernel@lists.infradead.org \ --cc=linux-pci@vger.kernel.org \ --cc=linux@arm.linux.org.uk \ --cc=lorenzo.pieralisi@arm.com \ --cc=maxime.chevallier@bootlin.com \ --cc=miquel.raynal@bootlin.com \ --cc=nadavh@marvell.com \ --cc=ray.jui@broadcom.com \ --cc=thomas.petazzoni@bootlin.com \ --cc=xigu@marvell.com \ --cc=zhangzg@marvell.com \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.