[PATCH 2/2] pci: fsl: rework PCI driver compatible with Layerscape
Lian Minghuan-b31939
B31939 at freescale.com
Fri Sep 27 21:29:16 EST 2013
Hi All,
Can anyone comment on my code or help to pick up?
Thanks,
Minghuan
On 09/18/2013 07:02 PM, Minghuan Lian wrote:
> The Freescale's Layerscape series processors will use the same PCI
> controller but change cores from PowerPC to ARM. This patch is to
> rework FSL PCI driver to support PowerPC and ARM simultaneously.
> PowerPC uses structure pci_controller to describe PCI controller,
> but arm uses structure hw_pci and pci_sys_data. They also have
> different architecture implementation and initialization flow.
> The architecture-dependent driver will bridge the gap, get the
> settings from the common driver and initialize the corresponding
> structure and call the related interface to register PCI controller.
> The common driver pci-fsl.c removes all the architecture-specific
> code and provides structure fsl_pci to store all the controller
> settings and the common functionalities that include reading/writing
> PCI configuration space, parsing dts node and getting the MEM/IO and
> bus number ranges, setting ATMU and check link status.
>
> Signed-off-by: Minghuan Lian <Minghuan.Lian at freescale.com>
> ---
> Based on upstream master
> Based on the discussion of RFC version here
> http://patchwork.ozlabs.org/patch/274488/
> The function has been tested on MPC8315ERDB MPC8572DS P5020DS P3041DS
> and T4240QDS boards
>
> arch/powerpc/Kconfig | 1 +
> arch/powerpc/sysdev/fsl_pci.c | 147 +++++++++-
> drivers/edac/mpc85xx_edac.c | 16 +-
> drivers/pci/host/Kconfig | 7 +
> drivers/pci/host/Makefile | 1 +
> drivers/pci/host/pci-fsl.c | 653 +++++++++++++++++++++++++++---------------
> include/linux/fsl/pci.h | 69 +++++
> 7 files changed, 653 insertions(+), 241 deletions(-)
>
> diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
> index 38f3b7e..6fd6348 100644
> --- a/arch/powerpc/Kconfig
> +++ b/arch/powerpc/Kconfig
> @@ -690,6 +690,7 @@ config FSL_SOC
>
> config FSL_PCI
> bool
> + select PCI_FSL if FSL_SOC_BOOKE || PPC_86xx
> select PPC_INDIRECT_PCI
> select PCI_QUIRKS
>
> diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c
> index a189ff0..1413257 100644
> --- a/arch/powerpc/sysdev/fsl_pci.c
> +++ b/arch/powerpc/sysdev/fsl_pci.c
> @@ -62,7 +62,11 @@ static void quirk_fsl_pcie_header(struct pci_dev *dev)
> #if defined(CONFIG_FSL_SOC_BOOKE) || defined(CONFIG_PPC_86xx)
>
> #define MAX_PHYS_ADDR_BITS 40
> -static u64 pci64_dma_offset = 1ull << MAX_PHYS_ADDR_BITS;
> +
> +u64 fsl_arch_pci64_dma_offset(void)
> +{
> + return 1ull << MAX_PHYS_ADDR_BITS;
> +}
>
> static int fsl_pci_dma_set_mask(struct device *dev, u64 dma_mask)
> {
> @@ -77,17 +81,43 @@ static int fsl_pci_dma_set_mask(struct device *dev, u64 dma_mask)
> if ((dev->bus == &pci_bus_type) &&
> dma_mask >= DMA_BIT_MASK(MAX_PHYS_ADDR_BITS)) {
> set_dma_ops(dev, &dma_direct_ops);
> - set_dma_offset(dev, pci64_dma_offset);
> + set_dma_offset(dev, fsl_arch_pci64_dma_offset());
> }
>
> *dev->dma_mask = dma_mask;
> return 0;
> }
>
> +struct fsl_pci *fsl_arch_sys_to_pci(void *sys)
> +{
> + struct pci_controller *hose = sys;
> + struct fsl_pci *pci = hose->private_data;
> +
> + /* Update the first bus number */
> + if (pci->first_busno != hose->first_busno)
> + pci->first_busno = hose->first_busno;
> +
> + return pci;
> +}
> +
> +struct pci_bus *fsl_arch_fake_pci_bus(struct fsl_pci *pci, int busnr)
> +{
> + static struct pci_bus bus;
> + static struct pci_controller hose;
> +
> + bus.number = busnr;
> + bus.sysdata = &hose;
> + hose.private_data = pci;
> + bus.ops = pci->ops;
> +
> + return &bus;
> +}
> +
> void fsl_pcibios_fixup_bus(struct pci_bus *bus)
> {
> struct pci_controller *hose = pci_bus_to_host(bus);
> - int i, is_pcie = 0, no_link;
> + int i, is_pcie, no_link;
> + struct fsl_pci *pci = fsl_arch_sys_to_pci(hose);
>
> /* The root complex bridge comes up with bogus resources,
> * we copy the PHB ones in.
> @@ -97,9 +127,8 @@ void fsl_pcibios_fixup_bus(struct pci_bus *bus)
> * tricky.
> */
>
> - if (fsl_pcie_bus_fixup)
> - is_pcie = early_find_capability(hose, 0, 0, PCI_CAP_ID_EXP);
> - no_link = !!(hose->indirect_type & PPC_INDIRECT_TYPE_NO_PCIE_LINK);
> + is_pcie = pci->is_pcie;
> + no_link = fsl_pci_check_link(pci);
>
> if (bus->parent == hose->bus && (is_pcie || no_link)) {
> for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; ++i) {
> @@ -121,6 +150,94 @@ void fsl_pcibios_fixup_bus(struct pci_bus *bus)
> }
> }
>
> +int fsl_arch_pci_exclude_device(struct fsl_pci *pci, u8 bus, u8 devfn)
> +{
> + struct pci_controller *hose = pci->sys;
> +
> + if (!hose)
> + return PCIBIOS_SUCCESSFUL;
> +
> + if (ppc_md.pci_exclude_device)
> + if (ppc_md.pci_exclude_device(hose, bus, devfn))
> + return PCIBIOS_DEVICE_NOT_FOUND;
> +
> + return PCIBIOS_SUCCESSFUL;
> +}
> +
> +int fsl_arch_pci_sys_register(struct fsl_pci *pci)
> +{
> + struct pci_controller *hose;
> +
> + pci_add_flags(PCI_REASSIGN_ALL_BUS);
> + hose = pcibios_alloc_controller(pci->dn);
> + if (!hose)
> + return -ENOMEM;
> +
> + /* set platform device as the parent */
> + hose->private_data = pci;
> + hose->parent = pci->dev;
> + hose->first_busno = pci->first_busno;
> + hose->last_busno = pci->last_busno;
> + hose->ops = pci->ops;
> +
> +#ifdef CONFIG_PPC32
> + /* On 32 bits, limit I/O space to 16MB */
> + if (pci->pci_io_size > 0x01000000)
> + pci->pci_io_size = 0x01000000;
> +
> + /* 32 bits needs to map IOs here */
> + hose->io_base_virt = ioremap(pci->io_base_phys + pci->io_resource.start,
> + pci->pci_io_size);
> +
> + /* Expect trouble if pci_addr is not 0 */
> + if (fsl_pci_primary == pci->dn)
> + isa_io_base = (unsigned long)hose->io_base_virt;
> +#endif /* CONFIG_PPC32 */
> +
> + hose->pci_io_size = pci->io_resource.start + pci->pci_io_size;
> + hose->io_base_phys = pci->io_base_phys;
> + hose->io_resource = pci->io_resource;
> +
> + memcpy(hose->mem_offset, pci->mem_offset, sizeof(hose->mem_offset));
> + memcpy(hose->mem_resources, pci->mem_resources,
> + sizeof(hose->mem_resources));
> + hose->dma_window_base_cur = pci->dma_window_base_cur;
> + hose->dma_window_size = pci->dma_window_size;
> +
> + pci->sys = hose;
> +
> + /*
> + * Install our own dma_set_mask handler to fixup dma_ops
> + * and dma_offset when memory is more than dma window size
> + */
> + if (pci->is_pcie && memblock_end_of_DRAM() > hose->dma_window_size)
> + ppc_md.dma_set_mask = fsl_pci_dma_set_mask;
> +
> +#ifdef CONFIG_SWIOTLB
> + /*
> + * if we couldn't map all of DRAM via the dma windows
> + * we need SWIOTLB to handle buffers located outside of
> + * dma capable memory region
> + */
> + if (memblock_end_of_DRAM() - 1 > hose->dma_window_base_cur +
> + hose->dma_window_size)
> + ppc_swiotlb_enable = 1;
> +#endif
> +
> + mpc85xx_pci_err_probe(to_platform_device(pci->dev));
> + return 0;
> +}
> +
> +void fsl_arch_pci_sys_remove(struct fsl_pci *pci)
> +{
> + struct pci_controller *hose = pci->sys;
> +
> + if (!hose)
> + return;
> +
> + pcibios_free_controller(hose);
> +}
> +
> #endif /* CONFIG_FSL_SOC_BOOKE || CONFIG_PPC_86xx */
>
> DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_FREESCALE, PCI_ANY_ID, quirk_fsl_pcie_header);
> @@ -260,6 +377,16 @@ static struct pci_ops mpc83xx_pcie_ops = {
> .write = mpc83xx_pcie_write_config,
> };
>
> +static int mpc83xx_pcie_check_link(struct pci_controller *hose)
> +{
> + u32 val = 0;
> +
> + early_read_config_dword(hose, 0, 0, PCIE_LTSSM, &val);
> + if (val < PCIE_LTSSM_L0)
> + return 1;
> + return 0;
> +}
> +
> static int __init mpc83xx_pcie_setup(struct pci_controller *hose,
> struct resource *reg)
> {
> @@ -294,7 +421,7 @@ static int __init mpc83xx_pcie_setup(struct pci_controller *hose,
> out_le32(pcie->cfg_type0 + PEX_OUTWIN0_TAH, 0);
> out_le32(pcie->cfg_type0 + PEX_OUTWIN0_TAL, 0);
>
> - if (fsl_pcie_check_link(hose))
> + if (mpc83xx_pcie_check_link(hose))
> hose->indirect_type |= PPC_INDIRECT_TYPE_NO_PCIE_LINK;
>
> return 0;
> @@ -592,6 +719,7 @@ int fsl_pci_mcheck_exception(struct pt_regs *regs)
> #if defined(CONFIG_FSL_SOC_BOOKE) || defined(CONFIG_PPC_86xx)
>
> struct device_node *fsl_pci_primary;
> +extern const struct of_device_id fsl_pci_ids[];
>
> void fsl_pci_assign_primary(void)
> {
> @@ -607,7 +735,8 @@ void fsl_pci_assign_primary(void)
> of_node_put(np);
> np = fsl_pci_primary;
>
> - if (of_match_node(pci_ids, np) && of_device_is_available(np))
> + if (of_match_node(fsl_pci_ids, np) &&
> + of_device_is_available(np))
> return;
> }
>
> @@ -616,7 +745,7 @@ void fsl_pci_assign_primary(void)
> * designate one as primary. This can go away once
> * various bugs with primary-less systems are fixed.
> */
> - for_each_matching_node(np, pci_ids) {
> + for_each_matching_node(np, fsl_pci_ids) {
> if (of_device_is_available(np)) {
> fsl_pci_primary = np;
> of_node_put(np);
> diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c
> index 3eb32f6..2e51575 100644
> --- a/drivers/edac/mpc85xx_edac.c
> +++ b/drivers/edac/mpc85xx_edac.c
> @@ -239,7 +239,6 @@ int mpc85xx_pci_err_probe(struct platform_device *op)
> pdata = pci->pvt_info;
> pdata->name = "mpc85xx_pci_err";
> pdata->irq = NO_IRQ;
> - dev_set_drvdata(&op->dev, pci);
> pci->dev = &op->dev;
> pci->mod_name = EDAC_MOD_STR;
> pci->ctl_name = pdata->name;
> @@ -260,14 +259,13 @@ int mpc85xx_pci_err_probe(struct platform_device *op)
> /* we only need the error registers */
> r.start += 0xe00;
>
> - if (!devm_request_mem_region(&op->dev, r.start, resource_size(&r),
> - pdata->name)) {
> - printk(KERN_ERR "%s: Error while requesting mem region\n",
> - __func__);
> - res = -EBUSY;
> - goto err;
> - }
> -
> + /*
> + * The main pci driver has been changed to call
> + * devm_request_mem_region() to request all PCI controller register
> + * region. PCI EDAC driver can not request error register region
> + * again. so it just only need to call devm_ioremap() to map the error
> + * register region.
> + */
> pdata->pci_vbase = devm_ioremap(&op->dev, r.start, resource_size(&r));
> if (!pdata->pci_vbase) {
> printk(KERN_ERR "%s: Unable to setup PCI err regs\n", __func__);
> diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
> index 3d95048..e829b18 100644
> --- a/drivers/pci/host/Kconfig
> +++ b/drivers/pci/host/Kconfig
> @@ -19,4 +19,11 @@ config PCI_TEGRA
> bool "NVIDIA Tegra PCIe controller"
> depends on ARCH_TEGRA
>
> +config PCI_FSL
> + bool "Freescale PCI/PCIe controller"
> + depends on FSL_SOC_BOOKE || PPC_86xx
> + help
> + Include support for PCI/PCIE controller on Freescale embedded
> + processors 85xx/86xx/QorIQ/Layerscape.
> +
> endmenu
> diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
> index c9a997b..3447a27 100644
> --- a/drivers/pci/host/Makefile
> +++ b/drivers/pci/host/Makefile
> @@ -2,3 +2,4 @@ obj-$(CONFIG_PCIE_DW) += pcie-designware.o
> obj-$(CONFIG_PCI_EXYNOS) += pci-exynos.o
> obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o
> obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o
> +obj-$(CONFIG_PCI_FSL) += pci-fsl.o
> diff --git a/drivers/pci/host/pci-fsl.c b/drivers/pci/host/pci-fsl.c
> index 69d338b..0423e72 100644
> --- a/drivers/pci/host/pci-fsl.c
> +++ b/drivers/pci/host/pci-fsl.c
> @@ -22,38 +22,159 @@
> #include <linux/bootmem.h>
> #include <linux/memblock.h>
> #include <linux/log2.h>
> -#include <linux/slab.h>
> -#include <linux/uaccess.h>
> -
> -#include <asm/io.h>
> -#include <asm/prom.h>
> -#include <asm/pci-bridge.h>
> -#include <asm/ppc-pci.h>
> -#include <asm/machdep.h>
> -#include <asm/disassemble.h>
> -#include <asm/ppc-opcode.h>
> -#include <sysdev/fsl_soc.h>
> -#include <sysdev/fsl_pci.h>
> -
> -static int fsl_pcie_check_link(struct pci_controller *hose)
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_pci.h>
> +#include <linux/pci_regs.h>
> +#include <linux/platform_device.h>
> +#include <linux/resource.h>
> +#include <linux/types.h>
> +#include <linux/memblock.h>
> +#include <linux/fsl/pci.h>
> +
> +/* Indirect type */
> +#define INDIRECT_TYPE_EXT_REG 0x00000002
> +#define INDIRECT_TYPE_SURPRESS_PRIMARY_BUS 0x00000004
> +#define INDIRECT_TYPE_NO_PCIE_LINK 0x00000008
> +#define INDIRECT_TYPE_BIG_ENDIAN 0x00000010
> +#define INDIRECT_TYPE_FSL_CFG_REG_LINK 0x00000040
> +
> +u64 __weak fsl_arch_pci64_dma_offset(void)
> +{
> + return 0;
> +}
> +
> +struct fsl_pci * __weak fsl_arch_sys_to_pci(void *sys)
> +{
> + return NULL;
> +}
> +
> +struct pci_bus * __weak fsl_arch_fake_pci_bus(struct fsl_pci *pci, int busnr)
> +{
> + return NULL;
> +}
> +
> +int __weak fsl_arch_pci_exclude_device(struct fsl_pci *pci, u8 bus, u8 devfn)
> +{
> + return PCIBIOS_SUCCESSFUL;
> +}
> +
> +static int fsl_pci_read_config(struct fsl_pci *pci, int bus, int devfn,
> + int offset, int len, u32 *val)
> +{
> + u32 bus_no, reg, data;
> +
> + if (pci->indirect_type & INDIRECT_TYPE_NO_PCIE_LINK) {
> + if (bus != pci->first_busno)
> + return PCIBIOS_DEVICE_NOT_FOUND;
> + if (devfn != 0)
> + return PCIBIOS_DEVICE_NOT_FOUND;
> + }
> +
> + if (fsl_arch_pci_exclude_device(pci, bus, devfn))
> + return PCIBIOS_DEVICE_NOT_FOUND;
> +
> + bus_no = (bus == pci->first_busno) ? pci->self_busno : bus;
> +
> + if (pci->indirect_type & INDIRECT_TYPE_EXT_REG)
> + reg = ((offset & 0xf00) << 16) | (offset & 0xfc);
> + else
> + reg = offset & 0xfc;
> +
> + if (pci->indirect_type & INDIRECT_TYPE_BIG_ENDIAN)
> + iowrite32be(0x80000000 | (bus_no << 16) | (devfn << 8) | reg,
> + &pci->regs->config_addr);
> + else
> + iowrite32(0x80000000 | (bus_no << 16) | (devfn << 8) | reg,
> + &pci->regs->config_addr);
> +
> + /*
> + * Note: the caller has already checked that offset is
> + * suitably aligned and that len is 1, 2 or 4.
> + */
> + data = ioread32(&pci->regs->config_data);
> + switch (len) {
> + case 1:
> + *val = (data >> (8 * (offset & 3))) & 0xff;
> + break;
> + case 2:
> + *val = (data >> (8 * (offset & 3))) & 0xffff;
> + break;
> + default:
> + *val = data;
> + break;
> + }
> +
> + return PCIBIOS_SUCCESSFUL;
> +}
> +
> +static int fsl_pci_write_config(struct fsl_pci *pci, int bus, int devfn,
> + int offset, int len, u32 val)
> +{
> + void __iomem *cfg_data;
> + u32 bus_no, reg;
> +
> + if (pci->indirect_type & INDIRECT_TYPE_NO_PCIE_LINK) {
> + if (bus != pci->first_busno)
> + return PCIBIOS_DEVICE_NOT_FOUND;
> + if (devfn != 0)
> + return PCIBIOS_DEVICE_NOT_FOUND;
> + }
> +
> + if (fsl_arch_pci_exclude_device(pci, bus, devfn))
> + return PCIBIOS_DEVICE_NOT_FOUND;
> +
> + bus_no = (bus == pci->first_busno) ?
> + pci->self_busno : bus;
> +
> + if (pci->indirect_type & INDIRECT_TYPE_EXT_REG)
> + reg = ((offset & 0xf00) << 16) | (offset & 0xfc);
> + else
> + reg = offset & 0xfc;
> +
> + if (pci->indirect_type & INDIRECT_TYPE_BIG_ENDIAN)
> + iowrite32be(0x80000000 | (bus_no << 16) | (devfn << 8) | reg,
> + &pci->regs->config_addr);
> + else
> + iowrite32(0x80000000 | (bus_no << 16) | (devfn << 8) | reg,
> + &pci->regs->config_addr);
> +
> + /* suppress setting of PCI_PRIMARY_BUS */
> + if (pci->indirect_type & INDIRECT_TYPE_SURPRESS_PRIMARY_BUS)
> + if ((offset == PCI_PRIMARY_BUS) &&
> + (bus == pci->first_busno))
> + val &= 0xffffff00;
> +
> + /*
> + * Note: the caller has already checked that offset is
> + * suitably aligned and that len is 1, 2 or 4.
> + */
> + cfg_data = ((void *) &(pci->regs->config_data)) + (offset & 3);
> + switch (len) {
> + case 1:
> + iowrite8(val, cfg_data);
> + break;
> + case 2:
> + iowrite16(val, cfg_data);
> + break;
> + default:
> + iowrite32(val, cfg_data);
> + break;
> + }
> + return PCIBIOS_SUCCESSFUL;
> +}
> +
> +int fsl_pci_check_link(struct fsl_pci *pci)
> {
> u32 val = 0;
>
> - if (hose->indirect_type & PPC_INDIRECT_TYPE_FSL_CFG_REG_LINK) {
> - if (hose->ops->read == fsl_indirect_read_config) {
> - struct pci_bus bus;
> - bus.number = hose->first_busno;
> - bus.sysdata = hose;
> - bus.ops = hose->ops;
> - indirect_read_config(&bus, 0, PCIE_LTSSM, 4, &val);
> - } else
> - early_read_config_dword(hose, 0, 0, PCIE_LTSSM, &val);
> + if (pci->indirect_type & INDIRECT_TYPE_FSL_CFG_REG_LINK) {
> + fsl_pci_read_config(pci, 0, 0, PCIE_LTSSM, 4, &val);
> if (val < PCIE_LTSSM_L0)
> return 1;
> } else {
> - struct ccsr_pci __iomem *pci = hose->private_data;
> /* for PCIe IP rev 3.0 or greater use CSR0 for link state */
> - val = (in_be32(&pci->pex_csr0) & PEX_CSR0_LTSSM_MASK)
> + val = (in_be32(&pci->regs->pex_csr0) & PEX_CSR0_LTSSM_MASK)
> >> PEX_CSR0_LTSSM_SHIFT;
> if (val != PEX_CSR0_LTSSM_L0)
> return 1;
> @@ -65,27 +186,65 @@ static int fsl_pcie_check_link(struct pci_controller *hose)
> static int fsl_indirect_read_config(struct pci_bus *bus, unsigned int devfn,
> int offset, int len, u32 *val)
> {
> - struct pci_controller *hose = pci_bus_to_host(bus);
> + struct fsl_pci *pci = fsl_arch_sys_to_pci(bus->sysdata);
> +
> + if (!pci)
> + return PCIBIOS_DEVICE_NOT_FOUND;
>
> - if (fsl_pcie_check_link(hose))
> - hose->indirect_type |= PPC_INDIRECT_TYPE_NO_PCIE_LINK;
> + if (fsl_pci_check_link(pci))
> + pci->indirect_type |= INDIRECT_TYPE_NO_PCIE_LINK;
> else
> - hose->indirect_type &= ~PPC_INDIRECT_TYPE_NO_PCIE_LINK;
> + pci->indirect_type &= ~INDIRECT_TYPE_NO_PCIE_LINK;
>
> - return indirect_read_config(bus, devfn, offset, len, val);
> + return fsl_pci_read_config(pci, bus->number, devfn, offset, len, val);
> }
>
> -#if defined(CONFIG_FSL_SOC_BOOKE) || defined(CONFIG_PPC_86xx)
> -
> -static struct pci_ops fsl_indirect_pcie_ops =
> +static int fsl_indirect_write_config(struct pci_bus *bus, unsigned int devfn,
> + int offset, int len, u32 val)
> {
> + struct fsl_pci *pci = fsl_arch_sys_to_pci(bus->sysdata);
> +
> + if (!pci)
> + return PCIBIOS_DEVICE_NOT_FOUND;
> +
> + return fsl_pci_write_config(pci, bus->number, devfn,
> + offset, len, val);
> +}
> +
> +static struct pci_ops fsl_indirect_pci_ops = {
> .read = fsl_indirect_read_config,
> - .write = indirect_write_config,
> + .write = fsl_indirect_write_config,
> };
>
> +#define EARLY_FSL_PCI_OP(rw, size, type) \
> +int early_fsl_##rw##_config_##size(struct fsl_pci *pci, int bus, \
> + int devfn, int offset, type value) \
> +{ \
> + return pci_bus_##rw##_config_##size(fsl_arch_fake_pci_bus(pci, bus),\
> + devfn, offset, value); \
> +}
> +
> +EARLY_FSL_PCI_OP(read, byte, u8 *)
> +EARLY_FSL_PCI_OP(read, word, u16 *)
> +EARLY_FSL_PCI_OP(read, dword, u32 *)
> +EARLY_FSL_PCI_OP(write, byte, u8)
> +EARLY_FSL_PCI_OP(write, word, u16)
> +EARLY_FSL_PCI_OP(write, dword, u32)
> +
> +static int early_fsl_find_capability(struct fsl_pci *pci,
> + int busnr, int devfn, int cap)
> +{
> + struct pci_bus *bus = fsl_arch_fake_pci_bus(pci, busnr);
> +
> + if (!bus)
> + return 0;
> +
> + return pci_bus_find_capability(bus, devfn, cap);
> +}
> +
> static int setup_one_atmu(struct ccsr_pci __iomem *pci,
> - unsigned int index, const struct resource *res,
> - resource_size_t offset)
> + unsigned int index, const struct resource *res,
> + resource_size_t offset)
> {
> resource_size_t pci_addr = res->start - offset;
> resource_size_t phys_addr = res->start;
> @@ -106,10 +265,10 @@ static int setup_one_atmu(struct ccsr_pci __iomem *pci,
> if (index + i >= 5)
> return -1;
>
> - out_be32(&pci->pow[index + i].potar, pci_addr >> 12);
> - out_be32(&pci->pow[index + i].potear, (u64)pci_addr >> 44);
> - out_be32(&pci->pow[index + i].powbar, phys_addr >> 12);
> - out_be32(&pci->pow[index + i].powar, flags | (bits - 1));
> + iowrite32be(pci_addr >> 12, &pci->pow[index + i].potar);
> + iowrite32be((u64)pci_addr >> 44, &pci->pow[index + i].potear);
> + iowrite32be(phys_addr >> 12, &pci->pow[index + i].powbar);
> + iowrite32be(flags | (bits - 1), &pci->pow[index + i].powar);
>
> pci_addr += (resource_size_t)1U << bits;
> phys_addr += (resource_size_t)1U << bits;
> @@ -120,21 +279,19 @@ static int setup_one_atmu(struct ccsr_pci __iomem *pci,
> }
>
> /* atmu setup for fsl pci/pcie controller */
> -static void setup_pci_atmu(struct pci_controller *hose)
> +static void setup_pci_atmu(struct fsl_pci *pci)
> {
> - struct ccsr_pci __iomem *pci = hose->private_data;
> int i, j, n, mem_log, win_idx = 3, start_idx = 1, end_idx = 4;
> u64 mem, sz, paddr_hi = 0;
> u64 offset = 0, paddr_lo = ULLONG_MAX;
> u32 pcicsrbar = 0, pcicsrbar_sz;
> u32 piwar = PIWAR_EN | PIWAR_PF | PIWAR_TGI_LOCAL |
> PIWAR_READ_SNOOP | PIWAR_WRITE_SNOOP;
> - const char *name = hose->dn->full_name;
> const u64 *reg;
> int len;
>
> - if (early_find_capability(hose, 0, 0, PCI_CAP_ID_EXP)) {
> - if (in_be32(&pci->block_rev1) >= PCIE_IP_REV_2_2) {
> + if (pci->is_pcie) {
> + if (in_be32(&pci->regs->block_rev1) >= PCIE_IP_REV_2_2) {
> win_idx = 2;
> start_idx = 0;
> end_idx = 3;
> @@ -142,47 +299,54 @@ static void setup_pci_atmu(struct pci_controller *hose)
> }
>
> /* Disable all windows (except powar0 since it's ignored) */
> - for(i = 1; i < 5; i++)
> - out_be32(&pci->pow[i].powar, 0);
> + for (i = 1; i < 5; i++)
> + iowrite32be(0, &pci->regs->pow[i].powar);
> for (i = start_idx; i < end_idx; i++)
> - out_be32(&pci->piw[i].piwar, 0);
> + iowrite32be(0, &pci->regs->piw[i].piwar);
>
> /* Setup outbound MEM window */
> - for(i = 0, j = 1; i < 3; i++) {
> - if (!(hose->mem_resources[i].flags & IORESOURCE_MEM))
> + for (i = 0, j = 1; i < 3; i++) {
> + if (!(pci->mem_resources[i].flags & IORESOURCE_MEM))
> continue;
>
> - paddr_lo = min(paddr_lo, (u64)hose->mem_resources[i].start);
> - paddr_hi = max(paddr_hi, (u64)hose->mem_resources[i].end);
> + paddr_lo = min_t(u64, paddr_lo, pci->mem_resources[i].start);
> + paddr_hi = max_t(u64, paddr_hi, pci->mem_resources[i].end);
>
> /* We assume all memory resources have the same offset */
> - offset = hose->mem_offset[i];
> - n = setup_one_atmu(pci, j, &hose->mem_resources[i], offset);
> + offset = pci->mem_offset[i];
> + n = setup_one_atmu(pci->regs, j, &pci->mem_resources[i],
> + offset);
>
> if (n < 0 || j >= 5) {
> - pr_err("Ran out of outbound PCI ATMUs for resource %d!\n", i);
> - hose->mem_resources[i].flags |= IORESOURCE_DISABLED;
> + dev_err(pci->dev,
> + "Ran out of outbound PCI ATMUs for resource %d!\n",
> + i);
> + pci->mem_resources[i].flags |= IORESOURCE_DISABLED;
> } else
> j += n;
> }
>
> /* Setup outbound IO window */
> - if (hose->io_resource.flags & IORESOURCE_IO) {
> - if (j >= 5) {
> - pr_err("Ran out of outbound PCI ATMUs for IO resource\n");
> - } else {
> - pr_debug("PCI IO resource start 0x%016llx, size 0x%016llx, "
> - "phy base 0x%016llx.\n",
> - (u64)hose->io_resource.start,
> - (u64)resource_size(&hose->io_resource),
> - (u64)hose->io_base_phys);
> - out_be32(&pci->pow[j].potar, (hose->io_resource.start >> 12));
> - out_be32(&pci->pow[j].potear, 0);
> - out_be32(&pci->pow[j].powbar, (hose->io_base_phys >> 12));
> + if (pci->io_resource.flags & IORESOURCE_IO) {
> + if (j >= 5)
> + dev_err(pci->dev,
> + "Ran out of outbound PCI ATMUs for IO resource\n");
> + else {
> + dev_dbg(pci->dev,
> + "PCI IO resource start 0x%016llx,"
> + "size 0x%016llx, phy base 0x%016llx.\n",
> + (u64)pci->io_resource.start,
> + (u64)resource_size(&pci->io_resource),
> + (u64)pci->io_base_phys);
> + iowrite32be(pci->io_resource.start >> 12,
> + &pci->regs->pow[j].potar);
> + iowrite32be(0, &pci->regs->pow[j].potear);
> + iowrite32be(pci->io_base_phys >> 12,
> + &pci->regs->pow[j].powbar);
> /* Enable, IO R/W */
> - out_be32(&pci->pow[j].powar, 0x80088000
> - | (ilog2(hose->io_resource.end
> - - hose->io_resource.start + 1) - 1));
> + iowrite32be(0x80088000 |
> + (ilog2(resource_size(&pci->io_resource)) - 1),
> + &pci->regs->pow[j].powar);
> }
> }
>
> @@ -191,18 +355,20 @@ static void setup_pci_atmu(struct pci_controller *hose)
> paddr_lo -= offset;
>
> if (paddr_hi == paddr_lo) {
> - pr_err("%s: No outbound window space\n", name);
> + dev_err(pci->dev, "No outbound window space\n");
> return;
> }
>
> if (paddr_lo == 0) {
> - pr_err("%s: No space for inbound window\n", name);
> + dev_err(pci->dev, "No space for inbound window\n");
> return;
> }
>
> /* setup PCSRBAR/PEXCSRBAR */
> - early_write_config_dword(hose, 0, 0, PCI_BASE_ADDRESS_0, 0xffffffff);
> - early_read_config_dword(hose, 0, 0, PCI_BASE_ADDRESS_0, &pcicsrbar_sz);
> + early_fsl_write_config_dword(pci, 0, 0, PCI_BASE_ADDRESS_0,
> + 0xffffffff);
> + early_fsl_read_config_dword(pci, 0, 0, PCI_BASE_ADDRESS_0,
> + &pcicsrbar_sz);
> pcicsrbar_sz = ~pcicsrbar_sz + 1;
>
> if (paddr_hi < (0x100000000ull - pcicsrbar_sz) ||
> @@ -210,11 +376,12 @@ static void setup_pci_atmu(struct pci_controller *hose)
> pcicsrbar = 0x100000000ull - pcicsrbar_sz;
> else
> pcicsrbar = (paddr_lo - pcicsrbar_sz) & -pcicsrbar_sz;
> - early_write_config_dword(hose, 0, 0, PCI_BASE_ADDRESS_0, pcicsrbar);
> + early_fsl_write_config_dword(pci, 0, 0, PCI_BASE_ADDRESS_0,
> + pcicsrbar);
>
> - paddr_lo = min(paddr_lo, (u64)pcicsrbar);
> + paddr_lo = min_t(u64, paddr_lo, pcicsrbar);
>
> - pr_info("%s: PCICSRBAR @ 0x%x\n", name, pcicsrbar);
> + dev_info(pci->dev, "PCICSRBAR @ 0x%x\n", pcicsrbar);
>
> /* Setup inbound mem window */
> mem = memblock_end_of_DRAM();
> @@ -231,17 +398,19 @@ static void setup_pci_atmu(struct pci_controller *hose)
> * can avoid allocating a new ATMU by extending the DDR ATMU by one
> * page.
> */
> - reg = of_get_property(hose->dn, "msi-address-64", &len);
> + reg = of_get_property(pci->dn, "msi-address-64", &len);
> if (reg && (len == sizeof(u64))) {
> u64 address = be64_to_cpup(reg);
>
> if ((address >= mem) && (address < (mem + PAGE_SIZE))) {
> - pr_info("%s: extending DDR ATMU to cover MSIIR", name);
> + dev_info(pci->dev,
> + "extending DDR ATMU to cover MSIIR\n");
> mem += PAGE_SIZE;
> } else {
> /* TODO: Create a new ATMU for MSIIR */
> - pr_warn("%s: msi-address-64 address of %llx is "
> - "unsupported\n", name, address);
> + dev_warn(pci->dev,
> + "msi-address-64 address of %llx is "
> + "unsupported\n", address);
> }
> }
>
> @@ -249,25 +418,26 @@ static void setup_pci_atmu(struct pci_controller *hose)
> mem_log = ilog2(sz);
>
> /* PCIe can overmap inbound & outbound since RX & TX are separated */
> - if (early_find_capability(hose, 0, 0, PCI_CAP_ID_EXP)) {
> + if (pci->is_pcie) {
> /* Size window to exact size if power-of-two or one size up */
> if ((1ull << mem_log) != mem) {
> mem_log++;
> if ((1ull << mem_log) > mem)
> - pr_info("%s: Setting PCI inbound window "
> - "greater than memory size\n", name);
> + dev_info(pci->dev,
> + "Setting PCI inbound window "
> + "greater than memory size\n");
> }
>
> piwar |= ((mem_log - 1) & PIWAR_SZ_MASK);
>
> /* Setup inbound memory window */
> - out_be32(&pci->piw[win_idx].pitar, 0x00000000);
> - out_be32(&pci->piw[win_idx].piwbar, 0x00000000);
> - out_be32(&pci->piw[win_idx].piwar, piwar);
> + iowrite32be(0, &pci->regs->piw[win_idx].pitar);
> + iowrite32be(0, &pci->regs->piw[win_idx].piwbar);
> + iowrite32be(piwar, &pci->regs->piw[win_idx].piwar);
> win_idx--;
>
> - hose->dma_window_base_cur = 0x00000000;
> - hose->dma_window_size = (resource_size_t)sz;
> + pci->dma_window_base_cur = 0x00000000;
> + pci->dma_window_size = (resource_size_t)sz;
>
> /*
> * if we have >4G of memory setup second PCI inbound window to
> @@ -284,28 +454,22 @@ static void setup_pci_atmu(struct pci_controller *hose)
> piwar = (piwar & ~PIWAR_SZ_MASK) | (mem_log - 1);
>
> /* Setup inbound memory window */
> - out_be32(&pci->piw[win_idx].pitar, 0x00000000);
> - out_be32(&pci->piw[win_idx].piwbear,
> - pci64_dma_offset >> 44);
> - out_be32(&pci->piw[win_idx].piwbar,
> - pci64_dma_offset >> 12);
> - out_be32(&pci->piw[win_idx].piwar, piwar);
> -
> - /*
> - * install our own dma_set_mask handler to fixup dma_ops
> - * and dma_offset
> - */
> - ppc_md.dma_set_mask = fsl_pci_dma_set_mask;
> -
> - pr_info("%s: Setup 64-bit PCI DMA window\n", name);
> + iowrite32be(0, &pci->regs->piw[win_idx].pitar);
> + iowrite32be(fsl_arch_pci64_dma_offset() >> 44,
> + &pci->regs->piw[win_idx].piwbear);
> + iowrite32be(fsl_arch_pci64_dma_offset() >> 12,
> + &pci->regs->piw[win_idx].piwbar);
> + iowrite32be(piwar,
> + &pci->regs->piw[win_idx].piwar);
> }
> } else {
> u64 paddr = 0;
>
> /* Setup inbound memory window */
> - out_be32(&pci->piw[win_idx].pitar, paddr >> 12);
> - out_be32(&pci->piw[win_idx].piwbar, paddr >> 12);
> - out_be32(&pci->piw[win_idx].piwar, (piwar | (mem_log - 1)));
> + iowrite32be(paddr >> 12, &pci->regs->piw[win_idx].pitar);
> + iowrite32be(paddr >> 12, &pci->regs->piw[win_idx].piwbar);
> + iowrite32be((piwar | (mem_log - 1)),
> + &pci->regs->piw[win_idx].piwar);
> win_idx--;
>
> paddr += 1ull << mem_log;
> @@ -315,167 +479,181 @@ static void setup_pci_atmu(struct pci_controller *hose)
> mem_log = ilog2(sz);
> piwar |= (mem_log - 1);
>
> - out_be32(&pci->piw[win_idx].pitar, paddr >> 12);
> - out_be32(&pci->piw[win_idx].piwbar, paddr >> 12);
> - out_be32(&pci->piw[win_idx].piwar, piwar);
> + iowrite32be(paddr >> 12,
> + &pci->regs->piw[win_idx].pitar);
> + iowrite32be(paddr >> 12,
> + &pci->regs->piw[win_idx].piwbar);
> + iowrite32be(piwar,
> + &pci->regs->piw[win_idx].piwar);
> win_idx--;
>
> paddr += 1ull << mem_log;
> }
>
> - hose->dma_window_base_cur = 0x00000000;
> - hose->dma_window_size = (resource_size_t)paddr;
> + pci->dma_window_base_cur = 0x00000000;
> + pci->dma_window_size = (resource_size_t)paddr;
> }
>
> - if (hose->dma_window_size < mem) {
> -#ifdef CONFIG_SWIOTLB
> - ppc_swiotlb_enable = 1;
> -#else
> - pr_err("%s: ERROR: Memory size exceeds PCI ATMU ability to "
> - "map - enable CONFIG_SWIOTLB to avoid dma errors.\n",
> - name);
> + if (pci->dma_window_size < mem) {
> +#ifndef CONFIG_SWIOTLB
> + dev_err(pci->dev,
> + "Memory size exceeds PCI ATMU ability to "
> + "map - enable CONFIG_SWIOTLB to avoid dma errors.\n");
> #endif
> /* adjusting outbound windows could reclaim space in mem map */
> if (paddr_hi < 0xffffffffull)
> - pr_warning("%s: WARNING: Outbound window cfg leaves "
> + dev_warn(pci->dev,
> + "Outbound window cfg leaves "
> "gaps in memory map. Adjusting the memory map "
> - "could reduce unnecessary bounce buffering.\n",
> - name);
> + "could reduce unnecessary bounce buffering.\n");
>
> - pr_info("%s: DMA window size is 0x%llx\n", name,
> - (u64)hose->dma_window_size);
> + dev_info(pci->dev, "DMA window size is 0x%llx\n",
> + (u64)pci->dma_window_size);
> }
> }
>
> -static void __init setup_pci_cmd(struct pci_controller *hose)
> +static void __init setup_pci_cmd(struct fsl_pci *pci)
> {
> u16 cmd;
> int cap_x;
>
> - early_read_config_word(hose, 0, 0, PCI_COMMAND, &cmd);
> + early_fsl_read_config_word(pci, 0, 0, PCI_COMMAND, &cmd);
> cmd |= PCI_COMMAND_SERR | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY
> | PCI_COMMAND_IO;
> - early_write_config_word(hose, 0, 0, PCI_COMMAND, cmd);
> + early_fsl_write_config_word(pci, 0, 0, PCI_COMMAND, cmd);
>
> - cap_x = early_find_capability(hose, 0, 0, PCI_CAP_ID_PCIX);
> + cap_x = early_fsl_find_capability(pci, 0, 0, PCI_CAP_ID_PCIX);
> if (cap_x) {
> int pci_x_cmd = cap_x + PCI_X_CMD;
> cmd = PCI_X_CMD_MAX_SPLIT | PCI_X_CMD_MAX_READ
> | PCI_X_CMD_ERO | PCI_X_CMD_DPERR_E;
> - early_write_config_word(hose, 0, 0, pci_x_cmd, cmd);
> - } else {
> - early_write_config_byte(hose, 0, 0, PCI_LATENCY_TIMER, 0x80);
> - }
> + early_fsl_write_config_word(pci, 0, 0, pci_x_cmd, cmd);
> + } else
> + early_fsl_write_config_byte(pci, 0, 0, PCI_LATENCY_TIMER,
> + 0x80);
> }
>
> -int __init fsl_add_bridge(struct platform_device *pdev, int is_primary)
> +static int __init
> +fsl_pci_setup(struct platform_device *pdev, struct fsl_pci *pci)
> {
> - int len;
> - struct pci_controller *hose;
> - struct resource rsrc;
> - const int *bus_range;
> + struct resource *rsrc;
> u8 hdr_type, progif;
> - struct device_node *dev;
> - struct ccsr_pci __iomem *pci;
> + struct device_node *dn;
> + struct of_pci_range range;
> + struct of_pci_range_parser parser;
> + int mem = 0;
>
> - dev = pdev->dev.of_node;
> + dn = pdev->dev.of_node;
> + pci->dn = dn;
> + pci->dev = &pdev->dev;
>
> - if (!of_device_is_available(dev)) {
> - pr_warning("%s: disabled\n", dev->full_name);
> - return -ENODEV;
> - }
> -
> - pr_debug("Adding PCI host bridge %s\n", dev->full_name);
> + dev_info(&pdev->dev, "Find controller %s\n", dn->full_name);
>
> /* Fetch host bridge registers address */
> - if (of_address_to_resource(dev, 0, &rsrc)) {
> - printk(KERN_WARNING "Can't get pci register base!");
> - return -ENOMEM;
> + rsrc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + if (!rsrc) {
> + dev_err(&pdev->dev, "Can't get pci register base!");
> + return -EINVAL;
> }
> + dev_info(&pdev->dev, "REG 0x%016llx..0x%016llx\n",
> + (u64)rsrc->start, (u64)rsrc->end);
>
> - /* Get bus range if any */
> - bus_range = of_get_property(dev, "bus-range", &len);
> - if (bus_range == NULL || len < 2 * sizeof(int))
> - printk(KERN_WARNING "Can't get bus-range for %s, assume"
> - " bus 0\n", dev->full_name);
> -
> - pci_add_flags(PCI_REASSIGN_ALL_BUS);
> - hose = pcibios_alloc_controller(dev);
> - if (!hose)
> - return -ENOMEM;
> + /* Parse pci range resources from device tree */
> + if (of_pci_range_parser_init(&parser, dn)) {
> + dev_err(&pdev->dev, "missing ranges property\n");
> + return -EINVAL;
> + }
>
> - /* set platform device as the parent */
> - hose->parent = &pdev->dev;
> - hose->first_busno = bus_range ? bus_range[0] : 0x0;
> - hose->last_busno = bus_range ? bus_range[1] : 0xff;
> + /* Get the I/O and memory ranges from device tree */
> + for_each_of_pci_range(&parser, &range) {
> + unsigned long restype = range.flags & IORESOURCE_TYPE_BITS;
> + if (restype == IORESOURCE_IO) {
> + of_pci_range_to_resource(&range, dn,
> + &pci->io_resource);
> + pci->io_resource.name = "I/O";
> + pci->io_resource.start = range.pci_addr;
> + pci->io_resource.end = range.pci_addr + range.size - 1;
> + pci->pci_io_size = range.size;
> + pci->io_base_phys = range.cpu_addr - range.pci_addr;
> + dev_info(&pdev->dev,
> + " IO 0x%016llx..0x%016llx -> 0x%016llx\n",
> + range.cpu_addr,
> + range.cpu_addr + range.size - 1,
> + range.pci_addr);
> + }
> + if (restype == IORESOURCE_MEM) {
> + if (mem >= 3)
> + continue;
> + of_pci_range_to_resource(&range, dn,
> + &pci->mem_resources[mem]);
> + pci->mem_resources[mem].name = "MEM";
> + pci->mem_offset[mem] = range.cpu_addr - range.pci_addr;
> + dev_info(&pdev->dev,
> + "MEM 0x%016llx..0x%016llx -> 0x%016llx\n",
> + (u64)pci->mem_resources[mem].start,
> + (u64)pci->mem_resources[mem].end,
> + range.pci_addr);
> + }
> + }
>
> - pr_debug("PCI memory map start 0x%016llx, size 0x%016llx\n",
> - (u64)rsrc.start, (u64)resource_size(&rsrc));
> + /* Get bus range */
> + if (of_pci_parse_bus_range(dn, &pci->busn)) {
> + dev_err(&pdev->dev, "failed to parse bus-range property\n");
> + pci->first_busno = 0x0;
> + pci->last_busno = 0xff;
> + } else {
> + pci->first_busno = pci->busn.start;
> + pci->last_busno = pci->busn.end;
> + }
> + dev_info(&pdev->dev, "Firmware bus number %d->%d\n",
> + pci->first_busno, pci->last_busno);
>
> - pci = hose->private_data = ioremap(rsrc.start, resource_size(&rsrc));
> - if (!hose->private_data)
> - goto no_bridge;
> + pci->regs = devm_ioremap_resource(&pdev->dev, rsrc);
> + if (IS_ERR(pci->regs))
> + return PTR_ERR(pci->regs);
>
> - setup_indirect_pci(hose, rsrc.start, rsrc.start + 0x4,
> - PPC_INDIRECT_TYPE_BIG_ENDIAN);
> + pci->ops = &fsl_indirect_pci_ops;
> + pci->indirect_type = INDIRECT_TYPE_BIG_ENDIAN;
>
> - if (in_be32(&pci->block_rev1) < PCIE_IP_REV_3_0)
> - hose->indirect_type |= PPC_INDIRECT_TYPE_FSL_CFG_REG_LINK;
> + if (in_be32(&pci->regs->block_rev1) < PCIE_IP_REV_3_0)
> + pci->indirect_type |= INDIRECT_TYPE_FSL_CFG_REG_LINK;
>
> - if (early_find_capability(hose, 0, 0, PCI_CAP_ID_EXP)) {
> - /* use fsl_indirect_read_config for PCIe */
> - hose->ops = &fsl_indirect_pcie_ops;
> - /* For PCIE read HEADER_TYPE to identify controler mode */
> - early_read_config_byte(hose, 0, 0, PCI_HEADER_TYPE, &hdr_type);
> - if ((hdr_type & 0x7f) != PCI_HEADER_TYPE_BRIDGE)
> + pci->is_pcie = early_fsl_find_capability(pci, 0, 0, PCI_CAP_ID_EXP);
> + if (pci->is_pcie) {
> + /* For PCIE read HEADER_TYPE to identify controller mode */
> + early_fsl_read_config_byte(pci, 0, 0, PCI_HEADER_TYPE,
> + &hdr_type);
> + if ((hdr_type & 0x7f) == PCI_HEADER_TYPE_NORMAL)
> goto no_bridge;
> -
> } else {
> /* For PCI read PROG to identify controller mode */
> - early_read_config_byte(hose, 0, 0, PCI_CLASS_PROG, &progif);
> + early_fsl_read_config_byte(pci, 0, 0, PCI_CLASS_PROG, &progif);
> if ((progif & 1) == 1)
> goto no_bridge;
> }
>
> - setup_pci_cmd(hose);
> + setup_pci_cmd(pci);
>
> /* check PCI express link status */
> - if (early_find_capability(hose, 0, 0, PCI_CAP_ID_EXP)) {
> - hose->indirect_type |= PPC_INDIRECT_TYPE_EXT_REG |
> - PPC_INDIRECT_TYPE_SURPRESS_PRIMARY_BUS;
> - if (fsl_pcie_check_link(hose))
> - hose->indirect_type |= PPC_INDIRECT_TYPE_NO_PCIE_LINK;
> + if (pci->is_pcie) {
> + pci->indirect_type |= INDIRECT_TYPE_EXT_REG |
> + INDIRECT_TYPE_SURPRESS_PRIMARY_BUS;
> + if (fsl_pci_check_link(pci))
> + pci->indirect_type |= INDIRECT_TYPE_NO_PCIE_LINK;
> }
>
> - printk(KERN_INFO "Found FSL PCI host bridge at 0x%016llx. "
> - "Firmware bus number: %d->%d\n",
> - (unsigned long long)rsrc.start, hose->first_busno,
> - hose->last_busno);
> -
> - pr_debug(" ->Hose at 0x%p, cfg_addr=0x%p,cfg_data=0x%p\n",
> - hose, hose->cfg_addr, hose->cfg_data);
> -
> - /* Interpret the "ranges" property */
> - /* This also maps the I/O region and sets isa_io/mem_base */
> - pci_process_bridge_OF_ranges(hose, dev, is_primary);
> -
> /* Setup PEX window registers */
> - setup_pci_atmu(hose);
> + setup_pci_atmu(pci);
> +
> + platform_set_drvdata(pdev, pci);
>
> return 0;
>
> no_bridge:
> - iounmap(hose->private_data);
> - /* unmap cfg_data & cfg_addr separately if not on same page */
> - if (((unsigned long)hose->cfg_data & PAGE_MASK) !=
> - ((unsigned long)hose->cfg_addr & PAGE_MASK))
> - iounmap(hose->cfg_data);
> - iounmap(hose->cfg_addr);
> - pcibios_free_controller(hose);
> return -ENODEV;
> }
>
> -static const struct of_device_id pci_ids[] = {
> +const struct of_device_id fsl_pci_ids[] = {
> { .compatible = "fsl,mpc8540-pci", },
> { .compatible = "fsl,mpc8548-pcie", },
> { .compatible = "fsl,mpc8610-pci", },
> @@ -496,35 +674,63 @@ static const struct of_device_id pci_ids[] = {
> {},
> };
>
> -static int fsl_pci_probe(struct platform_device *pdev)
> +static int __init fsl_pci_probe(struct platform_device *pdev)
> {
> int ret;
> - struct device_node *node;
> + struct fsl_pci *pci;
> +
> + if (!of_device_is_available(pdev->dev.of_node)) {
> + dev_warn(&pdev->dev, "disabled\n");
> + return -ENODEV;
> + }
> +
> + if (!fsl_arch_pci_sys_register) {
> + dev_err(&pdev->dev,
> + "no fsl_arch_pci_sys_register implementation\n");
> + return -EPERM;
> + }
> +
> + pci = devm_kzalloc(&pdev->dev, sizeof(*pci), GFP_KERNEL);
> + if (!pci) {
> + dev_err(&pdev->dev, "no memory for fsl_pci\n");
> + return -ENOMEM;
> + }
>
> - node = pdev->dev.of_node;
> - ret = fsl_add_bridge(pdev, fsl_pci_primary == node);
> + ret = fsl_pci_setup(pdev, pci);
> + if (ret)
> + return ret;
>
> - mpc85xx_pci_err_probe(pdev);
> + ret = fsl_arch_pci_sys_register(pci);
> + if (ret) {
> + dev_err(&pdev->dev, "failed to register pcie to Arch\n");
> + return ret;
> + }
>
> return 0;
> }
>
> -#ifdef CONFIG_PM
> -static int fsl_pci_resume(struct device *dev)
> +static int __exit fsl_pci_remove(struct platform_device *pdev)
> {
> - struct pci_controller *hose;
> - struct resource pci_rsrc;
> + struct fsl_pci *pci = platform_get_drvdata(pdev);
>
> - hose = pci_find_hose_for_OF_device(dev->of_node);
> - if (!hose)
> + if (!pci)
> return -ENODEV;
>
> - if (of_address_to_resource(dev->of_node, 0, &pci_rsrc)) {
> - dev_err(dev, "Get pci register base failed.");
> + if (fsl_arch_pci_sys_remove)
> + fsl_arch_pci_sys_remove(pci);
> +
> + return 0;
> +}
> +
> +#ifdef CONFIG_PM
> +static int fsl_pci_resume(struct device *dev)
> +{
> + struct fsl_pci *pci = dev_get_drvdata(dev);
> +
> + if (!pci)
> return -ENODEV;
> - }
>
> - setup_pci_atmu(hose);
> + setup_pci_atmu(pci);
>
> return 0;
> }
> @@ -545,9 +751,10 @@ static struct platform_driver fsl_pci_driver = {
> .driver = {
> .name = "fsl-pci",
> .pm = PCI_PM_OPS,
> - .of_match_table = pci_ids,
> + .of_match_table = fsl_pci_ids,
> },
> .probe = fsl_pci_probe,
> + .remove = fsl_pci_remove,
> };
>
> static int __init fsl_pci_init(void)
> diff --git a/include/linux/fsl/pci.h b/include/linux/fsl/pci.h
> index bfc241d..500bdbb 100644
> --- a/include/linux/fsl/pci.h
> +++ b/include/linux/fsl/pci.h
> @@ -102,5 +102,74 @@ struct ccsr_pci {
>
> };
>
> +/*
> + * Structure of a PCI controller (host bridge)
> + */
> +struct fsl_pci {
> + struct list_head node;
> + int is_pcie;
> + struct device_node *dn;
> + struct device *dev;
> +
> + int first_busno;
> + int last_busno;
> + int self_busno;
> + struct resource busn;
> +
> + struct pci_ops *ops;
> + struct ccsr_pci __iomem *regs;
> +
> + u32 indirect_type;
> +
> + struct resource io_resource;
> + resource_size_t io_base_phys;
> + resource_size_t pci_io_size;
> +
> + struct resource mem_resources[3];
> + resource_size_t mem_offset[3];
> +
> + int global_number; /* PCI domain number */
> +
> + resource_size_t dma_window_base_cur;
> + resource_size_t dma_window_size;
> +
> + void *sys;
> +};
> +
> +/* Return link status 0-> link, 1-> no link */
> +int fsl_pci_check_link(struct fsl_pci *pci);
> +
> +/*
> + * The fsl_arch_* functions are arch hooks. Those functions are
> + * implemented as weak symbols so that they can be overridden by
> + * architecture specific code if needed.
> + */
> +
> +/* Return PCI64 DMA offset */
> +u64 fsl_arch_pci64_dma_offset(void);
> +
> +/*
> + * Convert architecture specific pci controller structure to fsl_pci
> + * PowerPC uses structure pci_controller and ARM uses structure pci_sys_data
> + * to describe pci controller.
> + */
> +struct fsl_pci *fsl_arch_sys_to_pci(void *sys);
> +
> +/*
> + * To fake a PCI bus
> + * it is called by early_fsl_*(), at that time the architecture-dependent
> + * pci controller and pci bus have not been created.
> + */
> +struct pci_bus *fsl_arch_fake_pci_bus(struct fsl_pci *pci, int busnr);
> +
> +/* To avoid touching specified devices */
> +int fsl_arch_pci_exclude_device(struct fsl_pci *pci, u8 bus, u8 devfn);
> +
> +/* Register PCI/PCIe controller to architecture system */
> +int __weak fsl_arch_pci_sys_register(struct fsl_pci *pci);
> +
> +/* Remove PCI/PCIe controller from architecture system */
> +void __weak fsl_arch_pci_sys_remove(struct fsl_pci *pci);
> +
> #endif /* __PCI_H */
> #endif /* __KERNEL__ */
More information about the Linuxppc-dev
mailing list