Skip to content

Commit

Permalink
Merge branch 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git…
Browse files Browse the repository at this point in the history
…/benh/powerpc

* 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc:
  powerpc/ptrace: Remove BUG_ON when full register set not available
  powerpc: Factoring mpic cpu id fetching into a function
  powerpc: Make MPIC honor the "pic-no-reset" device tree property
  powerpc: Document the Open PIC device tree binding
  powerpc/pci: Fix crash in PCI code on ppc64 when matching device nodes
  • Loading branch information
Linus Torvalds committed Mar 21, 2011
2 parents a44f99c + a71f5d5 commit 111f426
Show file tree
Hide file tree
Showing 6 changed files with 184 additions and 27 deletions.
98 changes: 98 additions & 0 deletions Documentation/devicetree/bindings/open-pic.txt
Original file line number Diff line number Diff line change
@@ -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 <string> 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 <prop-encoded-array>.

- 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 <u32> and the value shall be 2.

- #address-cells: Specifies the number of cells needed to encode an
address. The type shall be <u32> 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)

4 changes: 4 additions & 0 deletions arch/powerpc/include/asm/mpic.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions arch/powerpc/include/asm/ptrace.h
Original file line number Diff line number Diff line change
Expand Up @@ -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) \
Expand Down
7 changes: 5 additions & 2 deletions arch/powerpc/kernel/pci_dn.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
15 changes: 12 additions & 3 deletions arch/powerpc/kernel/ptrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand Down
85 changes: 63 additions & 22 deletions arch/powerpc/sysdev/mpic.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -913,6 +918,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,
Expand Down Expand Up @@ -993,6 +1012,16 @@ 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)) {
mpic_set_vector(virq, hw);
mpic_set_destination(virq, mpic_processor_id(mpic));
mpic_irq_set_priority(virq, 8);
}

return 0;
}

Expand Down Expand Up @@ -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
*/
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -1320,22 +1362,21 @@ 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);

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 */
Expand Down

0 comments on commit 111f426

Please sign in to comment.