Re: [RFC PATCH V5 3/5] PCI: Check platform specific ECAM quirks
On Tuesday, September 6, 2016 7:49:49 PM CEST Tomasz Nowicki wrote: > On 05.09.2016 04:25, Bjorn Helgaas wrote: > > On Mon, Aug 08, 2016 at 03:05:39PM +0200, Tomasz Nowicki wrote: > >> Some platforms may not be fully compliant with generic set of PCI config > >> accessors. For these cases we implement the way to overwrite accessors > >> set. Algorithm traverses available quirk list (static array), > >> matches againstand > >> returns pci_config_window structure with fancy PCI config ops. > >> oem_id, oem_table_id and rev come from MCFG table standard header. > >> > >> It is possible to define custom init call which is responsible for > >> setting up PCI configuration access accordingly to quirk requirements. > >> If custom init call is not defined, use standard > >> pci_acpi_setup_ecam_mapping(). > >> > >> pci_generic_ecam_ops will be used for platforms free from quirks. > >> > >> Signed-off-by: Tomasz Nowicki > >> Signed-off-by: Dongdong Liu > >> Signed-off-by: Christopher Covington > >> --- > >> drivers/pci/host/Makefile | 1 + > >> drivers/pci/host/mcfg-quirks.c | 86 > >> ++ > >> drivers/pci/host/mcfg-quirks.h | 20 ++ > >> include/linux/pci-acpi.h | 2 + > >> 4 files changed, 109 insertions(+) > >> create mode 100644 drivers/pci/host/mcfg-quirks.c > >> create mode 100644 drivers/pci/host/mcfg-quirks.h > > > > If the object is to work around defects in the ACPI MCFG table, I > > think I'd put the quirks closer to drivers/acpi/pci_mcfg.c, where we > > parse that table. What if we actually put them directly *in* > > drivers/acpi/pci_mcfg.c? > > Then we need to export quirk init calls or ecam ops from > drivers/pci/host/* directory. > > Currently we keep mcfg quirk handling code and related drivers in one > place drivers/pci/host/ I think that's the wrong place to have it, it just leads to people trying to share code with the host drivers in that directory, which hasn't really worked out so far, it just adds complexity. Arnd
Re: [RFC PATCH V5 3/5] PCI: Check platform specific ECAM quirks
On Tuesday, September 6, 2016 7:49:49 PM CEST Tomasz Nowicki wrote: > On 05.09.2016 04:25, Bjorn Helgaas wrote: > > On Mon, Aug 08, 2016 at 03:05:39PM +0200, Tomasz Nowicki wrote: > >> Some platforms may not be fully compliant with generic set of PCI config > >> accessors. For these cases we implement the way to overwrite accessors > >> set. Algorithm traverses available quirk list (static array), > >> matches against and > >> returns pci_config_window structure with fancy PCI config ops. > >> oem_id, oem_table_id and rev come from MCFG table standard header. > >> > >> It is possible to define custom init call which is responsible for > >> setting up PCI configuration access accordingly to quirk requirements. > >> If custom init call is not defined, use standard > >> pci_acpi_setup_ecam_mapping(). > >> > >> pci_generic_ecam_ops will be used for platforms free from quirks. > >> > >> Signed-off-by: Tomasz Nowicki > >> Signed-off-by: Dongdong Liu > >> Signed-off-by: Christopher Covington > >> --- > >> drivers/pci/host/Makefile | 1 + > >> drivers/pci/host/mcfg-quirks.c | 86 > >> ++ > >> drivers/pci/host/mcfg-quirks.h | 20 ++ > >> include/linux/pci-acpi.h | 2 + > >> 4 files changed, 109 insertions(+) > >> create mode 100644 drivers/pci/host/mcfg-quirks.c > >> create mode 100644 drivers/pci/host/mcfg-quirks.h > > > > If the object is to work around defects in the ACPI MCFG table, I > > think I'd put the quirks closer to drivers/acpi/pci_mcfg.c, where we > > parse that table. What if we actually put them directly *in* > > drivers/acpi/pci_mcfg.c? > > Then we need to export quirk init calls or ecam ops from > drivers/pci/host/* directory. > > Currently we keep mcfg quirk handling code and related drivers in one > place drivers/pci/host/ I think that's the wrong place to have it, it just leads to people trying to share code with the host drivers in that directory, which hasn't really worked out so far, it just adds complexity. Arnd
Re: [RFC PATCH V5 3/5] PCI: Check platform specific ECAM quirks
On 05.09.2016 04:25, Bjorn Helgaas wrote: On Mon, Aug 08, 2016 at 03:05:39PM +0200, Tomasz Nowicki wrote: Some platforms may not be fully compliant with generic set of PCI config accessors. For these cases we implement the way to overwrite accessors set. Algorithm traverses available quirk list (static array), matches againstand returns pci_config_window structure with fancy PCI config ops. oem_id, oem_table_id and rev come from MCFG table standard header. It is possible to define custom init call which is responsible for setting up PCI configuration access accordingly to quirk requirements. If custom init call is not defined, use standard pci_acpi_setup_ecam_mapping(). pci_generic_ecam_ops will be used for platforms free from quirks. Signed-off-by: Tomasz Nowicki Signed-off-by: Dongdong Liu Signed-off-by: Christopher Covington --- drivers/pci/host/Makefile | 1 + drivers/pci/host/mcfg-quirks.c | 86 ++ drivers/pci/host/mcfg-quirks.h | 20 ++ include/linux/pci-acpi.h | 2 + 4 files changed, 109 insertions(+) create mode 100644 drivers/pci/host/mcfg-quirks.c create mode 100644 drivers/pci/host/mcfg-quirks.h If the object is to work around defects in the ACPI MCFG table, I think I'd put the quirks closer to drivers/acpi/pci_mcfg.c, where we parse that table. What if we actually put them directly *in* drivers/acpi/pci_mcfg.c? Then we need to export quirk init calls or ecam ops from drivers/pci/host/* directory. Currently we keep mcfg quirk handling code and related drivers in one place drivers/pci/host/ Tomasz
Re: [RFC PATCH V5 3/5] PCI: Check platform specific ECAM quirks
On 05.09.2016 04:25, Bjorn Helgaas wrote: On Mon, Aug 08, 2016 at 03:05:39PM +0200, Tomasz Nowicki wrote: Some platforms may not be fully compliant with generic set of PCI config accessors. For these cases we implement the way to overwrite accessors set. Algorithm traverses available quirk list (static array), matches against and returns pci_config_window structure with fancy PCI config ops. oem_id, oem_table_id and rev come from MCFG table standard header. It is possible to define custom init call which is responsible for setting up PCI configuration access accordingly to quirk requirements. If custom init call is not defined, use standard pci_acpi_setup_ecam_mapping(). pci_generic_ecam_ops will be used for platforms free from quirks. Signed-off-by: Tomasz Nowicki Signed-off-by: Dongdong Liu Signed-off-by: Christopher Covington --- drivers/pci/host/Makefile | 1 + drivers/pci/host/mcfg-quirks.c | 86 ++ drivers/pci/host/mcfg-quirks.h | 20 ++ include/linux/pci-acpi.h | 2 + 4 files changed, 109 insertions(+) create mode 100644 drivers/pci/host/mcfg-quirks.c create mode 100644 drivers/pci/host/mcfg-quirks.h If the object is to work around defects in the ACPI MCFG table, I think I'd put the quirks closer to drivers/acpi/pci_mcfg.c, where we parse that table. What if we actually put them directly *in* drivers/acpi/pci_mcfg.c? Then we need to export quirk init calls or ecam ops from drivers/pci/host/* directory. Currently we keep mcfg quirk handling code and related drivers in one place drivers/pci/host/ Tomasz
Re: [RFC PATCH V5 3/5] PCI: Check platform specific ECAM quirks
On Mon, Aug 08, 2016 at 03:05:39PM +0200, Tomasz Nowicki wrote: > Some platforms may not be fully compliant with generic set of PCI config > accessors. For these cases we implement the way to overwrite accessors > set. Algorithm traverses available quirk list (static array), > matches againstand > returns pci_config_window structure with fancy PCI config ops. > oem_id, oem_table_id and rev come from MCFG table standard header. > > It is possible to define custom init call which is responsible for > setting up PCI configuration access accordingly to quirk requirements. > If custom init call is not defined, use standard > pci_acpi_setup_ecam_mapping(). > > pci_generic_ecam_ops will be used for platforms free from quirks. > > Signed-off-by: Tomasz Nowicki > Signed-off-by: Dongdong Liu > Signed-off-by: Christopher Covington > --- > drivers/pci/host/Makefile | 1 + > drivers/pci/host/mcfg-quirks.c | 86 > ++ > drivers/pci/host/mcfg-quirks.h | 20 ++ > include/linux/pci-acpi.h | 2 + > 4 files changed, 109 insertions(+) > create mode 100644 drivers/pci/host/mcfg-quirks.c > create mode 100644 drivers/pci/host/mcfg-quirks.h > > diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile > index 8843410..500cf78 100644 > --- a/drivers/pci/host/Makefile > +++ b/drivers/pci/host/Makefile > @@ -31,3 +31,4 @@ obj-$(CONFIG_PCI_HOST_THUNDER_ECAM) += pci-thunder-ecam.o > obj-$(CONFIG_PCI_HOST_THUNDER_PEM) += pci-thunder-pem.o > obj-$(CONFIG_PCIE_ARMADA_8K) += pcie-armada8k.o > obj-$(CONFIG_PCIE_ARTPEC6) += pcie-artpec6.o > +obj-$(CONFIG_ACPI_MCFG) += mcfg-quirks.o > diff --git a/drivers/pci/host/mcfg-quirks.c b/drivers/pci/host/mcfg-quirks.c > new file mode 100644 > index 000..aa9907b > --- /dev/null > +++ b/drivers/pci/host/mcfg-quirks.c > @@ -0,0 +1,86 @@ > +/* > + * Copyright (C) 2016 Semihalf > + * Author: Tomasz Nowicki > + * > + * 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 (the "GPL"). > + * > + * This program is distributed in the hope that it will be useful, but > + * WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * General Public License version 2 (GPLv2) for more details. > + * > + * You should have received a copy of the GNU General Public License > + * version 2 (GPLv2) along with this source code. > + */ > + > +#include > +#include > +#include > +#include > +#include > + > +#include "mcfg-quirks.h" > + > +struct pci_cfg_fixup { > + char oem_id[ACPI_OEM_ID_SIZE + 1]; > + char oem_table_id[ACPI_OEM_TABLE_ID_SIZE + 1]; > + u32 oem_revision; > + struct resource domain_range; > + struct resource bus_range; > + struct pci_ops *ops; > + struct pci_config_window *(*init)(struct acpi_pci_root *root, > + struct pci_ops *ops); > +}; > + > +#define MCFG_DOM_RANGE(start, end) DEFINE_RES_NAMED((start), \ > + ((end) - (start) + 1), NULL, 0) > +#define MCFG_DOM_ANY MCFG_DOM_RANGE(0x0, 0x) > +#define MCFG_BUS_RANGE(start, end) DEFINE_RES_NAMED((start), \ > + ((end) - (start) + 1), \ > + NULL, IORESOURCE_BUS) > +#define MCFG_BUS_ANY MCFG_BUS_RANGE(0x0, 0xff) > + > +static struct pci_cfg_fixup mcfg_quirks[] __initconst = { > +/* { OEM_ID, OEM_TABLE_ID, REV, DOMAIN, BUS_RANGE, pci_ops, init_hook }, */ > +}; > + > +static bool pci_mcfg_fixup_match(struct pci_cfg_fixup *f, > + struct acpi_table_header *mcfg_header) > +{ > + return (!memcmp(f->oem_id, mcfg_header->oem_id, ACPI_OEM_ID_SIZE) && > + !memcmp(f->oem_table_id, mcfg_header->oem_table_id, > + ACPI_OEM_TABLE_ID_SIZE) && > + f->oem_revision == mcfg_header->oem_revision); > +} > + > +struct pci_config_window *pci_mcfg_match_quirks(struct acpi_pci_root *root) > +{ > + struct resource dom_res = MCFG_DOM_RANGE(root->segment, root->segment); > + struct resource *bus_res = >secondary; > + struct pci_cfg_fixup *f = mcfg_quirks; > + struct acpi_table_header *mcfg_header; > + acpi_status status; > + int i; > + > + status = acpi_get_table(ACPI_SIG_MCFG, 0, _header); > + if (ACPI_FAILURE(status)) > + return NULL; I remember working out why pci_mcfg_parse() has to cache the data from MCFG, but I don't remember the actual reason... a comment there would have been helpful. Anyway, now I wonder why it's OK to call acpi_get_table(ACPI_SIG_MCFG) again here. I
Re: [RFC PATCH V5 3/5] PCI: Check platform specific ECAM quirks
On Mon, Aug 08, 2016 at 03:05:39PM +0200, Tomasz Nowicki wrote: > Some platforms may not be fully compliant with generic set of PCI config > accessors. For these cases we implement the way to overwrite accessors > set. Algorithm traverses available quirk list (static array), > matches against and > returns pci_config_window structure with fancy PCI config ops. > oem_id, oem_table_id and rev come from MCFG table standard header. > > It is possible to define custom init call which is responsible for > setting up PCI configuration access accordingly to quirk requirements. > If custom init call is not defined, use standard > pci_acpi_setup_ecam_mapping(). > > pci_generic_ecam_ops will be used for platforms free from quirks. > > Signed-off-by: Tomasz Nowicki > Signed-off-by: Dongdong Liu > Signed-off-by: Christopher Covington > --- > drivers/pci/host/Makefile | 1 + > drivers/pci/host/mcfg-quirks.c | 86 > ++ > drivers/pci/host/mcfg-quirks.h | 20 ++ > include/linux/pci-acpi.h | 2 + > 4 files changed, 109 insertions(+) > create mode 100644 drivers/pci/host/mcfg-quirks.c > create mode 100644 drivers/pci/host/mcfg-quirks.h > > diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile > index 8843410..500cf78 100644 > --- a/drivers/pci/host/Makefile > +++ b/drivers/pci/host/Makefile > @@ -31,3 +31,4 @@ obj-$(CONFIG_PCI_HOST_THUNDER_ECAM) += pci-thunder-ecam.o > obj-$(CONFIG_PCI_HOST_THUNDER_PEM) += pci-thunder-pem.o > obj-$(CONFIG_PCIE_ARMADA_8K) += pcie-armada8k.o > obj-$(CONFIG_PCIE_ARTPEC6) += pcie-artpec6.o > +obj-$(CONFIG_ACPI_MCFG) += mcfg-quirks.o > diff --git a/drivers/pci/host/mcfg-quirks.c b/drivers/pci/host/mcfg-quirks.c > new file mode 100644 > index 000..aa9907b > --- /dev/null > +++ b/drivers/pci/host/mcfg-quirks.c > @@ -0,0 +1,86 @@ > +/* > + * Copyright (C) 2016 Semihalf > + * Author: Tomasz Nowicki > + * > + * 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 (the "GPL"). > + * > + * This program is distributed in the hope that it will be useful, but > + * WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * General Public License version 2 (GPLv2) for more details. > + * > + * You should have received a copy of the GNU General Public License > + * version 2 (GPLv2) along with this source code. > + */ > + > +#include > +#include > +#include > +#include > +#include > + > +#include "mcfg-quirks.h" > + > +struct pci_cfg_fixup { > + char oem_id[ACPI_OEM_ID_SIZE + 1]; > + char oem_table_id[ACPI_OEM_TABLE_ID_SIZE + 1]; > + u32 oem_revision; > + struct resource domain_range; > + struct resource bus_range; > + struct pci_ops *ops; > + struct pci_config_window *(*init)(struct acpi_pci_root *root, > + struct pci_ops *ops); > +}; > + > +#define MCFG_DOM_RANGE(start, end) DEFINE_RES_NAMED((start), \ > + ((end) - (start) + 1), NULL, 0) > +#define MCFG_DOM_ANY MCFG_DOM_RANGE(0x0, 0x) > +#define MCFG_BUS_RANGE(start, end) DEFINE_RES_NAMED((start), \ > + ((end) - (start) + 1), \ > + NULL, IORESOURCE_BUS) > +#define MCFG_BUS_ANY MCFG_BUS_RANGE(0x0, 0xff) > + > +static struct pci_cfg_fixup mcfg_quirks[] __initconst = { > +/* { OEM_ID, OEM_TABLE_ID, REV, DOMAIN, BUS_RANGE, pci_ops, init_hook }, */ > +}; > + > +static bool pci_mcfg_fixup_match(struct pci_cfg_fixup *f, > + struct acpi_table_header *mcfg_header) > +{ > + return (!memcmp(f->oem_id, mcfg_header->oem_id, ACPI_OEM_ID_SIZE) && > + !memcmp(f->oem_table_id, mcfg_header->oem_table_id, > + ACPI_OEM_TABLE_ID_SIZE) && > + f->oem_revision == mcfg_header->oem_revision); > +} > + > +struct pci_config_window *pci_mcfg_match_quirks(struct acpi_pci_root *root) > +{ > + struct resource dom_res = MCFG_DOM_RANGE(root->segment, root->segment); > + struct resource *bus_res = >secondary; > + struct pci_cfg_fixup *f = mcfg_quirks; > + struct acpi_table_header *mcfg_header; > + acpi_status status; > + int i; > + > + status = acpi_get_table(ACPI_SIG_MCFG, 0, _header); > + if (ACPI_FAILURE(status)) > + return NULL; I remember working out why pci_mcfg_parse() has to cache the data from MCFG, but I don't remember the actual reason... a comment there would have been helpful. Anyway, now I wonder why it's OK to call acpi_get_table(ACPI_SIG_MCFG) again here. I guess I'd be inclined to just cache the OEM info along with the rest of the data so you don't have to get the table again here. > +
Re: [RFC PATCH V5 3/5] PCI: Check platform specific ECAM quirks
On Mon, Aug 08, 2016 at 03:05:39PM +0200, Tomasz Nowicki wrote: > Some platforms may not be fully compliant with generic set of PCI config > accessors. For these cases we implement the way to overwrite accessors > set. Algorithm traverses available quirk list (static array), > matches againstand > returns pci_config_window structure with fancy PCI config ops. > oem_id, oem_table_id and rev come from MCFG table standard header. > > It is possible to define custom init call which is responsible for > setting up PCI configuration access accordingly to quirk requirements. > If custom init call is not defined, use standard > pci_acpi_setup_ecam_mapping(). > > pci_generic_ecam_ops will be used for platforms free from quirks. > > Signed-off-by: Tomasz Nowicki > Signed-off-by: Dongdong Liu > Signed-off-by: Christopher Covington > --- > drivers/pci/host/Makefile | 1 + > drivers/pci/host/mcfg-quirks.c | 86 > ++ > drivers/pci/host/mcfg-quirks.h | 20 ++ > include/linux/pci-acpi.h | 2 + > 4 files changed, 109 insertions(+) > create mode 100644 drivers/pci/host/mcfg-quirks.c > create mode 100644 drivers/pci/host/mcfg-quirks.h If the object is to work around defects in the ACPI MCFG table, I think I'd put the quirks closer to drivers/acpi/pci_mcfg.c, where we parse that table. What if we actually put them directly *in* drivers/acpi/pci_mcfg.c? > diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile > index 8843410..500cf78 100644 > --- a/drivers/pci/host/Makefile > +++ b/drivers/pci/host/Makefile > @@ -31,3 +31,4 @@ obj-$(CONFIG_PCI_HOST_THUNDER_ECAM) += pci-thunder-ecam.o > obj-$(CONFIG_PCI_HOST_THUNDER_PEM) += pci-thunder-pem.o > obj-$(CONFIG_PCIE_ARMADA_8K) += pcie-armada8k.o > obj-$(CONFIG_PCIE_ARTPEC6) += pcie-artpec6.o > +obj-$(CONFIG_ACPI_MCFG) += mcfg-quirks.o > diff --git a/drivers/pci/host/mcfg-quirks.c b/drivers/pci/host/mcfg-quirks.c > new file mode 100644 > index 000..aa9907b > --- /dev/null > +++ b/drivers/pci/host/mcfg-quirks.c > @@ -0,0 +1,86 @@ > +/* > + * Copyright (C) 2016 Semihalf > + * Author: Tomasz Nowicki > + * > + * 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 (the "GPL"). > + * > + * This program is distributed in the hope that it will be useful, but > + * WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * General Public License version 2 (GPLv2) for more details. > + * > + * You should have received a copy of the GNU General Public License > + * version 2 (GPLv2) along with this source code. > + */ > + > +#include > +#include > +#include > +#include > +#include > + > +#include "mcfg-quirks.h" > + > +struct pci_cfg_fixup { > + char oem_id[ACPI_OEM_ID_SIZE + 1]; > + char oem_table_id[ACPI_OEM_TABLE_ID_SIZE + 1]; > + u32 oem_revision; > + struct resource domain_range; > + struct resource bus_range; > + struct pci_ops *ops; > + struct pci_config_window *(*init)(struct acpi_pci_root *root, > + struct pci_ops *ops); > +}; > + > +#define MCFG_DOM_RANGE(start, end) DEFINE_RES_NAMED((start), \ > + ((end) - (start) + 1), NULL, 0) > +#define MCFG_DOM_ANY MCFG_DOM_RANGE(0x0, 0x) > +#define MCFG_BUS_RANGE(start, end) DEFINE_RES_NAMED((start), \ > + ((end) - (start) + 1), \ > + NULL, IORESOURCE_BUS) > +#define MCFG_BUS_ANY MCFG_BUS_RANGE(0x0, 0xff) > + > +static struct pci_cfg_fixup mcfg_quirks[] __initconst = { > +/* { OEM_ID, OEM_TABLE_ID, REV, DOMAIN, BUS_RANGE, pci_ops, init_hook }, */ > +}; > + > +static bool pci_mcfg_fixup_match(struct pci_cfg_fixup *f, > + struct acpi_table_header *mcfg_header) > +{ > + return (!memcmp(f->oem_id, mcfg_header->oem_id, ACPI_OEM_ID_SIZE) && > + !memcmp(f->oem_table_id, mcfg_header->oem_table_id, > + ACPI_OEM_TABLE_ID_SIZE) && > + f->oem_revision == mcfg_header->oem_revision); > +} > + > +struct pci_config_window *pci_mcfg_match_quirks(struct acpi_pci_root *root) > +{ > + struct resource dom_res = MCFG_DOM_RANGE(root->segment, root->segment); > + struct resource *bus_res = >secondary; > + struct pci_cfg_fixup *f = mcfg_quirks; > + struct acpi_table_header *mcfg_header; > + acpi_status status; > + int i; > + > + status = acpi_get_table(ACPI_SIG_MCFG, 0, _header); > + if (ACPI_FAILURE(status)) > + return NULL; > + > + /* > + *
Re: [RFC PATCH V5 3/5] PCI: Check platform specific ECAM quirks
On Mon, Aug 08, 2016 at 03:05:39PM +0200, Tomasz Nowicki wrote: > Some platforms may not be fully compliant with generic set of PCI config > accessors. For these cases we implement the way to overwrite accessors > set. Algorithm traverses available quirk list (static array), > matches against and > returns pci_config_window structure with fancy PCI config ops. > oem_id, oem_table_id and rev come from MCFG table standard header. > > It is possible to define custom init call which is responsible for > setting up PCI configuration access accordingly to quirk requirements. > If custom init call is not defined, use standard > pci_acpi_setup_ecam_mapping(). > > pci_generic_ecam_ops will be used for platforms free from quirks. > > Signed-off-by: Tomasz Nowicki > Signed-off-by: Dongdong Liu > Signed-off-by: Christopher Covington > --- > drivers/pci/host/Makefile | 1 + > drivers/pci/host/mcfg-quirks.c | 86 > ++ > drivers/pci/host/mcfg-quirks.h | 20 ++ > include/linux/pci-acpi.h | 2 + > 4 files changed, 109 insertions(+) > create mode 100644 drivers/pci/host/mcfg-quirks.c > create mode 100644 drivers/pci/host/mcfg-quirks.h If the object is to work around defects in the ACPI MCFG table, I think I'd put the quirks closer to drivers/acpi/pci_mcfg.c, where we parse that table. What if we actually put them directly *in* drivers/acpi/pci_mcfg.c? > diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile > index 8843410..500cf78 100644 > --- a/drivers/pci/host/Makefile > +++ b/drivers/pci/host/Makefile > @@ -31,3 +31,4 @@ obj-$(CONFIG_PCI_HOST_THUNDER_ECAM) += pci-thunder-ecam.o > obj-$(CONFIG_PCI_HOST_THUNDER_PEM) += pci-thunder-pem.o > obj-$(CONFIG_PCIE_ARMADA_8K) += pcie-armada8k.o > obj-$(CONFIG_PCIE_ARTPEC6) += pcie-artpec6.o > +obj-$(CONFIG_ACPI_MCFG) += mcfg-quirks.o > diff --git a/drivers/pci/host/mcfg-quirks.c b/drivers/pci/host/mcfg-quirks.c > new file mode 100644 > index 000..aa9907b > --- /dev/null > +++ b/drivers/pci/host/mcfg-quirks.c > @@ -0,0 +1,86 @@ > +/* > + * Copyright (C) 2016 Semihalf > + * Author: Tomasz Nowicki > + * > + * 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 (the "GPL"). > + * > + * This program is distributed in the hope that it will be useful, but > + * WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * General Public License version 2 (GPLv2) for more details. > + * > + * You should have received a copy of the GNU General Public License > + * version 2 (GPLv2) along with this source code. > + */ > + > +#include > +#include > +#include > +#include > +#include > + > +#include "mcfg-quirks.h" > + > +struct pci_cfg_fixup { > + char oem_id[ACPI_OEM_ID_SIZE + 1]; > + char oem_table_id[ACPI_OEM_TABLE_ID_SIZE + 1]; > + u32 oem_revision; > + struct resource domain_range; > + struct resource bus_range; > + struct pci_ops *ops; > + struct pci_config_window *(*init)(struct acpi_pci_root *root, > + struct pci_ops *ops); > +}; > + > +#define MCFG_DOM_RANGE(start, end) DEFINE_RES_NAMED((start), \ > + ((end) - (start) + 1), NULL, 0) > +#define MCFG_DOM_ANY MCFG_DOM_RANGE(0x0, 0x) > +#define MCFG_BUS_RANGE(start, end) DEFINE_RES_NAMED((start), \ > + ((end) - (start) + 1), \ > + NULL, IORESOURCE_BUS) > +#define MCFG_BUS_ANY MCFG_BUS_RANGE(0x0, 0xff) > + > +static struct pci_cfg_fixup mcfg_quirks[] __initconst = { > +/* { OEM_ID, OEM_TABLE_ID, REV, DOMAIN, BUS_RANGE, pci_ops, init_hook }, */ > +}; > + > +static bool pci_mcfg_fixup_match(struct pci_cfg_fixup *f, > + struct acpi_table_header *mcfg_header) > +{ > + return (!memcmp(f->oem_id, mcfg_header->oem_id, ACPI_OEM_ID_SIZE) && > + !memcmp(f->oem_table_id, mcfg_header->oem_table_id, > + ACPI_OEM_TABLE_ID_SIZE) && > + f->oem_revision == mcfg_header->oem_revision); > +} > + > +struct pci_config_window *pci_mcfg_match_quirks(struct acpi_pci_root *root) > +{ > + struct resource dom_res = MCFG_DOM_RANGE(root->segment, root->segment); > + struct resource *bus_res = >secondary; > + struct pci_cfg_fixup *f = mcfg_quirks; > + struct acpi_table_header *mcfg_header; > + acpi_status status; > + int i; > + > + status = acpi_get_table(ACPI_SIG_MCFG, 0, _header); > + if (ACPI_FAILURE(status)) > + return NULL; > + > + /* > + * First match against PCI topology then use OEM ID, OEM > + * table ID, and OEM revision from MCFG table standard header. > + */
Re: [RFC PATCH V5 3/5] PCI: Check platform specific ECAM quirks
On 08.08.2016 17:34, Mark Salter wrote: On Mon, 2016-08-08 at 15:05 +0200, Tomasz Nowicki wrote: Some platforms may not be fully compliant with generic set of PCI config accessors. For these cases we implement the way to overwrite accessors set. Algorithm traverses available quirk list (static array), matches againstand returns pci_config_window structure with fancy PCI config ops. oem_id, oem_table_id and rev come from MCFG table standard header. It is possible to define custom init call which is responsible for setting up PCI configuration access accordingly to quirk requirements. If custom init call is not defined, use standard pci_acpi_setup_ecam_mapping(). pci_generic_ecam_ops will be used for platforms free from quirks. Signed-off-by: Tomasz Nowicki Signed-off-by: Dongdong Liu Signed-off-by: Christopher Covington --- drivers/pci/host/Makefile | 1 + drivers/pci/host/mcfg-quirks.c | 86 ++ drivers/pci/host/mcfg-quirks.h | 20 ++ include/linux/pci-acpi.h | 2 + 4 files changed, 109 insertions(+) create mode 100644 drivers/pci/host/mcfg-quirks.c create mode 100644 drivers/pci/host/mcfg-quirks.h diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile index 8843410..500cf78 100644 --- a/drivers/pci/host/Makefile +++ b/drivers/pci/host/Makefile @@ -31,3 +31,4 @@ obj-$(CONFIG_PCI_HOST_THUNDER_ECAM) += pci-thunder-ecam.o obj-$(CONFIG_PCI_HOST_THUNDER_PEM) += pci-thunder-pem.o obj-$(CONFIG_PCIE_ARMADA_8K) += pcie-armada8k.o obj-$(CONFIG_PCIE_ARTPEC6) += pcie-artpec6.o +obj-$(CONFIG_ACPI_MCFG) += mcfg-quirks.o diff --git a/drivers/pci/host/mcfg-quirks.c b/drivers/pci/host/mcfg-quirks.c new file mode 100644 index 000..aa9907b --- /dev/null +++ b/drivers/pci/host/mcfg-quirks.c @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2016 Semihalf + * Author: Tomasz Nowicki + * + * 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 (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ + +#include +#include +#include +#include +#include + +#include "mcfg-quirks.h" + +struct pci_cfg_fixup { + char oem_id[ACPI_OEM_ID_SIZE + 1]; + char oem_table_id[ACPI_OEM_TABLE_ID_SIZE + 1]; + u32 oem_revision; + struct resource domain_range; + struct resource bus_range; + struct pci_ops *ops; + struct pci_config_window *(*init)(struct acpi_pci_root *root, + struct pci_ops *ops); +}; + +#define MCFG_DOM_RANGE(start, end) DEFINE_RES_NAMED((start), \ + ((end) - (start) + 1), NULL, 0) +#define MCFG_DOM_ANY MCFG_DOM_RANGE(0x0, 0x) +#define MCFG_BUS_RANGE(start, end) DEFINE_RES_NAMED((start), \ + ((end) - (start) + 1), \ + NULL, IORESOURCE_BUS) +#define MCFG_BUS_ANY MCFG_BUS_RANGE(0x0, 0xff) + +static struct pci_cfg_fixup mcfg_quirks[] __initconst = { ^^ I get section warnings because pci_cfg_fixup_match() is not an init function. WARNING: vmlinux.o(.text+0x3f6c74): Section mismatch in reference from the function pci_mcfg_match_quirks() to the variable .init.rodata:$d The function pci_mcfg_match_quirks() references the variable __initconst $d. This is often because pci_mcfg_match_quirks lacks a __initconst annotation or the annotation of $d is wrong. Thanks Mark. I will fix it. Tomasz
Re: [RFC PATCH V5 3/5] PCI: Check platform specific ECAM quirks
On 08.08.2016 17:34, Mark Salter wrote: On Mon, 2016-08-08 at 15:05 +0200, Tomasz Nowicki wrote: Some platforms may not be fully compliant with generic set of PCI config accessors. For these cases we implement the way to overwrite accessors set. Algorithm traverses available quirk list (static array), matches against and returns pci_config_window structure with fancy PCI config ops. oem_id, oem_table_id and rev come from MCFG table standard header. It is possible to define custom init call which is responsible for setting up PCI configuration access accordingly to quirk requirements. If custom init call is not defined, use standard pci_acpi_setup_ecam_mapping(). pci_generic_ecam_ops will be used for platforms free from quirks. Signed-off-by: Tomasz Nowicki Signed-off-by: Dongdong Liu Signed-off-by: Christopher Covington --- drivers/pci/host/Makefile | 1 + drivers/pci/host/mcfg-quirks.c | 86 ++ drivers/pci/host/mcfg-quirks.h | 20 ++ include/linux/pci-acpi.h | 2 + 4 files changed, 109 insertions(+) create mode 100644 drivers/pci/host/mcfg-quirks.c create mode 100644 drivers/pci/host/mcfg-quirks.h diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile index 8843410..500cf78 100644 --- a/drivers/pci/host/Makefile +++ b/drivers/pci/host/Makefile @@ -31,3 +31,4 @@ obj-$(CONFIG_PCI_HOST_THUNDER_ECAM) += pci-thunder-ecam.o obj-$(CONFIG_PCI_HOST_THUNDER_PEM) += pci-thunder-pem.o obj-$(CONFIG_PCIE_ARMADA_8K) += pcie-armada8k.o obj-$(CONFIG_PCIE_ARTPEC6) += pcie-artpec6.o +obj-$(CONFIG_ACPI_MCFG) += mcfg-quirks.o diff --git a/drivers/pci/host/mcfg-quirks.c b/drivers/pci/host/mcfg-quirks.c new file mode 100644 index 000..aa9907b --- /dev/null +++ b/drivers/pci/host/mcfg-quirks.c @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2016 Semihalf + * Author: Tomasz Nowicki + * + * 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 (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ + +#include +#include +#include +#include +#include + +#include "mcfg-quirks.h" + +struct pci_cfg_fixup { + char oem_id[ACPI_OEM_ID_SIZE + 1]; + char oem_table_id[ACPI_OEM_TABLE_ID_SIZE + 1]; + u32 oem_revision; + struct resource domain_range; + struct resource bus_range; + struct pci_ops *ops; + struct pci_config_window *(*init)(struct acpi_pci_root *root, + struct pci_ops *ops); +}; + +#define MCFG_DOM_RANGE(start, end) DEFINE_RES_NAMED((start), \ + ((end) - (start) + 1), NULL, 0) +#define MCFG_DOM_ANY MCFG_DOM_RANGE(0x0, 0x) +#define MCFG_BUS_RANGE(start, end) DEFINE_RES_NAMED((start), \ + ((end) - (start) + 1), \ + NULL, IORESOURCE_BUS) +#define MCFG_BUS_ANY MCFG_BUS_RANGE(0x0, 0xff) + +static struct pci_cfg_fixup mcfg_quirks[] __initconst = { ^^ I get section warnings because pci_cfg_fixup_match() is not an init function. WARNING: vmlinux.o(.text+0x3f6c74): Section mismatch in reference from the function pci_mcfg_match_quirks() to the variable .init.rodata:$d The function pci_mcfg_match_quirks() references the variable __initconst $d. This is often because pci_mcfg_match_quirks lacks a __initconst annotation or the annotation of $d is wrong. Thanks Mark. I will fix it. Tomasz
Re: [RFC PATCH V5 3/5] PCI: Check platform specific ECAM quirks
On Mon, 2016-08-08 at 15:05 +0200, Tomasz Nowicki wrote: > Some platforms may not be fully compliant with generic set of PCI config > accessors. For these cases we implement the way to overwrite accessors > set. Algorithm traverses available quirk list (static array), > matches againstand > returns pci_config_window structure with fancy PCI config ops. > oem_id, oem_table_id and rev come from MCFG table standard header. > > It is possible to define custom init call which is responsible for > setting up PCI configuration access accordingly to quirk requirements. > If custom init call is not defined, use standard > pci_acpi_setup_ecam_mapping(). > > pci_generic_ecam_ops will be used for platforms free from quirks. > > Signed-off-by: Tomasz Nowicki > Signed-off-by: Dongdong Liu > Signed-off-by: Christopher Covington > --- > drivers/pci/host/Makefile | 1 + > drivers/pci/host/mcfg-quirks.c | 86 > ++ > drivers/pci/host/mcfg-quirks.h | 20 ++ > include/linux/pci-acpi.h | 2 + > 4 files changed, 109 insertions(+) > create mode 100644 drivers/pci/host/mcfg-quirks.c > create mode 100644 drivers/pci/host/mcfg-quirks.h > > diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile > index 8843410..500cf78 100644 > --- a/drivers/pci/host/Makefile > +++ b/drivers/pci/host/Makefile > @@ -31,3 +31,4 @@ obj-$(CONFIG_PCI_HOST_THUNDER_ECAM) += pci-thunder-ecam.o > obj-$(CONFIG_PCI_HOST_THUNDER_PEM) += pci-thunder-pem.o > obj-$(CONFIG_PCIE_ARMADA_8K) += pcie-armada8k.o > obj-$(CONFIG_PCIE_ARTPEC6) += pcie-artpec6.o > +obj-$(CONFIG_ACPI_MCFG) += mcfg-quirks.o > diff --git a/drivers/pci/host/mcfg-quirks.c b/drivers/pci/host/mcfg-quirks.c > new file mode 100644 > index 000..aa9907b > --- /dev/null > +++ b/drivers/pci/host/mcfg-quirks.c > @@ -0,0 +1,86 @@ > +/* > + * Copyright (C) 2016 Semihalf > + * Author: Tomasz Nowicki > + * > + * 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 (the "GPL"). > + * > + * This program is distributed in the hope that it will be useful, but > + * WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * General Public License version 2 (GPLv2) for more details. > + * > + * You should have received a copy of the GNU General Public License > + * version 2 (GPLv2) along with this source code. > + */ > + > +#include > +#include > +#include > +#include > +#include > + > +#include "mcfg-quirks.h" > + > +struct pci_cfg_fixup { > + char oem_id[ACPI_OEM_ID_SIZE + 1]; > + char oem_table_id[ACPI_OEM_TABLE_ID_SIZE + 1]; > + u32 oem_revision; > + struct resource domain_range; > + struct resource bus_range; > + struct pci_ops *ops; > + struct pci_config_window *(*init)(struct acpi_pci_root *root, > + struct pci_ops *ops); > +}; > + > +#define MCFG_DOM_RANGE(start, end) DEFINE_RES_NAMED((start), \ > + ((end) - (start) + 1), NULL, 0) > +#define MCFG_DOM_ANY MCFG_DOM_RANGE(0x0, 0x) > +#define MCFG_BUS_RANGE(start, end) DEFINE_RES_NAMED((start), \ > + ((end) - (start) + 1), \ > + NULL, IORESOURCE_BUS) > +#define MCFG_BUS_ANY MCFG_BUS_RANGE(0x0, 0xff) > + > +static struct pci_cfg_fixup mcfg_quirks[] __initconst = { ^^ I get section warnings because pci_cfg_fixup_match() is not an init function. WARNING: vmlinux.o(.text+0x3f6c74): Section mismatch in reference from the function pci_mcfg_match_quirks() to the variable .init.rodata:$d The function pci_mcfg_match_quirks() references the variable __initconst $d. This is often because pci_mcfg_match_quirks lacks a __initconst annotation or the annotation of $d is wrong. > +/* { OEM_ID, OEM_TABLE_ID, REV, DOMAIN, BUS_RANGE, pci_ops, init_hook }, */ > +}; > + > +static bool pci_mcfg_fixup_match(struct pci_cfg_fixup *f, > + struct acpi_table_header *mcfg_header) > +{ > + return (!memcmp(f->oem_id, mcfg_header->oem_id, ACPI_OEM_ID_SIZE) && > + !memcmp(f->oem_table_id, mcfg_header->oem_table_id, > + ACPI_OEM_TABLE_ID_SIZE) && > + f->oem_revision == mcfg_header->oem_revision); > +} > + > +struct pci_config_window *pci_mcfg_match_quirks(struct acpi_pci_root *root) > +{ > + struct resource dom_res = MCFG_DOM_RANGE(root->segment, root->segment); > + struct resource *bus_res = >secondary; > + struct pci_cfg_fixup *f = mcfg_quirks; > +
Re: [RFC PATCH V5 3/5] PCI: Check platform specific ECAM quirks
On Mon, 2016-08-08 at 15:05 +0200, Tomasz Nowicki wrote: > Some platforms may not be fully compliant with generic set of PCI config > accessors. For these cases we implement the way to overwrite accessors > set. Algorithm traverses available quirk list (static array), > matches against and > returns pci_config_window structure with fancy PCI config ops. > oem_id, oem_table_id and rev come from MCFG table standard header. > > It is possible to define custom init call which is responsible for > setting up PCI configuration access accordingly to quirk requirements. > If custom init call is not defined, use standard > pci_acpi_setup_ecam_mapping(). > > pci_generic_ecam_ops will be used for platforms free from quirks. > > Signed-off-by: Tomasz Nowicki > Signed-off-by: Dongdong Liu > Signed-off-by: Christopher Covington > --- > drivers/pci/host/Makefile | 1 + > drivers/pci/host/mcfg-quirks.c | 86 > ++ > drivers/pci/host/mcfg-quirks.h | 20 ++ > include/linux/pci-acpi.h | 2 + > 4 files changed, 109 insertions(+) > create mode 100644 drivers/pci/host/mcfg-quirks.c > create mode 100644 drivers/pci/host/mcfg-quirks.h > > diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile > index 8843410..500cf78 100644 > --- a/drivers/pci/host/Makefile > +++ b/drivers/pci/host/Makefile > @@ -31,3 +31,4 @@ obj-$(CONFIG_PCI_HOST_THUNDER_ECAM) += pci-thunder-ecam.o > obj-$(CONFIG_PCI_HOST_THUNDER_PEM) += pci-thunder-pem.o > obj-$(CONFIG_PCIE_ARMADA_8K) += pcie-armada8k.o > obj-$(CONFIG_PCIE_ARTPEC6) += pcie-artpec6.o > +obj-$(CONFIG_ACPI_MCFG) += mcfg-quirks.o > diff --git a/drivers/pci/host/mcfg-quirks.c b/drivers/pci/host/mcfg-quirks.c > new file mode 100644 > index 000..aa9907b > --- /dev/null > +++ b/drivers/pci/host/mcfg-quirks.c > @@ -0,0 +1,86 @@ > +/* > + * Copyright (C) 2016 Semihalf > + * Author: Tomasz Nowicki > + * > + * 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 (the "GPL"). > + * > + * This program is distributed in the hope that it will be useful, but > + * WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * General Public License version 2 (GPLv2) for more details. > + * > + * You should have received a copy of the GNU General Public License > + * version 2 (GPLv2) along with this source code. > + */ > + > +#include > +#include > +#include > +#include > +#include > + > +#include "mcfg-quirks.h" > + > +struct pci_cfg_fixup { > + char oem_id[ACPI_OEM_ID_SIZE + 1]; > + char oem_table_id[ACPI_OEM_TABLE_ID_SIZE + 1]; > + u32 oem_revision; > + struct resource domain_range; > + struct resource bus_range; > + struct pci_ops *ops; > + struct pci_config_window *(*init)(struct acpi_pci_root *root, > + struct pci_ops *ops); > +}; > + > +#define MCFG_DOM_RANGE(start, end) DEFINE_RES_NAMED((start), \ > + ((end) - (start) + 1), NULL, 0) > +#define MCFG_DOM_ANY MCFG_DOM_RANGE(0x0, 0x) > +#define MCFG_BUS_RANGE(start, end) DEFINE_RES_NAMED((start), \ > + ((end) - (start) + 1), \ > + NULL, IORESOURCE_BUS) > +#define MCFG_BUS_ANY MCFG_BUS_RANGE(0x0, 0xff) > + > +static struct pci_cfg_fixup mcfg_quirks[] __initconst = { ^^ I get section warnings because pci_cfg_fixup_match() is not an init function. WARNING: vmlinux.o(.text+0x3f6c74): Section mismatch in reference from the function pci_mcfg_match_quirks() to the variable .init.rodata:$d The function pci_mcfg_match_quirks() references the variable __initconst $d. This is often because pci_mcfg_match_quirks lacks a __initconst annotation or the annotation of $d is wrong. > +/* { OEM_ID, OEM_TABLE_ID, REV, DOMAIN, BUS_RANGE, pci_ops, init_hook }, */ > +}; > + > +static bool pci_mcfg_fixup_match(struct pci_cfg_fixup *f, > + struct acpi_table_header *mcfg_header) > +{ > + return (!memcmp(f->oem_id, mcfg_header->oem_id, ACPI_OEM_ID_SIZE) && > + !memcmp(f->oem_table_id, mcfg_header->oem_table_id, > + ACPI_OEM_TABLE_ID_SIZE) && > + f->oem_revision == mcfg_header->oem_revision); > +} > + > +struct pci_config_window *pci_mcfg_match_quirks(struct acpi_pci_root *root) > +{ > + struct resource dom_res = MCFG_DOM_RANGE(root->segment, root->segment); > + struct resource *bus_res = >secondary; > + struct pci_cfg_fixup *f = mcfg_quirks; > + struct acpi_table_header *mcfg_header; > + acpi_status status; > + int i; > + > + status = acpi_get_table(ACPI_SIG_MCFG,
[RFC PATCH V5 3/5] PCI: Check platform specific ECAM quirks
Some platforms may not be fully compliant with generic set of PCI config accessors. For these cases we implement the way to overwrite accessors set. Algorithm traverses available quirk list (static array), matches againstand returns pci_config_window structure with fancy PCI config ops. oem_id, oem_table_id and rev come from MCFG table standard header. It is possible to define custom init call which is responsible for setting up PCI configuration access accordingly to quirk requirements. If custom init call is not defined, use standard pci_acpi_setup_ecam_mapping(). pci_generic_ecam_ops will be used for platforms free from quirks. Signed-off-by: Tomasz Nowicki Signed-off-by: Dongdong Liu Signed-off-by: Christopher Covington --- drivers/pci/host/Makefile | 1 + drivers/pci/host/mcfg-quirks.c | 86 ++ drivers/pci/host/mcfg-quirks.h | 20 ++ include/linux/pci-acpi.h | 2 + 4 files changed, 109 insertions(+) create mode 100644 drivers/pci/host/mcfg-quirks.c create mode 100644 drivers/pci/host/mcfg-quirks.h diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile index 8843410..500cf78 100644 --- a/drivers/pci/host/Makefile +++ b/drivers/pci/host/Makefile @@ -31,3 +31,4 @@ obj-$(CONFIG_PCI_HOST_THUNDER_ECAM) += pci-thunder-ecam.o obj-$(CONFIG_PCI_HOST_THUNDER_PEM) += pci-thunder-pem.o obj-$(CONFIG_PCIE_ARMADA_8K) += pcie-armada8k.o obj-$(CONFIG_PCIE_ARTPEC6) += pcie-artpec6.o +obj-$(CONFIG_ACPI_MCFG) += mcfg-quirks.o diff --git a/drivers/pci/host/mcfg-quirks.c b/drivers/pci/host/mcfg-quirks.c new file mode 100644 index 000..aa9907b --- /dev/null +++ b/drivers/pci/host/mcfg-quirks.c @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2016 Semihalf + * Author: Tomasz Nowicki + * + * 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 (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ + +#include +#include +#include +#include +#include + +#include "mcfg-quirks.h" + +struct pci_cfg_fixup { + char oem_id[ACPI_OEM_ID_SIZE + 1]; + char oem_table_id[ACPI_OEM_TABLE_ID_SIZE + 1]; + u32 oem_revision; + struct resource domain_range; + struct resource bus_range; + struct pci_ops *ops; + struct pci_config_window *(*init)(struct acpi_pci_root *root, + struct pci_ops *ops); +}; + +#define MCFG_DOM_RANGE(start, end) DEFINE_RES_NAMED((start), \ + ((end) - (start) + 1), NULL, 0) +#define MCFG_DOM_ANY MCFG_DOM_RANGE(0x0, 0x) +#define MCFG_BUS_RANGE(start, end) DEFINE_RES_NAMED((start), \ + ((end) - (start) + 1), \ + NULL, IORESOURCE_BUS) +#define MCFG_BUS_ANY MCFG_BUS_RANGE(0x0, 0xff) + +static struct pci_cfg_fixup mcfg_quirks[] __initconst = { +/* { OEM_ID, OEM_TABLE_ID, REV, DOMAIN, BUS_RANGE, pci_ops, init_hook }, */ +}; + +static bool pci_mcfg_fixup_match(struct pci_cfg_fixup *f, +struct acpi_table_header *mcfg_header) +{ + return (!memcmp(f->oem_id, mcfg_header->oem_id, ACPI_OEM_ID_SIZE) && + !memcmp(f->oem_table_id, mcfg_header->oem_table_id, + ACPI_OEM_TABLE_ID_SIZE) && + f->oem_revision == mcfg_header->oem_revision); +} + +struct pci_config_window *pci_mcfg_match_quirks(struct acpi_pci_root *root) +{ + struct resource dom_res = MCFG_DOM_RANGE(root->segment, root->segment); + struct resource *bus_res = >secondary; + struct pci_cfg_fixup *f = mcfg_quirks; + struct acpi_table_header *mcfg_header; + acpi_status status; + int i; + + status = acpi_get_table(ACPI_SIG_MCFG, 0, _header); + if (ACPI_FAILURE(status)) + return NULL; + + /* +* First match against PCI topology then use OEM ID, OEM +* table ID, and OEM revision from MCFG table standard header. +*/ + for (i = 0; i < ARRAY_SIZE(mcfg_quirks); i++, f++) { + if (resource_contains(>domain_range, _res) && + resource_contains(>bus_range, bus_res) && + pci_mcfg_fixup_match(f, mcfg_header)) { + dev_info(>device->dev, "Applying PCI MCFG
[RFC PATCH V5 3/5] PCI: Check platform specific ECAM quirks
Some platforms may not be fully compliant with generic set of PCI config accessors. For these cases we implement the way to overwrite accessors set. Algorithm traverses available quirk list (static array), matches against and returns pci_config_window structure with fancy PCI config ops. oem_id, oem_table_id and rev come from MCFG table standard header. It is possible to define custom init call which is responsible for setting up PCI configuration access accordingly to quirk requirements. If custom init call is not defined, use standard pci_acpi_setup_ecam_mapping(). pci_generic_ecam_ops will be used for platforms free from quirks. Signed-off-by: Tomasz Nowicki Signed-off-by: Dongdong Liu Signed-off-by: Christopher Covington --- drivers/pci/host/Makefile | 1 + drivers/pci/host/mcfg-quirks.c | 86 ++ drivers/pci/host/mcfg-quirks.h | 20 ++ include/linux/pci-acpi.h | 2 + 4 files changed, 109 insertions(+) create mode 100644 drivers/pci/host/mcfg-quirks.c create mode 100644 drivers/pci/host/mcfg-quirks.h diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile index 8843410..500cf78 100644 --- a/drivers/pci/host/Makefile +++ b/drivers/pci/host/Makefile @@ -31,3 +31,4 @@ obj-$(CONFIG_PCI_HOST_THUNDER_ECAM) += pci-thunder-ecam.o obj-$(CONFIG_PCI_HOST_THUNDER_PEM) += pci-thunder-pem.o obj-$(CONFIG_PCIE_ARMADA_8K) += pcie-armada8k.o obj-$(CONFIG_PCIE_ARTPEC6) += pcie-artpec6.o +obj-$(CONFIG_ACPI_MCFG) += mcfg-quirks.o diff --git a/drivers/pci/host/mcfg-quirks.c b/drivers/pci/host/mcfg-quirks.c new file mode 100644 index 000..aa9907b --- /dev/null +++ b/drivers/pci/host/mcfg-quirks.c @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2016 Semihalf + * Author: Tomasz Nowicki + * + * 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 (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ + +#include +#include +#include +#include +#include + +#include "mcfg-quirks.h" + +struct pci_cfg_fixup { + char oem_id[ACPI_OEM_ID_SIZE + 1]; + char oem_table_id[ACPI_OEM_TABLE_ID_SIZE + 1]; + u32 oem_revision; + struct resource domain_range; + struct resource bus_range; + struct pci_ops *ops; + struct pci_config_window *(*init)(struct acpi_pci_root *root, + struct pci_ops *ops); +}; + +#define MCFG_DOM_RANGE(start, end) DEFINE_RES_NAMED((start), \ + ((end) - (start) + 1), NULL, 0) +#define MCFG_DOM_ANY MCFG_DOM_RANGE(0x0, 0x) +#define MCFG_BUS_RANGE(start, end) DEFINE_RES_NAMED((start), \ + ((end) - (start) + 1), \ + NULL, IORESOURCE_BUS) +#define MCFG_BUS_ANY MCFG_BUS_RANGE(0x0, 0xff) + +static struct pci_cfg_fixup mcfg_quirks[] __initconst = { +/* { OEM_ID, OEM_TABLE_ID, REV, DOMAIN, BUS_RANGE, pci_ops, init_hook }, */ +}; + +static bool pci_mcfg_fixup_match(struct pci_cfg_fixup *f, +struct acpi_table_header *mcfg_header) +{ + return (!memcmp(f->oem_id, mcfg_header->oem_id, ACPI_OEM_ID_SIZE) && + !memcmp(f->oem_table_id, mcfg_header->oem_table_id, + ACPI_OEM_TABLE_ID_SIZE) && + f->oem_revision == mcfg_header->oem_revision); +} + +struct pci_config_window *pci_mcfg_match_quirks(struct acpi_pci_root *root) +{ + struct resource dom_res = MCFG_DOM_RANGE(root->segment, root->segment); + struct resource *bus_res = >secondary; + struct pci_cfg_fixup *f = mcfg_quirks; + struct acpi_table_header *mcfg_header; + acpi_status status; + int i; + + status = acpi_get_table(ACPI_SIG_MCFG, 0, _header); + if (ACPI_FAILURE(status)) + return NULL; + + /* +* First match against PCI topology then use OEM ID, OEM +* table ID, and OEM revision from MCFG table standard header. +*/ + for (i = 0; i < ARRAY_SIZE(mcfg_quirks); i++, f++) { + if (resource_contains(>domain_range, _res) && + resource_contains(>bus_range, bus_res) && + pci_mcfg_fixup_match(f, mcfg_header)) { + dev_info(>device->dev, "Applying PCI MCFG quirks for %s %s rev: %d\n", +f->oem_id, f->oem_table_id, f->oem_revision); +