From e7fa1d131472b1134d33aba56a83f8f7689f54fd Mon Sep 17 00:00:00 2001 From: Ayman El-Khashab Date: Wed, 20 Jul 2011 03:02:29 +0000 Subject: powerpc/4xx: enable and fix pcie gen1/gen2 on the 460sx Adds a register to the config space for the 460sx. Changes the vc0 detect to a pll detect. maps configuration space to test the link status. changes the setup to enable gen2 devices to operate at gen2 speeds. fixes mapping that was not correct for the 460sx. added bit definitions for the OMRxMSKL registers. Removed reserved bit that was set incorrectly in the OMR2MSKL register. tested on the 460sx eiger and custom board Signed-off-by: Ayman El-Khashab Signed-off-by: Josh Boyer --- arch/powerpc/sysdev/ppc4xx_pci.c | 89 ++++++++++++++++++++++++++++++++-------- arch/powerpc/sysdev/ppc4xx_pci.h | 12 ++++++ 2 files changed, 84 insertions(+), 17 deletions(-) (limited to 'arch/powerpc/sysdev') diff --git a/arch/powerpc/sysdev/ppc4xx_pci.c b/arch/powerpc/sysdev/ppc4xx_pci.c index a59ba96d2c21..edd51c85835a 100644 --- a/arch/powerpc/sysdev/ppc4xx_pci.c +++ b/arch/powerpc/sysdev/ppc4xx_pci.c @@ -1091,6 +1091,10 @@ static int __init ppc460sx_pciex_core_init(struct device_node *np) mtdcri(SDR0, PESDR1_460SX_HSSSLEW, 0xFFFF0000); mtdcri(SDR0, PESDR2_460SX_HSSSLEW, 0xFFFF0000); + /* Set HSS PRBS enabled */ + mtdcri(SDR0, PESDR0_460SX_HSSCTLSET, 0x00001130); + mtdcri(SDR0, PESDR2_460SX_HSSCTLSET, 0x00001130); + udelay(100); /* De-assert PLLRESET */ @@ -1131,9 +1135,6 @@ static int ppc460sx_pciex_init_port_hw(struct ppc4xx_pciex_port *port) dcri_clrset(SDR0, port->sdr_base + PESDRn_UTLSET2, 0, 0x01000000); - /*Gen-1*/ - mtdcri(SDR0, port->sdr_base + PESDRn_460SX_RCEI, 0x08000000); - dcri_clrset(SDR0, port->sdr_base + PESDRn_RCSSET, (PESDRx_RCSSET_RSTGU | PESDRx_RCSSET_RSTDL), PESDRx_RCSSET_RSTPYN); @@ -1147,14 +1148,42 @@ static int ppc460sx_pciex_init_utl(struct ppc4xx_pciex_port *port) { /* Max 128 Bytes */ out_be32 (port->utl_base + PEUTL_PBBSZ, 0x00000000); + /* Assert VRB and TXE - per datasheet turn off addr validation */ + out_be32(port->utl_base + PEUTL_PCTL, 0x80800000); return 0; } +static void __init ppc460sx_pciex_check_link(struct ppc4xx_pciex_port *port) +{ + void __iomem *mbase; + int attempt = 50; + + port->link = 0; + + mbase = ioremap(port->cfg_space.start + 0x10000000, 0x1000); + if (mbase == NULL) { + printk(KERN_ERR "%s: Can't map internal config space !", + port->node->full_name); + goto done; + } + + while (attempt && (0 == (in_le32(mbase + PECFG_460SX_DLLSTA) + & PECFG_460SX_DLLSTA_LINKUP))) { + attempt--; + mdelay(10); + } + if (attempt) + port->link = 1; +done: + iounmap(mbase); + +} + static struct ppc4xx_pciex_hwops ppc460sx_pcie_hwops __initdata = { .core_init = ppc460sx_pciex_core_init, .port_init_hw = ppc460sx_pciex_init_port_hw, .setup_utl = ppc460sx_pciex_init_utl, - .check_link = ppc4xx_pciex_check_link_sdr, + .check_link = ppc460sx_pciex_check_link, }; #endif /* CONFIG_44x */ @@ -1337,15 +1366,15 @@ static int __init ppc4xx_pciex_port_init(struct ppc4xx_pciex_port *port) if (rc != 0) return rc; - if (ppc4xx_pciex_hwops->check_link) - ppc4xx_pciex_hwops->check_link(port); - /* * Initialize mapping: disable all regions and configure * CFG and REG regions based on resources in the device tree */ ppc4xx_pciex_port_init_mapping(port); + if (ppc4xx_pciex_hwops->check_link) + ppc4xx_pciex_hwops->check_link(port); + /* * Map UTL */ @@ -1359,13 +1388,23 @@ static int __init ppc4xx_pciex_port_init(struct ppc4xx_pciex_port *port) ppc4xx_pciex_hwops->setup_utl(port); /* - * Check for VC0 active and assert RDY. + * Check for VC0 active or PLL Locked and assert RDY. */ if (port->sdr_base) { - if (port->link && - ppc4xx_pciex_wait_on_sdr(port, PESDRn_RCSSTS, - 1 << 16, 1 << 16, 5000)) { - printk(KERN_INFO "PCIE%d: VC0 not active\n", port->index); + if (of_device_is_compatible(port->node, + "ibm,plb-pciex-460sx")){ + if (port->link && ppc4xx_pciex_wait_on_sdr(port, + PESDRn_RCSSTS, + 1 << 12, 1 << 12, 5000)) { + printk(KERN_INFO "PCIE%d: PLL not locked\n", + port->index); + port->link = 0; + } + } else if (port->link && + ppc4xx_pciex_wait_on_sdr(port, PESDRn_RCSSTS, + 1 << 16, 1 << 16, 5000)) { + printk(KERN_INFO "PCIE%d: VC0 not active\n", + port->index); port->link = 0; } @@ -1572,8 +1611,15 @@ static int __init ppc4xx_setup_one_pciex_POM(struct ppc4xx_pciex_port *port, dcr_write(port->dcrs, DCRO_PEGPL_OMR1BAH, lah); dcr_write(port->dcrs, DCRO_PEGPL_OMR1BAL, lal); dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKH, 0x7fffffff); - /* Note that 3 here means enabled | single region */ - dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKL, sa | 3); + /*Enabled and single region */ + if (of_device_is_compatible(port->node, "ibm,plb-pciex-460sx")) + dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKL, + sa | DCRO_PEGPL_460SX_OMR1MSKL_UOT + | DCRO_PEGPL_OMRxMSKL_VAL); + else + dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKL, + sa | DCRO_PEGPL_OMR1MSKL_UOT + | DCRO_PEGPL_OMRxMSKL_VAL); break; case 1: out_le32(mbase + PECFG_POM1LAH, pciah); @@ -1581,8 +1627,8 @@ static int __init ppc4xx_setup_one_pciex_POM(struct ppc4xx_pciex_port *port, dcr_write(port->dcrs, DCRO_PEGPL_OMR2BAH, lah); dcr_write(port->dcrs, DCRO_PEGPL_OMR2BAL, lal); dcr_write(port->dcrs, DCRO_PEGPL_OMR2MSKH, 0x7fffffff); - /* Note that 3 here means enabled | single region */ - dcr_write(port->dcrs, DCRO_PEGPL_OMR2MSKL, sa | 3); + dcr_write(port->dcrs, DCRO_PEGPL_OMR2MSKL, + sa | DCRO_PEGPL_OMRxMSKL_VAL); break; case 2: out_le32(mbase + PECFG_POM2LAH, pciah); @@ -1591,7 +1637,9 @@ static int __init ppc4xx_setup_one_pciex_POM(struct ppc4xx_pciex_port *port, dcr_write(port->dcrs, DCRO_PEGPL_OMR3BAL, lal); dcr_write(port->dcrs, DCRO_PEGPL_OMR3MSKH, 0x7fffffff); /* Note that 3 here means enabled | IO space !!! */ - dcr_write(port->dcrs, DCRO_PEGPL_OMR3MSKL, sa | 3); + dcr_write(port->dcrs, DCRO_PEGPL_OMR3MSKL, + sa | DCRO_PEGPL_OMR3MSKL_IO + | DCRO_PEGPL_OMRxMSKL_VAL); break; } @@ -1692,6 +1740,9 @@ static void __init ppc4xx_configure_pciex_PIMs(struct ppc4xx_pciex_port *port, if (res->flags & IORESOURCE_PREFETCH) sa |= 0x8; + if (of_device_is_compatible(port->node, "ibm,plb-pciex-460sx")) + sa |= PCI_BASE_ADDRESS_MEM_TYPE_64; + out_le32(mbase + PECFG_BAR0HMPA, RES_TO_U32_HIGH(sa)); out_le32(mbase + PECFG_BAR0LMPA, RES_TO_U32_LOW(sa)); @@ -1853,6 +1904,10 @@ static void __init ppc4xx_pciex_port_setup_hose(struct ppc4xx_pciex_port *port) } out_le16(mbase + 0x202, val); + /* Enable Bus master, memory, and io space */ + if (of_device_is_compatible(port->node, "ibm,plb-pciex-460sx")) + out_le16(mbase + 0x204, 0x7); + if (!port->endpoint) { /* Set Class Code to PCI-PCI bridge and Revision Id to 1 */ out_le32(mbase + 0x208, 0x06040001); diff --git a/arch/powerpc/sysdev/ppc4xx_pci.h b/arch/powerpc/sysdev/ppc4xx_pci.h index c39a134e8684..32ce763a375a 100644 --- a/arch/powerpc/sysdev/ppc4xx_pci.h +++ b/arch/powerpc/sysdev/ppc4xx_pci.h @@ -464,6 +464,18 @@ #define PECFG_POM2LAL 0x390 #define PECFG_POM2LAH 0x394 +/* 460sx only */ +#define PECFG_460SX_DLLSTA 0x3f8 + +/* 460sx Bit Mappings */ +#define PECFG_460SX_DLLSTA_LINKUP 0x00000010 +#define DCRO_PEGPL_460SX_OMR1MSKL_UOT 0x00000004 + +/* PEGPL Bit Mappings */ +#define DCRO_PEGPL_OMRxMSKL_VAL 0x00000001 +#define DCRO_PEGPL_OMR1MSKL_UOT 0x00000002 +#define DCRO_PEGPL_OMR3MSKL_IO 0x00000002 + /* SDR Bit Mappings */ #define PESDRx_RCSSET_HLDPLB 0x10000000 #define PESDRx_RCSSET_RSTGU 0x01000000 -- cgit v1.2.2 From 14b9247019432fc25e606b78262eb16a4a33b8ed Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Fri, 8 Jul 2011 11:12:42 +0000 Subject: powerpc/mpic: Add support for discontiguous cores There is one place in the MPIC driver that assumes that the cores are numbered from 0 to n-1. However, this is not true if the CPUs are not numbered sequentially. This can happen on a eight-core SOC where cores two and three are removed in the device tree. So instead of blindly looping, we iterate over the discovered CPUs and use the SMP ID as the index. This means that we no longer ask the MPIC how many CPUs there are, so we also delete mpic->num_cpus. We also catch if the number of CPUs in the SOC exceeds the number that the MPIC supports. This should never happen, of course, but it's good to be sure. Signed-off-by: Timur Tabi Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/sysdev/mpic.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) (limited to 'arch/powerpc/sysdev') diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index d5d3ff3d757e..9678081dc4e2 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -1285,13 +1285,11 @@ struct mpic * __init mpic_alloc(struct device_node *node, mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) | MPIC_GREG_GCONF_MCK); - /* Read feature register, calculate num CPUs and, for non-ISU - * MPICs, num sources as well. On ISU MPICs, sources are counted - * as ISUs are added + /* + * Read feature register. For non-ISU MPICs, num sources as well. On + * ISU MPICs, sources are counted as ISUs are added */ greg_feature = mpic_read(mpic->gregs, MPIC_INFO(GREG_FEATURE_0)); - mpic->num_cpus = ((greg_feature & MPIC_GREG_FEATURE_LAST_CPU_MASK) - >> MPIC_GREG_FEATURE_LAST_CPU_SHIFT) + 1; if (isu_size == 0) { if (flags & MPIC_BROKEN_FRR_NIRQS) mpic->num_sources = mpic->irq_count; @@ -1301,10 +1299,18 @@ struct mpic * __init mpic_alloc(struct device_node *node, >> MPIC_GREG_FEATURE_LAST_SRC_SHIFT) + 1; } + /* + * The MPIC driver will crash if there are more cores than we + * can initialize, so we may as well catch that problem here. + */ + BUG_ON(num_possible_cpus() > MPIC_MAX_CPUS); + /* Map the per-CPU registers */ - for (i = 0; i < mpic->num_cpus; i++) { - mpic_map(mpic, node, paddr, &mpic->cpuregs[i], - MPIC_INFO(CPU_BASE) + i * MPIC_INFO(CPU_STRIDE), + for_each_possible_cpu(i) { + unsigned int cpu = get_hard_smp_processor_id(i); + + mpic_map(mpic, node, paddr, &mpic->cpuregs[cpu], + MPIC_INFO(CPU_BASE) + cpu * MPIC_INFO(CPU_STRIDE), 0x1000); } @@ -1343,7 +1349,7 @@ struct mpic * __init mpic_alloc(struct device_node *node, } printk(KERN_INFO "mpic: Setting up MPIC \"%s\" version %s at %llx," " max %d CPUs\n", - name, vers, (unsigned long long)paddr, mpic->num_cpus); + name, vers, (unsigned long long)paddr, num_possible_cpus()); printk(KERN_INFO "mpic: ISU size: %d, shift: %d, mask: %x\n", mpic->isu_size, mpic->isu_shift, mpic->isu_mask); -- cgit v1.2.2 From 9c57a32b2f1615e0ad77e9d3b68fd720f43430da Mon Sep 17 00:00:00 2001 From: Tony Breeds Date: Wed, 10 Aug 2011 20:16:54 +0000 Subject: powerpc/4xx/pci: Add __init annotations for *init_port_hw() functions. The various port_init_hw methods of ppc4xx_pciex_hwops should have been marked __init and when I added ppc4xx_pciex_port_reset_sdr(), which is __init. This added many section mismatch warnings like: WARNING: arch/powerpc/sysdev/built-in.o(.text+0x5c68): Section mismatch in reference from the function ppc440spe_pciex_init_port_hw() to the function .init.text:ppc4xx_pciex_port_reset_sdr() The function ppc440spe_pciex_init_port_hw() references the function __init ppc4xx_pciex_port_reset_sdr(). This is often because ppc440spe_pciex_init_port_hw lacks a __init annotation or the annotation of ppc4xx_pciex_port_reset_sdr is wrong. Trivial patch to silence those warnings. Reported-By: Stephen Rothwell Signed-off-by: Tony Breeds Yours Tony Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/sysdev/ppc4xx_pci.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'arch/powerpc/sysdev') diff --git a/arch/powerpc/sysdev/ppc4xx_pci.c b/arch/powerpc/sysdev/ppc4xx_pci.c index 2ec046d0a394..862f11b3821e 100644 --- a/arch/powerpc/sysdev/ppc4xx_pci.c +++ b/arch/powerpc/sysdev/ppc4xx_pci.c @@ -834,7 +834,7 @@ static int __init ppc440spe_pciex_core_init(struct device_node *np) return 3; } -static int ppc440spe_pciex_init_port_hw(struct ppc4xx_pciex_port *port) +static int __init ppc440spe_pciex_init_port_hw(struct ppc4xx_pciex_port *port) { u32 val = 1 << 24; @@ -872,12 +872,12 @@ static int ppc440spe_pciex_init_port_hw(struct ppc4xx_pciex_port *port) return ppc4xx_pciex_port_reset_sdr(port); } -static int ppc440speA_pciex_init_port_hw(struct ppc4xx_pciex_port *port) +static int __init ppc440speA_pciex_init_port_hw(struct ppc4xx_pciex_port *port) { return ppc440spe_pciex_init_port_hw(port); } -static int ppc440speB_pciex_init_port_hw(struct ppc4xx_pciex_port *port) +static int __init ppc440speB_pciex_init_port_hw(struct ppc4xx_pciex_port *port) { int rc = ppc440spe_pciex_init_port_hw(port); @@ -936,7 +936,7 @@ static int __init ppc460ex_pciex_core_init(struct device_node *np) return 2; } -static int ppc460ex_pciex_init_port_hw(struct ppc4xx_pciex_port *port) +static int __init ppc460ex_pciex_init_port_hw(struct ppc4xx_pciex_port *port) { u32 val; u32 utlset1; @@ -1126,7 +1126,7 @@ static int __init ppc460sx_pciex_core_init(struct device_node *np) return 2; } -static int ppc460sx_pciex_init_port_hw(struct ppc4xx_pciex_port *port) +static int __init ppc460sx_pciex_init_port_hw(struct ppc4xx_pciex_port *port) { if (port->endpoint) @@ -1218,7 +1218,7 @@ static void ppc405ex_pcie_phy_reset(struct ppc4xx_pciex_port *port) mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET, 0x00101000); } -static int ppc405ex_pciex_init_port_hw(struct ppc4xx_pciex_port *port) +static int __init ppc405ex_pciex_init_port_hw(struct ppc4xx_pciex_port *port) { u32 val; -- cgit v1.2.2 From cf01a404d96f9bf6f514074579f0a2d355bfa38e Mon Sep 17 00:00:00 2001 From: Arnaud Lacombe Date: Thu, 25 Aug 2011 06:07:13 +0000 Subject: powerpc/xics: Add __init to marker icp_native_init() This should fix the following warning: LD arch/powerpc/sysdev/xics/built-in.o WARNING: arch/powerpc/sysdev/xics/built-in.o(.text+0x1310): Section mismatch in reference from the function .icp_native_init() to the function .init.text:.icp_native_init_one_node() The function .icp_native_init() references the function __init .icp_native_init_one_node(). This is often because .icp_native_init lacks a __init annotation or the annotation of .icp_native_init_one_node is wrong. icp_native_init() is only referenced in `arch/powerpc/sysdev/xics/xics-common.c' by xics_init() which is itself marked with __init. = not built-tested = Reported-by: Timur Tabi Signed-off-by: Arnaud Lacombe Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/sysdev/xics/icp-native.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/powerpc/sysdev') diff --git a/arch/powerpc/sysdev/xics/icp-native.c b/arch/powerpc/sysdev/xics/icp-native.c index 50e32afe392e..4c79b6fbee1c 100644 --- a/arch/powerpc/sysdev/xics/icp-native.c +++ b/arch/powerpc/sysdev/xics/icp-native.c @@ -276,7 +276,7 @@ static const struct icp_ops icp_native_ops = { #endif }; -int icp_native_init(void) +int __init icp_native_init(void) { struct device_node *np; u32 indx = 0; -- cgit v1.2.2 From 5c7c1e9444d8bfb721a27a35bba3eeb5236c75d8 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 19 Sep 2011 17:45:02 +0000 Subject: powerpc/powernv: Add OPAL ICS backend OPAL handles HW access to the various ICS or equivalent chips for us (with the exception of p5ioc2 based HEA which uses a different backend) similarily to what RTAS does on pSeries. Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/sysdev/xics/Makefile | 1 + arch/powerpc/sysdev/xics/ics-opal.c | 244 +++++++++++++++++++++++++++++++++ arch/powerpc/sysdev/xics/xics-common.c | 8 +- 3 files changed, 247 insertions(+), 6 deletions(-) create mode 100644 arch/powerpc/sysdev/xics/ics-opal.c (limited to 'arch/powerpc/sysdev') diff --git a/arch/powerpc/sysdev/xics/Makefile b/arch/powerpc/sysdev/xics/Makefile index b75a6059337f..c606aa8ba60a 100644 --- a/arch/powerpc/sysdev/xics/Makefile +++ b/arch/powerpc/sysdev/xics/Makefile @@ -4,3 +4,4 @@ obj-y += xics-common.o obj-$(CONFIG_PPC_ICP_NATIVE) += icp-native.o obj-$(CONFIG_PPC_ICP_HV) += icp-hv.o obj-$(CONFIG_PPC_ICS_RTAS) += ics-rtas.o +obj-$(CONFIG_PPC_POWERNV) += ics-opal.o diff --git a/arch/powerpc/sysdev/xics/ics-opal.c b/arch/powerpc/sysdev/xics/ics-opal.c new file mode 100644 index 000000000000..f7e8609df0d5 --- /dev/null +++ b/arch/powerpc/sysdev/xics/ics-opal.c @@ -0,0 +1,244 @@ +/* + * ICS backend for OPAL managed interrupts. + * + * Copyright 2011 IBM Corp. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#undef DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +static int ics_opal_mangle_server(int server) +{ + /* No link for now */ + return server << 2; +} + +static int ics_opal_unmangle_server(int server) +{ + /* No link for now */ + return server >> 2; +} + +static void ics_opal_unmask_irq(struct irq_data *d) +{ + unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d); + int64_t rc; + int server; + + pr_devel("ics-hal: unmask virq %d [hw 0x%x]\n", d->irq, hw_irq); + + if (hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS) + return; + + server = xics_get_irq_server(d->irq, d->affinity, 0); + server = ics_opal_mangle_server(server); + + rc = opal_set_xive(hw_irq, server, DEFAULT_PRIORITY); + if (rc != OPAL_SUCCESS) + pr_err("%s: opal_set_xive(irq=%d [hw 0x%x] server=%x)" + " error %lld\n", + __func__, d->irq, hw_irq, server, rc); +} + +static unsigned int ics_opal_startup(struct irq_data *d) +{ +#ifdef CONFIG_PCI_MSI + /* + * The generic MSI code returns with the interrupt disabled on the + * card, using the MSI mask bits. Firmware doesn't appear to unmask + * at that level, so we do it here by hand. + */ + if (d->msi_desc) + unmask_msi_irq(d); +#endif + + /* unmask it */ + ics_opal_unmask_irq(d); + return 0; +} + +static void ics_opal_mask_real_irq(unsigned int hw_irq) +{ + int server = ics_opal_mangle_server(xics_default_server); + int64_t rc; + + if (hw_irq == XICS_IPI) + return; + + /* Have to set XIVE to 0xff to be able to remove a slot */ + rc = opal_set_xive(hw_irq, server, 0xff); + if (rc != OPAL_SUCCESS) + pr_err("%s: opal_set_xive(0xff) irq=%u returned %lld\n", + __func__, hw_irq, rc); +} + +static void ics_opal_mask_irq(struct irq_data *d) +{ + unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d); + + pr_devel("ics-hal: mask virq %d [hw 0x%x]\n", d->irq, hw_irq); + + if (hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS) + return; + ics_opal_mask_real_irq(hw_irq); +} + +static int ics_opal_set_affinity(struct irq_data *d, + const struct cpumask *cpumask, + bool force) +{ + unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d); + int16_t server; + int8_t priority; + int64_t rc; + int wanted_server; + + if (hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS) + return -1; + + rc = opal_get_xive(hw_irq, &server, &priority); + if (rc != OPAL_SUCCESS) { + pr_err("%s: opal_set_xive(irq=%d [hw 0x%x] server=%x)" + " error %lld\n", + __func__, d->irq, hw_irq, server, rc); + return -1; + } + + wanted_server = xics_get_irq_server(d->irq, cpumask, 1); + if (wanted_server < 0) { + char cpulist[128]; + cpumask_scnprintf(cpulist, sizeof(cpulist), cpumask); + pr_warning("%s: No online cpus in the mask %s for irq %d\n", + __func__, cpulist, d->irq); + return -1; + } + server = ics_opal_mangle_server(wanted_server); + + pr_devel("ics-hal: set-affinity irq %d [hw 0x%x] server: 0x%x/0x%x\n", + d->irq, hw_irq, wanted_server, server); + + rc = opal_set_xive(hw_irq, server, priority); + if (rc != OPAL_SUCCESS) { + pr_err("%s: opal_set_xive(irq=%d [hw 0x%x] server=%x)" + " error %lld\n", + __func__, d->irq, hw_irq, server, rc); + return -1; + } + return 0; +} + +static struct irq_chip ics_opal_irq_chip = { + .name = "OPAL ICS", + .irq_startup = ics_opal_startup, + .irq_mask = ics_opal_mask_irq, + .irq_unmask = ics_opal_unmask_irq, + .irq_eoi = NULL, /* Patched at init time */ + .irq_set_affinity = ics_opal_set_affinity +}; + +static int ics_opal_map(struct ics *ics, unsigned int virq); +static void ics_opal_mask_unknown(struct ics *ics, unsigned long vec); +static long ics_opal_get_server(struct ics *ics, unsigned long vec); + +static int ics_opal_host_match(struct ics *ics, struct device_node *node) +{ + return 1; +} + +/* Only one global & state struct ics */ +static struct ics ics_hal = { + .map = ics_opal_map, + .mask_unknown = ics_opal_mask_unknown, + .get_server = ics_opal_get_server, + .host_match = ics_opal_host_match, +}; + +static int ics_opal_map(struct ics *ics, unsigned int virq) +{ + unsigned int hw_irq = (unsigned int)virq_to_hw(virq); + int64_t rc; + int16_t server; + int8_t priority; + + if (WARN_ON(hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS)) + return -EINVAL; + + /* Check if HAL knows about this interrupt */ + rc = opal_get_xive(hw_irq, &server, &priority); + if (rc != OPAL_SUCCESS) + return -ENXIO; + + irq_set_chip_and_handler(virq, &ics_opal_irq_chip, handle_fasteoi_irq); + irq_set_chip_data(virq, &ics_hal); + + return 0; +} + +static void ics_opal_mask_unknown(struct ics *ics, unsigned long vec) +{ + int64_t rc; + int16_t server; + int8_t priority; + + /* Check if HAL knows about this interrupt */ + rc = opal_get_xive(vec, &server, &priority); + if (rc != OPAL_SUCCESS) + return; + + ics_opal_mask_real_irq(vec); +} + +static long ics_opal_get_server(struct ics *ics, unsigned long vec) +{ + int64_t rc; + int16_t server; + int8_t priority; + + /* Check if HAL knows about this interrupt */ + rc = opal_get_xive(vec, &server, &priority); + if (rc != OPAL_SUCCESS) + return -1; + return ics_opal_unmangle_server(server); +} + +int __init ics_opal_init(void) +{ + if (!firmware_has_feature(FW_FEATURE_OPAL)) + return -ENODEV; + + /* We need to patch our irq chip's EOI to point to the + * right ICP + */ + ics_opal_irq_chip.irq_eoi = icp_ops->eoi; + + /* Register ourselves */ + xics_register_ics(&ics_hal); + + pr_info("ICS OPAL backend registered\n"); + + return 0; +} diff --git a/arch/powerpc/sysdev/xics/xics-common.c b/arch/powerpc/sysdev/xics/xics-common.c index 445c5a01b766..3d93a8ded0f8 100644 --- a/arch/powerpc/sysdev/xics/xics-common.c +++ b/arch/powerpc/sysdev/xics/xics-common.c @@ -409,14 +409,10 @@ void __init xics_init(void) int rc = -1; /* Fist locate ICP */ -#ifdef CONFIG_PPC_ICP_HV if (firmware_has_feature(FW_FEATURE_LPAR)) rc = icp_hv_init(); -#endif -#ifdef CONFIG_PPC_ICP_NATIVE if (rc < 0) rc = icp_native_init(); -#endif if (rc < 0) { pr_warning("XICS: Cannot find a Presentation Controller !\n"); return; @@ -429,9 +425,9 @@ void __init xics_init(void) xics_ipi_chip.irq_eoi = icp_ops->eoi; /* Now locate ICS */ -#ifdef CONFIG_PPC_ICS_RTAS rc = ics_rtas_init(); -#endif + if (rc < 0) + rc = ics_opal_init(); if (rc < 0) pr_warning("XICS: Cannot find a Source Controller !\n"); -- cgit v1.2.2 From c68308dd50c3827a4ce77a1d70e0eb2d2521cafd Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 21 Sep 2011 12:49:20 +0200 Subject: gpio: move mpc8xxx/512x gpio driver to drivers/gpio Move the driver to the place where it is expected to be nowadays. Also rename its CONFIG-name to match the rest and adapt the defconfigs. Finally, move selection of REQUIRE_GPIOLIB or WANTS_OPTIONAL_GPIOLIB to the platforms, because this option is per-platform and not per-driver. Signed-off-by: Wolfram Sang Cc: Anatolij Gustschin Cc: Grant Likely Cc: Benjamin Herrenschmidt Acked-by: Grant Likely Signed-off-by: Anatolij Gustschin --- arch/powerpc/sysdev/Makefile | 1 - arch/powerpc/sysdev/mpc8xxx_gpio.c | 395 ------------------------------------- 2 files changed, 396 deletions(-) delete mode 100644 arch/powerpc/sysdev/mpc8xxx_gpio.c (limited to 'arch/powerpc/sysdev') diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile index cf736ca0cf05..84e13253aec5 100644 --- a/arch/powerpc/sysdev/Makefile +++ b/arch/powerpc/sysdev/Makefile @@ -18,7 +18,6 @@ obj-$(CONFIG_FSL_PCI) += fsl_pci.o $(fsl-msi-obj-y) obj-$(CONFIG_FSL_PMC) += fsl_pmc.o obj-$(CONFIG_FSL_LBC) += fsl_lbc.o obj-$(CONFIG_FSL_GTM) += fsl_gtm.o -obj-$(CONFIG_MPC8xxx_GPIO) += mpc8xxx_gpio.o obj-$(CONFIG_FSL_85XX_CACHE_SRAM) += fsl_85xx_l2ctlr.o fsl_85xx_cache_sram.o obj-$(CONFIG_SIMPLE_GPIO) += simple_gpio.o obj-$(CONFIG_FSL_RIO) += fsl_rio.o diff --git a/arch/powerpc/sysdev/mpc8xxx_gpio.c b/arch/powerpc/sysdev/mpc8xxx_gpio.c deleted file mode 100644 index fb4963abdf55..000000000000 --- a/arch/powerpc/sysdev/mpc8xxx_gpio.c +++ /dev/null @@ -1,395 +0,0 @@ -/* - * GPIOs on MPC512x/8349/8572/8610 and compatible - * - * Copyright (C) 2008 Peter Korsgaard - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define MPC8XXX_GPIO_PINS 32 - -#define GPIO_DIR 0x00 -#define GPIO_ODR 0x04 -#define GPIO_DAT 0x08 -#define GPIO_IER 0x0c -#define GPIO_IMR 0x10 -#define GPIO_ICR 0x14 -#define GPIO_ICR2 0x18 - -struct mpc8xxx_gpio_chip { - struct of_mm_gpio_chip mm_gc; - spinlock_t lock; - - /* - * shadowed data register to be able to clear/set output pins in - * open drain mode safely - */ - u32 data; - struct irq_host *irq; - void *of_dev_id_data; -}; - -static inline u32 mpc8xxx_gpio2mask(unsigned int gpio) -{ - return 1u << (MPC8XXX_GPIO_PINS - 1 - gpio); -} - -static inline struct mpc8xxx_gpio_chip * -to_mpc8xxx_gpio_chip(struct of_mm_gpio_chip *mm) -{ - return container_of(mm, struct mpc8xxx_gpio_chip, mm_gc); -} - -static void mpc8xxx_gpio_save_regs(struct of_mm_gpio_chip *mm) -{ - struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm); - - mpc8xxx_gc->data = in_be32(mm->regs + GPIO_DAT); -} - -/* Workaround GPIO 1 errata on MPC8572/MPC8536. The status of GPIOs - * defined as output cannot be determined by reading GPDAT register, - * so we use shadow data register instead. The status of input pins - * is determined by reading GPDAT register. - */ -static int mpc8572_gpio_get(struct gpio_chip *gc, unsigned int gpio) -{ - u32 val; - struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc); - struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm); - - val = in_be32(mm->regs + GPIO_DAT) & ~in_be32(mm->regs + GPIO_DIR); - - return (val | mpc8xxx_gc->data) & mpc8xxx_gpio2mask(gpio); -} - -static int mpc8xxx_gpio_get(struct gpio_chip *gc, unsigned int gpio) -{ - struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc); - - return in_be32(mm->regs + GPIO_DAT) & mpc8xxx_gpio2mask(gpio); -} - -static void mpc8xxx_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) -{ - struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc); - struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm); - unsigned long flags; - - spin_lock_irqsave(&mpc8xxx_gc->lock, flags); - - if (val) - mpc8xxx_gc->data |= mpc8xxx_gpio2mask(gpio); - else - mpc8xxx_gc->data &= ~mpc8xxx_gpio2mask(gpio); - - out_be32(mm->regs + GPIO_DAT, mpc8xxx_gc->data); - - spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); -} - -static int mpc8xxx_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio) -{ - struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc); - struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm); - unsigned long flags; - - spin_lock_irqsave(&mpc8xxx_gc->lock, flags); - - clrbits32(mm->regs + GPIO_DIR, mpc8xxx_gpio2mask(gpio)); - - spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); - - return 0; -} - -static int mpc8xxx_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) -{ - struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc); - struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm); - unsigned long flags; - - mpc8xxx_gpio_set(gc, gpio, val); - - spin_lock_irqsave(&mpc8xxx_gc->lock, flags); - - setbits32(mm->regs + GPIO_DIR, mpc8xxx_gpio2mask(gpio)); - - spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); - - return 0; -} - -static int mpc8xxx_gpio_to_irq(struct gpio_chip *gc, unsigned offset) -{ - struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc); - struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm); - - if (mpc8xxx_gc->irq && offset < MPC8XXX_GPIO_PINS) - return irq_create_mapping(mpc8xxx_gc->irq, offset); - else - return -ENXIO; -} - -static void mpc8xxx_gpio_irq_cascade(unsigned int irq, struct irq_desc *desc) -{ - struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_desc_get_handler_data(desc); - struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc; - unsigned int mask; - - mask = in_be32(mm->regs + GPIO_IER) & in_be32(mm->regs + GPIO_IMR); - if (mask) - generic_handle_irq(irq_linear_revmap(mpc8xxx_gc->irq, - 32 - ffs(mask))); -} - -static void mpc8xxx_irq_unmask(struct irq_data *d) -{ - struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d); - struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc; - unsigned long flags; - - spin_lock_irqsave(&mpc8xxx_gc->lock, flags); - - setbits32(mm->regs + GPIO_IMR, mpc8xxx_gpio2mask(irqd_to_hwirq(d))); - - spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); -} - -static void mpc8xxx_irq_mask(struct irq_data *d) -{ - struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d); - struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc; - unsigned long flags; - - spin_lock_irqsave(&mpc8xxx_gc->lock, flags); - - clrbits32(mm->regs + GPIO_IMR, mpc8xxx_gpio2mask(irqd_to_hwirq(d))); - - spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); -} - -static void mpc8xxx_irq_ack(struct irq_data *d) -{ - struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d); - struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc; - - out_be32(mm->regs + GPIO_IER, mpc8xxx_gpio2mask(irqd_to_hwirq(d))); -} - -static int mpc8xxx_irq_set_type(struct irq_data *d, unsigned int flow_type) -{ - struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d); - struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc; - unsigned long flags; - - switch (flow_type) { - case IRQ_TYPE_EDGE_FALLING: - spin_lock_irqsave(&mpc8xxx_gc->lock, flags); - setbits32(mm->regs + GPIO_ICR, - mpc8xxx_gpio2mask(irqd_to_hwirq(d))); - spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); - break; - - case IRQ_TYPE_EDGE_BOTH: - spin_lock_irqsave(&mpc8xxx_gc->lock, flags); - clrbits32(mm->regs + GPIO_ICR, - mpc8xxx_gpio2mask(irqd_to_hwirq(d))); - spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); - break; - - default: - return -EINVAL; - } - - return 0; -} - -static int mpc512x_irq_set_type(struct irq_data *d, unsigned int flow_type) -{ - struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d); - struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc; - unsigned long gpio = irqd_to_hwirq(d); - void __iomem *reg; - unsigned int shift; - unsigned long flags; - - if (gpio < 16) { - reg = mm->regs + GPIO_ICR; - shift = (15 - gpio) * 2; - } else { - reg = mm->regs + GPIO_ICR2; - shift = (15 - (gpio % 16)) * 2; - } - - switch (flow_type) { - case IRQ_TYPE_EDGE_FALLING: - case IRQ_TYPE_LEVEL_LOW: - spin_lock_irqsave(&mpc8xxx_gc->lock, flags); - clrsetbits_be32(reg, 3 << shift, 2 << shift); - spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); - break; - - case IRQ_TYPE_EDGE_RISING: - case IRQ_TYPE_LEVEL_HIGH: - spin_lock_irqsave(&mpc8xxx_gc->lock, flags); - clrsetbits_be32(reg, 3 << shift, 1 << shift); - spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); - break; - - case IRQ_TYPE_EDGE_BOTH: - spin_lock_irqsave(&mpc8xxx_gc->lock, flags); - clrbits32(reg, 3 << shift); - spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); - break; - - default: - return -EINVAL; - } - - return 0; -} - -static struct irq_chip mpc8xxx_irq_chip = { - .name = "mpc8xxx-gpio", - .irq_unmask = mpc8xxx_irq_unmask, - .irq_mask = mpc8xxx_irq_mask, - .irq_ack = mpc8xxx_irq_ack, - .irq_set_type = mpc8xxx_irq_set_type, -}; - -static int mpc8xxx_gpio_irq_map(struct irq_host *h, unsigned int virq, - irq_hw_number_t hw) -{ - struct mpc8xxx_gpio_chip *mpc8xxx_gc = h->host_data; - - if (mpc8xxx_gc->of_dev_id_data) - mpc8xxx_irq_chip.irq_set_type = mpc8xxx_gc->of_dev_id_data; - - irq_set_chip_data(virq, h->host_data); - irq_set_chip_and_handler(virq, &mpc8xxx_irq_chip, handle_level_irq); - irq_set_irq_type(virq, IRQ_TYPE_NONE); - - return 0; -} - -static int mpc8xxx_gpio_irq_xlate(struct irq_host *h, struct device_node *ct, - const u32 *intspec, unsigned int intsize, - irq_hw_number_t *out_hwirq, - unsigned int *out_flags) - -{ - /* interrupt sense values coming from the device tree equal either - * EDGE_FALLING or EDGE_BOTH - */ - *out_hwirq = intspec[0]; - *out_flags = intspec[1]; - - return 0; -} - -static struct irq_host_ops mpc8xxx_gpio_irq_ops = { - .map = mpc8xxx_gpio_irq_map, - .xlate = mpc8xxx_gpio_irq_xlate, -}; - -static struct of_device_id mpc8xxx_gpio_ids[] __initdata = { - { .compatible = "fsl,mpc8349-gpio", }, - { .compatible = "fsl,mpc8572-gpio", }, - { .compatible = "fsl,mpc8610-gpio", }, - { .compatible = "fsl,mpc5121-gpio", .data = mpc512x_irq_set_type, }, - { .compatible = "fsl,qoriq-gpio", }, - {} -}; - -static void __init mpc8xxx_add_controller(struct device_node *np) -{ - struct mpc8xxx_gpio_chip *mpc8xxx_gc; - struct of_mm_gpio_chip *mm_gc; - struct gpio_chip *gc; - const struct of_device_id *id; - unsigned hwirq; - int ret; - - mpc8xxx_gc = kzalloc(sizeof(*mpc8xxx_gc), GFP_KERNEL); - if (!mpc8xxx_gc) { - ret = -ENOMEM; - goto err; - } - - spin_lock_init(&mpc8xxx_gc->lock); - - mm_gc = &mpc8xxx_gc->mm_gc; - gc = &mm_gc->gc; - - mm_gc->save_regs = mpc8xxx_gpio_save_regs; - gc->ngpio = MPC8XXX_GPIO_PINS; - gc->direction_input = mpc8xxx_gpio_dir_in; - gc->direction_output = mpc8xxx_gpio_dir_out; - if (of_device_is_compatible(np, "fsl,mpc8572-gpio")) - gc->get = mpc8572_gpio_get; - else - gc->get = mpc8xxx_gpio_get; - gc->set = mpc8xxx_gpio_set; - gc->to_irq = mpc8xxx_gpio_to_irq; - - ret = of_mm_gpiochip_add(np, mm_gc); - if (ret) - goto err; - - hwirq = irq_of_parse_and_map(np, 0); - if (hwirq == NO_IRQ) - goto skip_irq; - - mpc8xxx_gc->irq = - irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, MPC8XXX_GPIO_PINS, - &mpc8xxx_gpio_irq_ops, MPC8XXX_GPIO_PINS); - if (!mpc8xxx_gc->irq) - goto skip_irq; - - id = of_match_node(mpc8xxx_gpio_ids, np); - if (id) - mpc8xxx_gc->of_dev_id_data = id->data; - - mpc8xxx_gc->irq->host_data = mpc8xxx_gc; - - /* ack and mask all irqs */ - out_be32(mm_gc->regs + GPIO_IER, 0xffffffff); - out_be32(mm_gc->regs + GPIO_IMR, 0); - - irq_set_handler_data(hwirq, mpc8xxx_gc); - irq_set_chained_handler(hwirq, mpc8xxx_gpio_irq_cascade); - -skip_irq: - return; - -err: - pr_err("%s: registration failed with status %d\n", - np->full_name, ret); - kfree(mpc8xxx_gc); - - return; -} - -static int __init mpc8xxx_add_gpiochips(void) -{ - struct device_node *np; - - for_each_matching_node(np, mpc8xxx_gpio_ids) - mpc8xxx_add_controller(np); - - return 0; -} -arch_initcall(mpc8xxx_add_gpiochips); -- cgit v1.2.2 From 2228511833e267e833514cc85ba9626f9dacd661 Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Tue, 13 Sep 2011 16:17:00 -0500 Subject: powerpc/fsl_msi: fix support for multiple MSI ranges Commit 6820fead ("powerpc/fsl_msi: Handle msi-available-ranges better") added support for multiple ranges in the msi-available-ranges property, but it miscalculated the MSIR index when multiple ranges are used. Signed-off-by: Timur Tabi Acked-by: Scott Wood Signed-off-by: Kumar Gala --- arch/powerpc/sysdev/fsl_msi.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'arch/powerpc/sysdev') diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c index 419a77239bd7..1cca25146b1f 100644 --- a/arch/powerpc/sysdev/fsl_msi.c +++ b/arch/powerpc/sysdev/fsl_msi.c @@ -296,7 +296,7 @@ static int __devinit fsl_msi_setup_hwirq(struct fsl_msi *msi, } msi->msi_virqs[irq_index] = virt_msir; - cascade_data->index = offset + irq_index; + cascade_data->index = offset; cascade_data->msi_data = msi; irq_set_handler_data(virt_msir, cascade_data); irq_set_chained_handler(virt_msir, fsl_msi_cascade); @@ -376,8 +376,10 @@ static int __devinit fsl_of_msi_probe(struct platform_device *dev) goto error_out; } - if (!p) + if (!p) { p = all_avail; + len = sizeof(all_avail); + } for (irq_index = 0, i = 0; i < len / (2 * sizeof(u32)); i++) { if (p[i * 2] % IRQS_PER_MSI_REG || @@ -393,7 +395,7 @@ static int __devinit fsl_of_msi_probe(struct platform_device *dev) count = p[i * 2 + 1] / IRQS_PER_MSI_REG; for (j = 0; j < count; j++, irq_index++) { - err = fsl_msi_setup_hwirq(msi, dev, offset, irq_index); + err = fsl_msi_setup_hwirq(msi, dev, offset + j, irq_index); if (err) goto error_out; } -- cgit v1.2.2 From 2bcd1c0cfcf53a384159c272c972645e7e822140 Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Fri, 23 Sep 2011 12:41:35 -0500 Subject: powerpc/fsl_msi: add support for "msi-address-64" property Add support for the msi-address-64 property of a PCI node. This property specifies the PCI address of MSIIR (message signaled interrupt index register). In commit 3da34aae ("powerpc/fsl: Support unique MSI addresses per PCIe Root Complex"), the msi_addr_hi/msi_addr_lo fields of struct fsl_msi were redefined from an actual address to just an offset, but the fields were not renamed accordingly. These fields are replace with a single field, msiir_offset, to reflect the new meaning. Signed-off-by: Timur Tabi Signed-off-by: Kumar Gala --- arch/powerpc/sysdev/fsl_msi.c | 20 ++++++++++++++------ arch/powerpc/sysdev/fsl_msi.h | 3 +-- 2 files changed, 15 insertions(+), 8 deletions(-) (limited to 'arch/powerpc/sysdev') diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c index 1cca25146b1f..e5c344d336ea 100644 --- a/arch/powerpc/sysdev/fsl_msi.c +++ b/arch/powerpc/sysdev/fsl_msi.c @@ -30,7 +30,7 @@ LIST_HEAD(msi_head); struct fsl_msi_feature { u32 fsl_pic_ip; - u32 msiir_offset; + u32 msiir_offset; /* Offset of MSIIR, relative to start of MSIR bank */ }; struct fsl_msi_cascade_data { @@ -126,10 +126,19 @@ static void fsl_compose_msi_msg(struct pci_dev *pdev, int hwirq, { struct fsl_msi *msi_data = fsl_msi_data; struct pci_controller *hose = pci_bus_to_host(pdev->bus); - u64 base = fsl_pci_immrbar_base(hose); + u64 address; /* Physical address of the MSIIR */ + int len; + const u64 *reg; + + /* If the msi-address-64 property exists, then use it */ + reg = of_get_property(hose->dn, "msi-address-64", &len); + if (reg && (len == sizeof(u64))) + address = be64_to_cpup(reg); + else + address = fsl_pci_immrbar_base(hose) + msi_data->msiir_offset; - msg->address_lo = msi_data->msi_addr_lo + lower_32_bits(base); - msg->address_hi = msi_data->msi_addr_hi + upper_32_bits(base); + msg->address_lo = lower_32_bits(address); + msg->address_hi = upper_32_bits(address); msg->data = hwirq; @@ -359,8 +368,7 @@ static int __devinit fsl_of_msi_probe(struct platform_device *dev) msi->irqhost->host_data = msi; - msi->msi_addr_hi = 0x0; - msi->msi_addr_lo = features->msiir_offset + (res.start & 0xfffff); + msi->msiir_offset = features->msiir_offset + (res.start & 0xfffff); rc = fsl_msi_init_allocator(msi); if (rc) { diff --git a/arch/powerpc/sysdev/fsl_msi.h b/arch/powerpc/sysdev/fsl_msi.h index 624580c252d7..1313abbc5200 100644 --- a/arch/powerpc/sysdev/fsl_msi.h +++ b/arch/powerpc/sysdev/fsl_msi.h @@ -28,8 +28,7 @@ struct fsl_msi { unsigned long cascade_irq; - u32 msi_addr_lo; - u32 msi_addr_hi; + u32 msiir_offset; /* Offset of MSIIR, relative to start of CCSR */ void __iomem *msi_regs; u32 feature; int msi_virqs[NR_MSI_REG]; -- cgit v1.2.2 From 1661e5bd550bf024b04dfa7abf2963d04ab119e3 Mon Sep 17 00:00:00 2001 From: Hongjun Chen Date: Fri, 26 Mar 2010 16:43:46 +0800 Subject: powerpc/cpm: Clear muram before it is in use. We need to ensure that MURAM is in a known and cleared out state before using it as the bootloader could have utilized it from its own purposes and left it in an unknown state. If we don't clear it out we've seen issues with UCC ethernet: * Multi ethernet interfaces can't work simultanously. * Multi up/down Ethernet interfaces will halt these ports. * UCC1 RGMII can't work when kernel boots from some hosts. Signed-off-by: Kai.Jiang Signed-off-by: Hongjun Chen Signed-off-by: Kumar Gala --- arch/powerpc/sysdev/cpm_common.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'arch/powerpc/sysdev') diff --git a/arch/powerpc/sysdev/cpm_common.c b/arch/powerpc/sysdev/cpm_common.c index d55d0ad0deab..8db10bb90042 100644 --- a/arch/powerpc/sysdev/cpm_common.c +++ b/arch/powerpc/sysdev/cpm_common.c @@ -3,7 +3,7 @@ * * Author: Scott Wood * - * Copyright 2007 Freescale Semiconductor, Inc. + * Copyright 2007-2008,2010 Freescale Semiconductor, Inc. * * Some parts derived from commproc.c/cpm2_common.c, which is: * Copyright (c) 1997 Dan error_act (dmalek@jlc.net) @@ -146,6 +146,7 @@ unsigned long cpm_muram_alloc(unsigned long size, unsigned long align) spin_lock_irqsave(&cpm_muram_lock, flags); cpm_muram_info.alignment = align; start = rh_alloc(&cpm_muram_info, size, "commproc"); + memset(cpm_muram_addr(start), 0, size); spin_unlock_irqrestore(&cpm_muram_lock, flags); return start; -- cgit v1.2.2 From 44f16fcf2fba79cffb268d8f3c1f744efefa5dc9 Mon Sep 17 00:00:00 2001 From: Matthew McClintock Date: Wed, 26 Oct 2011 13:46:57 -0500 Subject: powerpc/85xx: issue 15 EOI after core reset for FSL CoreNet devices This is listed as a requirement for Freescale CoreNet based devices (e.g p4080ds with MPIC v4.x) after issuing a core reset to properly clear pending interrupts. Signed-off-by: Matthew McClintock Signed-off-by: Kumar Gala --- arch/powerpc/sysdev/mpic.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'arch/powerpc/sysdev') diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 9678081dc4e2..0842c6f8a3e6 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -1748,6 +1748,7 @@ void mpic_reset_core(int cpu) struct mpic *mpic = mpic_primary; u32 pir; int cpuid = get_hard_smp_processor_id(cpu); + int i; /* Set target bit for core reset */ pir = mpic_read(mpic->gregs, MPIC_INFO(GREG_PROCESSOR_INIT)); @@ -1759,6 +1760,15 @@ void mpic_reset_core(int cpu) pir &= ~(1 << cpuid); mpic_write(mpic->gregs, MPIC_INFO(GREG_PROCESSOR_INIT), pir); mpic_read(mpic->gregs, MPIC_INFO(GREG_PROCESSOR_INIT)); + + /* Perform 15 EOI on each reset core to clear pending interrupts. + * This is required for FSL CoreNet based devices */ + if (mpic->flags & MPIC_FSL) { + for (i = 0; i < 15; i++) { + _mpic_write(mpic->reg_type, &mpic->cpuregs[cpuid], + MPIC_CPU_EOI, 0); + } + } } #endif /* CONFIG_SMP */ -- cgit v1.2.2