From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from ch1outboundpool.messaging.microsoft.com (ch1ehsobe004.messaging.microsoft.com [216.32.181.184]) (using TLSv1 with cipher AES128-SHA (128/128 bits)) (Client CN "mail.global.frontbridge.com", Issuer "MSIT Machine Auth CA 2" (not verified)) by ozlabs.org (Postfix) with ESMTPS id 99DA12C0356 for ; Fri, 27 Sep 2013 21:28:12 +1000 (EST) Message-ID: <52456C0C.2020504@freescale.com> Date: Fri, 27 Sep 2013 19:29:16 +0800 From: Lian Minghuan-b31939 MIME-Version: 1.0 To: Minghuan Lian , Subject: Re: [PATCH 2/2] pci: fsl: rework PCI driver compatible with Layerscape References: <1379502122-20792-1-git-send-email-Minghuan.Lian@freescale.com> <1379502122-20792-2-git-send-email-Minghuan.Lian@freescale.com> In-Reply-To: <1379502122-20792-2-git-send-email-Minghuan.Lian@freescale.com> Content-Type: text/plain; charset="ISO-8859-1"; format=flowed Cc: Scott Wood , Bjorn Helgaas , linux-pci@vger.kernel.org, Zang Roy-R61911 List-Id: Linux on PowerPC Developers Mail List List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , 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 > --- > 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 > #include > #include > -#include > -#include > - > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > - > -static int fsl_pcie_check_link(struct pci_controller *hose) > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +/* 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__ */