lkml.org 
[lkml]   [2017]   [Apr]   [10]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.9 083/152] PCI: Add MCFG quirks for HiSilicon Hip05/06/07 host controllers
    Date
    4.9-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Dongdong Liu <liudongdong3@huawei.com>

    [ 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 <liudongdong3@huawei.com>
    Signed-off-by: Gabriele Paoloni <gabriele.paoloni@huawei.com>
    Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
    Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    ---
    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(-)

    --- a/drivers/acpi/pci_mcfg.c
    +++ b/drivers/acpi/pci_mcfg.c
    @@ -62,6 +62,18 @@ static struct mcfg_fixup mcfg_quirks[] =
    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),
    };

    static char mcfg_oem_id[ACPI_OEM_ID_SIZE];
    --- a/drivers/pci/host/Makefile
    +++ b/drivers/pci/host/Makefile
    @@ -25,7 +25,7 @@ obj-$(CONFIG_PCIE_IPROC_PLATFORM) += pci
    obj-$(CONFIG_PCIE_IPROC_BCMA) += pcie-iproc-bcma.o
    obj-$(CONFIG_PCIE_ALTERA) += pcie-altera.o
    obj-$(CONFIG_PCIE_ALTERA_MSI) += pcie-altera-msi.o
    -obj-$(CONFIG_PCI_HISI) += pcie-hisi.o
    +obj-$(CONFIG_ARM64) += pcie-hisi.o
    obj-$(CONFIG_PCIE_QCOM) += pcie-qcom.o
    obj-$(CONFIG_PCI_HOST_THUNDER_ECAM) += pci-thunder-ecam.o
    obj-$(CONFIG_PCI_HOST_THUNDER_PEM) += pci-thunder-pem.o
    --- a/drivers/pci/host/pcie-hisi.c
    +++ b/drivers/pci/host/pcie-hisi.c
    @@ -18,7 +18,106 @@
    #include <linux/of_pci.h>
    #include <linux/platform_device.h>
    #include <linux/of_device.h>
    +#include <linux/pci.h>
    +#include <linux/pci-acpi.h>
    +#include <linux/pci-ecam.h>
    #include <linux/regmap.h>
    +#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 where,
    + int size, u32 *val)
    +{
    + struct pci_config_window *cfg = bus->sysdata;
    + int dev = PCI_SLOT(devfn);
    +
    + if (bus->number == 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 = bus->sysdata;
    + int dev = PCI_SLOT(devfn);
    +
    + if (bus->number == 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 devfn,
    + int where)
    +{
    + struct pci_config_window *cfg = bus->sysdata;
    + void __iomem *reg_base = cfg->priv;
    +
    + if (bus->number == 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 = cfg->parent;
    + struct acpi_device *adev = to_acpi_device(dev);
    + struct acpi_pci_root *root = 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 = devm_kzalloc(dev, sizeof(*res), GFP_KERNEL);
    + if (!res)
    + return -ENOMEM;
    +
    + ret = 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 = devm_ioremap(dev, res->start, resource_size(res));
    + if (!reg_base)
    + return -ENOMEM;
    +
    + cfg->priv = reg_base;
    + return 0;
    +}
    +
    +struct pci_ecam_ops hisi_pcie_ops = {
    + .bus_shift = 20,
    + .init = hisi_pcie_init,
    + .pci_ops = {
    + .map_bus = hisi_pcie_map_bus,
    + .read = hisi_pcie_acpi_rd_conf,
    + .write = hisi_pcie_acpi_wr_conf,
    + }
    +};
    +
    +#endif
    +
    +#ifdef CONFIG_PCI_HISI

    #include "pcie-designware.h"

    @@ -227,3 +326,5 @@ static struct platform_driver hisi_pcie_
    },
    };
    builtin_platform_driver(hisi_pcie_driver);
    +
    +#endif
    --- a/include/linux/pci-ecam.h
    +++ b/include/linux/pci-ecam.h
    @@ -61,6 +61,7 @@ extern struct pci_ecam_ops pci_generic_e

    #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

    #ifdef CONFIG_PCI_HOST_GENERIC

    \
     
     \ /
      Last update: 2017-04-10 19:35    [W:4.358 / U:0.008 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site