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
|
@ -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
|
||||
/* 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
|
||||
|
|
|
@ -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) \
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
|
Loading…
Reference in New Issue