From 90407c9976939e061f32b0e07602e5ce4887d9e8 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 21 Mar 2011 10:57:57 +1100 Subject: powerpc/pci: Fix crash in PCI code on ppc64 when matching device nodes Commit b5d937de0367d26f65b9af1aef5f2c34c1939be0 has a bug which causes basically a NULL dereference in the PCI code during boot on ppc64 machines. fetch_dev_dn() is called when dev->dev.of_node is NULL, so using that as the starting point for the search makes no sense. It should instead start from the device node of the PHB. Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/pci_dn.c b/arch/powerpc/kernel/pci_dn.c index 2985268..d225d99 100644 --- a/arch/powerpc/kernel/pci_dn.c +++ b/arch/powerpc/kernel/pci_dn.c @@ -176,11 +176,14 @@ static void *is_devfn_node(struct device_node *dn, void *data) */ struct device_node *fetch_dev_dn(struct pci_dev *dev) { - struct device_node *orig_dn = dev->dev.of_node; + struct pci_controller *phb = dev->sysdata; struct device_node *dn; unsigned long searchval = (dev->bus->number << 8) | dev->devfn; - dn = traverse_pci_devices(orig_dn, is_devfn_node, (void *)searchval); + if (WARN_ON(!phb)) + return NULL; + + dn = traverse_pci_devices(phb->dn, is_devfn_node, (void *)searchval); if (dn) dev->dev.of_node = dn; return dn; -- cgit v0.10.2 From a99eff39c0549fe68fed150d39ec0c750e5ce1f1 Mon Sep 17 00:00:00 2001 From: Meador Inge Date: Mon, 14 Mar 2011 10:01:05 +0000 Subject: powerpc: Document the Open PIC device tree binding This binding documents several properties that have been in use for quite some time, and adds one new property 'pic-no-reset', which controls the runtime initialization behavior of the PIC. More specifically, the presence of 'pic-no-reset' mandates that the PIC shall not be reset during runtime initialization and that any initialization related to interrupt sources shall be limited to sources explicitly referenced in the device tree. This functionality is useful in AMP systems where multiple OSes are sharing the PIC and the reinitialization of the PIC can interfere with OSes that are already up and running. The interrupt specifier definition is based off of Stuart Yoder's FSL MPIC binding. Signed-off-by: Meador Inge Cc: Grant Likely Cc: Stuart Yoder Cc: Hollis Blanchard Signed-off-by: Benjamin Herrenschmidt diff --git a/Documentation/devicetree/bindings/open-pic.txt b/Documentation/devicetree/bindings/open-pic.txt new file mode 100644 index 0000000..909a902 --- /dev/null +++ b/Documentation/devicetree/bindings/open-pic.txt @@ -0,0 +1,98 @@ +* Open PIC Binding + +This binding specifies what properties must be available in the device tree +representation of an Open PIC compliant interrupt controller. This binding is +based on the binding defined for Open PIC in [1] and is a superset of that +binding. + +Required properties: + + NOTE: Many of these descriptions were paraphrased here from [1] to aid + readability. + + - compatible: Specifies the compatibility list for the PIC. The type + shall be and the value shall include "open-pic". + + - reg: Specifies the base physical address(s) and size(s) of this + PIC's addressable register space. The type shall be . + + - interrupt-controller: The presence of this property identifies the node + as an Open PIC. No property value shall be defined. + + - #interrupt-cells: Specifies the number of cells needed to encode an + interrupt source. The type shall be a and the value shall be 2. + + - #address-cells: Specifies the number of cells needed to encode an + address. The type shall be and the value shall be 0. As such, + 'interrupt-map' nodes do not have to specify a parent unit address. + +Optional properties: + + - pic-no-reset: The presence of this property indicates that the PIC + shall not be reset during runtime initialization. No property value shall + be defined. The presence of this property also mandates that any + initialization related to interrupt sources shall be limited to sources + explicitly referenced in the device tree. + +* Interrupt Specifier Definition + + Interrupt specifiers consists of 2 cells encoded as + follows: + + - <1st-cell>: The interrupt-number that identifies the interrupt source. + + - <2nd-cell>: The level-sense information, encoded as follows: + 0 = low-to-high edge triggered + 1 = active low level-sensitive + 2 = active high level-sensitive + 3 = high-to-low edge triggered + +* Examples + +Example 1: + + /* + * An Open PIC interrupt controller + */ + mpic: pic@40000 { + // This is an interrupt controller node. + interrupt-controller; + + // No address cells so that 'interrupt-map' nodes which reference + // this Open PIC node do not need a parent address specifier. + #address-cells = <0>; + + // Two cells to encode interrupt sources. + #interrupt-cells = <2>; + + // Offset address of 0x40000 and size of 0x40000. + reg = <0x40000 0x40000>; + + // Compatible with Open PIC. + compatible = "open-pic"; + + // The PIC shall not be reset. + pic-no-reset; + }; + +Example 2: + + /* + * An interrupt generating device that is wired to an Open PIC. + */ + serial0: serial@4500 { + // Interrupt source '42' that is active high level-sensitive. + // Note that there are only two cells as specified in the interrupt + // parent's '#interrupt-cells' property. + interrupts = <42 2>; + + // The interrupt controller that this device is wired to. + interrupt-parent = <&mpic>; + }; + +* References + +[1] Power.org (TM) Standard for Embedded Power Architecture (TM) Platform + Requirements (ePAPR), Version 1.0, July 2008. + (http://www.power.org/resources/downloads/Power_ePAPR_APPROVED_v1.0.pdf) + -- cgit v0.10.2 From dfec2202729e2460d67649a04756f0c3d8dcd8a6 Mon Sep 17 00:00:00 2001 From: Meador Inge Date: Mon, 14 Mar 2011 10:01:06 +0000 Subject: powerpc: Make MPIC honor the "pic-no-reset" device tree property This property, defined in the Open PIC binding, tells the kernel not to use the reset bit in the global configuration register. Additionally, its presence mandates that only sources which are actually used (i.e. appear in the device tree) should have their VECPRI bits initialized. Although, "pic-no-reset" can be used for the same use cases that "protected-sources" is covering, the "protected-sources" implementation was left completely intact. This is a more pragmatic approach as there are already several existing systems which use protected sources. If "pic-no-reset" *and* "protected-sources" are both used, however, then "pic-no-reset" takes precedence in terms of the init behavior and the sanity checks done by protected sources will still take place. Signed-off-by: Meador Inge Cc: Hollis Blanchard Cc: Benjamin Herrenschmidt Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/mpic.h b/arch/powerpc/include/asm/mpic.h index 946ec49..7005ee0 100644 --- a/arch/powerpc/include/asm/mpic.h +++ b/arch/powerpc/include/asm/mpic.h @@ -367,6 +367,10 @@ struct mpic #define MPIC_SINGLE_DEST_CPU 0x00001000 /* Enable CoreInt delivery of interrupts */ #define MPIC_ENABLE_COREINT 0x00002000 +/* Disable resetting of the MPIC. + * NOTE: This flag trumps MPIC_WANTS_RESET. + */ +#define MPIC_NO_RESET 0x00004000 /* MPIC HW modification ID */ #define MPIC_REGSET_MASK 0xf0000000 diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index eb70218..3bf7103 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -913,6 +913,20 @@ void mpic_set_vector(unsigned int virq, unsigned int vector) mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), vecpri); } +void mpic_set_destination(unsigned int virq, unsigned int cpuid) +{ + struct mpic *mpic = mpic_from_irq(virq); + unsigned int src = mpic_irq_to_hw(virq); + + DBG("mpic: set_destination(mpic:@%p,virq:%d,src:%d,cpuid:0x%x)\n", + mpic, virq, src, cpuid); + + if (src >= mpic->irq_count) + return; + + mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), 1 << cpuid); +} + static struct irq_chip mpic_irq_chip = { .irq_mask = mpic_mask_irq, .irq_unmask = mpic_unmask_irq, @@ -993,6 +1007,21 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq, /* Set default irq type */ set_irq_type(virq, IRQ_TYPE_NONE); + /* If the MPIC was reset, then all vectors have already been + * initialized. Otherwise, a per source lazy initialization + * is done here. + */ + if (!mpic_is_ipi(mpic, hw) && (mpic->flags & MPIC_NO_RESET)) { + unsigned int cpu = 0; + + if (mpic->flags & MPIC_PRIMARY) + cpu = hard_smp_processor_id(); + + mpic_set_vector(virq, hw); + mpic_set_destination(virq, cpu); + mpic_irq_set_priority(virq, 8); + } + return 0; } @@ -1040,6 +1069,11 @@ static struct irq_host_ops mpic_host_ops = { .xlate = mpic_host_xlate, }; +static int mpic_reset_prohibited(struct device_node *node) +{ + return node && of_get_property(node, "pic-no-reset", NULL); +} + /* * Exported functions */ @@ -1160,7 +1194,15 @@ struct mpic * __init mpic_alloc(struct device_node *node, mpic_map(mpic, node, paddr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000); /* Reset */ - if (flags & MPIC_WANTS_RESET) { + + /* When using a device-node, reset requests are only honored if the MPIC + * is allowed to reset. + */ + if (mpic_reset_prohibited(node)) + mpic->flags |= MPIC_NO_RESET; + + if ((flags & MPIC_WANTS_RESET) && !(mpic->flags & MPIC_NO_RESET)) { + printk(KERN_DEBUG "mpic: Resetting\n"); mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0), mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) | MPIC_GREG_GCONF_RESET); @@ -1325,17 +1367,19 @@ void __init mpic_init(struct mpic *mpic) else cpu = 0; - for (i = 0; i < mpic->num_sources; i++) { - /* start with vector = source number, and masked */ - u32 vecpri = MPIC_VECPRI_MASK | i | - (8 << MPIC_VECPRI_PRIORITY_SHIFT); + if (!(mpic->flags & MPIC_NO_RESET)) { + for (i = 0; i < mpic->num_sources; i++) { + /* start with vector = source number, and masked */ + u32 vecpri = MPIC_VECPRI_MASK | i | + (8 << MPIC_VECPRI_PRIORITY_SHIFT); - /* check if protected */ - if (mpic->protected && test_bit(i, mpic->protected)) - continue; - /* init hw */ - mpic_irq_write(i, MPIC_INFO(IRQ_VECTOR_PRI), vecpri); - mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION), 1 << cpu); + /* check if protected */ + if (mpic->protected && test_bit(i, mpic->protected)) + continue; + /* init hw */ + mpic_irq_write(i, MPIC_INFO(IRQ_VECTOR_PRI), vecpri); + mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION), 1 << cpu); + } } /* Init spurious vector */ -- cgit v0.10.2 From d6a2639b887fcf90b422caccca4aee216bd1120e Mon Sep 17 00:00:00 2001 From: Meador Inge Date: Mon, 14 Mar 2011 10:01:07 +0000 Subject: powerpc: Factoring mpic cpu id fetching into a function The following code snippet: unsigned int cpu = 0; if (mpic->flags & MPIC_PRIMARY) cpu = hard_smp_processor_id(); is seen in several places in the 'mpic.c' code. This changeset factors that pattern out into a helper function called 'mpic_processor_id'. Signed-off-by: Meador Inge Cc: Benjamin Herrenschmidt Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 3bf7103..0f7c671 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -147,6 +147,16 @@ static u32 mpic_infos[][MPIC_IDX_END] = { #endif /* CONFIG_MPIC_WEIRD */ +static inline unsigned int mpic_processor_id(struct mpic *mpic) +{ + unsigned int cpu = 0; + + if (mpic->flags & MPIC_PRIMARY) + cpu = hard_smp_processor_id(); + + return cpu; +} + /* * Register accessor functions */ @@ -210,19 +220,14 @@ static inline void _mpic_ipi_write(struct mpic *mpic, unsigned int ipi, u32 valu static inline u32 _mpic_cpu_read(struct mpic *mpic, unsigned int reg) { - unsigned int cpu = 0; + unsigned int cpu = mpic_processor_id(mpic); - if (mpic->flags & MPIC_PRIMARY) - cpu = hard_smp_processor_id(); return _mpic_read(mpic->reg_type, &mpic->cpuregs[cpu], reg); } static inline void _mpic_cpu_write(struct mpic *mpic, unsigned int reg, u32 value) { - unsigned int cpu = 0; - - if (mpic->flags & MPIC_PRIMARY) - cpu = hard_smp_processor_id(); + unsigned int cpu = mpic_processor_id(mpic); _mpic_write(mpic->reg_type, &mpic->cpuregs[cpu], reg, value); } @@ -1012,13 +1017,8 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq, * is done here. */ if (!mpic_is_ipi(mpic, hw) && (mpic->flags & MPIC_NO_RESET)) { - unsigned int cpu = 0; - - if (mpic->flags & MPIC_PRIMARY) - cpu = hard_smp_processor_id(); - mpic_set_vector(virq, hw); - mpic_set_destination(virq, cpu); + mpic_set_destination(virq, mpic_processor_id(mpic)); mpic_irq_set_priority(virq, 8); } @@ -1362,10 +1362,7 @@ void __init mpic_init(struct mpic *mpic) mpic_pasemi_msi_init(mpic); - if (mpic->flags & MPIC_PRIMARY) - cpu = hard_smp_processor_id(); - else - cpu = 0; + cpu = mpic_processor_id(mpic); if (!(mpic->flags & MPIC_NO_RESET)) { for (i = 0; i < mpic->num_sources; i++) { -- cgit v0.10.2 From a71f5d5d279375205009a4be56a3cf6682921292 Mon Sep 17 00:00:00 2001 From: Mike Wolf Date: Mon, 21 Mar 2011 11:14:53 +1100 Subject: powerpc/ptrace: Remove BUG_ON when full register set not available In some cases during a threaded core dump not all the threads will have a full register set. This happens when the signal causing the core dump races with a thread exiting. The race happens when the exiting thread has entered the kernel for the last time before the signal arrives, but doesn't get far enough through the exit code to avoid being included in the core dump. So we get a thread included in the core dump which is never going to go out to userspace again and only has a partial register set recorded Normally we would catch each thread as it is about to go into userspace and capture the full register set then. However, this exiting thread is never going to go out to userspace again, so we have no way to capture its full register set. It doesn't really matter, though, as this is a thread which is effectively already dead. So instead of hitting a BUG() in this case (a really bad choice of action in the first place), we use a poison value for the register values. [BenH]: Some cosmetic/stylistic changes and fix build on ppc32 Signed-off-by: Mike Wolf Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/ptrace.h b/arch/powerpc/include/asm/ptrace.h index 0175a67..48223f9 100644 --- a/arch/powerpc/include/asm/ptrace.h +++ b/arch/powerpc/include/asm/ptrace.h @@ -125,8 +125,10 @@ extern int ptrace_put_reg(struct task_struct *task, int regno, #endif /* ! __powerpc64__ */ #define TRAP(regs) ((regs)->trap & ~0xF) #ifdef __powerpc64__ +#define NV_REG_POISON 0xdeadbeefdeadbeefUL #define CHECK_FULL_REGS(regs) BUG_ON(regs->trap & 1) #else +#define NV_REG_POISON 0xdeadbeef #define CHECK_FULL_REGS(regs) \ do { \ if ((regs)->trap & 1) \ diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 9065369..895b082 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -229,12 +229,16 @@ static int gpr_get(struct task_struct *target, const struct user_regset *regset, unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) { - int ret; + int i, ret; if (target->thread.regs == NULL) return -EIO; - CHECK_FULL_REGS(target->thread.regs); + if (!FULL_REGS(target->thread.regs)) { + /* We have a partial register set. Fill 14-31 with bogus values */ + for (i = 14; i < 32; i++) + target->thread.regs->gpr[i] = NV_REG_POISON; + } ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, target->thread.regs, @@ -641,11 +645,16 @@ static int gpr32_get(struct task_struct *target, compat_ulong_t *k = kbuf; compat_ulong_t __user *u = ubuf; compat_ulong_t reg; + int i; if (target->thread.regs == NULL) return -EIO; - CHECK_FULL_REGS(target->thread.regs); + if (!FULL_REGS(target->thread.regs)) { + /* We have a partial register set. Fill 14-31 with bogus values */ + for (i = 14; i < 32; i++) + target->thread.regs->gpr[i] = NV_REG_POISON; + } pos /= sizeof(reg); count /= sizeof(reg); -- cgit v0.10.2