Message ID | 1411573068-12952-2-git-send-email-rric@kernel.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Wednesday 24 September 2014 17:37:43 Robert Richter wrote: > From: Sunil Goutham <sgoutham@cavium.com> > > This patch adds support for PCI host controller of Cavium Thunder > SoCs. I had expected this hardware to be SBSA compliant. Why do you need a hardware specific driver, is this a workaround for buggy hardware or just noncompliant? > +/* > + * All PCIe devices in Thunder have fixed resources, shouldn't be reassigned. > + * Also claim the device's valid resources to set 'res->parent' hierarchy. > + */ > +static void pci_dev_resource_fixup(struct pci_dev *dev) > +{ > + struct resource *res; > + int resno; > + > + for (resno = 0; resno < PCI_NUM_RESOURCES; resno++) > + dev->resource[resno].flags |= IORESOURCE_PCI_FIXED; You have listed these as relocatable in DT, why do you have to mark them as nonrelocatable here? > +static void __iomem *thunder_pcie_cfg_base(struct thunder_pcie *pcie, > + unsigned int bus, unsigned int devfn) > +{ > + return pcie->cfg_base + ((bus << THUNDER_PCIE_BUS_SHIFT) > + | (PCI_SLOT(devfn) << THUNDER_PCIE_DEV_SHIFT) > + | (PCI_FUNC(devfn) << THUNDER_PCIE_FUNC_SHIFT)); > +} > + > +static int thunder_pcie_read_config(struct pci_bus *bus, unsigned int devfn, > + int reg, int size, u32 *val) > +{ > + struct thunder_pcie *pcie = bus->sysdata; > + void __iomem *addr; > + unsigned int busnr = bus->number; > + > + if (busnr > 255 || devfn > 255 || reg > 4095) > + return PCIBIOS_DEVICE_NOT_FOUND; > + > + addr = thunder_pcie_cfg_base(pcie, busnr, devfn) + reg; > + > + switch (size) { > + case 1: > + *val = readb(addr); > + break; > + case 2: > + *val = readw(addr); > + break; > + case 4: > + *val = readl(addr); > + break; > + default: > + return PCIBIOS_BAD_REGISTER_NUMBER; > + } > + > + return PCIBIOS_SUCCESSFUL; > +} This looks roughly ECAM compliant, are you sure you need a private implementation? > +static int thunder_pcie_msi_enable(struct thunder_pcie *pcie, > + struct pci_bus *bus) > +{ > + struct device_node *msi_node; > + > + msi_node = of_parse_phandle(pcie->node, "msi-parent", 0); > + if (!msi_node) > + return -ENODEV; > + > + pcie->msi = of_pci_find_msi_chip_by_node(msi_node); > + if (!pcie->msi) > + return -ENODEV; > + > + pcie->msi->dev = pcie->dev; > + bus->msi = pcie->msi; > + > + return 0; > +} This is probably something we should add to the generic host driver as well, so it can work with SBSA compliant implementations that come with an MSI controller. Maybe move it into common code so it can be shared with that driver. Arnd
On Wed, Sep 24, 2014 at 05:12:26PM +0100, Arnd Bergmann wrote: > On Wednesday 24 September 2014 17:37:43 Robert Richter wrote: > > From: Sunil Goutham <sgoutham@cavium.com> > > > > This patch adds support for PCI host controller of Cavium Thunder > > SoCs. > > I had expected this hardware to be SBSA compliant. Why do you need > a hardware specific driver, is this a workaround for buggy hardware > or just noncompliant? Patches welcome to pci-host-generic.c :) Lorenzo already has code to port it to Liviu's new API, so do shout if it's not suitable for your needs. > > +static int thunder_pcie_msi_enable(struct thunder_pcie *pcie, > > + struct pci_bus *bus) > > +{ > > + struct device_node *msi_node; > > + > > + msi_node = of_parse_phandle(pcie->node, "msi-parent", 0); > > + if (!msi_node) > > + return -ENODEV; > > + > > + pcie->msi = of_pci_find_msi_chip_by_node(msi_node); > > + if (!pcie->msi) > > + return -ENODEV; > > + > > + pcie->msi->dev = pcie->dev; > > + bus->msi = pcie->msi; > > + > > + return 0; > > +} > > This is probably something we should add to the generic host driver as well, > so it can work with SBSA compliant implementations that come with an MSI > controller. Maybe move it into common code so it can be shared with that > driver. Agreed. I've been carrying something similar [1] (based on a hacked-up version of bios32, so not bothered to post it) whilst I've been waiting for the arm64 core PCI code to get merged. Will [1] https://git.kernel.org/cgit/linux/kernel/git/will/linux.git/commit/drivers/pci/host/pci-host-generic.c?h=iommu/pci&id=b719acf062ceccfbd79ee7b1ae0b7904ea4da27e
Will/Arnd Thanks for the comments. There is another patch submitted for adding MSI controller to Generic driver. https://lkml.org/lkml/2014/9/28/150 Will go through these and comeback. On Wed, Sep 24, 2014 at 10:19 PM, Will Deacon <will.deacon@arm.com> wrote: > On Wed, Sep 24, 2014 at 05:12:26PM +0100, Arnd Bergmann wrote: >> On Wednesday 24 September 2014 17:37:43 Robert Richter wrote: >> > From: Sunil Goutham <sgoutham@cavium.com> >> > >> > This patch adds support for PCI host controller of Cavium Thunder >> > SoCs. >> >> I had expected this hardware to be SBSA compliant. Why do you need >> a hardware specific driver, is this a workaround for buggy hardware >> or just noncompliant? > > Patches welcome to pci-host-generic.c :) Lorenzo already has code to port > it to Liviu's new API, so do shout if it's not suitable for your needs. > >> > +static int thunder_pcie_msi_enable(struct thunder_pcie *pcie, >> > + struct pci_bus *bus) >> > +{ >> > + struct device_node *msi_node; >> > + >> > + msi_node = of_parse_phandle(pcie->node, "msi-parent", 0); >> > + if (!msi_node) >> > + return -ENODEV; >> > + >> > + pcie->msi = of_pci_find_msi_chip_by_node(msi_node); >> > + if (!pcie->msi) >> > + return -ENODEV; >> > + >> > + pcie->msi->dev = pcie->dev; >> > + bus->msi = pcie->msi; >> > + >> > + return 0; >> > +} >> >> This is probably something we should add to the generic host driver as well, >> so it can work with SBSA compliant implementations that come with an MSI >> controller. Maybe move it into common code so it can be shared with that >> driver. > > Agreed. I've been carrying something similar [1] (based on a hacked-up version > of bios32, so not bothered to post it) whilst I've been waiting for the > arm64 core PCI code to get merged. > > Will > > [1] https://git.kernel.org/cgit/linux/kernel/git/will/linux.git/commit/drivers/pci/host/pci-host-generic.c?h=iommu/pci&id=b719acf062ceccfbd79ee7b1ae0b7904ea4da27e > -- > To unsubscribe from this list: send the line "unsubscribe linux-pci" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig index 90f5ccacce4b..269c3ff786bc 100644 --- a/drivers/pci/host/Kconfig +++ b/drivers/pci/host/Kconfig @@ -63,4 +63,12 @@ config PCIE_SPEAR13XX help Say Y here if you want PCIe support on SPEAr13XX SoCs. +config PCI_THUNDER + bool "Thunder PCIe host controller" + depends on ARM64 || COMPILE_TEST + depends on OF_PCI + depends on PCI_MSI + help + Say Y here if you want internal PCI support on Thunder SoC. + endmenu diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile index d0e88f114ff9..fd8041da1719 100644 --- a/drivers/pci/host/Makefile +++ b/drivers/pci/host/Makefile @@ -8,3 +8,4 @@ obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o obj-$(CONFIG_PCI_RCAR_GEN2_PCIE) += pcie-rcar.o obj-$(CONFIG_PCI_HOST_GENERIC) += pci-host-generic.o obj-$(CONFIG_PCIE_SPEAR13XX) += pcie-spear13xx.o +obj-$(CONFIG_PCI_THUNDER) += pcie-thunder.o diff --git a/drivers/pci/host/pcie-thunder.c b/drivers/pci/host/pcie-thunder.c new file mode 100644 index 000000000000..947fad3b1980 --- /dev/null +++ b/drivers/pci/host/pcie-thunder.c @@ -0,0 +1,246 @@ +/* + * PCIe host controller driver for Cavium Thunder SOC + * + * Copyright (C) 2014, Cavium Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + */ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/of_irq.h> +#include <linux/of_pci.h> +#include <linux/pci.h> +#include <linux/platform_device.h> +#include <linux/msi.h> + +#define PCI_DEVICE_ID_THUNDER_BRIDGE 0xa002 + +#define THUNDER_PCIE_BUS_SHIFT 20 +#define THUNDER_PCIE_DEV_SHIFT 15 +#define THUNDER_PCIE_FUNC_SHIFT 12 + +struct thunder_pcie { + struct device_node *node; + struct device *dev; + void __iomem *cfg_base; + struct msi_chip *msi; +}; + +/* + * This bridge is just for the sake of supporting ARI for + * downstream devices. No resources are attached to it. + * Copy upstream root bus resources to bridge which aide in + * resource claiming for downstream devices + */ +static void pci_bridge_resource_fixup(struct pci_dev *dev) +{ + struct pci_bus *bus; + int resno; + + bus = dev->subordinate; + for (resno = 0; resno < PCI_BRIDGE_RESOURCE_NUM; resno++) { + bus->resource[resno] = pci_bus_resource_n(bus->parent, + PCI_BRIDGE_RESOURCE_NUM + resno); + } + + for (resno = PCI_BRIDGE_RESOURCES; + resno <= PCI_BRIDGE_RESOURCE_END; resno++) { + dev->resource[resno].start = dev->resource[resno].end = 0; + dev->resource[resno].flags = 0; + } +} +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CAVIUM, PCI_DEVICE_ID_THUNDER_BRIDGE, + pci_bridge_resource_fixup); + +/* + * All PCIe devices in Thunder have fixed resources, shouldn't be reassigned. + * Also claim the device's valid resources to set 'res->parent' hierarchy. + */ +static void pci_dev_resource_fixup(struct pci_dev *dev) +{ + struct resource *res; + int resno; + + for (resno = 0; resno < PCI_NUM_RESOURCES; resno++) + dev->resource[resno].flags |= IORESOURCE_PCI_FIXED; + + for (resno = 0; resno < PCI_BRIDGE_RESOURCES; resno++) { + res = &dev->resource[resno]; + if (res->parent || !(res->flags & IORESOURCE_MEM)) + continue; + pci_claim_resource(dev, resno); + } +} +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CAVIUM, PCI_ANY_ID, + pci_dev_resource_fixup); + +static void __iomem *thunder_pcie_cfg_base(struct thunder_pcie *pcie, + unsigned int bus, unsigned int devfn) +{ + return pcie->cfg_base + ((bus << THUNDER_PCIE_BUS_SHIFT) + | (PCI_SLOT(devfn) << THUNDER_PCIE_DEV_SHIFT) + | (PCI_FUNC(devfn) << THUNDER_PCIE_FUNC_SHIFT)); +} + +static int thunder_pcie_read_config(struct pci_bus *bus, unsigned int devfn, + int reg, int size, u32 *val) +{ + struct thunder_pcie *pcie = bus->sysdata; + void __iomem *addr; + unsigned int busnr = bus->number; + + if (busnr > 255 || devfn > 255 || reg > 4095) + return PCIBIOS_DEVICE_NOT_FOUND; + + addr = thunder_pcie_cfg_base(pcie, busnr, devfn) + reg; + + switch (size) { + case 1: + *val = readb(addr); + break; + case 2: + *val = readw(addr); + break; + case 4: + *val = readl(addr); + break; + default: + return PCIBIOS_BAD_REGISTER_NUMBER; + } + + return PCIBIOS_SUCCESSFUL; +} + +static int thunder_pcie_write_config(struct pci_bus *bus, unsigned int devfn, + int reg, int size, u32 val) +{ + struct thunder_pcie *pcie = bus->sysdata; + void __iomem *addr; + unsigned int busnr = bus->number; + + if (busnr > 255 || devfn > 255 || reg > 4095) + return PCIBIOS_DEVICE_NOT_FOUND; + + addr = thunder_pcie_cfg_base(pcie, busnr, devfn) + reg; + + switch (size) { + case 1: + writeb(val, addr); + break; + case 2: + writew(val, addr); + break; + case 4: + writel(val, addr); + break; + default: + return PCIBIOS_BAD_REGISTER_NUMBER; + } + + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops thunder_pcie_ops = { + .read = thunder_pcie_read_config, + .write = thunder_pcie_write_config, +}; + +static int thunder_pcie_msi_enable(struct thunder_pcie *pcie, + struct pci_bus *bus) +{ + struct device_node *msi_node; + + msi_node = of_parse_phandle(pcie->node, "msi-parent", 0); + if (!msi_node) + return -ENODEV; + + pcie->msi = of_pci_find_msi_chip_by_node(msi_node); + if (!pcie->msi) + return -ENODEV; + + pcie->msi->dev = pcie->dev; + bus->msi = pcie->msi; + + return 0; +} + +static int thunder_pcie_probe(struct platform_device *pdev) +{ + struct thunder_pcie *pcie; + struct resource *cfg_base; + struct pci_bus *bus; + int ret; + LIST_HEAD(res); + + pcie = devm_kzalloc(&pdev->dev, sizeof(*pcie), GFP_KERNEL); + if (!pcie) + return -ENOMEM; + + pcie->node = of_node_get(pdev->dev.of_node); + pcie->dev = &pdev->dev; + + /* Get controller's configuration space range */ + cfg_base = platform_get_resource(pdev, IORESOURCE_MEM, 0); + pcie->cfg_base = devm_ioremap_resource(&pdev->dev, cfg_base); + if (IS_ERR(pcie->cfg_base)) { + ret = PTR_ERR(pcie->cfg_base); + goto err_ioremap; + } + + ret = of_pci_get_host_bridge_resources(pdev->dev.of_node, + 0, 255, &res, NULL); + if (ret) + goto err_get_host; + + bus = pci_create_root_bus(&pdev->dev, 0, &thunder_pcie_ops, pcie, &res); + if (!bus) { + ret = -ENODEV; + goto err_root_bus; + } + + /* Set reference to MSI chip */ + ret = thunder_pcie_msi_enable(pcie, bus); + if (ret) + goto err_msi; + + platform_set_drvdata(pdev, pcie); + + pci_scan_child_bus(bus); + pci_bus_add_devices(bus); + + return 0; +err_msi: + pci_remove_root_bus(bus); +err_root_bus: + pci_free_resource_list(&res); +err_get_host: + devm_ioremap_release(pcie->dev, pcie->cfg_base); +err_ioremap: + of_node_put(pcie->node); + kfree(pcie); + return ret; +} + +static const struct of_device_id thunder_pcie_of_match[] = { + { .compatible = "cavium,thunder-pcie", }, + {}, +}; +MODULE_DEVICE_TABLE(of, thunder_pcie_of_match); + +static struct platform_driver thunder_pcie_driver = { + .driver = { + .name = "thunder-pcie", + .owner = THIS_MODULE, + .of_match_table = thunder_pcie_of_match, + }, + .probe = thunder_pcie_probe, +}; +module_platform_driver(thunder_pcie_driver); + +MODULE_AUTHOR("Sunil Goutham"); +MODULE_DESCRIPTION("Cavium Thunder PCIe host controller driver"); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 6ed0bb73a864..60f16b888c9d 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2322,6 +2322,8 @@ #define PCI_DEVICE_ID_ALTIMA_AC9100 0x03ea #define PCI_DEVICE_ID_ALTIMA_AC1003 0x03eb +#define PCI_VENDOR_ID_CAVIUM 0x177d + #define PCI_VENDOR_ID_BELKIN 0x1799 #define PCI_DEVICE_ID_BELKIN_F5D7010V7 0x701f