From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from omzsmtpe03.verizonbusiness.com ([199.249.25.208]:9345 "EHLO omzsmtpe03.verizonbusiness.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752936AbdDDTcs (ORCPT ); Tue, 4 Apr 2017 15:32:48 -0400 From: alexander.levin@verizon.com To: "gregkh@linuxfoundation.org" CC: "stable@vger.kernel.org" Subject: [PATCH for 4.9 24/98] PCI: Add MCFG quirks for HiSilicon Hip05/06/07 host controllers Date: Tue, 4 Apr 2017 19:32:11 +0000 Message-ID: <20170404193158.19041-25-alexander.levin@verizon.com> References: <20170404193158.19041-1-alexander.levin@verizon.com> In-Reply-To: <20170404193158.19041-1-alexander.levin@verizon.com> Content-Language: en-US Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Sender: stable-owner@vger.kernel.org List-ID: From: Dongdong Liu [ Upstream commit 5f00f1a0178cf52928366a5e1f376a65f1f3f389 ] The PCIe controller in Hip05/Hip06/Hip07 SoCs is not completely ECAM-compliant. It is non-ECAM only for the RC bus config space; for any other bus underneath the root bus it does support ECAM access. Add specific quirks for PCI config space accessors. This involves: 1. New initialization call hisi_pcie_init() to obtain RC base addresses from PNP0C02 at the root of the ACPI namespace (under \_SB). 2. New entry in common quirk array. [bhelgaas: move to pcie-hisi.c and change Makefile/ifdefs so quirk doesn't depend on CONFIG_PCI_HISI] Signed-off-by: Dongdong Liu Signed-off-by: Gabriele Paoloni Signed-off-by: Bjorn Helgaas Signed-off-by: Sasha Levin --- drivers/acpi/pci_mcfg.c | 12 +++++ drivers/pci/host/Makefile | 2 +- drivers/pci/host/pcie-hisi.c | 101 +++++++++++++++++++++++++++++++++++++++= ++++ include/linux/pci-ecam.h | 1 + 4 files changed, 115 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c index cee33b0..dd16224 100644 --- a/drivers/acpi/pci_mcfg.c +++ b/drivers/acpi/pci_mcfg.c @@ -62,6 +62,18 @@ static struct mcfg_fixup mcfg_quirks[] =3D { QCOM_ECAM32(5), QCOM_ECAM32(6), QCOM_ECAM32(7), + +#define HISI_QUAD_DOM(table_id, seg, ops) \ + { "HISI ", table_id, 0, (seg) + 0, MCFG_BUS_ANY, ops }, \ + { "HISI ", table_id, 0, (seg) + 1, MCFG_BUS_ANY, ops }, \ + { "HISI ", table_id, 0, (seg) + 2, MCFG_BUS_ANY, ops }, \ + { "HISI ", table_id, 0, (seg) + 3, MCFG_BUS_ANY, ops } + HISI_QUAD_DOM("HIP05 ", 0, &hisi_pcie_ops), + HISI_QUAD_DOM("HIP06 ", 0, &hisi_pcie_ops), + HISI_QUAD_DOM("HIP07 ", 0, &hisi_pcie_ops), + HISI_QUAD_DOM("HIP07 ", 4, &hisi_pcie_ops), + HISI_QUAD_DOM("HIP07 ", 8, &hisi_pcie_ops), + HISI_QUAD_DOM("HIP07 ", 12, &hisi_pcie_ops), }; =20 static char mcfg_oem_id[ACPI_OEM_ID_SIZE]; diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile index 084cb49..64845f0 100644 --- a/drivers/pci/host/Makefile +++ b/drivers/pci/host/Makefile @@ -25,7 +25,7 @@ obj-$(CONFIG_PCIE_IPROC_PLATFORM) +=3D pcie-iproc-platfor= m.o obj-$(CONFIG_PCIE_IPROC_BCMA) +=3D pcie-iproc-bcma.o obj-$(CONFIG_PCIE_ALTERA) +=3D pcie-altera.o obj-$(CONFIG_PCIE_ALTERA_MSI) +=3D pcie-altera-msi.o -obj-$(CONFIG_PCI_HISI) +=3D pcie-hisi.o +obj-$(CONFIG_ARM64) +=3D pcie-hisi.o obj-$(CONFIG_PCIE_QCOM) +=3D pcie-qcom.o obj-$(CONFIG_PCI_HOST_THUNDER_ECAM) +=3D pci-thunder-ecam.o obj-$(CONFIG_PCI_HOST_THUNDER_PEM) +=3D pci-thunder-pem.o diff --git a/drivers/pci/host/pcie-hisi.c b/drivers/pci/host/pcie-hisi.c index 56154c2..9bfa1ab 100644 --- a/drivers/pci/host/pcie-hisi.c +++ b/drivers/pci/host/pcie-hisi.c @@ -18,7 +18,106 @@ #include #include #include +#include +#include +#include #include +#include "../pci.h" + +#if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS) + +static int hisi_pcie_acpi_rd_conf(struct pci_bus *bus, u32 devfn, int wher= e, + int size, u32 *val) +{ + struct pci_config_window *cfg =3D bus->sysdata; + int dev =3D PCI_SLOT(devfn); + + if (bus->number =3D=3D cfg->busr.start) { + /* access only one slot on each root port */ + if (dev > 0) + return PCIBIOS_DEVICE_NOT_FOUND; + else + return pci_generic_config_read32(bus, devfn, where, + size, val); + } + + return pci_generic_config_read(bus, devfn, where, size, val); +} + +static int hisi_pcie_acpi_wr_conf(struct pci_bus *bus, u32 devfn, + int where, int size, u32 val) +{ + struct pci_config_window *cfg =3D bus->sysdata; + int dev =3D PCI_SLOT(devfn); + + if (bus->number =3D=3D cfg->busr.start) { + /* access only one slot on each root port */ + if (dev > 0) + return PCIBIOS_DEVICE_NOT_FOUND; + else + return pci_generic_config_write32(bus, devfn, where, + size, val); + } + + return pci_generic_config_write(bus, devfn, where, size, val); +} + +static void __iomem *hisi_pcie_map_bus(struct pci_bus *bus, unsigned int d= evfn, + int where) +{ + struct pci_config_window *cfg =3D bus->sysdata; + void __iomem *reg_base =3D cfg->priv; + + if (bus->number =3D=3D cfg->busr.start) + return reg_base + where; + else + return pci_ecam_map_bus(bus, devfn, where); +} + +static int hisi_pcie_init(struct pci_config_window *cfg) +{ + struct device *dev =3D cfg->parent; + struct acpi_device *adev =3D to_acpi_device(dev); + struct acpi_pci_root *root =3D acpi_driver_data(adev); + struct resource *res; + void __iomem *reg_base; + int ret; + + /* + * Retrieve RC base and size from a HISI0081 device with _UID + * matching our segment. + */ + res =3D devm_kzalloc(dev, sizeof(*res), GFP_KERNEL); + if (!res) + return -ENOMEM; + + ret =3D acpi_get_rc_resources(dev, "HISI0081", root->segment, res); + if (ret) { + dev_err(dev, "can't get rc base address\n"); + return -ENOMEM; + } + + reg_base =3D devm_ioremap(dev, res->start, resource_size(res)); + if (!reg_base) + return -ENOMEM; + + cfg->priv =3D reg_base; + return 0; +} + +struct pci_ecam_ops hisi_pcie_ops =3D { + .bus_shift =3D 20, + .init =3D hisi_pcie_init, + .pci_ops =3D { + .map_bus =3D hisi_pcie_map_bus, + .read =3D hisi_pcie_acpi_rd_conf, + .write =3D hisi_pcie_acpi_wr_conf, + } +}; + +#endif + +#ifdef CONFIG_PCI_HISI =20 #include "pcie-designware.h" =20 @@ -227,3 +326,5 @@ static struct platform_driver hisi_pcie_driver =3D { }, }; builtin_platform_driver(hisi_pcie_driver); + +#endif diff --git a/include/linux/pci-ecam.h b/include/linux/pci-ecam.h index 739d233..bdacbc8 100644 --- a/include/linux/pci-ecam.h +++ b/include/linux/pci-ecam.h @@ -61,6 +61,7 @@ extern struct pci_ecam_ops pci_generic_ecam_ops; =20 #if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS) extern struct pci_ecam_ops pci_32b_ops; /* 32-bit accesses only */ +extern struct pci_ecam_ops hisi_pcie_ops; /* HiSilicon */ #endif =20 #ifdef CONFIG_PCI_HOST_GENERIC --=20 2.9.3