Message ID | 20170828180437.2646-2-ard.biesheuvel@linaro.org (mailing list archive) |
---|---|
State | New, archived |
Delegated to: | Bjorn Helgaas |
Headers | show |
[+cc Will] On Mon, Aug 28, 2017 at 07:04:36PM +0100, Ard Biesheuvel wrote: > Some implementations of the Synopsys Designware PCIe controller implement > a so-called ECAM shift mode, which allows a static memory window to be > configured that covers the configuration space of the entire bus range. > > If the firmware performs all the low level configuration that is required > to expose this controller in a fully ECAM compatible manner, we can > simply describe it as "pci-host-ecam-generic" and be done with it. > However, it appears that in some cases (one of which is the Armada 80x0), > the IP is synthesized with an ATU window size that does not allow the > first bus to be mapped in a way that prevents the device on the > downstream port from appearing more than once. > > So implement a driver that relies on the firmware to perform all low > level initialization, and drives the controller in ECAM mode, but > overrides the config space accessors to take the above quirk into > account. > > Note that, unlike most drivers for this IP, this driver does not expose > a fake bridge device at B/D/F 00:00.0. There is no point in doing so, > given that this is not a true bridge, and does not require any windows > to be configured in order for the downstream device to operate correctly. > Omitting it also prevents the PCI resource allocation routines from > handing out BAR space to it unnecessarily. This is a tangent, but does this mean the other drivers do not need to expose a fake 00:00.0 device either? s/Designware/DesignWare/ in comments, changelogs, Kconfig text, etc. > Cc: Bjorn Helgaas <bhelgaas@google.com> > Cc: Jingoo Han <jingoohan1@gmail.com> > Cc: Joao Pinto <Joao.Pinto@synopsys.com> > Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> > --- > drivers/pci/dwc/Kconfig | 11 +++ > drivers/pci/dwc/Makefile | 1 + > drivers/pci/dwc/pcie-designware-ecam.c | 77 ++++++++++++++++++++ This really doesn't have any DesignWare specifics in it, and it seems more related to drivers/pci/host/pci-host-generic.c than to anything in drivers/pci/dwc. Maybe it should be drivers/pci/host/pci-host-generic-quirks.c or something? That's unwieldy, I admit. Putting it in pci/dwc would make Jingoo and Joao the default maintainers; I don't know how they feel about that. We would probably have to tweak MAINTAINERS if we *didn't* put it in pci/dwc. Any thoughts on this, Will? > 3 files changed, 89 insertions(+) > > diff --git a/drivers/pci/dwc/Kconfig b/drivers/pci/dwc/Kconfig > index d275aadc47ee..477576d07911 100644 > --- a/drivers/pci/dwc/Kconfig > +++ b/drivers/pci/dwc/Kconfig > @@ -169,4 +169,15 @@ config PCIE_KIRIN > Say Y here if you want PCIe controller support > on HiSilicon Kirin series SoCs. > > +config PCIE_DW_HOST_ECAM > + bool "Synopsys DesignWare PCIe controller in ECAM mode" > + depends on OF && PCI > + select PCI_HOST_COMMON > + select IRQ_DOMAIN > + help > + Add support for Synopsys DesignWare PCIe controllers configured > + by the firmware into ECAM shift mode. In some cases, these are > + fully ECAM compliant, in which case the pci-host-generic driver > + may be used instead. This doesn't quite read right. It sounds like a controller in ECAM shift mode might be fully ECAM compliant, but I don't think that's what you intended. IIUC, the controller can be in either "ECAM shift mode" (where we need this new driver) or in a "fully ECAM compliant mode" (where we can use pci-host-generic). > endmenu > diff --git a/drivers/pci/dwc/Makefile b/drivers/pci/dwc/Makefile > index c61be9738cce..7d5a23e5b767 100644 > --- a/drivers/pci/dwc/Makefile > +++ b/drivers/pci/dwc/Makefile > @@ -1,5 +1,6 @@ > obj-$(CONFIG_PCIE_DW) += pcie-designware.o > obj-$(CONFIG_PCIE_DW_HOST) += pcie-designware-host.o > +obj-$(CONFIG_PCIE_DW_HOST_ECAM) += pcie-designware-ecam.o > obj-$(CONFIG_PCIE_DW_EP) += pcie-designware-ep.o > obj-$(CONFIG_PCIE_DW_PLAT) += pcie-designware-plat.o > ifneq ($(filter y,$(CONFIG_PCI_DRA7XX_HOST) $(CONFIG_PCI_DRA7XX_EP)),) > diff --git a/drivers/pci/dwc/pcie-designware-ecam.c b/drivers/pci/dwc/pcie-designware-ecam.c > new file mode 100644 > index 000000000000..ede627d7d08b > --- /dev/null > +++ b/drivers/pci/dwc/pcie-designware-ecam.c > @@ -0,0 +1,77 @@ > +/* > + * Driver for mostly ECAM compatible Synopsys dw PCIe controllers > + * configured by the firmware into RC mode > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License version 2 as > + * published by the Free Software Foundation. > + * > + * Copyright (C) 2014 ARM Limited > + * Copyright (C) 2017 Linaro Limited > + * > + * Authors: Will Deacon <will.deacon@arm.com> > + * Ard Biesheuvel <ard.biesheuvel@linaro.org> > + */ > + > +#include <linux/kernel.h> > +#include <linux/init.h> > +#include <linux/of_address.h> > +#include <linux/of_pci.h> > +#include <linux/pci-ecam.h> > +#include <linux/platform_device.h> > + > +static int pci_dw_ecam_config_read(struct pci_bus *bus, u32 devfn, int where, > + int size, u32 *val) > +{ > + struct pci_config_window *cfg = bus->sysdata; > + > + /* > + * The Synopsys dw PCIe controller in RC mode will not filter type 0 > + * config TLPs sent to devices 1 and up on its downstream port, > + * resulting in devices appearing multiple times on bus 0 unless we > + * filter them here. > + */ > + if (bus->number == cfg->busr.start && PCI_SLOT(devfn) > 0) { Trivial, but maybe you could factor out this test? We already have these functions that do basically the same thing and it'd be nice to use a similar pattern (altera and dw also check for the link being up, which seems racy and possibly bogus to me): altera_pcie_valid_device() dw_pcie_valid_device() rockchip_pcie_valid_device() The fact that altera and rockchip do essentially the same thing as dw here suggests that this pattern is not limited to DesignWare. These other functions also do something similar, though not structured the same way: hisi_pcie_rd_conf() advk_pcie_rd_conf() thunder_pem_bridge_read() rcar_pcie_config_access() gapspci_config_access() > + *val = 0xffffffff; > + return PCIBIOS_DEVICE_NOT_FOUND; > + } > + return pci_generic_config_read(bus, devfn, where, size, val); > +} > + > +static int pci_dw_ecam_config_write(struct pci_bus *bus, u32 devfn, int where, > + int size, u32 val) > +{ > + struct pci_config_window *cfg = bus->sysdata; > + > + if (bus->number == cfg->busr.start && PCI_SLOT(devfn) > 0) > + return PCIBIOS_DEVICE_NOT_FOUND; > + > + return pci_generic_config_write(bus, devfn, where, size, val); > +} > + > +static struct pci_ecam_ops pci_dw_ecam_bus_ops = { > + .pci_ops.map_bus = pci_ecam_map_bus, > + .pci_ops.read = pci_dw_ecam_config_read, > + .pci_ops.write = pci_dw_ecam_config_write, > + .bus_shift = 20, > +}; > + > +static const struct of_device_id pci_dw_ecam_of_match[] = { > + { .compatible = "marvell,armada8k-pcie-ecam" }, > + { .compatible = "socionext,synquacer-pcie-ecam" }, > + { .compatible = "snps,dw-pcie-ecam" }, > + { }, > +}; > + > +static int pci_dw_ecam_probe(struct platform_device *pdev) > +{ > + return pci_host_common_probe(pdev, &pci_dw_ecam_bus_ops); > +} > + > +static struct platform_driver pci_dw_ecam_driver = { > + .driver.name = "pcie-designware-ecam", > + .driver.of_match_table = pci_dw_ecam_of_match, > + .driver.suppress_bind_attrs = true, > + .probe = pci_dw_ecam_probe, > +}; > +builtin_platform_driver(pci_dw_ecam_driver); > -- > 2.11.0 >
On Tue, Sep 26, 2017 at 12:32:00PM -0500, Bjorn Helgaas wrote: > [+cc Will] > > On Mon, Aug 28, 2017 at 07:04:36PM +0100, Ard Biesheuvel wrote: > > Some implementations of the Synopsys Designware PCIe controller implement > > a so-called ECAM shift mode, which allows a static memory window to be > > configured that covers the configuration space of the entire bus range. > > > > If the firmware performs all the low level configuration that is required > > to expose this controller in a fully ECAM compatible manner, we can > > simply describe it as "pci-host-ecam-generic" and be done with it. > > However, it appears that in some cases (one of which is the Armada 80x0), > > the IP is synthesized with an ATU window size that does not allow the > > first bus to be mapped in a way that prevents the device on the > > downstream port from appearing more than once. > > > > So implement a driver that relies on the firmware to perform all low > > level initialization, and drives the controller in ECAM mode, but > > overrides the config space accessors to take the above quirk into > > account. > > > > Note that, unlike most drivers for this IP, this driver does not expose > > a fake bridge device at B/D/F 00:00.0. There is no point in doing so, > > given that this is not a true bridge, and does not require any windows > > to be configured in order for the downstream device to operate correctly. > > Omitting it also prevents the PCI resource allocation routines from > > handing out BAR space to it unnecessarily. > > This is a tangent, but does this mean the other drivers do not need to > expose a fake 00:00.0 device either? > > s/Designware/DesignWare/ in comments, changelogs, Kconfig text, etc. > > > Cc: Bjorn Helgaas <bhelgaas@google.com> > > Cc: Jingoo Han <jingoohan1@gmail.com> > > Cc: Joao Pinto <Joao.Pinto@synopsys.com> > > Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> > > --- > > drivers/pci/dwc/Kconfig | 11 +++ > > drivers/pci/dwc/Makefile | 1 + > > drivers/pci/dwc/pcie-designware-ecam.c | 77 ++++++++++++++++++++ > > This really doesn't have any DesignWare specifics in it, and it seems > more related to drivers/pci/host/pci-host-generic.c than to anything > in drivers/pci/dwc. Maybe it should be > drivers/pci/host/pci-host-generic-quirks.c or something? That's > unwieldy, I admit. > > Putting it in pci/dwc would make Jingoo and Joao the default > maintainers; I don't know how they feel about that. We would probably > have to tweak MAINTAINERS if we *didn't* put it in pci/dwc. > > Any thoughts on this, Will? The idea of a "generic quirk" makes me smile, I must admit :) I think there are two options: 1. Use the full DWC driver, and don't rely on firmware -or- 2. Rely on firmware, but teach pci-host-generic to deal with the funny config space For (2), we probably want to describe this as generically as possible in case some other SoCs run into the same problem. Will
On 26 September 2017 at 10:32, Bjorn Helgaas <helgaas@kernel.org> wrote: > [+cc Will] > > On Mon, Aug 28, 2017 at 07:04:36PM +0100, Ard Biesheuvel wrote: >> Some implementations of the Synopsys Designware PCIe controller implement >> a so-called ECAM shift mode, which allows a static memory window to be >> configured that covers the configuration space of the entire bus range. >> >> If the firmware performs all the low level configuration that is required >> to expose this controller in a fully ECAM compatible manner, we can >> simply describe it as "pci-host-ecam-generic" and be done with it. >> However, it appears that in some cases (one of which is the Armada 80x0), >> the IP is synthesized with an ATU window size that does not allow the >> first bus to be mapped in a way that prevents the device on the >> downstream port from appearing more than once. >> >> So implement a driver that relies on the firmware to perform all low >> level initialization, and drives the controller in ECAM mode, but >> overrides the config space accessors to take the above quirk into >> account. >> >> Note that, unlike most drivers for this IP, this driver does not expose >> a fake bridge device at B/D/F 00:00.0. There is no point in doing so, >> given that this is not a true bridge, and does not require any windows >> to be configured in order for the downstream device to operate correctly. >> Omitting it also prevents the PCI resource allocation routines from >> handing out BAR space to it unnecessarily. > > This is a tangent, but does this mean the other drivers do not need to > expose a fake 00:00.0 device either? > To be honest, I am not so sure anymore. I am seeing some issues in ASPM code making the assumption that any device which is not a root port has a parent. If this is mandated by the spec, I guess there isn't a whole lot we can do except expose a fake root port on b/d/f 0/0/0. This used to work fine, though, and I have to confirm whether the issues I am seeing currently are due to different hardware or changes in the software. > s/Designware/DesignWare/ in comments, changelogs, Kconfig text, etc. > OK >> Cc: Bjorn Helgaas <bhelgaas@google.com> >> Cc: Jingoo Han <jingoohan1@gmail.com> >> Cc: Joao Pinto <Joao.Pinto@synopsys.com> >> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> >> --- >> drivers/pci/dwc/Kconfig | 11 +++ >> drivers/pci/dwc/Makefile | 1 + >> drivers/pci/dwc/pcie-designware-ecam.c | 77 ++++++++++++++++++++ > > This really doesn't have any DesignWare specifics in it, and it seems > more related to drivers/pci/host/pci-host-generic.c than to anything > in drivers/pci/dwc. Maybe it should be > drivers/pci/host/pci-host-generic-quirks.c or something? That's > unwieldy, I admit. > I don't care where we put it, and I am fine with owning it if you prefer. > Putting it in pci/dwc would make Jingoo and Joao the default > maintainers; I don't know how they feel about that. We would probably > have to tweak MAINTAINERS if we *didn't* put it in pci/dwc. > > Any thoughts on this, Will? > >> 3 files changed, 89 insertions(+) >> >> diff --git a/drivers/pci/dwc/Kconfig b/drivers/pci/dwc/Kconfig >> index d275aadc47ee..477576d07911 100644 >> --- a/drivers/pci/dwc/Kconfig >> +++ b/drivers/pci/dwc/Kconfig >> @@ -169,4 +169,15 @@ config PCIE_KIRIN >> Say Y here if you want PCIe controller support >> on HiSilicon Kirin series SoCs. >> >> +config PCIE_DW_HOST_ECAM >> + bool "Synopsys DesignWare PCIe controller in ECAM mode" >> + depends on OF && PCI >> + select PCI_HOST_COMMON >> + select IRQ_DOMAIN >> + help >> + Add support for Synopsys DesignWare PCIe controllers configured >> + by the firmware into ECAM shift mode. In some cases, these are >> + fully ECAM compliant, in which case the pci-host-generic driver >> + may be used instead. > > This doesn't quite read right. It sounds like a controller in ECAM > shift mode might be fully ECAM compliant, but I don't think that's > what you intended. > Yes, that is what I mean. ECAM shift mode results in a fully compliant ECAM config space iff the IP was synthesized with a 32 KB granularity for the iATU windows. The default is 64 KB, though, in which case you need this driver. > IIUC, the controller can be in either "ECAM shift mode" (where we need > this new driver) or in a "fully ECAM compliant mode" (where we can use > pci-host-generic). > No, this is not the case >> endmenu >> diff --git a/drivers/pci/dwc/Makefile b/drivers/pci/dwc/Makefile >> index c61be9738cce..7d5a23e5b767 100644 >> --- a/drivers/pci/dwc/Makefile >> +++ b/drivers/pci/dwc/Makefile >> @@ -1,5 +1,6 @@ >> obj-$(CONFIG_PCIE_DW) += pcie-designware.o >> obj-$(CONFIG_PCIE_DW_HOST) += pcie-designware-host.o >> +obj-$(CONFIG_PCIE_DW_HOST_ECAM) += pcie-designware-ecam.o >> obj-$(CONFIG_PCIE_DW_EP) += pcie-designware-ep.o >> obj-$(CONFIG_PCIE_DW_PLAT) += pcie-designware-plat.o >> ifneq ($(filter y,$(CONFIG_PCI_DRA7XX_HOST) $(CONFIG_PCI_DRA7XX_EP)),) >> diff --git a/drivers/pci/dwc/pcie-designware-ecam.c b/drivers/pci/dwc/pcie-designware-ecam.c >> new file mode 100644 >> index 000000000000..ede627d7d08b >> --- /dev/null >> +++ b/drivers/pci/dwc/pcie-designware-ecam.c >> @@ -0,0 +1,77 @@ >> +/* >> + * Driver for mostly ECAM compatible Synopsys dw PCIe controllers >> + * configured by the firmware into RC mode >> + * >> + * This program is free software; you can redistribute it and/or modify >> + * it under the terms of the GNU General Public License version 2 as >> + * published by the Free Software Foundation. >> + * >> + * Copyright (C) 2014 ARM Limited >> + * Copyright (C) 2017 Linaro Limited >> + * >> + * Authors: Will Deacon <will.deacon@arm.com> >> + * Ard Biesheuvel <ard.biesheuvel@linaro.org> >> + */ >> + >> +#include <linux/kernel.h> >> +#include <linux/init.h> >> +#include <linux/of_address.h> >> +#include <linux/of_pci.h> >> +#include <linux/pci-ecam.h> >> +#include <linux/platform_device.h> >> + >> +static int pci_dw_ecam_config_read(struct pci_bus *bus, u32 devfn, int where, >> + int size, u32 *val) >> +{ >> + struct pci_config_window *cfg = bus->sysdata; >> + >> + /* >> + * The Synopsys dw PCIe controller in RC mode will not filter type 0 >> + * config TLPs sent to devices 1 and up on its downstream port, >> + * resulting in devices appearing multiple times on bus 0 unless we >> + * filter them here. >> + */ >> + if (bus->number == cfg->busr.start && PCI_SLOT(devfn) > 0) { > > Trivial, but maybe you could factor out this test? We already have > these functions that do basically the same thing and it'd be nice to > use a similar pattern (altera and dw also check for the link being up, > which seems racy and possibly bogus to me): > > altera_pcie_valid_device() > dw_pcie_valid_device() > rockchip_pcie_valid_device() > > The fact that altera and rockchip do essentially the same thing as dw > here suggests that this pattern is not limited to DesignWare. > > These other functions also do something similar, though not structured > the same way: > > hisi_pcie_rd_conf() > advk_pcie_rd_conf() > thunder_pem_bridge_read() > rcar_pcie_config_access() > gapspci_config_access() > I can look into that. >> + *val = 0xffffffff; >> + return PCIBIOS_DEVICE_NOT_FOUND; >> + } >> + return pci_generic_config_read(bus, devfn, where, size, val); >> +} >> + >> +static int pci_dw_ecam_config_write(struct pci_bus *bus, u32 devfn, int where, >> + int size, u32 val) >> +{ >> + struct pci_config_window *cfg = bus->sysdata; >> + >> + if (bus->number == cfg->busr.start && PCI_SLOT(devfn) > 0) >> + return PCIBIOS_DEVICE_NOT_FOUND; >> + >> + return pci_generic_config_write(bus, devfn, where, size, val); >> +} >> + >> +static struct pci_ecam_ops pci_dw_ecam_bus_ops = { >> + .pci_ops.map_bus = pci_ecam_map_bus, >> + .pci_ops.read = pci_dw_ecam_config_read, >> + .pci_ops.write = pci_dw_ecam_config_write, >> + .bus_shift = 20, >> +}; >> + >> +static const struct of_device_id pci_dw_ecam_of_match[] = { >> + { .compatible = "marvell,armada8k-pcie-ecam" }, >> + { .compatible = "socionext,synquacer-pcie-ecam" }, >> + { .compatible = "snps,dw-pcie-ecam" }, >> + { }, >> +}; >> + >> +static int pci_dw_ecam_probe(struct platform_device *pdev) >> +{ >> + return pci_host_common_probe(pdev, &pci_dw_ecam_bus_ops); >> +} >> + >> +static struct platform_driver pci_dw_ecam_driver = { >> + .driver.name = "pcie-designware-ecam", >> + .driver.of_match_table = pci_dw_ecam_of_match, >> + .driver.suppress_bind_attrs = true, >> + .probe = pci_dw_ecam_probe, >> +}; >> +builtin_platform_driver(pci_dw_ecam_driver); >> -- >> 2.11.0 >>
On 28 September 2017 at 02:03, Will Deacon <will.deacon@arm.com> wrote: > On Tue, Sep 26, 2017 at 12:32:00PM -0500, Bjorn Helgaas wrote: >> [+cc Will] >> >> On Mon, Aug 28, 2017 at 07:04:36PM +0100, Ard Biesheuvel wrote: >> > Some implementations of the Synopsys Designware PCIe controller implement >> > a so-called ECAM shift mode, which allows a static memory window to be >> > configured that covers the configuration space of the entire bus range. >> > >> > If the firmware performs all the low level configuration that is required >> > to expose this controller in a fully ECAM compatible manner, we can >> > simply describe it as "pci-host-ecam-generic" and be done with it. >> > However, it appears that in some cases (one of which is the Armada 80x0), >> > the IP is synthesized with an ATU window size that does not allow the >> > first bus to be mapped in a way that prevents the device on the >> > downstream port from appearing more than once. >> > >> > So implement a driver that relies on the firmware to perform all low >> > level initialization, and drives the controller in ECAM mode, but >> > overrides the config space accessors to take the above quirk into >> > account. >> > >> > Note that, unlike most drivers for this IP, this driver does not expose >> > a fake bridge device at B/D/F 00:00.0. There is no point in doing so, >> > given that this is not a true bridge, and does not require any windows >> > to be configured in order for the downstream device to operate correctly. >> > Omitting it also prevents the PCI resource allocation routines from >> > handing out BAR space to it unnecessarily. >> >> This is a tangent, but does this mean the other drivers do not need to >> expose a fake 00:00.0 device either? >> >> s/Designware/DesignWare/ in comments, changelogs, Kconfig text, etc. >> >> > Cc: Bjorn Helgaas <bhelgaas@google.com> >> > Cc: Jingoo Han <jingoohan1@gmail.com> >> > Cc: Joao Pinto <Joao.Pinto@synopsys.com> >> > Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> >> > --- >> > drivers/pci/dwc/Kconfig | 11 +++ >> > drivers/pci/dwc/Makefile | 1 + >> > drivers/pci/dwc/pcie-designware-ecam.c | 77 ++++++++++++++++++++ >> >> This really doesn't have any DesignWare specifics in it, and it seems >> more related to drivers/pci/host/pci-host-generic.c than to anything >> in drivers/pci/dwc. Maybe it should be >> drivers/pci/host/pci-host-generic-quirks.c or something? That's >> unwieldy, I admit. >> >> Putting it in pci/dwc would make Jingoo and Joao the default >> maintainers; I don't know how they feel about that. We would probably >> have to tweak MAINTAINERS if we *didn't* put it in pci/dwc. >> >> Any thoughts on this, Will? > > The idea of a "generic quirk" makes me smile, I must admit :) > > I think there are two options: > > 1. Use the full DWC driver, and don't rely on firmware > -or- > 2. Rely on firmware, but teach pci-host-generic to deal with the funny > config space > > For (2), we probably want to describe this as generically as possible > in case some other SoCs run into the same problem. > I take it this implies a DT property. I could add one that consists of an array of val/mask tuples or base/size tuples that allow us to disable arbitrary subregions of the config space. I could also add a simple boolean property that implements this exact quirk. Do you have any preference?
On Thu, Sep 28, 2017 at 08:57:28AM -0700, Ard Biesheuvel wrote: > On 28 September 2017 at 02:03, Will Deacon <will.deacon@arm.com> wrote: > > On Tue, Sep 26, 2017 at 12:32:00PM -0500, Bjorn Helgaas wrote: > >> [+cc Will] > >> > >> On Mon, Aug 28, 2017 at 07:04:36PM +0100, Ard Biesheuvel wrote: > >> > Some implementations of the Synopsys Designware PCIe controller implement > >> > a so-called ECAM shift mode, which allows a static memory window to be > >> > configured that covers the configuration space of the entire bus range. > >> > > >> > If the firmware performs all the low level configuration that is required > >> > to expose this controller in a fully ECAM compatible manner, we can > >> > simply describe it as "pci-host-ecam-generic" and be done with it. > >> > However, it appears that in some cases (one of which is the Armada 80x0), > >> > the IP is synthesized with an ATU window size that does not allow the > >> > first bus to be mapped in a way that prevents the device on the > >> > downstream port from appearing more than once. > >> > > >> > So implement a driver that relies on the firmware to perform all low > >> > level initialization, and drives the controller in ECAM mode, but > >> > overrides the config space accessors to take the above quirk into > >> > account. > >> > > >> > Note that, unlike most drivers for this IP, this driver does not expose > >> > a fake bridge device at B/D/F 00:00.0. There is no point in doing so, > >> > given that this is not a true bridge, and does not require any windows > >> > to be configured in order for the downstream device to operate correctly. > >> > Omitting it also prevents the PCI resource allocation routines from > >> > handing out BAR space to it unnecessarily. > >> > >> This is a tangent, but does this mean the other drivers do not need to > >> expose a fake 00:00.0 device either? > >> > >> s/Designware/DesignWare/ in comments, changelogs, Kconfig text, etc. > >> > >> > Cc: Bjorn Helgaas <bhelgaas@google.com> > >> > Cc: Jingoo Han <jingoohan1@gmail.com> > >> > Cc: Joao Pinto <Joao.Pinto@synopsys.com> > >> > Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> > >> > --- > >> > drivers/pci/dwc/Kconfig | 11 +++ > >> > drivers/pci/dwc/Makefile | 1 + > >> > drivers/pci/dwc/pcie-designware-ecam.c | 77 ++++++++++++++++++++ > >> > >> This really doesn't have any DesignWare specifics in it, and it seems > >> more related to drivers/pci/host/pci-host-generic.c than to anything > >> in drivers/pci/dwc. Maybe it should be > >> drivers/pci/host/pci-host-generic-quirks.c or something? That's > >> unwieldy, I admit. > >> > >> Putting it in pci/dwc would make Jingoo and Joao the default > >> maintainers; I don't know how they feel about that. We would probably > >> have to tweak MAINTAINERS if we *didn't* put it in pci/dwc. > >> > >> Any thoughts on this, Will? > > > > The idea of a "generic quirk" makes me smile, I must admit :) > > > > I think there are two options: > > > > 1. Use the full DWC driver, and don't rely on firmware > > -or- > > 2. Rely on firmware, but teach pci-host-generic to deal with the funny > > config space > > > > For (2), we probably want to describe this as generically as possible > > in case some other SoCs run into the same problem. > > > > I take it this implies a DT property. I could add one that consists of > an array of val/mask tuples or base/size tuples that allow us to > disable arbitrary subregions of the config space. I could also add a > simple boolean property that implements this exact quirk. Do you have > any preference? I'd say either a boolean property or a new compatible string. I think Rob prefers the latter, from what he said recently on an SMMU thread. Will
On 28 September 2017 at 09:00, Will Deacon <will.deacon@arm.com> wrote: > On Thu, Sep 28, 2017 at 08:57:28AM -0700, Ard Biesheuvel wrote: >> On 28 September 2017 at 02:03, Will Deacon <will.deacon@arm.com> wrote: >> > On Tue, Sep 26, 2017 at 12:32:00PM -0500, Bjorn Helgaas wrote: >> >> [+cc Will] >> >> >> >> On Mon, Aug 28, 2017 at 07:04:36PM +0100, Ard Biesheuvel wrote: >> >> > Some implementations of the Synopsys Designware PCIe controller implement >> >> > a so-called ECAM shift mode, which allows a static memory window to be >> >> > configured that covers the configuration space of the entire bus range. >> >> > >> >> > If the firmware performs all the low level configuration that is required >> >> > to expose this controller in a fully ECAM compatible manner, we can >> >> > simply describe it as "pci-host-ecam-generic" and be done with it. >> >> > However, it appears that in some cases (one of which is the Armada 80x0), >> >> > the IP is synthesized with an ATU window size that does not allow the >> >> > first bus to be mapped in a way that prevents the device on the >> >> > downstream port from appearing more than once. >> >> > >> >> > So implement a driver that relies on the firmware to perform all low >> >> > level initialization, and drives the controller in ECAM mode, but >> >> > overrides the config space accessors to take the above quirk into >> >> > account. >> >> > >> >> > Note that, unlike most drivers for this IP, this driver does not expose >> >> > a fake bridge device at B/D/F 00:00.0. There is no point in doing so, >> >> > given that this is not a true bridge, and does not require any windows >> >> > to be configured in order for the downstream device to operate correctly. >> >> > Omitting it also prevents the PCI resource allocation routines from >> >> > handing out BAR space to it unnecessarily. >> >> >> >> This is a tangent, but does this mean the other drivers do not need to >> >> expose a fake 00:00.0 device either? >> >> >> >> s/Designware/DesignWare/ in comments, changelogs, Kconfig text, etc. >> >> >> >> > Cc: Bjorn Helgaas <bhelgaas@google.com> >> >> > Cc: Jingoo Han <jingoohan1@gmail.com> >> >> > Cc: Joao Pinto <Joao.Pinto@synopsys.com> >> >> > Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> >> >> > --- >> >> > drivers/pci/dwc/Kconfig | 11 +++ >> >> > drivers/pci/dwc/Makefile | 1 + >> >> > drivers/pci/dwc/pcie-designware-ecam.c | 77 ++++++++++++++++++++ >> >> >> >> This really doesn't have any DesignWare specifics in it, and it seems >> >> more related to drivers/pci/host/pci-host-generic.c than to anything >> >> in drivers/pci/dwc. Maybe it should be >> >> drivers/pci/host/pci-host-generic-quirks.c or something? That's >> >> unwieldy, I admit. >> >> >> >> Putting it in pci/dwc would make Jingoo and Joao the default >> >> maintainers; I don't know how they feel about that. We would probably >> >> have to tweak MAINTAINERS if we *didn't* put it in pci/dwc. >> >> >> >> Any thoughts on this, Will? >> > >> > The idea of a "generic quirk" makes me smile, I must admit :) >> > >> > I think there are two options: >> > >> > 1. Use the full DWC driver, and don't rely on firmware >> > -or- >> > 2. Rely on firmware, but teach pci-host-generic to deal with the funny >> > config space >> > >> > For (2), we probably want to describe this as generically as possible >> > in case some other SoCs run into the same problem. >> > >> >> I take it this implies a DT property. I could add one that consists of >> an array of val/mask tuples or base/size tuples that allow us to >> disable arbitrary subregions of the config space. I could also add a >> simple boolean property that implements this exact quirk. Do you have >> any preference? > > I'd say either a boolean property or a new compatible string. I think Rob > prefers the latter, from what he said recently on an SMMU thread. > OK. Given that Rob already acked the binding for this driver, I'll go ahead and rework the patch to add + { .compatible = "marvell,armada8k-pcie-ecam" }, + { .compatible = "socionext,synquacer-pcie-ecam" }, + { .compatible = "snps,dw-pcie-ecam" }, to the pci-host-ecam-generic driver instead. Thanks, Ard.
On Thu, Sep 28, 2017 at 08:51:43AM -0700, Ard Biesheuvel wrote: > On 26 September 2017 at 10:32, Bjorn Helgaas <helgaas@kernel.org> wrote: > > On Mon, Aug 28, 2017 at 07:04:36PM +0100, Ard Biesheuvel wrote: > >> Some implementations of the Synopsys Designware PCIe controller implement > >> a so-called ECAM shift mode, which allows a static memory window to be > >> configured that covers the configuration space of the entire bus range. > >> Note that, unlike most drivers for this IP, this driver does not expose > >> a fake bridge device at B/D/F 00:00.0. There is no point in doing so, > >> given that this is not a true bridge, and does not require any windows > >> to be configured in order for the downstream device to operate correctly. > >> Omitting it also prevents the PCI resource allocation routines from > >> handing out BAR space to it unnecessarily. > > > > This is a tangent, but does this mean the other drivers do not need to > > expose a fake 00:00.0 device either? > > To be honest, I am not so sure anymore. I am seeing some issues in > ASPM code making the assumption that any device which is not a root > port has a parent. If this is mandated by the spec, I guess there > isn't a whole lot we can do except expose a fake root port on b/d/f > 0/0/0. This used to work fine, though, and I have to confirm whether > the issues I am seeing currently are due to different hardware or > changes in the software. I agree that our ASPM code had some assumptions that any non-root port device should have a parent. I think the spec also makes that assumption, but I haven't found an explicit mandate. And there *are* systems lacking root ports: http://lkml.kernel.org/r/1439808478-23253-1-git-send-email-wangyijing@huawei.com We fixed one such assumption in that thread, but I wouldn't be surprised if more remain. If there are, I think we should fix the code to remove the assumption. > > This really doesn't have any DesignWare specifics in it, and it seems > > more related to drivers/pci/host/pci-host-generic.c than to anything > > in drivers/pci/dwc. Maybe it should be > > drivers/pci/host/pci-host-generic-quirks.c or something? That's > > unwieldy, I admit. > > I don't care where we put it, and I am fine with owning it if you prefer. I think Will's idea of teaching pci-host-generic to deal with this is perfect. > >> +config PCIE_DW_HOST_ECAM > >> + bool "Synopsys DesignWare PCIe controller in ECAM mode" > >> + depends on OF && PCI > >> + select PCI_HOST_COMMON > >> + select IRQ_DOMAIN > >> + help > >> + Add support for Synopsys DesignWare PCIe controllers configured > >> + by the firmware into ECAM shift mode. In some cases, these are > >> + fully ECAM compliant, in which case the pci-host-generic driver > >> + may be used instead. > > > > This doesn't quite read right. It sounds like a controller in ECAM > > shift mode might be fully ECAM compliant, but I don't think that's > > what you intended. > > Yes, that is what I mean. ECAM shift mode results in a fully compliant > ECAM config space iff the IP was synthesized with a 32 KB granularity > for the iATU windows. The default is 64 KB, though, in which case you > need this driver. OK. I'm trying to figure out how I as a user would know whether to select this option. Maybe the config option will go away if you add the smarts to pci-host-generic? Bjorn
On 28 September 2017 at 10:48, Bjorn Helgaas <helgaas@kernel.org> wrote: > On Thu, Sep 28, 2017 at 08:51:43AM -0700, Ard Biesheuvel wrote: >> On 26 September 2017 at 10:32, Bjorn Helgaas <helgaas@kernel.org> wrote: >> > On Mon, Aug 28, 2017 at 07:04:36PM +0100, Ard Biesheuvel wrote: >> >> Some implementations of the Synopsys Designware PCIe controller implement >> >> a so-called ECAM shift mode, which allows a static memory window to be >> >> configured that covers the configuration space of the entire bus range. > >> >> Note that, unlike most drivers for this IP, this driver does not expose >> >> a fake bridge device at B/D/F 00:00.0. There is no point in doing so, >> >> given that this is not a true bridge, and does not require any windows >> >> to be configured in order for the downstream device to operate correctly. >> >> Omitting it also prevents the PCI resource allocation routines from >> >> handing out BAR space to it unnecessarily. >> > >> > This is a tangent, but does this mean the other drivers do not need to >> > expose a fake 00:00.0 device either? >> >> To be honest, I am not so sure anymore. I am seeing some issues in >> ASPM code making the assumption that any device which is not a root >> port has a parent. If this is mandated by the spec, I guess there >> isn't a whole lot we can do except expose a fake root port on b/d/f >> 0/0/0. This used to work fine, though, and I have to confirm whether >> the issues I am seeing currently are due to different hardware or >> changes in the software. > > I agree that our ASPM code had some assumptions that any non-root port > device should have a parent. I think the spec also makes that > assumption, but I haven't found an explicit mandate. And there *are* > systems lacking root ports: > > http://lkml.kernel.org/r/1439808478-23253-1-git-send-email-wangyijing@huawei.com > > We fixed one such assumption in that thread, but I wouldn't be > surprised if more remain. If there are, I think we should fix the > code to remove the assumption. > OK, that is good to know. What I am seeing on my board is the following crash Unable to handle kernel NULL pointer dereference at virtual address 00000090 [0000000000000090] user address but active_mm is swapper Internal error: Oops: 96000004 [#1] SMP Modules linked in: CPU: 23 PID: 1 Comm: swapper/0 Not tainted 4.13.0+ #1 Hardware name: Synquacer Evaluation Board (DT) task: ffff800f5c574080 task.stack: ffff800f5c578000 PC is at pcie_aspm_init_link_state+0x204/0xa38 LR is at pcie_aspm_init_link_state+0x184/0xa38 ... [<ffff0000084fda0c>] pcie_aspm_init_link_state+0x204/0xa38 [<ffff0000084e2924>] pci_scan_slot+0x10c/0x150 [<ffff0000084e3a9c>] pci_scan_child_bus+0x3c/0x1b0 [<ffff0000084e37b4>] pci_scan_bridge+0x30c/0x5b8 [<ffff0000084e3b1c>] pci_scan_child_bus+0xbc/0x1b0 [<ffff0000084e37b4>] pci_scan_bridge+0x30c/0x5b8 [<ffff0000084e3b1c>] pci_scan_child_bus+0xbc/0x1b0 [<ffff0000084e3e0c>] pci_scan_root_bus_bridge+0xdc/0xf8 [<ffff000008509c28>] pci_host_common_probe+0x148/0x400 [<ffff00000850ee4c>] pci_dw_ecam_probe+0x2c/0x38 [<ffff0000086348c8>] platform_drv_probe+0x60/0xc8 [<ffff000008631b3c>] driver_probe_device+0x2e4/0x460 [<ffff000008631de4>] __driver_attach+0x12c/0x130 [<ffff00000862f1e0>] bus_for_each_dev+0x88/0xe8 [<ffff000008631218>] driver_attach+0x30/0x40 [<ffff000008630b90>] bus_add_driver+0x200/0x2b8 [<ffff000008632fd8>] driver_register+0x68/0x100 [<ffff0000086347ec>] __platform_driver_register+0x54/0x60 [<ffff000008c44520>] pci_dw_ecam_driver_init+0x20/0x28 [<ffff00000808399c>] do_one_initcall+0x5c/0x168 [<ffff000008c10f98>] kernel_init_freeable+0x1e8/0x288 [<ffff0000088ae9b8>] kernel_init+0x18/0x108 [<ffff0000080836d0>] ret_from_fork+0x10/0x40 Code: 54000f20 f9400aa0 f9400800 f9401c00 (f9404816) which is essentially caused by this code [in alloc_pcie_link_state()] if (pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT || pci_pcie_type(pdev) == PCI_EXP_TYPE_PCIE_BRIDGE) { link->root = link; } else { struct pcie_link_state *parent; parent = pdev->bus->parent->self->link_state; ... so I guess we should fix this instance as well. >> > This really doesn't have any DesignWare specifics in it, and it seems >> > more related to drivers/pci/host/pci-host-generic.c than to anything >> > in drivers/pci/dwc. Maybe it should be >> > drivers/pci/host/pci-host-generic-quirks.c or something? That's >> > unwieldy, I admit. >> >> I don't care where we put it, and I am fine with owning it if you prefer. > > I think Will's idea of teaching pci-host-generic to deal with this is > perfect. > I agree. I originally thought people would prefer the DesignWare quirks to live under dwc/, but it does fit more naturally into the generic driver. >> >> +config PCIE_DW_HOST_ECAM >> >> + bool "Synopsys DesignWare PCIe controller in ECAM mode" >> >> + depends on OF && PCI >> >> + select PCI_HOST_COMMON >> >> + select IRQ_DOMAIN >> >> + help >> >> + Add support for Synopsys DesignWare PCIe controllers configured >> >> + by the firmware into ECAM shift mode. In some cases, these are >> >> + fully ECAM compliant, in which case the pci-host-generic driver >> >> + may be used instead. >> > >> > This doesn't quite read right. It sounds like a controller in ECAM >> > shift mode might be fully ECAM compliant, but I don't think that's >> > what you intended. >> >> Yes, that is what I mean. ECAM shift mode results in a fully compliant >> ECAM config space iff the IP was synthesized with a 32 KB granularity >> for the iATU windows. The default is 64 KB, though, in which case you >> need this driver. > > OK. I'm trying to figure out how I as a user would know whether to > select this option. Maybe the config option will go away if you add > the smarts to pci-host-generic? > Yes. The firmware knows, and so the firmware should expose the correct compatible string in this case, either pci-host-ecam-generic or one of the quirked ones.
On Thursday, September 28, 2017 1:49 PM, Bjorn Helgaas wrote: > On Thu, Sep 28, 2017 at 08:51:43AM -0700, Ard Biesheuvel wrote: > > On 26 September 2017 at 10:32, Bjorn Helgaas <helgaas@kernel.org> wrote: > > > On Mon, Aug 28, 2017 at 07:04:36PM +0100, Ard Biesheuvel wrote: > > >> Some implementations of the Synopsys Designware PCIe controller > implement > > >> a so-called ECAM shift mode, which allows a static memory window to > be > > >> configured that covers the configuration space of the entire bus > range. > > > >> Note that, unlike most drivers for this IP, this driver does not > expose > > >> a fake bridge device at B/D/F 00:00.0. There is no point in doing so, > > >> given that this is not a true bridge, and does not require any > windows > > >> to be configured in order for the downstream device to operate > correctly. > > >> Omitting it also prevents the PCI resource allocation routines from > > >> handing out BAR space to it unnecessarily. > > > > > > This is a tangent, but does this mean the other drivers do not need to > > > expose a fake 00:00.0 device either? > > > > To be honest, I am not so sure anymore. I am seeing some issues in > > ASPM code making the assumption that any device which is not a root > > port has a parent. If this is mandated by the spec, I guess there > > isn't a whole lot we can do except expose a fake root port on b/d/f > > 0/0/0. This used to work fine, though, and I have to confirm whether > > the issues I am seeing currently are due to different hardware or > > changes in the software. > > I agree that our ASPM code had some assumptions that any non-root port > device should have a parent. I think the spec also makes that > assumption, but I haven't found an explicit mandate. And there *are* > systems lacking root ports: > > http://lkml.kernel.org/r/1439808478-23253-1-git-send-email- > wangyijing@huawei.com > > We fixed one such assumption in that thread, but I wouldn't be > surprised if more remain. If there are, I think we should fix the > code to remove the assumption. > > > > This really doesn't have any DesignWare specifics in it, and it seems > > > more related to drivers/pci/host/pci-host-generic.c than to anything > > > in drivers/pci/dwc. Maybe it should be > > > drivers/pci/host/pci-host-generic-quirks.c or something? That's > > > unwieldy, I admit. > > > > I don't care where we put it, and I am fine with owning it if you prefer. > > I think Will's idea of teaching pci-host-generic to deal with this is > perfect. I agree. I cannot find any reason to create new dwc-specific file. Reusing 'pci-host-generic.c' looks better. Maybe 'pci-host-generic.c with quirks' will be good. Best regards, Jingoo Han > > > >> +config PCIE_DW_HOST_ECAM > > >> + bool "Synopsys DesignWare PCIe controller in ECAM mode" > > >> + depends on OF && PCI > > >> + select PCI_HOST_COMMON > > >> + select IRQ_DOMAIN > > >> + help > > >> + Add support for Synopsys DesignWare PCIe controllers > configured > > >> + by the firmware into ECAM shift mode. In some cases, these are > > >> + fully ECAM compliant, in which case the pci-host-generic > driver > > >> + may be used instead. > > > > > > This doesn't quite read right. It sounds like a controller in ECAM > > > shift mode might be fully ECAM compliant, but I don't think that's > > > what you intended. > > > > Yes, that is what I mean. ECAM shift mode results in a fully compliant > > ECAM config space iff the IP was synthesized with a 32 KB granularity > > for the iATU windows. The default is 64 KB, though, in which case you > > need this driver. > > OK. I'm trying to figure out how I as a user would know whether to > select this option. Maybe the config option will go away if you add > the smarts to pci-host-generic? > > Bjorn
On 28 September 2017 at 16:51, Ard Biesheuvel <ard.biesheuvel@linaro.org> wrote: > On 26 September 2017 at 10:32, Bjorn Helgaas <helgaas@kernel.org> wrote: >> [+cc Will] >> >> On Mon, Aug 28, 2017 at 07:04:36PM +0100, Ard Biesheuvel wrote: >>> Some implementations of the Synopsys Designware PCIe controller implement >>> a so-called ECAM shift mode, which allows a static memory window to be >>> configured that covers the configuration space of the entire bus range. >>> >>> If the firmware performs all the low level configuration that is required >>> to expose this controller in a fully ECAM compatible manner, we can >>> simply describe it as "pci-host-ecam-generic" and be done with it. >>> However, it appears that in some cases (one of which is the Armada 80x0), >>> the IP is synthesized with an ATU window size that does not allow the >>> first bus to be mapped in a way that prevents the device on the >>> downstream port from appearing more than once. >>> >>> So implement a driver that relies on the firmware to perform all low >>> level initialization, and drives the controller in ECAM mode, but >>> overrides the config space accessors to take the above quirk into >>> account. >>> >>> Note that, unlike most drivers for this IP, this driver does not expose >>> a fake bridge device at B/D/F 00:00.0. There is no point in doing so, >>> given that this is not a true bridge, and does not require any windows >>> to be configured in order for the downstream device to operate correctly. >>> Omitting it also prevents the PCI resource allocation routines from >>> handing out BAR space to it unnecessarily. >> >> This is a tangent, but does this mean the other drivers do not need to >> expose a fake 00:00.0 device either? >> > > To be honest, I am not so sure anymore. I am seeing some issues in > ASPM code making the assumption that any device which is not a root > port has a parent. If this is mandated by the spec, I guess there > isn't a whole lot we can do except expose a fake root port on b/d/f > 0/0/0. This used to work fine, though, and I have to confirm whether > the issues I am seeing currently are due to different hardware or > changes in the software. > OK, so the issue was new because I hadn't tried using a PCIe switch before, and you have already queued the fix to make the ASPM code deal with that. So I think it /would/ be better for the other drivers to not bother mocking up the root port, and simply expose the downstream device as B/D/F 0/0/0 (assuming the bus range starts at 0). It really looks like Altera, Aardvark, Sigma, etc are all in the same boat here, and need to a) filter type 0 config TLPs to avoid the downstream device to appear 32 times, and b) mangle config space accesses to the 'root port' to hide BARs that have different meanings in this context (the size of the inbound window), in order to prevent the PCI resource allocation routines to waste huge amounts of BAR space on them. >> s/Designware/DesignWare/ in comments, changelogs, Kconfig text, etc. >> > > OK > >>> Cc: Bjorn Helgaas <bhelgaas@google.com> >>> Cc: Jingoo Han <jingoohan1@gmail.com> >>> Cc: Joao Pinto <Joao.Pinto@synopsys.com> >>> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> >>> --- >>> drivers/pci/dwc/Kconfig | 11 +++ >>> drivers/pci/dwc/Makefile | 1 + >>> drivers/pci/dwc/pcie-designware-ecam.c | 77 ++++++++++++++++++++ >> >> This really doesn't have any DesignWare specifics in it, and it seems >> more related to drivers/pci/host/pci-host-generic.c than to anything >> in drivers/pci/dwc. Maybe it should be >> drivers/pci/host/pci-host-generic-quirks.c or something? That's >> unwieldy, I admit. >> > > I don't care where we put it, and I am fine with owning it if you prefer. > >> Putting it in pci/dwc would make Jingoo and Joao the default >> maintainers; I don't know how they feel about that. We would probably >> have to tweak MAINTAINERS if we *didn't* put it in pci/dwc. >> >> Any thoughts on this, Will? >> >>> 3 files changed, 89 insertions(+) >>> >>> diff --git a/drivers/pci/dwc/Kconfig b/drivers/pci/dwc/Kconfig >>> index d275aadc47ee..477576d07911 100644 >>> --- a/drivers/pci/dwc/Kconfig >>> +++ b/drivers/pci/dwc/Kconfig >>> @@ -169,4 +169,15 @@ config PCIE_KIRIN >>> Say Y here if you want PCIe controller support >>> on HiSilicon Kirin series SoCs. >>> >>> +config PCIE_DW_HOST_ECAM >>> + bool "Synopsys DesignWare PCIe controller in ECAM mode" >>> + depends on OF && PCI >>> + select PCI_HOST_COMMON >>> + select IRQ_DOMAIN >>> + help >>> + Add support for Synopsys DesignWare PCIe controllers configured >>> + by the firmware into ECAM shift mode. In some cases, these are >>> + fully ECAM compliant, in which case the pci-host-generic driver >>> + may be used instead. >> >> This doesn't quite read right. It sounds like a controller in ECAM >> shift mode might be fully ECAM compliant, but I don't think that's >> what you intended. >> > > Yes, that is what I mean. ECAM shift mode results in a fully compliant > ECAM config space iff the IP was synthesized with a 32 KB granularity > for the iATU windows. The default is 64 KB, though, in which case you > need this driver. > >> IIUC, the controller can be in either "ECAM shift mode" (where we need >> this new driver) or in a "fully ECAM compliant mode" (where we can use >> pci-host-generic). >> > > No, this is not the case > >>> endmenu >>> diff --git a/drivers/pci/dwc/Makefile b/drivers/pci/dwc/Makefile >>> index c61be9738cce..7d5a23e5b767 100644 >>> --- a/drivers/pci/dwc/Makefile >>> +++ b/drivers/pci/dwc/Makefile >>> @@ -1,5 +1,6 @@ >>> obj-$(CONFIG_PCIE_DW) += pcie-designware.o >>> obj-$(CONFIG_PCIE_DW_HOST) += pcie-designware-host.o >>> +obj-$(CONFIG_PCIE_DW_HOST_ECAM) += pcie-designware-ecam.o >>> obj-$(CONFIG_PCIE_DW_EP) += pcie-designware-ep.o >>> obj-$(CONFIG_PCIE_DW_PLAT) += pcie-designware-plat.o >>> ifneq ($(filter y,$(CONFIG_PCI_DRA7XX_HOST) $(CONFIG_PCI_DRA7XX_EP)),) >>> diff --git a/drivers/pci/dwc/pcie-designware-ecam.c b/drivers/pci/dwc/pcie-designware-ecam.c >>> new file mode 100644 >>> index 000000000000..ede627d7d08b >>> --- /dev/null >>> +++ b/drivers/pci/dwc/pcie-designware-ecam.c >>> @@ -0,0 +1,77 @@ >>> +/* >>> + * Driver for mostly ECAM compatible Synopsys dw PCIe controllers >>> + * configured by the firmware into RC mode >>> + * >>> + * This program is free software; you can redistribute it and/or modify >>> + * it under the terms of the GNU General Public License version 2 as >>> + * published by the Free Software Foundation. >>> + * >>> + * Copyright (C) 2014 ARM Limited >>> + * Copyright (C) 2017 Linaro Limited >>> + * >>> + * Authors: Will Deacon <will.deacon@arm.com> >>> + * Ard Biesheuvel <ard.biesheuvel@linaro.org> >>> + */ >>> + >>> +#include <linux/kernel.h> >>> +#include <linux/init.h> >>> +#include <linux/of_address.h> >>> +#include <linux/of_pci.h> >>> +#include <linux/pci-ecam.h> >>> +#include <linux/platform_device.h> >>> + >>> +static int pci_dw_ecam_config_read(struct pci_bus *bus, u32 devfn, int where, >>> + int size, u32 *val) >>> +{ >>> + struct pci_config_window *cfg = bus->sysdata; >>> + >>> + /* >>> + * The Synopsys dw PCIe controller in RC mode will not filter type 0 >>> + * config TLPs sent to devices 1 and up on its downstream port, >>> + * resulting in devices appearing multiple times on bus 0 unless we >>> + * filter them here. >>> + */ >>> + if (bus->number == cfg->busr.start && PCI_SLOT(devfn) > 0) { >> >> Trivial, but maybe you could factor out this test? We already have >> these functions that do basically the same thing and it'd be nice to >> use a similar pattern (altera and dw also check for the link being up, >> which seems racy and possibly bogus to me): >> >> altera_pcie_valid_device() >> dw_pcie_valid_device() >> rockchip_pcie_valid_device() >> This is rather difficult to factor out, I'm afraid: static bool altera_pcie_valid_device(struct altera_pcie *pcie, struct pci_bus *bus, int dev) static int dw_pcie_valid_device(struct pcie_port *pp, struct pci_bus *bus, int dev) static int rockchip_pcie_valid_device(struct rockchip_pcie *rockchip, struct pci_bus *bus, int dev) They all use different struct types to describe the RC, and the fact that they model a root port means the type0 TLP filter should be applied to bus 1 not bus 0. So I agree there is some similarity between these, but not as much with the driver I am proposing. >> The fact that altera and rockchip do essentially the same thing as dw >> here suggests that this pattern is not limited to DesignWare. >> No. >> These other functions also do something similar, though not structured >> the same way: >> >> hisi_pcie_rd_conf() >> advk_pcie_rd_conf() >> thunder_pem_bridge_read() >> rcar_pcie_config_access() >> gapspci_config_access() >> > > I can look into that. > I think only hisi_pcie_rd_conf() comes close to what I need to do in this driver, and this is not surprising given that it uses Synopsys IP as well. I would like to replace that entirely with this driver at some point, but for now I'd like to proceed with Marvell Armada 8k and Socionext Synquacer only, given that those are the only ones I can actually test myself. So what I will do is respin the patch as an extension to pci-host-generic, so we'll have something to poke at, and perhaps you could give some more detailed guidance as to how to refactor these existing routines. Thanks, Ard.
On Fri, Oct 06, 2017 at 03:52:03PM +0100, Ard Biesheuvel wrote: > On 28 September 2017 at 16:51, Ard Biesheuvel <ard.biesheuvel@linaro.org> wrote: > > On 26 September 2017 at 10:32, Bjorn Helgaas <helgaas@kernel.org> wrote: > >> [+cc Will] > >> > >> On Mon, Aug 28, 2017 at 07:04:36PM +0100, Ard Biesheuvel wrote: > >>> Some implementations of the Synopsys Designware PCIe controller implement > >>> a so-called ECAM shift mode, which allows a static memory window to be > >>> configured that covers the configuration space of the entire bus range. > >>> > >>> If the firmware performs all the low level configuration that is required > >>> to expose this controller in a fully ECAM compatible manner, we can > >>> simply describe it as "pci-host-ecam-generic" and be done with it. > >>> However, it appears that in some cases (one of which is the Armada 80x0), > >>> the IP is synthesized with an ATU window size that does not allow the > >>> first bus to be mapped in a way that prevents the device on the > >>> downstream port from appearing more than once. > >>> > >>> So implement a driver that relies on the firmware to perform all low > >>> level initialization, and drives the controller in ECAM mode, but > >>> overrides the config space accessors to take the above quirk into > >>> account. > >>> > >>> Note that, unlike most drivers for this IP, this driver does not expose > >>> a fake bridge device at B/D/F 00:00.0. There is no point in doing so, > >>> given that this is not a true bridge, and does not require any windows > >>> to be configured in order for the downstream device to operate correctly. > >>> Omitting it also prevents the PCI resource allocation routines from > >>> handing out BAR space to it unnecessarily. > >> > >> This is a tangent, but does this mean the other drivers do not need to > >> expose a fake 00:00.0 device either? > >> > > > > To be honest, I am not so sure anymore. I am seeing some issues in > > ASPM code making the assumption that any device which is not a root > > port has a parent. If this is mandated by the spec, I guess there > > isn't a whole lot we can do except expose a fake root port on b/d/f > > 0/0/0. This used to work fine, though, and I have to confirm whether > > the issues I am seeing currently are due to different hardware or > > changes in the software. > > > > OK, so the issue was new because I hadn't tried using a PCIe switch > before, and you have already queued the fix to make the ASPM code deal > with that. > > So I think it /would/ be better for the other drivers to not bother > mocking up the root port, and simply expose the downstream device as > B/D/F 0/0/0 (assuming the bus range starts at 0). > > It really looks like Altera, Aardvark, Sigma, etc are all in the same > boat here, and need to > a) filter type 0 config TLPs to avoid the downstream device to appear > 32 times, and > b) mangle config space accesses to the 'root port' to hide BARs that > have different meanings in this context (the size of the inbound > window), in order to prevent the PCI resource allocation routines to > waste huge amounts of BAR space on them. I don't know what to do about this. Obviously it's not your problem to clean this up. I don't know anything about the topology of those systems. If the ASPM thing was the only issue, we can probably fix that. Of course, that means no device connected to the link from those RCs could use ASPM (maybe that's the case anyway with the mocked-up root ports). > >>> +static int pci_dw_ecam_config_read(struct pci_bus *bus, u32 devfn, int where, > >>> + int size, u32 *val) > >>> +{ > >>> + struct pci_config_window *cfg = bus->sysdata; > >>> + > >>> + /* > >>> + * The Synopsys dw PCIe controller in RC mode will not filter type 0 > >>> + * config TLPs sent to devices 1 and up on its downstream port, > >>> + * resulting in devices appearing multiple times on bus 0 unless we > >>> + * filter them here. > >>> + */ > >>> + if (bus->number == cfg->busr.start && PCI_SLOT(devfn) > 0) { > >> > >> Trivial, but maybe you could factor out this test? We already have > >> these functions that do basically the same thing and it'd be nice to > >> use a similar pattern (altera and dw also check for the link being up, > >> which seems racy and possibly bogus to me): > >> > >> altera_pcie_valid_device() > >> dw_pcie_valid_device() > >> rockchip_pcie_valid_device() > >> > > This is rather difficult to factor out, I'm afraid: > > static bool altera_pcie_valid_device(struct altera_pcie *pcie, > struct pci_bus *bus, int dev) > > static int dw_pcie_valid_device(struct pcie_port *pp, struct pci_bus *bus, > int dev) > > static int rockchip_pcie_valid_device(struct rockchip_pcie *rockchip, > struct pci_bus *bus, int dev) > > They all use different struct types to describe the RC, and the fact > that they model a root port means the type0 TLP filter should be > applied to bus 1 not bus 0. > So I agree there is some similarity between these, but not as much > with the driver I am proposing. Sorry, I didn't mean to factor all these out into a single routine; I just meant maybe we could add a pci_dw_valid_device() with a structure similar to those I mentioned. > >> The fact that altera and rockchip do essentially the same thing as dw > >> here suggests that this pattern is not limited to DesignWare. > >> > > No. > >> These other functions also do something similar, though not structured > >> the same way: > >> > >> hisi_pcie_rd_conf() > >> advk_pcie_rd_conf() > >> thunder_pem_bridge_read() > >> rcar_pcie_config_access() > >> gapspci_config_access() > >> > > > > I can look into that. > > > > I think only hisi_pcie_rd_conf() comes close to what I need to do in > this driver, and this is not surprising given that it uses Synopsys IP > as well. I would like to replace that entirely with this driver at > some point, but for now I'd like to proceed with Marvell Armada 8k and > Socionext Synquacer only, given that those are the only ones I can > actually test myself. Sorry again, more unclear communication on my part. I don't think we can easily factor these things out; I was really just making the observation that these all look pretty similar and it would be good to make this new driver look as similar to the existing ones as possible. Bjorn
On 6 October 2017 at 23:45, Bjorn Helgaas <helgaas@kernel.org> wrote: > On Fri, Oct 06, 2017 at 03:52:03PM +0100, Ard Biesheuvel wrote: >> On 28 September 2017 at 16:51, Ard Biesheuvel <ard.biesheuvel@linaro.org> wrote: >> > On 26 September 2017 at 10:32, Bjorn Helgaas <helgaas@kernel.org> wrote: >> >> [+cc Will] >> >> >> >> On Mon, Aug 28, 2017 at 07:04:36PM +0100, Ard Biesheuvel wrote: >> >>> Some implementations of the Synopsys Designware PCIe controller implement >> >>> a so-called ECAM shift mode, which allows a static memory window to be >> >>> configured that covers the configuration space of the entire bus range. >> >>> >> >>> If the firmware performs all the low level configuration that is required >> >>> to expose this controller in a fully ECAM compatible manner, we can >> >>> simply describe it as "pci-host-ecam-generic" and be done with it. >> >>> However, it appears that in some cases (one of which is the Armada 80x0), >> >>> the IP is synthesized with an ATU window size that does not allow the >> >>> first bus to be mapped in a way that prevents the device on the >> >>> downstream port from appearing more than once. >> >>> >> >>> So implement a driver that relies on the firmware to perform all low >> >>> level initialization, and drives the controller in ECAM mode, but >> >>> overrides the config space accessors to take the above quirk into >> >>> account. >> >>> >> >>> Note that, unlike most drivers for this IP, this driver does not expose >> >>> a fake bridge device at B/D/F 00:00.0. There is no point in doing so, >> >>> given that this is not a true bridge, and does not require any windows >> >>> to be configured in order for the downstream device to operate correctly. >> >>> Omitting it also prevents the PCI resource allocation routines from >> >>> handing out BAR space to it unnecessarily. >> >> >> >> This is a tangent, but does this mean the other drivers do not need to >> >> expose a fake 00:00.0 device either? >> >> >> > >> > To be honest, I am not so sure anymore. I am seeing some issues in >> > ASPM code making the assumption that any device which is not a root >> > port has a parent. If this is mandated by the spec, I guess there >> > isn't a whole lot we can do except expose a fake root port on b/d/f >> > 0/0/0. This used to work fine, though, and I have to confirm whether >> > the issues I am seeing currently are due to different hardware or >> > changes in the software. >> > >> >> OK, so the issue was new because I hadn't tried using a PCIe switch >> before, and you have already queued the fix to make the ASPM code deal >> with that. >> >> So I think it /would/ be better for the other drivers to not bother >> mocking up the root port, and simply expose the downstream device as >> B/D/F 0/0/0 (assuming the bus range starts at 0). >> >> It really looks like Altera, Aardvark, Sigma, etc are all in the same >> boat here, and need to >> a) filter type 0 config TLPs to avoid the downstream device to appear >> 32 times, and >> b) mangle config space accesses to the 'root port' to hide BARs that >> have different meanings in this context (the size of the inbound >> window), in order to prevent the PCI resource allocation routines to >> waste huge amounts of BAR space on them. > > I don't know what to do about this. Obviously it's not your problem > to clean this up. > > I don't know anything about the topology of those systems. If the > ASPM thing was the only issue, we can probably fix that. Of course, > that means no device connected to the link from those RCs could use > ASPM (maybe that's the case anyway with the mocked-up root ports). > That may be the answer, although I am not sure. The limited Synopsys documentation I have access to does list 'L0s and L1 ASPM support; software L1 and L2 support' as a feature, and what they expose as the root port is actually a set of PCIe config registers that are in the MMIO region of the controller (but cannot be remapped statically in the ECAM space). But the same MMIO region has a BAR to configure the inbound window, and has bridge BARs that can be programmed but don't actually affect what gets passed onto the link. The almost-ECAM mode is much more appealing for the use cases I am involved with, and losing ASPM is no big deal, so I'd rather not use the dwc/ drivers if I can avoid it. >> >>> +static int pci_dw_ecam_config_read(struct pci_bus *bus, u32 devfn, int where, >> >>> + int size, u32 *val) >> >>> +{ >> >>> + struct pci_config_window *cfg = bus->sysdata; >> >>> + >> >>> + /* >> >>> + * The Synopsys dw PCIe controller in RC mode will not filter type 0 >> >>> + * config TLPs sent to devices 1 and up on its downstream port, >> >>> + * resulting in devices appearing multiple times on bus 0 unless we >> >>> + * filter them here. >> >>> + */ >> >>> + if (bus->number == cfg->busr.start && PCI_SLOT(devfn) > 0) { >> >> >> >> Trivial, but maybe you could factor out this test? We already have >> >> these functions that do basically the same thing and it'd be nice to >> >> use a similar pattern (altera and dw also check for the link being up, >> >> which seems racy and possibly bogus to me): >> >> >> >> altera_pcie_valid_device() >> >> dw_pcie_valid_device() >> >> rockchip_pcie_valid_device() >> >> >> >> This is rather difficult to factor out, I'm afraid: >> >> static bool altera_pcie_valid_device(struct altera_pcie *pcie, >> struct pci_bus *bus, int dev) >> >> static int dw_pcie_valid_device(struct pcie_port *pp, struct pci_bus *bus, >> int dev) >> >> static int rockchip_pcie_valid_device(struct rockchip_pcie *rockchip, >> struct pci_bus *bus, int dev) >> >> They all use different struct types to describe the RC, and the fact >> that they model a root port means the type0 TLP filter should be >> applied to bus 1 not bus 0. >> So I agree there is some similarity between these, but not as much >> with the driver I am proposing. > > Sorry, I didn't mean to factor all these out into a single routine; I > just meant maybe we could add a pci_dw_valid_device() with a structure > similar to those I mentioned. > >> >> The fact that altera and rockchip do essentially the same thing as dw >> >> here suggests that this pattern is not limited to DesignWare. >> >> >> >> No. >> >> These other functions also do something similar, though not structured >> >> the same way: >> >> >> >> hisi_pcie_rd_conf() >> >> advk_pcie_rd_conf() >> >> thunder_pem_bridge_read() >> >> rcar_pcie_config_access() >> >> gapspci_config_access() >> >> >> > >> > I can look into that. >> > >> >> I think only hisi_pcie_rd_conf() comes close to what I need to do in >> this driver, and this is not surprising given that it uses Synopsys IP >> as well. I would like to replace that entirely with this driver at >> some point, but for now I'd like to proceed with Marvell Armada 8k and >> Socionext Synquacer only, given that those are the only ones I can >> actually test myself. > > Sorry again, more unclear communication on my part. I don't think we > can easily factor these things out; I was really just making the > observation that these all look pretty similar and it would be good to > make this new driver look as similar to the existing ones as possible. > OK, fair enough. I took Will's advice and extended the pci-host-generic driver instead, but I'm happy to do another round if necessary.
diff --git a/drivers/pci/dwc/Kconfig b/drivers/pci/dwc/Kconfig index d275aadc47ee..477576d07911 100644 --- a/drivers/pci/dwc/Kconfig +++ b/drivers/pci/dwc/Kconfig @@ -169,4 +169,15 @@ config PCIE_KIRIN Say Y here if you want PCIe controller support on HiSilicon Kirin series SoCs. +config PCIE_DW_HOST_ECAM + bool "Synopsys DesignWare PCIe controller in ECAM mode" + depends on OF && PCI + select PCI_HOST_COMMON + select IRQ_DOMAIN + help + Add support for Synopsys DesignWare PCIe controllers configured + by the firmware into ECAM shift mode. In some cases, these are + fully ECAM compliant, in which case the pci-host-generic driver + may be used instead. + endmenu diff --git a/drivers/pci/dwc/Makefile b/drivers/pci/dwc/Makefile index c61be9738cce..7d5a23e5b767 100644 --- a/drivers/pci/dwc/Makefile +++ b/drivers/pci/dwc/Makefile @@ -1,5 +1,6 @@ obj-$(CONFIG_PCIE_DW) += pcie-designware.o obj-$(CONFIG_PCIE_DW_HOST) += pcie-designware-host.o +obj-$(CONFIG_PCIE_DW_HOST_ECAM) += pcie-designware-ecam.o obj-$(CONFIG_PCIE_DW_EP) += pcie-designware-ep.o obj-$(CONFIG_PCIE_DW_PLAT) += pcie-designware-plat.o ifneq ($(filter y,$(CONFIG_PCI_DRA7XX_HOST) $(CONFIG_PCI_DRA7XX_EP)),) diff --git a/drivers/pci/dwc/pcie-designware-ecam.c b/drivers/pci/dwc/pcie-designware-ecam.c new file mode 100644 index 000000000000..ede627d7d08b --- /dev/null +++ b/drivers/pci/dwc/pcie-designware-ecam.c @@ -0,0 +1,77 @@ +/* + * Driver for mostly ECAM compatible Synopsys dw PCIe controllers + * configured by the firmware into RC mode + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Copyright (C) 2014 ARM Limited + * Copyright (C) 2017 Linaro Limited + * + * Authors: Will Deacon <will.deacon@arm.com> + * Ard Biesheuvel <ard.biesheuvel@linaro.org> + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/of_address.h> +#include <linux/of_pci.h> +#include <linux/pci-ecam.h> +#include <linux/platform_device.h> + +static int pci_dw_ecam_config_read(struct pci_bus *bus, u32 devfn, int where, + int size, u32 *val) +{ + struct pci_config_window *cfg = bus->sysdata; + + /* + * The Synopsys dw PCIe controller in RC mode will not filter type 0 + * config TLPs sent to devices 1 and up on its downstream port, + * resulting in devices appearing multiple times on bus 0 unless we + * filter them here. + */ + if (bus->number == cfg->busr.start && PCI_SLOT(devfn) > 0) { + *val = 0xffffffff; + return PCIBIOS_DEVICE_NOT_FOUND; + } + return pci_generic_config_read(bus, devfn, where, size, val); +} + +static int pci_dw_ecam_config_write(struct pci_bus *bus, u32 devfn, int where, + int size, u32 val) +{ + struct pci_config_window *cfg = bus->sysdata; + + if (bus->number == cfg->busr.start && PCI_SLOT(devfn) > 0) + return PCIBIOS_DEVICE_NOT_FOUND; + + return pci_generic_config_write(bus, devfn, where, size, val); +} + +static struct pci_ecam_ops pci_dw_ecam_bus_ops = { + .pci_ops.map_bus = pci_ecam_map_bus, + .pci_ops.read = pci_dw_ecam_config_read, + .pci_ops.write = pci_dw_ecam_config_write, + .bus_shift = 20, +}; + +static const struct of_device_id pci_dw_ecam_of_match[] = { + { .compatible = "marvell,armada8k-pcie-ecam" }, + { .compatible = "socionext,synquacer-pcie-ecam" }, + { .compatible = "snps,dw-pcie-ecam" }, + { }, +}; + +static int pci_dw_ecam_probe(struct platform_device *pdev) +{ + return pci_host_common_probe(pdev, &pci_dw_ecam_bus_ops); +} + +static struct platform_driver pci_dw_ecam_driver = { + .driver.name = "pcie-designware-ecam", + .driver.of_match_table = pci_dw_ecam_of_match, + .driver.suppress_bind_attrs = true, + .probe = pci_dw_ecam_probe, +}; +builtin_platform_driver(pci_dw_ecam_driver);
Some implementations of the Synopsys Designware PCIe controller implement a so-called ECAM shift mode, which allows a static memory window to be configured that covers the configuration space of the entire bus range. If the firmware performs all the low level configuration that is required to expose this controller in a fully ECAM compatible manner, we can simply describe it as "pci-host-ecam-generic" and be done with it. However, it appears that in some cases (one of which is the Armada 80x0), the IP is synthesized with an ATU window size that does not allow the first bus to be mapped in a way that prevents the device on the downstream port from appearing more than once. So implement a driver that relies on the firmware to perform all low level initialization, and drives the controller in ECAM mode, but overrides the config space accessors to take the above quirk into account. Note that, unlike most drivers for this IP, this driver does not expose a fake bridge device at B/D/F 00:00.0. There is no point in doing so, given that this is not a true bridge, and does not require any windows to be configured in order for the downstream device to operate correctly. Omitting it also prevents the PCI resource allocation routines from handing out BAR space to it unnecessarily. Cc: Bjorn Helgaas <bhelgaas@google.com> Cc: Jingoo Han <jingoohan1@gmail.com> Cc: Joao Pinto <Joao.Pinto@synopsys.com> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> --- drivers/pci/dwc/Kconfig | 11 +++ drivers/pci/dwc/Makefile | 1 + drivers/pci/dwc/pcie-designware-ecam.c | 77 ++++++++++++++++++++ 3 files changed, 89 insertions(+)