Merge branch 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/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
This commit is contained in:
commit
111f4268bd
98
Documentation/devicetree/bindings/open-pic.txt
Normal file
98
Documentation/devicetree/bindings/open-pic.txt
Normal file
|
@ -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)
|
||||||
|
|
|
@ -367,6 +367,10 @@ struct mpic
|
||||||
#define MPIC_SINGLE_DEST_CPU 0x00001000
|
#define MPIC_SINGLE_DEST_CPU 0x00001000
|
||||||
/* Enable CoreInt delivery of interrupts */
|
/* Enable CoreInt delivery of interrupts */
|
||||||
#define MPIC_ENABLE_COREINT 0x00002000
|
#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 */
|
/* MPIC HW modification ID */
|
||||||
#define MPIC_REGSET_MASK 0xf0000000
|
#define MPIC_REGSET_MASK 0xf0000000
|
||||||
|
|
|
@ -125,8 +125,10 @@ extern int ptrace_put_reg(struct task_struct *task, int regno,
|
||||||
#endif /* ! __powerpc64__ */
|
#endif /* ! __powerpc64__ */
|
||||||
#define TRAP(regs) ((regs)->trap & ~0xF)
|
#define TRAP(regs) ((regs)->trap & ~0xF)
|
||||||
#ifdef __powerpc64__
|
#ifdef __powerpc64__
|
||||||
|
#define NV_REG_POISON 0xdeadbeefdeadbeefUL
|
||||||
#define CHECK_FULL_REGS(regs) BUG_ON(regs->trap & 1)
|
#define CHECK_FULL_REGS(regs) BUG_ON(regs->trap & 1)
|
||||||
#else
|
#else
|
||||||
|
#define NV_REG_POISON 0xdeadbeef
|
||||||
#define CHECK_FULL_REGS(regs) \
|
#define CHECK_FULL_REGS(regs) \
|
||||||
do { \
|
do { \
|
||||||
if ((regs)->trap & 1) \
|
if ((regs)->trap & 1) \
|
||||||
|
|
|
@ -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 *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;
|
struct device_node *dn;
|
||||||
unsigned long searchval = (dev->bus->number << 8) | dev->devfn;
|
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)
|
if (dn)
|
||||||
dev->dev.of_node = dn;
|
dev->dev.of_node = dn;
|
||||||
return dn;
|
return dn;
|
||||||
|
|
|
@ -229,12 +229,16 @@ static int gpr_get(struct task_struct *target, const struct user_regset *regset,
|
||||||
unsigned int pos, unsigned int count,
|
unsigned int pos, unsigned int count,
|
||||||
void *kbuf, void __user *ubuf)
|
void *kbuf, void __user *ubuf)
|
||||||
{
|
{
|
||||||
int ret;
|
int i, ret;
|
||||||
|
|
||||||
if (target->thread.regs == NULL)
|
if (target->thread.regs == NULL)
|
||||||
return -EIO;
|
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,
|
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||||
target->thread.regs,
|
target->thread.regs,
|
||||||
|
@ -641,11 +645,16 @@ static int gpr32_get(struct task_struct *target,
|
||||||
compat_ulong_t *k = kbuf;
|
compat_ulong_t *k = kbuf;
|
||||||
compat_ulong_t __user *u = ubuf;
|
compat_ulong_t __user *u = ubuf;
|
||||||
compat_ulong_t reg;
|
compat_ulong_t reg;
|
||||||
|
int i;
|
||||||
|
|
||||||
if (target->thread.regs == NULL)
|
if (target->thread.regs == NULL)
|
||||||
return -EIO;
|
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);
|
pos /= sizeof(reg);
|
||||||
count /= sizeof(reg);
|
count /= sizeof(reg);
|
||||||
|
|
|
@ -147,6 +147,16 @@ static u32 mpic_infos[][MPIC_IDX_END] = {
|
||||||
|
|
||||||
#endif /* CONFIG_MPIC_WEIRD */
|
#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
|
* 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)
|
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);
|
return _mpic_read(mpic->reg_type, &mpic->cpuregs[cpu], reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void _mpic_cpu_write(struct mpic *mpic, unsigned int reg, u32 value)
|
static inline void _mpic_cpu_write(struct mpic *mpic, unsigned int reg, u32 value)
|
||||||
{
|
{
|
||||||
unsigned int cpu = 0;
|
unsigned int cpu = mpic_processor_id(mpic);
|
||||||
|
|
||||||
if (mpic->flags & MPIC_PRIMARY)
|
|
||||||
cpu = hard_smp_processor_id();
|
|
||||||
|
|
||||||
_mpic_write(mpic->reg_type, &mpic->cpuregs[cpu], reg, value);
|
_mpic_write(mpic->reg_type, &mpic->cpuregs[cpu], reg, value);
|
||||||
}
|
}
|
||||||
|
@ -913,6 +918,20 @@ void mpic_set_vector(unsigned int virq, unsigned int vector)
|
||||||
mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), vecpri);
|
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 = {
|
static struct irq_chip mpic_irq_chip = {
|
||||||
.irq_mask = mpic_mask_irq,
|
.irq_mask = mpic_mask_irq,
|
||||||
.irq_unmask = mpic_unmask_irq,
|
.irq_unmask = mpic_unmask_irq,
|
||||||
|
@ -993,6 +1012,16 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq,
|
||||||
/* Set default irq type */
|
/* Set default irq type */
|
||||||
set_irq_type(virq, IRQ_TYPE_NONE);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1040,6 +1069,11 @@ static struct irq_host_ops mpic_host_ops = {
|
||||||
.xlate = mpic_host_xlate,
|
.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
|
* 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);
|
mpic_map(mpic, node, paddr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000);
|
||||||
|
|
||||||
/* Reset */
|
/* 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_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0),
|
||||||
mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0))
|
mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0))
|
||||||
| MPIC_GREG_GCONF_RESET);
|
| MPIC_GREG_GCONF_RESET);
|
||||||
|
@ -1320,22 +1362,21 @@ void __init mpic_init(struct mpic *mpic)
|
||||||
|
|
||||||
mpic_pasemi_msi_init(mpic);
|
mpic_pasemi_msi_init(mpic);
|
||||||
|
|
||||||
if (mpic->flags & MPIC_PRIMARY)
|
cpu = mpic_processor_id(mpic);
|
||||||
cpu = hard_smp_processor_id();
|
|
||||||
else
|
|
||||||
cpu = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < mpic->num_sources; i++) {
|
if (!(mpic->flags & MPIC_NO_RESET)) {
|
||||||
/* start with vector = source number, and masked */
|
for (i = 0; i < mpic->num_sources; i++) {
|
||||||
u32 vecpri = MPIC_VECPRI_MASK | i |
|
/* start with vector = source number, and masked */
|
||||||
(8 << MPIC_VECPRI_PRIORITY_SHIFT);
|
u32 vecpri = MPIC_VECPRI_MASK | i |
|
||||||
|
(8 << MPIC_VECPRI_PRIORITY_SHIFT);
|
||||||
|
|
||||||
/* check if protected */
|
/* check if protected */
|
||||||
if (mpic->protected && test_bit(i, mpic->protected))
|
if (mpic->protected && test_bit(i, mpic->protected))
|
||||||
continue;
|
continue;
|
||||||
/* init hw */
|
/* init hw */
|
||||||
mpic_irq_write(i, MPIC_INFO(IRQ_VECTOR_PRI), vecpri);
|
mpic_irq_write(i, MPIC_INFO(IRQ_VECTOR_PRI), vecpri);
|
||||||
mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION), 1 << cpu);
|
mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION), 1 << cpu);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Init spurious vector */
|
/* Init spurious vector */
|
||||||
|
|
Loading…
Reference in a new issue