From cc6ea0dd28d450925dd43135647fcb73f171c748 Mon Sep 17 00:00:00 2001 From: Roy ZANG Date: Fri, 21 Sep 2012 04:12:52 +0000 Subject: powerpc/85xx: Add support for FSL PCIe controller v3.0 The T4240 utilizes a new PCIe controller block that has some minor programming model differences from previous versions. The major one that impacts initialization is how we determine the link state. On the 3.x controllers we have a memory mapped SoC register instead of a PCI config register that reports the link state. Signed-off-by: Roy Zang Signed-off-by: Andy Fleming Signed-off-by: Kumar Gala --- arch/powerpc/sysdev/fsl_pci.c | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) (limited to 'arch/powerpc/sysdev/fsl_pci.c') diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c index 682084dba19b..3271177239b9 100644 --- a/arch/powerpc/sysdev/fsl_pci.c +++ b/arch/powerpc/sysdev/fsl_pci.c @@ -54,13 +54,35 @@ static void quirk_fsl_pcie_header(struct pci_dev *dev) return; } -static int __init fsl_pcie_check_link(struct pci_controller *hose) +static int __init fsl_pcie_check_link(struct pci_controller *hose, + struct resource *rsrc) { + struct ccsr_pci __iomem *pci = NULL; u32 val; + /* for PCIe IP rev 3.0 or greater use CSR0 for link state */ + if (rsrc) { + pr_debug("PCI memory map start 0x%016llx, size 0x%016llx\n", + (u64)rsrc->start, (u64)rsrc->end - (u64)rsrc->start + 1); + pci = ioremap(rsrc->start, rsrc->end - rsrc->start + 1); + if (!pci) { + dev_err(hose->parent, "Unable to map PCIe registers\n"); + return -ENOMEM; + } + if (in_be32(&pci->block_rev1) >= PCIE_IP_REV_3_0) { + val = (in_be32(&pci->pex_csr0) & PEX_CSR0_LTSSM_MASK) + >> PEX_CSR0_LTSSM_SHIFT; + if (val != PEX_CSR0_LTSSM_L0) + return 1; + iounmap(pci); + return 0; + } + iounmap(pci); + } early_read_config_dword(hose, 0, 0, PCIE_LTSSM, &val); if (val < PCIE_LTSSM_L0) return 1; + return 0; } @@ -483,7 +505,7 @@ int __init fsl_add_bridge(struct platform_device *pdev, int is_primary) 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)) + if (fsl_pcie_check_link(hose, &rsrc)) hose->indirect_type |= PPC_INDIRECT_TYPE_NO_PCIE_LINK; } @@ -685,7 +707,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 (fsl_pcie_check_link(hose, NULL)) hose->indirect_type |= PPC_INDIRECT_TYPE_NO_PCIE_LINK; return 0; @@ -836,6 +858,7 @@ static const struct of_device_id pci_ids[] = { { .compatible = "fsl,qoriq-pcie-v2.2", }, { .compatible = "fsl,qoriq-pcie-v2.3", }, { .compatible = "fsl,qoriq-pcie-v2.4", }, + { .compatible = "fsl,qoriq-pcie-v3.0", }, /* * The following entries are for compatibility with older device -- cgit v1.2.3 From 2b4a8bd242d2880b232d07105981a8d31e8bc262 Mon Sep 17 00:00:00 2001 From: Roy Zang Date: Fri, 29 Mar 2013 21:06:17 +0800 Subject: powerpc/fsl_pci: fix 64 bit pci size issue The size might be 64 bit, so use ilog2() instead of __ilog2() or __ilog2_u64(). ilog2() can select 32bit or 64bit function automatically. Signed-off-by: Roy Zang Signed-off-by: Kumar Gala --- arch/powerpc/sysdev/fsl_pci.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'arch/powerpc/sysdev/fsl_pci.c') diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c index 3271177239b9..e7ec337f03fd 100644 --- a/arch/powerpc/sysdev/fsl_pci.c +++ b/arch/powerpc/sysdev/fsl_pci.c @@ -128,7 +128,7 @@ static int setup_one_atmu(struct ccsr_pci __iomem *pci, flags |= 0x10000000; /* enable relaxed ordering */ for (i = 0; size > 0; i++) { - unsigned int bits = min(__ilog2(size), + unsigned int bits = min(ilog2(size), __ffs(pci_addr | phys_addr)); if (index + i >= 5) @@ -218,7 +218,7 @@ static void setup_pci_atmu(struct pci_controller *hose, out_be32(&pci->pow[j].powbar, (hose->io_base_phys >> 12)); /* Enable, IO R/W */ out_be32(&pci->pow[j].powar, 0x80088000 - | (__ilog2(hose->io_resource.end + | (ilog2(hose->io_resource.end - hose->io_resource.start + 1) - 1)); } } @@ -283,7 +283,7 @@ static void setup_pci_atmu(struct pci_controller *hose, } sz = min(mem, paddr_lo); - mem_log = __ilog2_u64(sz); + 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)) { @@ -312,7 +312,7 @@ static void setup_pci_atmu(struct pci_controller *hose, * SWIOTLB and access the full range of memory */ if (sz != mem) { - mem_log = __ilog2_u64(mem); + mem_log = ilog2(mem); /* Size window up if we dont fit in exact power-of-2 */ if ((1ull << mem_log) != mem) @@ -349,7 +349,7 @@ static void setup_pci_atmu(struct pci_controller *hose, sz -= 1ull << mem_log; if (sz) { - mem_log = __ilog2_u64(sz); + mem_log = ilog2(sz); piwar |= (mem_log - 1); out_be32(&pci->piw[win_idx].pitar, paddr >> 12); -- cgit v1.2.3 From 34642bbb3d12121333efcf4ea7dfe66685e403a1 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Wed, 13 Mar 2013 14:07:15 -0500 Subject: powerpc/fsl-pci: Keep PCI SoC controller registers in pci_controller Move to keeping the SoC registers that control and config the PCI controllers on FSL SoCs in the pci_controller struct. This allows us to not need to ioremap() the registers in multiple different places that use them. Signed-off-by: Kumar Gala --- arch/powerpc/sysdev/fsl_pci.c | 69 +++++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 39 deletions(-) (limited to 'arch/powerpc/sysdev/fsl_pci.c') diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c index e7ec337f03fd..83918c3e665a 100644 --- a/arch/powerpc/sysdev/fsl_pci.c +++ b/arch/powerpc/sysdev/fsl_pci.c @@ -54,34 +54,22 @@ static void quirk_fsl_pcie_header(struct pci_dev *dev) return; } -static int __init fsl_pcie_check_link(struct pci_controller *hose, - struct resource *rsrc) +static int __init fsl_pcie_check_link(struct pci_controller *hose) { - struct ccsr_pci __iomem *pci = NULL; u32 val; - /* for PCIe IP rev 3.0 or greater use CSR0 for link state */ - if (rsrc) { - pr_debug("PCI memory map start 0x%016llx, size 0x%016llx\n", - (u64)rsrc->start, (u64)rsrc->end - (u64)rsrc->start + 1); - pci = ioremap(rsrc->start, rsrc->end - rsrc->start + 1); - if (!pci) { - dev_err(hose->parent, "Unable to map PCIe registers\n"); - return -ENOMEM; - } - if (in_be32(&pci->block_rev1) >= PCIE_IP_REV_3_0) { - val = (in_be32(&pci->pex_csr0) & PEX_CSR0_LTSSM_MASK) - >> PEX_CSR0_LTSSM_SHIFT; - if (val != PEX_CSR0_LTSSM_L0) - return 1; - iounmap(pci); - return 0; - } - iounmap(pci); + if (hose->indirect_type & PPC_INDIRECT_TYPE_FSL_CFG_REG_LINK) { + early_read_config_dword(hose, 0, 0, PCIE_LTSSM, &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) + >> PEX_CSR0_LTSSM_SHIFT; + if (val != PEX_CSR0_LTSSM_L0) + return 1; } - early_read_config_dword(hose, 0, 0, PCIE_LTSSM, &val); - if (val < PCIE_LTSSM_L0) - return 1; return 0; } @@ -148,10 +136,9 @@ 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, - struct resource *rsrc) +static void setup_pci_atmu(struct pci_controller *hose) { - struct ccsr_pci __iomem *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 paddr_lo = ULLONG_MAX; @@ -162,15 +149,6 @@ static void setup_pci_atmu(struct pci_controller *hose, const u64 *reg; int len; - pr_debug("PCI memory map start 0x%016llx, size 0x%016llx\n", - (u64)rsrc->start, (u64)resource_size(rsrc)); - - pci = ioremap(rsrc->start, resource_size(rsrc)); - if (!pci) { - dev_err(hose->parent, "Unable to map ATMU registers\n"); - return; - } - if (early_find_capability(hose, 0, 0, PCI_CAP_ID_EXP)) { if (in_be32(&pci->block_rev1) >= PCIE_IP_REV_2_2) { win_idx = 2; @@ -451,6 +429,7 @@ int __init fsl_add_bridge(struct platform_device *pdev, int is_primary) const int *bus_range; u8 hdr_type, progif; struct device_node *dev; + struct ccsr_pci __iomem *pci; dev = pdev->dev.of_node; @@ -483,9 +462,19 @@ int __init fsl_add_bridge(struct platform_device *pdev, int is_primary) hose->first_busno = bus_range ? bus_range[0] : 0x0; hose->last_busno = bus_range ? bus_range[1] : 0xff; + pr_debug("PCI memory map start 0x%016llx, size 0x%016llx\n", + (u64)rsrc.start, (u64)resource_size(&rsrc)); + + pci = hose->private_data = ioremap(rsrc.start, resource_size(&rsrc)); + if (!hose->private_data) + goto no_bridge; + setup_indirect_pci(hose, rsrc.start, rsrc.start + 0x4, PPC_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 (early_find_capability(hose, 0, 0, PCI_CAP_ID_EXP)) { /* For PCIE read HEADER_TYPE to identify controler mode */ early_read_config_byte(hose, 0, 0, PCI_HEADER_TYPE, &hdr_type); @@ -505,7 +494,7 @@ int __init fsl_add_bridge(struct platform_device *pdev, int is_primary) 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, &rsrc)) + if (fsl_pcie_check_link(hose)) hose->indirect_type |= PPC_INDIRECT_TYPE_NO_PCIE_LINK; } @@ -522,11 +511,12 @@ int __init fsl_add_bridge(struct platform_device *pdev, int is_primary) pci_process_bridge_OF_ranges(hose, dev, is_primary); /* Setup PEX window registers */ - setup_pci_atmu(hose, &rsrc); + setup_pci_atmu(hose); 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)) @@ -703,11 +693,12 @@ static int __init mpc83xx_pcie_setup(struct pci_controller *hose, WARN_ON(hose->dn->data); hose->dn->data = pcie; hose->ops = &mpc83xx_pcie_ops; + hose->indirect_type |= PPC_INDIRECT_TYPE_FSL_CFG_REG_LINK; out_le32(pcie->cfg_type0 + PEX_OUTWIN0_TAH, 0); out_le32(pcie->cfg_type0 + PEX_OUTWIN0_TAL, 0); - if (fsl_pcie_check_link(hose, NULL)) + if (fsl_pcie_check_link(hose)) hose->indirect_type |= PPC_INDIRECT_TYPE_NO_PCIE_LINK; return 0; -- cgit v1.2.3 From 50d8f87d2b39313dae9d0a2d9b23d377328f2f7b Mon Sep 17 00:00:00 2001 From: Rojhalat Ibrahim Date: Mon, 8 Apr 2013 10:15:28 +0200 Subject: powerpc/fsl-pci Make PCIe hotplug work with Freescale PCIe controllers Up to now the PCIe link status on Freescale PCIe controllers was only checked once at boot time. So hotplug did not work. With this patch the link status is checked on every config read. PCIe devices not present at boot time are found after doing 'echo 1 >/sys/bus/pci/rescan'. Signed-off-by: Rojhalat Ibrahim Signed-off-by: Kumar Gala --- arch/powerpc/sysdev/fsl_pci.c | 51 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 44 insertions(+), 7 deletions(-) (limited to 'arch/powerpc/sysdev/fsl_pci.c') diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c index 83918c3e665a..40ffe29b7594 100644 --- a/arch/powerpc/sysdev/fsl_pci.c +++ b/arch/powerpc/sysdev/fsl_pci.c @@ -54,12 +54,22 @@ static void quirk_fsl_pcie_header(struct pci_dev *dev) return; } -static int __init fsl_pcie_check_link(struct pci_controller *hose) +static int fsl_indirect_read_config(struct pci_bus *, unsigned int, + int, int, u32 *); + +static int fsl_pcie_check_link(struct pci_controller *hose) { - u32 val; + u32 val = 0; if (hose->indirect_type & PPC_INDIRECT_TYPE_FSL_CFG_REG_LINK) { - early_read_config_dword(hose, 0, 0, PCIE_LTSSM, &val); + if (hose->ops->read == fsl_indirect_read_config) { + struct pci_bus bus; + bus.number = 0; + 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 (val < PCIE_LTSSM_L0) return 1; } else { @@ -74,6 +84,33 @@ static int __init fsl_pcie_check_link(struct pci_controller *hose) return 0; } +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); + + if (fsl_pcie_check_link(hose)) + hose->indirect_type |= PPC_INDIRECT_TYPE_NO_PCIE_LINK; + else + hose->indirect_type &= ~PPC_INDIRECT_TYPE_NO_PCIE_LINK; + + return indirect_read_config(bus, devfn, offset, len, val); +} + +static struct pci_ops fsl_indirect_pci_ops = +{ + .read = fsl_indirect_read_config, + .write = indirect_write_config, +}; + +static void __init fsl_setup_indirect_pci(struct pci_controller* hose, + resource_size_t cfg_addr, + resource_size_t cfg_data, u32 flags) +{ + setup_indirect_pci(hose, cfg_addr, cfg_data, flags); + hose->ops = &fsl_indirect_pci_ops; +} + #if defined(CONFIG_FSL_SOC_BOOKE) || defined(CONFIG_PPC_86xx) #define MAX_PHYS_ADDR_BITS 40 @@ -469,8 +506,8 @@ int __init fsl_add_bridge(struct platform_device *pdev, int is_primary) if (!hose->private_data) goto no_bridge; - setup_indirect_pci(hose, rsrc.start, rsrc.start + 0x4, - PPC_INDIRECT_TYPE_BIG_ENDIAN); + fsl_setup_indirect_pci(hose, rsrc.start, rsrc.start + 0x4, + PPC_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; @@ -779,8 +816,8 @@ int __init mpc83xx_add_bridge(struct device_node *dev) if (ret) goto err0; } else { - setup_indirect_pci(hose, rsrc_cfg.start, - rsrc_cfg.start + 4, 0); + fsl_setup_indirect_pci(hose, rsrc_cfg.start, + rsrc_cfg.start + 4, 0); } printk(KERN_INFO "Found FSL PCI host bridge at 0x%016llx. " -- cgit v1.2.3 From 04aa99cd0dff7c13bc4b441c23af08ac5c7838e1 Mon Sep 17 00:00:00 2001 From: Kevin Hao Date: Sat, 13 Apr 2013 15:14:41 +0800 Subject: powerpc/fsl-pci: don't unmap the PCI SoC controller registers in setup_pci_atmu In patch 34642bbb (powerpc/fsl-pci: Keep PCI SoC controller registers in pci_controller) we choose to keep the map of the PCI SoC controller registers. But we missed to delete the unmap in setup_pci_atmu function. This will cause the following call trace once we access the PCI SoC controller registers later. Unable to handle kernel paging request for data at address 0x8000080080040f14 Faulting instruction address: 0xc00000000002ea58 Oops: Kernel access of bad area, sig: 11 [#1] SMP NR_CPUS=24 T4240 QDS Modules linked in: NIP: c00000000002ea58 LR: c00000000002eaf4 CTR: c00000000002eac0 REGS: c00000017e10b4a0 TRAP: 0300 Not tainted (3.9.0-rc1-00052-gfa3529f-dirty) MSR: 0000000080029000 CR: 28adbe22 XER: 00000000 SOFTE: 0 DEAR: 8000080080040f14, ESR: 0000000000000000 TASK = c00000017e100000[1] 'swapper/0' THREAD: c00000017e108000 CPU: 2 GPR00: 0000000000000000 c00000017e10b720 c0000000009928d8 c00000017e578e00 GPR04: 0000000000000000 000000000000000c 0000000000000001 c00000017e10bb40 GPR08: 0000000000000000 8000080080040000 0000000000000000 0000000000000016 GPR12: 0000000088adbe22 c00000000fffa800 c000000000001ba0 0000000000000000 GPR16: 0000000000000000 0000000000000000 0000000000000000 0000000000000000 GPR20: 0000000000000000 0000000000000000 0000000000000000 c0000000008a5b70 GPR24: c0000000008af938 c0000000009a28d8 c0000000009bb5dc c00000017e10bb40 GPR28: c00000017e32a400 c00000017e10bc00 c00000017e32a400 c00000017e578e00 NIP [c00000000002ea58] .fsl_pcie_check_link+0x88/0xf0 LR [c00000000002eaf4] .fsl_indirect_read_config+0x34/0xb0 Call Trace: [c00000017e10b720] [c00000017e10b7a0] 0xc00000017e10b7a0 (unreliable) [c00000017e10ba30] [c00000000002eaf4] .fsl_indirect_read_config+0x34/0xb0 [c00000017e10bad0] [c00000000033aa08] .pci_bus_read_config_byte+0x88/0xd0 [c00000017e10bb90] [c00000000088d708] .pci_apply_final_quirks+0x9c/0x18c [c00000017e10bc40] [c0000000000013dc] .do_one_initcall+0x5c/0x1f0 [c00000017e10bcf0] [c00000000086ebac] .kernel_init_freeable+0x180/0x26c [c00000017e10bdb0] [c000000000001bbc] .kernel_init+0x1c/0x460 [c00000017e10be30] [c000000000000880] .ret_from_kernel_thread+0x64/0xe4 Instruction dump: 38210310 2b800015 4fdde842 7c600026 5463fffe e8010010 7c0803a6 4e800020 60000000 60000000 e92301d0 7c0004ac <80690f14> 0c030000 4c00012c 38210310 ---[ end trace 7a8fe0cbccb7d992 ]--- Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b Signed-off-by: Kevin Hao Acked-by: Roy Zang Signed-off-by: Kumar Gala --- arch/powerpc/sysdev/fsl_pci.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'arch/powerpc/sysdev/fsl_pci.c') diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c index 40ffe29b7594..cf81d6516514 100644 --- a/arch/powerpc/sysdev/fsl_pci.c +++ b/arch/powerpc/sysdev/fsl_pci.c @@ -244,12 +244,12 @@ static void setup_pci_atmu(struct pci_controller *hose) if (paddr_hi == paddr_lo) { pr_err("%s: No outbound window space\n", name); - goto out; + return; } if (paddr_lo == 0) { pr_err("%s: No space for inbound window\n", name); - goto out; + return; } /* setup PCSRBAR/PEXCSRBAR */ @@ -395,9 +395,6 @@ static void setup_pci_atmu(struct pci_controller *hose) pr_info("%s: DMA window size is 0x%llx\n", name, (u64)hose->dma_window_size); } - -out: - iounmap(pci); } static void __init setup_pci_cmd(struct pci_controller *hose) -- cgit v1.2.3