[POWERPC] Use the genirq framework
This adapts the generic powerpc interrupt handling code, and all of the platforms except for the embedded 6xx machines, to use the new genirq framework. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Paul Mackerras <paulus@samba.org>
This commit is contained in:
committed by
Paul Mackerras
parent
5a43a066b1
commit
b9e5b4e6a9
@@ -62,28 +62,27 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
int __irq_offset_value;
|
int __irq_offset_value;
|
||||||
#ifdef CONFIG_PPC32
|
|
||||||
EXPORT_SYMBOL(__irq_offset_value);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int ppc_spurious_interrupts;
|
static int ppc_spurious_interrupts;
|
||||||
|
|
||||||
#ifdef CONFIG_PPC32
|
#ifdef CONFIG_PPC32
|
||||||
#define NR_MASK_WORDS ((NR_IRQS + 31) / 32)
|
EXPORT_SYMBOL(__irq_offset_value);
|
||||||
|
|
||||||
unsigned long ppc_cached_irq_mask[NR_MASK_WORDS];
|
|
||||||
atomic_t ppc_n_lost_interrupts;
|
atomic_t ppc_n_lost_interrupts;
|
||||||
|
|
||||||
|
#ifndef CONFIG_PPC_MERGE
|
||||||
|
#define NR_MASK_WORDS ((NR_IRQS + 31) / 32)
|
||||||
|
unsigned long ppc_cached_irq_mask[NR_MASK_WORDS];
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_TAU_INT
|
#ifdef CONFIG_TAU_INT
|
||||||
extern int tau_initialized;
|
extern int tau_initialized;
|
||||||
extern int tau_interrupts(int);
|
extern int tau_interrupts(int);
|
||||||
#endif
|
#endif
|
||||||
|
#endif /* CONFIG_PPC32 */
|
||||||
|
|
||||||
#if defined(CONFIG_SMP) && !defined(CONFIG_PPC_MERGE)
|
#if defined(CONFIG_SMP) && !defined(CONFIG_PPC_MERGE)
|
||||||
extern atomic_t ipi_recv;
|
extern atomic_t ipi_recv;
|
||||||
extern atomic_t ipi_sent;
|
extern atomic_t ipi_sent;
|
||||||
#endif
|
#endif
|
||||||
#endif /* CONFIG_PPC32 */
|
|
||||||
|
|
||||||
#ifdef CONFIG_PPC64
|
#ifdef CONFIG_PPC64
|
||||||
EXPORT_SYMBOL(irq_desc);
|
EXPORT_SYMBOL(irq_desc);
|
||||||
@@ -219,15 +218,19 @@ void do_IRQ(struct pt_regs *regs)
|
|||||||
curtp = current_thread_info();
|
curtp = current_thread_info();
|
||||||
irqtp = hardirq_ctx[smp_processor_id()];
|
irqtp = hardirq_ctx[smp_processor_id()];
|
||||||
if (curtp != irqtp) {
|
if (curtp != irqtp) {
|
||||||
|
struct irq_desc *desc = irq_desc + irq;
|
||||||
|
void *handler = desc->handle_irq;
|
||||||
|
if (handler == NULL)
|
||||||
|
handler = &__do_IRQ;
|
||||||
irqtp->task = curtp->task;
|
irqtp->task = curtp->task;
|
||||||
irqtp->flags = 0;
|
irqtp->flags = 0;
|
||||||
call___do_IRQ(irq, regs, irqtp);
|
call_handle_irq(irq, desc, regs, irqtp, handler);
|
||||||
irqtp->task = NULL;
|
irqtp->task = NULL;
|
||||||
if (irqtp->flags)
|
if (irqtp->flags)
|
||||||
set_bits(irqtp->flags, &curtp->flags);
|
set_bits(irqtp->flags, &curtp->flags);
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
__do_IRQ(irq, regs);
|
generic_handle_irq(irq, regs);
|
||||||
} else if (irq != -2)
|
} else if (irq != -2)
|
||||||
/* That's not SMP safe ... but who cares ? */
|
/* That's not SMP safe ... but who cares ? */
|
||||||
ppc_spurious_interrupts++;
|
ppc_spurious_interrupts++;
|
||||||
@@ -245,15 +248,6 @@ void do_IRQ(struct pt_regs *regs)
|
|||||||
|
|
||||||
void __init init_IRQ(void)
|
void __init init_IRQ(void)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_PPC64
|
|
||||||
static int once = 0;
|
|
||||||
|
|
||||||
if (once)
|
|
||||||
return;
|
|
||||||
|
|
||||||
once++;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
ppc_md.init_IRQ();
|
ppc_md.init_IRQ();
|
||||||
#ifdef CONFIG_PPC64
|
#ifdef CONFIG_PPC64
|
||||||
irq_ctx_init();
|
irq_ctx_init();
|
||||||
|
@@ -51,12 +51,14 @@ _GLOBAL(call_do_softirq)
|
|||||||
mtlr r0
|
mtlr r0
|
||||||
blr
|
blr
|
||||||
|
|
||||||
_GLOBAL(call___do_IRQ)
|
_GLOBAL(call_handle_irq)
|
||||||
|
ld r8,0(r7)
|
||||||
mflr r0
|
mflr r0
|
||||||
std r0,16(r1)
|
std r0,16(r1)
|
||||||
stdu r1,THREAD_SIZE-112(r5)
|
mtctr r8
|
||||||
mr r1,r5
|
stdu r1,THREAD_SIZE-112(r6)
|
||||||
bl .__do_IRQ
|
mr r1,r6
|
||||||
|
bctrl
|
||||||
ld r1,0(r1)
|
ld r1,0(r1)
|
||||||
ld r0,16(r1)
|
ld r0,16(r1)
|
||||||
mtlr r0
|
mtlr r0
|
||||||
|
@@ -37,64 +37,51 @@
|
|||||||
struct iic {
|
struct iic {
|
||||||
struct cbe_iic_thread_regs __iomem *regs;
|
struct cbe_iic_thread_regs __iomem *regs;
|
||||||
u8 target_id;
|
u8 target_id;
|
||||||
|
u8 eoi_stack[16];
|
||||||
|
int eoi_ptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
static DEFINE_PER_CPU(struct iic, iic);
|
static DEFINE_PER_CPU(struct iic, iic);
|
||||||
|
|
||||||
void iic_local_enable(void)
|
static void iic_mask(unsigned int irq)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void iic_unmask(unsigned int irq)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void iic_eoi(unsigned int irq)
|
||||||
{
|
{
|
||||||
struct iic *iic = &__get_cpu_var(iic);
|
struct iic *iic = &__get_cpu_var(iic);
|
||||||
u64 tmp;
|
out_be64(&iic->regs->prio, iic->eoi_stack[--iic->eoi_ptr]);
|
||||||
|
BUG_ON(iic->eoi_ptr < 0);
|
||||||
/*
|
|
||||||
* There seems to be a bug that is present in DD2.x CPUs
|
|
||||||
* and still only partially fixed in DD3.1.
|
|
||||||
* This bug causes a value written to the priority register
|
|
||||||
* not to make it there, resulting in a system hang unless we
|
|
||||||
* write it again.
|
|
||||||
* Masking with 0xf0 is done because the Cell BE does not
|
|
||||||
* implement the lower four bits of the interrupt priority,
|
|
||||||
* they always read back as zeroes, although future CPUs
|
|
||||||
* might implement different bits.
|
|
||||||
*/
|
|
||||||
do {
|
|
||||||
out_be64(&iic->regs->prio, 0xff);
|
|
||||||
tmp = in_be64(&iic->regs->prio);
|
|
||||||
} while ((tmp & 0xf0) != 0xf0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void iic_local_disable(void)
|
static struct irq_chip iic_chip = {
|
||||||
{
|
|
||||||
out_be64(&__get_cpu_var(iic).regs->prio, 0x0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static unsigned int iic_startup(unsigned int irq)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void iic_enable(unsigned int irq)
|
|
||||||
{
|
|
||||||
iic_local_enable();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void iic_disable(unsigned int irq)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static void iic_end(unsigned int irq)
|
|
||||||
{
|
|
||||||
iic_local_enable();
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct hw_interrupt_type iic_pic = {
|
|
||||||
.typename = " CELL-IIC ",
|
.typename = " CELL-IIC ",
|
||||||
.startup = iic_startup,
|
.mask = iic_mask,
|
||||||
.enable = iic_enable,
|
.unmask = iic_unmask,
|
||||||
.disable = iic_disable,
|
.eoi = iic_eoi,
|
||||||
.end = iic_end,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* XXX All of this has to be reworked completely. We need to assign a real
|
||||||
|
* interrupt numbers to the external interrupts and remove all the hard coded
|
||||||
|
* interrupt maps (rely on the device-tree whenever possible).
|
||||||
|
*
|
||||||
|
* Basically, my scheme is to define the "pendings" bits to be the HW interrupt
|
||||||
|
* number (ignoring the data and flags here). That means we can sort-of split
|
||||||
|
* external sources based on priority, and we can use request_irq() on pretty
|
||||||
|
* much anything.
|
||||||
|
*
|
||||||
|
* For spider or axon, they have their own interrupt space. spider will just have
|
||||||
|
* local "hardward" interrupts 0...xx * node stride. The node stride is not
|
||||||
|
* necessary (separate interrupt chips will have separate HW number space), but
|
||||||
|
* will allow to be compatible with existing device-trees.
|
||||||
|
*
|
||||||
|
* All of thise little world will get a standard remapping scheme to map those HW
|
||||||
|
* numbers into the linux flat irq number space.
|
||||||
|
*/
|
||||||
static int iic_external_get_irq(struct cbe_iic_pending_bits pending)
|
static int iic_external_get_irq(struct cbe_iic_pending_bits pending)
|
||||||
{
|
{
|
||||||
int irq;
|
int irq;
|
||||||
@@ -118,9 +105,10 @@ static int iic_external_get_irq(struct cbe_iic_pending_bits pending)
|
|||||||
*/
|
*/
|
||||||
if (pending.class != 2)
|
if (pending.class != 2)
|
||||||
break;
|
break;
|
||||||
irq = IIC_EXT_OFFSET
|
/* TODO: We might want to silently ignore cascade interrupts
|
||||||
+ spider_get_irq(node)
|
* when no cascade handler exist yet
|
||||||
+ node * IIC_NODE_STRIDE;
|
*/
|
||||||
|
irq = IIC_EXT_CASCADE + node * IIC_NODE_STRIDE;
|
||||||
break;
|
break;
|
||||||
case 0x01 ... 0x04:
|
case 0x01 ... 0x04:
|
||||||
case 0x07 ... 0x0a:
|
case 0x07 ... 0x0a:
|
||||||
@@ -152,6 +140,8 @@ int iic_get_irq(struct pt_regs *regs)
|
|||||||
iic = &__get_cpu_var(iic);
|
iic = &__get_cpu_var(iic);
|
||||||
*(unsigned long *) &pending =
|
*(unsigned long *) &pending =
|
||||||
in_be64((unsigned long __iomem *) &iic->regs->pending_destr);
|
in_be64((unsigned long __iomem *) &iic->regs->pending_destr);
|
||||||
|
iic->eoi_stack[++iic->eoi_ptr] = pending.prio;
|
||||||
|
BUG_ON(iic->eoi_ptr > 15);
|
||||||
|
|
||||||
irq = -1;
|
irq = -1;
|
||||||
if (pending.flags & CBE_IIC_IRQ_VALID) {
|
if (pending.flags & CBE_IIC_IRQ_VALID) {
|
||||||
@@ -172,7 +162,7 @@ int iic_get_irq(struct pt_regs *regs)
|
|||||||
|
|
||||||
/* hardcoded part to be compatible with older firmware */
|
/* hardcoded part to be compatible with older firmware */
|
||||||
|
|
||||||
static int setup_iic_hardcoded(void)
|
static int __init setup_iic_hardcoded(void)
|
||||||
{
|
{
|
||||||
struct device_node *np;
|
struct device_node *np;
|
||||||
int nodeid, cpu;
|
int nodeid, cpu;
|
||||||
@@ -207,12 +197,13 @@ static int setup_iic_hardcoded(void)
|
|||||||
printk(KERN_INFO "IIC for CPU %d at %lx\n", cpu, regs);
|
printk(KERN_INFO "IIC for CPU %d at %lx\n", cpu, regs);
|
||||||
iic->regs = ioremap(regs, sizeof(struct cbe_iic_thread_regs));
|
iic->regs = ioremap(regs, sizeof(struct cbe_iic_thread_regs));
|
||||||
iic->target_id = (nodeid << 4) + ((cpu & 1) ? 0xf : 0xe);
|
iic->target_id = (nodeid << 4) + ((cpu & 1) ? 0xf : 0xe);
|
||||||
|
iic->eoi_stack[0] = 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int setup_iic(void)
|
static int __init setup_iic(void)
|
||||||
{
|
{
|
||||||
struct device_node *dn;
|
struct device_node *dn;
|
||||||
unsigned long *regs;
|
unsigned long *regs;
|
||||||
@@ -248,11 +239,14 @@ static int setup_iic(void)
|
|||||||
iic = &per_cpu(iic, np[0]);
|
iic = &per_cpu(iic, np[0]);
|
||||||
iic->regs = ioremap(regs[0], sizeof(struct cbe_iic_thread_regs));
|
iic->regs = ioremap(regs[0], sizeof(struct cbe_iic_thread_regs));
|
||||||
iic->target_id = ((np[0] & 2) << 3) + ((np[0] & 1) ? 0xf : 0xe);
|
iic->target_id = ((np[0] & 2) << 3) + ((np[0] & 1) ? 0xf : 0xe);
|
||||||
|
iic->eoi_stack[0] = 0xff;
|
||||||
printk("IIC for CPU %d at %lx mapped to %p\n", np[0], regs[0], iic->regs);
|
printk("IIC for CPU %d at %lx mapped to %p\n", np[0], regs[0], iic->regs);
|
||||||
|
|
||||||
iic = &per_cpu(iic, np[1]);
|
iic = &per_cpu(iic, np[1]);
|
||||||
iic->regs = ioremap(regs[2], sizeof(struct cbe_iic_thread_regs));
|
iic->regs = ioremap(regs[2], sizeof(struct cbe_iic_thread_regs));
|
||||||
iic->target_id = ((np[1] & 2) << 3) + ((np[1] & 1) ? 0xf : 0xe);
|
iic->target_id = ((np[1] & 2) << 3) + ((np[1] & 1) ? 0xf : 0xe);
|
||||||
|
iic->eoi_stack[0] = 0xff;
|
||||||
|
|
||||||
printk("IIC for CPU %d at %lx mapped to %p\n", np[1], regs[2], iic->regs);
|
printk("IIC for CPU %d at %lx mapped to %p\n", np[1], regs[2], iic->regs);
|
||||||
|
|
||||||
found++;
|
found++;
|
||||||
@@ -304,10 +298,10 @@ static void iic_request_ipi(int ipi, const char *name)
|
|||||||
int irq;
|
int irq;
|
||||||
|
|
||||||
irq = iic_ipi_to_irq(ipi);
|
irq = iic_ipi_to_irq(ipi);
|
||||||
|
|
||||||
/* IPIs are marked IRQF_DISABLED as they must run with irqs
|
/* IPIs are marked IRQF_DISABLED as they must run with irqs
|
||||||
* disabled */
|
* disabled */
|
||||||
get_irq_desc(irq)->chip = &iic_pic;
|
set_irq_chip_and_handler(irq, &iic_chip, handle_percpu_irq);
|
||||||
get_irq_desc(irq)->status |= IRQ_PER_CPU;
|
|
||||||
request_irq(irq, iic_ipi_action, IRQF_DISABLED, name, NULL);
|
request_irq(irq, iic_ipi_action, IRQF_DISABLED, name, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -321,20 +315,26 @@ void iic_request_IPIs(void)
|
|||||||
}
|
}
|
||||||
#endif /* CONFIG_SMP */
|
#endif /* CONFIG_SMP */
|
||||||
|
|
||||||
static void iic_setup_spe_handlers(void)
|
static void __init iic_setup_builtin_handlers(void)
|
||||||
{
|
{
|
||||||
int be, isrc;
|
int be, isrc;
|
||||||
|
|
||||||
/* Assume two threads per BE are present */
|
/* XXX FIXME: Assume two threads per BE are present */
|
||||||
for (be=0; be < num_present_cpus() / 2; be++) {
|
for (be=0; be < num_present_cpus() / 2; be++) {
|
||||||
|
int irq;
|
||||||
|
|
||||||
|
/* setup SPE chip and handlers */
|
||||||
for (isrc = 0; isrc < IIC_CLASS_STRIDE * 3; isrc++) {
|
for (isrc = 0; isrc < IIC_CLASS_STRIDE * 3; isrc++) {
|
||||||
int irq = IIC_NODE_STRIDE * be + IIC_SPE_OFFSET + isrc;
|
irq = IIC_NODE_STRIDE * be + IIC_SPE_OFFSET + isrc;
|
||||||
get_irq_desc(irq)->chip = &iic_pic;
|
set_irq_chip_and_handler(irq, &iic_chip, handle_fasteoi_irq);
|
||||||
}
|
}
|
||||||
|
/* setup cascade chip */
|
||||||
|
irq = IIC_EXT_CASCADE + be * IIC_NODE_STRIDE;
|
||||||
|
set_irq_chip_and_handler(irq, &iic_chip, handle_fasteoi_irq);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void iic_init_IRQ(void)
|
void __init iic_init_IRQ(void)
|
||||||
{
|
{
|
||||||
int cpu, irq_offset;
|
int cpu, irq_offset;
|
||||||
struct iic *iic;
|
struct iic *iic;
|
||||||
@@ -348,5 +348,6 @@ void iic_init_IRQ(void)
|
|||||||
if (iic->regs)
|
if (iic->regs)
|
||||||
out_be64(&iic->regs->prio, 0xff);
|
out_be64(&iic->regs->prio, 0xff);
|
||||||
}
|
}
|
||||||
iic_setup_spe_handlers();
|
iic_setup_builtin_handlers();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -38,6 +38,7 @@
|
|||||||
|
|
||||||
enum {
|
enum {
|
||||||
IIC_EXT_OFFSET = 0x00, /* Start of south bridge IRQs */
|
IIC_EXT_OFFSET = 0x00, /* Start of south bridge IRQs */
|
||||||
|
IIC_EXT_CASCADE = 0x20, /* There is no interrupt 32 on spider */
|
||||||
IIC_NUM_EXT = 0x40, /* Number of south bridge IRQs */
|
IIC_NUM_EXT = 0x40, /* Number of south bridge IRQs */
|
||||||
IIC_SPE_OFFSET = 0x40, /* Start of SPE interrupts */
|
IIC_SPE_OFFSET = 0x40, /* Start of SPE interrupts */
|
||||||
IIC_CLASS_STRIDE = 0x10, /* SPE IRQs per class */
|
IIC_CLASS_STRIDE = 0x10, /* SPE IRQs per class */
|
||||||
@@ -51,13 +52,10 @@ extern int iic_get_irq(struct pt_regs *regs);
|
|||||||
extern void iic_cause_IPI(int cpu, int mesg);
|
extern void iic_cause_IPI(int cpu, int mesg);
|
||||||
extern void iic_request_IPIs(void);
|
extern void iic_request_IPIs(void);
|
||||||
extern void iic_setup_cpu(void);
|
extern void iic_setup_cpu(void);
|
||||||
extern void iic_local_enable(void);
|
|
||||||
extern void iic_local_disable(void);
|
|
||||||
|
|
||||||
extern u8 iic_get_target_id(int cpu);
|
extern u8 iic_get_target_id(int cpu);
|
||||||
|
|
||||||
extern void spider_init_IRQ(void);
|
extern void spider_init_IRQ(void);
|
||||||
extern int spider_get_irq(int node);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
#endif /* ASM_CELL_PIC_H */
|
#endif /* ASM_CELL_PIC_H */
|
||||||
|
@@ -80,10 +80,14 @@ static void cell_progress(char *s, unsigned short hex)
|
|||||||
printk("*** %04x : %s\n", hex, s ? s : "");
|
printk("*** %04x : %s\n", hex, s ? s : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void __init cell_init_irq(void)
|
||||||
|
{
|
||||||
|
iic_init_IRQ();
|
||||||
|
spider_init_IRQ();
|
||||||
|
}
|
||||||
|
|
||||||
static void __init cell_setup_arch(void)
|
static void __init cell_setup_arch(void)
|
||||||
{
|
{
|
||||||
ppc_md.init_IRQ = iic_init_IRQ;
|
|
||||||
ppc_md.get_irq = iic_get_irq;
|
|
||||||
#ifdef CONFIG_SPU_BASE
|
#ifdef CONFIG_SPU_BASE
|
||||||
spu_priv1_ops = &spu_priv1_mmio_ops;
|
spu_priv1_ops = &spu_priv1_mmio_ops;
|
||||||
#endif
|
#endif
|
||||||
@@ -109,7 +113,6 @@ static void __init cell_setup_arch(void)
|
|||||||
/* Find and initialize PCI host bridges */
|
/* Find and initialize PCI host bridges */
|
||||||
init_pci_config_tokens();
|
init_pci_config_tokens();
|
||||||
find_and_init_phbs();
|
find_and_init_phbs();
|
||||||
spider_init_IRQ();
|
|
||||||
cbe_pervasive_init();
|
cbe_pervasive_init();
|
||||||
#ifdef CONFIG_DUMMY_CONSOLE
|
#ifdef CONFIG_DUMMY_CONSOLE
|
||||||
conswitchp = &dummy_con;
|
conswitchp = &dummy_con;
|
||||||
@@ -174,6 +177,9 @@ define_machine(cell) {
|
|||||||
.calibrate_decr = generic_calibrate_decr,
|
.calibrate_decr = generic_calibrate_decr,
|
||||||
.check_legacy_ioport = cell_check_legacy_ioport,
|
.check_legacy_ioport = cell_check_legacy_ioport,
|
||||||
.progress = cell_progress,
|
.progress = cell_progress,
|
||||||
|
.init_IRQ = cell_init_irq,
|
||||||
|
.get_irq = iic_get_irq,
|
||||||
|
|
||||||
#ifdef CONFIG_KEXEC
|
#ifdef CONFIG_KEXEC
|
||||||
.machine_kexec = default_machine_kexec,
|
.machine_kexec = default_machine_kexec,
|
||||||
.machine_kexec_prepare = default_machine_kexec_prepare,
|
.machine_kexec_prepare = default_machine_kexec_prepare,
|
||||||
|
@@ -82,17 +82,20 @@ static void __iomem *spider_get_irq_config(int irq)
|
|||||||
return pic + TIR_CFGA + 8 * spider_get_nr(irq);
|
return pic + TIR_CFGA + 8 * spider_get_nr(irq);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void spider_enable_irq(unsigned int irq)
|
static void spider_unmask_irq(unsigned int irq)
|
||||||
{
|
{
|
||||||
int nodeid = (irq / IIC_NODE_STRIDE) * 0x10;
|
int nodeid = (irq / IIC_NODE_STRIDE) * 0x10;
|
||||||
void __iomem *cfg = spider_get_irq_config(irq);
|
void __iomem *cfg = spider_get_irq_config(irq);
|
||||||
irq = spider_get_nr(irq);
|
irq = spider_get_nr(irq);
|
||||||
|
|
||||||
|
/* FIXME: Most of that is configuration and has nothing to do with enabling/disable,
|
||||||
|
* besides, it's also partially bogus.
|
||||||
|
*/
|
||||||
out_be32(cfg, (in_be32(cfg) & ~0xf0)| 0x3107000eu | nodeid);
|
out_be32(cfg, (in_be32(cfg) & ~0xf0)| 0x3107000eu | nodeid);
|
||||||
out_be32(cfg + 4, in_be32(cfg + 4) | 0x00020000u | irq);
|
out_be32(cfg + 4, in_be32(cfg + 4) | 0x00020000u | irq);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void spider_disable_irq(unsigned int irq)
|
static void spider_mask_irq(unsigned int irq)
|
||||||
{
|
{
|
||||||
void __iomem *cfg = spider_get_irq_config(irq);
|
void __iomem *cfg = spider_get_irq_config(irq);
|
||||||
irq = spider_get_nr(irq);
|
irq = spider_get_nr(irq);
|
||||||
@@ -100,39 +103,21 @@ static void spider_disable_irq(unsigned int irq)
|
|||||||
out_be32(cfg, in_be32(cfg) & ~0x30000000u);
|
out_be32(cfg, in_be32(cfg) & ~0x30000000u);
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int spider_startup_irq(unsigned int irq)
|
|
||||||
{
|
|
||||||
spider_enable_irq(irq);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void spider_shutdown_irq(unsigned int irq)
|
|
||||||
{
|
|
||||||
spider_disable_irq(irq);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void spider_end_irq(unsigned int irq)
|
|
||||||
{
|
|
||||||
spider_enable_irq(irq);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void spider_ack_irq(unsigned int irq)
|
static void spider_ack_irq(unsigned int irq)
|
||||||
{
|
{
|
||||||
spider_disable_irq(irq);
|
/* Should reset edge detection logic but we don't configure any edge interrupt
|
||||||
iic_local_enable();
|
* at the moment.
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct hw_interrupt_type spider_pic = {
|
static struct irq_chip spider_pic = {
|
||||||
.typename = " SPIDER ",
|
.typename = " SPIDER ",
|
||||||
.startup = spider_startup_irq,
|
.unmask = spider_unmask_irq,
|
||||||
.shutdown = spider_shutdown_irq,
|
.mask = spider_mask_irq,
|
||||||
.enable = spider_enable_irq,
|
|
||||||
.disable = spider_disable_irq,
|
|
||||||
.ack = spider_ack_irq,
|
.ack = spider_ack_irq,
|
||||||
.end = spider_end_irq,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
int spider_get_irq(int node)
|
static int spider_get_irq(int node)
|
||||||
{
|
{
|
||||||
unsigned long cs;
|
unsigned long cs;
|
||||||
void __iomem *regs = spider_pics[node];
|
void __iomem *regs = spider_pics[node];
|
||||||
@@ -145,95 +130,89 @@ int spider_get_irq(int node)
|
|||||||
return cs;
|
return cs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* hardcoded part to be compatible with older firmware */
|
static void spider_irq_cascade(unsigned int irq, struct irq_desc *desc,
|
||||||
|
struct pt_regs *regs)
|
||||||
void spider_init_IRQ_hardcoded(void)
|
|
||||||
{
|
{
|
||||||
int node;
|
int node = (int)(long)desc->handler_data;
|
||||||
long spiderpic;
|
int cascade_irq;
|
||||||
long pics[] = { 0x24000008000, 0x34000008000 };
|
|
||||||
int n;
|
|
||||||
|
|
||||||
pr_debug("%s(%d): Using hardcoded defaults\n", __FUNCTION__, __LINE__);
|
cascade_irq = spider_get_irq(node);
|
||||||
|
generic_handle_irq(cascade_irq, regs);
|
||||||
for (node = 0; node < num_present_cpus()/2; node++) {
|
desc->chip->eoi(irq);
|
||||||
spiderpic = pics[node];
|
|
||||||
printk(KERN_DEBUG "SPIDER addr: %lx\n", spiderpic);
|
|
||||||
spider_pics[node] = ioremap(spiderpic, 0x800);
|
|
||||||
for (n = 0; n < IIC_NUM_EXT; n++) {
|
|
||||||
int irq = n + IIC_EXT_OFFSET + node * IIC_NODE_STRIDE;
|
|
||||||
get_irq_desc(irq)->chip = &spider_pic;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* do not mask any interrupts because of level */
|
|
||||||
out_be32(spider_pics[node] + TIR_MSK, 0x0);
|
|
||||||
|
|
||||||
/* disable edge detection clear */
|
|
||||||
/* out_be32(spider_pics[node] + TIR_EDC, 0x0); */
|
|
||||||
|
|
||||||
/* enable interrupt packets to be output */
|
|
||||||
out_be32(spider_pics[node] + TIR_PIEN,
|
|
||||||
in_be32(spider_pics[node] + TIR_PIEN) | 0x1);
|
|
||||||
|
|
||||||
/* Enable the interrupt detection enable bit. Do this last! */
|
|
||||||
out_be32(spider_pics[node] + TIR_DEN,
|
|
||||||
in_be32(spider_pics[node] + TIR_DEN) | 0x1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void spider_init_IRQ(void)
|
/* hardcoded part to be compatible with older firmware */
|
||||||
|
|
||||||
|
static void __init spider_init_one(int node, unsigned long addr)
|
||||||
{
|
{
|
||||||
long spider_reg;
|
int n, irq;
|
||||||
|
|
||||||
|
spider_pics[node] = ioremap(addr, 0x800);
|
||||||
|
if (spider_pics[node] == NULL)
|
||||||
|
panic("spider_pic: can't map registers !");
|
||||||
|
|
||||||
|
printk(KERN_INFO "spider_pic: mapped for node %d, addr: 0x%lx mapped to %p\n",
|
||||||
|
node, addr, spider_pics[node]);
|
||||||
|
|
||||||
|
for (n = 0; n < IIC_NUM_EXT; n++) {
|
||||||
|
if (n == IIC_EXT_CASCADE)
|
||||||
|
continue;
|
||||||
|
irq = n + IIC_EXT_OFFSET + node * IIC_NODE_STRIDE;
|
||||||
|
set_irq_chip_and_handler(irq, &spider_pic, handle_level_irq);
|
||||||
|
get_irq_desc(irq)->status |= IRQ_LEVEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* do not mask any interrupts because of level */
|
||||||
|
out_be32(spider_pics[node] + TIR_MSK, 0x0);
|
||||||
|
|
||||||
|
/* disable edge detection clear */
|
||||||
|
/* out_be32(spider_pics[node] + TIR_EDC, 0x0); */
|
||||||
|
|
||||||
|
/* enable interrupt packets to be output */
|
||||||
|
out_be32(spider_pics[node] + TIR_PIEN,
|
||||||
|
in_be32(spider_pics[node] + TIR_PIEN) | 0x1);
|
||||||
|
|
||||||
|
/* Hook up cascade */
|
||||||
|
irq = IIC_EXT_CASCADE + node * IIC_NODE_STRIDE;
|
||||||
|
set_irq_data(irq, (void *)(long)node);
|
||||||
|
set_irq_chained_handler(irq, spider_irq_cascade);
|
||||||
|
|
||||||
|
/* Enable the interrupt detection enable bit. Do this last! */
|
||||||
|
out_be32(spider_pics[node] + TIR_DEN,
|
||||||
|
in_be32(spider_pics[node] + TIR_DEN) | 0x1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void __init spider_init_IRQ(void)
|
||||||
|
{
|
||||||
|
unsigned long *spider_reg;
|
||||||
struct device_node *dn;
|
struct device_node *dn;
|
||||||
char *compatible;
|
char *compatible;
|
||||||
int n, node = 0;
|
int node = 0;
|
||||||
|
|
||||||
|
/* XXX node numbers are totally bogus. We _hope_ we get the device nodes in the right
|
||||||
|
* order here but that's definitely not guaranteed, we need to get the node from the
|
||||||
|
* device tree instead. There is currently no proper property for it (but our whole
|
||||||
|
* device-tree is bogus anyway) so all we can do is pray or maybe test the address
|
||||||
|
* and deduce the node-id
|
||||||
|
*/
|
||||||
for (dn = NULL; (dn = of_find_node_by_name(dn, "interrupt-controller"));) {
|
for (dn = NULL; (dn = of_find_node_by_name(dn, "interrupt-controller"));) {
|
||||||
compatible = (char *)get_property(dn, "compatible", NULL);
|
compatible = (char *)get_property(dn, "compatible", NULL);
|
||||||
|
|
||||||
if (!compatible)
|
if (!compatible)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (strstr(compatible, "CBEA,platform-spider-pic"))
|
if (strstr(compatible, "CBEA,platform-spider-pic"))
|
||||||
spider_reg = *(long *)get_property(dn,"reg", NULL);
|
spider_reg = (unsigned long *)get_property(dn, "reg", NULL);
|
||||||
else if (strstr(compatible, "sti,platform-spider-pic")) {
|
else if (strstr(compatible, "sti,platform-spider-pic") && (node < 2)) {
|
||||||
spider_init_IRQ_hardcoded();
|
static long hard_coded_pics[] = { 0x24000008000, 0x34000008000 };
|
||||||
return;
|
spider_reg = &hard_coded_pics[node];
|
||||||
} else
|
} else
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!spider_reg)
|
if (spider_reg == NULL)
|
||||||
printk("interrupt controller does not have reg property !\n");
|
printk(KERN_ERR "spider_pic: No address for node %d\n", node);
|
||||||
|
|
||||||
n = prom_n_addr_cells(dn);
|
|
||||||
|
|
||||||
if ( n != 2)
|
|
||||||
printk("reg property with invalid number of elements \n");
|
|
||||||
|
|
||||||
spider_pics[node] = ioremap(spider_reg, 0x800);
|
|
||||||
|
|
||||||
printk("SPIDER addr: %lx with %i addr_cells mapped to %p\n",
|
|
||||||
spider_reg, n, spider_pics[node]);
|
|
||||||
|
|
||||||
for (n = 0; n < IIC_NUM_EXT; n++) {
|
|
||||||
int irq = n + IIC_EXT_OFFSET + node * IIC_NODE_STRIDE;
|
|
||||||
get_irq_desc(irq)->chip = &spider_pic;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* do not mask any interrupts because of level */
|
|
||||||
out_be32(spider_pics[node] + TIR_MSK, 0x0);
|
|
||||||
|
|
||||||
/* disable edge detection clear */
|
|
||||||
/* out_be32(spider_pics[node] + TIR_EDC, 0x0); */
|
|
||||||
|
|
||||||
/* enable interrupt packets to be output */
|
|
||||||
out_be32(spider_pics[node] + TIR_PIEN,
|
|
||||||
in_be32(spider_pics[node] + TIR_PIEN) | 0x1);
|
|
||||||
|
|
||||||
/* Enable the interrupt detection enable bit. Do this last! */
|
|
||||||
out_be32(spider_pics[node] + TIR_DEN,
|
|
||||||
in_be32(spider_pics[node] + TIR_DEN) | 0x1);
|
|
||||||
|
|
||||||
|
spider_init_one(node, *spider_reg);
|
||||||
node++;
|
node++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -315,6 +315,21 @@ chrp_event_scan(unsigned long unused)
|
|||||||
jiffies + event_scan_interval);
|
jiffies + event_scan_interval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void chrp_8259_cascade(unsigned int irq, struct irq_desc *desc,
|
||||||
|
struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
unsigned int max = 100;
|
||||||
|
|
||||||
|
while(max--) {
|
||||||
|
int irq = i8259_irq(regs);
|
||||||
|
if (max == 99)
|
||||||
|
desc->chip->eoi(irq);
|
||||||
|
if (irq < 0)
|
||||||
|
break;
|
||||||
|
generic_handle_irq(irq, regs);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Finds the open-pic node and sets up the mpic driver.
|
* Finds the open-pic node and sets up the mpic driver.
|
||||||
*/
|
*/
|
||||||
@@ -402,7 +417,7 @@ static void __init chrp_find_openpic(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
mpic_init(chrp_mpic);
|
mpic_init(chrp_mpic);
|
||||||
mpic_setup_cascade(NUM_ISA_INTERRUPTS, i8259_irq_cascade, NULL);
|
set_irq_chained_handler(NUM_ISA_INTERRUPTS, chrp_8259_cascade);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON)
|
#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON)
|
||||||
|
@@ -297,13 +297,13 @@ static void iseries_end_IRQ(unsigned int irq)
|
|||||||
(REAL_IRQ_TO_IDSEL(rirq) << 4) + REAL_IRQ_TO_FUNC(rirq));
|
(REAL_IRQ_TO_IDSEL(rirq) << 4) + REAL_IRQ_TO_FUNC(rirq));
|
||||||
}
|
}
|
||||||
|
|
||||||
static hw_irq_controller iSeries_IRQ_handler = {
|
static struct irq_chip iseries_pic = {
|
||||||
.typename = "iSeries irq controller",
|
.typename = "iSeries irq controller",
|
||||||
.startup = iseries_startup_IRQ,
|
.startup = iseries_startup_IRQ,
|
||||||
.shutdown = iseries_shutdown_IRQ,
|
.shutdown = iseries_shutdown_IRQ,
|
||||||
.enable = iseries_enable_IRQ,
|
.unmask = iseries_enable_IRQ,
|
||||||
.disable = iseries_disable_IRQ,
|
.mask = iseries_disable_IRQ,
|
||||||
.end = iseries_end_IRQ
|
.eoi = iseries_end_IRQ
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -322,8 +322,7 @@ int __init iSeries_allocate_IRQ(HvBusNumber bus,
|
|||||||
realirq = (((((sub_bus << 8) + (bus - 1)) << 3) + (idsel - 1)) << 3)
|
realirq = (((((sub_bus << 8) + (bus - 1)) << 3) + (idsel - 1)) << 3)
|
||||||
+ function;
|
+ function;
|
||||||
virtirq = virt_irq_create_mapping(realirq);
|
virtirq = virt_irq_create_mapping(realirq);
|
||||||
|
set_irq_chip_and_handler(virtirq, &iseries_pic, handle_fasteoi_irq);
|
||||||
irq_desc[virtirq].chip = &iSeries_IRQ_handler;
|
|
||||||
return virtirq;
|
return virtirq;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -70,18 +70,19 @@ static struct interrupt_info gatwick_int_pool[GATWICK_IRQ_POOL_SIZE];
|
|||||||
|
|
||||||
#define NR_MASK_WORDS ((NR_IRQS + 31) / 32)
|
#define NR_MASK_WORDS ((NR_IRQS + 31) / 32)
|
||||||
static unsigned long ppc_lost_interrupts[NR_MASK_WORDS];
|
static unsigned long ppc_lost_interrupts[NR_MASK_WORDS];
|
||||||
|
static unsigned long ppc_cached_irq_mask[NR_MASK_WORDS];
|
||||||
|
static int pmac_irq_cascade = -1;
|
||||||
|
|
||||||
/*
|
static void __pmac_retrigger(unsigned int irq_nr)
|
||||||
* Mark an irq as "lost". This is only used on the pmac
|
|
||||||
* since it can lose interrupts (see pmac_set_irq_mask).
|
|
||||||
* -- Cort
|
|
||||||
*/
|
|
||||||
void __set_lost(unsigned long irq_nr, int nokick)
|
|
||||||
{
|
{
|
||||||
if (!test_and_set_bit(irq_nr, ppc_lost_interrupts)) {
|
if (irq_nr >= max_real_irqs && pmac_irq_cascade > 0) {
|
||||||
|
__set_bit(irq_nr, ppc_lost_interrupts);
|
||||||
|
irq_nr = pmac_irq_cascade;
|
||||||
|
mb();
|
||||||
|
}
|
||||||
|
if (!__test_and_set_bit(irq_nr, ppc_lost_interrupts)) {
|
||||||
atomic_inc(&ppc_n_lost_interrupts);
|
atomic_inc(&ppc_n_lost_interrupts);
|
||||||
if (!nokick)
|
set_dec(1);
|
||||||
set_dec(1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,10 +95,10 @@ static void pmac_mask_and_ack_irq(unsigned int irq_nr)
|
|||||||
if ((unsigned)irq_nr >= max_irqs)
|
if ((unsigned)irq_nr >= max_irqs)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
clear_bit(irq_nr, ppc_cached_irq_mask);
|
|
||||||
if (test_and_clear_bit(irq_nr, ppc_lost_interrupts))
|
|
||||||
atomic_dec(&ppc_n_lost_interrupts);
|
|
||||||
spin_lock_irqsave(&pmac_pic_lock, flags);
|
spin_lock_irqsave(&pmac_pic_lock, flags);
|
||||||
|
__clear_bit(irq_nr, ppc_cached_irq_mask);
|
||||||
|
if (__test_and_clear_bit(irq_nr, ppc_lost_interrupts))
|
||||||
|
atomic_dec(&ppc_n_lost_interrupts);
|
||||||
out_le32(&pmac_irq_hw[i]->enable, ppc_cached_irq_mask[i]);
|
out_le32(&pmac_irq_hw[i]->enable, ppc_cached_irq_mask[i]);
|
||||||
out_le32(&pmac_irq_hw[i]->ack, bit);
|
out_le32(&pmac_irq_hw[i]->ack, bit);
|
||||||
do {
|
do {
|
||||||
@@ -109,7 +110,7 @@ static void pmac_mask_and_ack_irq(unsigned int irq_nr)
|
|||||||
spin_unlock_irqrestore(&pmac_pic_lock, flags);
|
spin_unlock_irqrestore(&pmac_pic_lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pmac_set_irq_mask(unsigned int irq_nr, int nokicklost)
|
static void pmac_ack_irq(unsigned int irq_nr)
|
||||||
{
|
{
|
||||||
unsigned long bit = 1UL << (irq_nr & 0x1f);
|
unsigned long bit = 1UL << (irq_nr & 0x1f);
|
||||||
int i = irq_nr >> 5;
|
int i = irq_nr >> 5;
|
||||||
@@ -118,7 +119,22 @@ static void pmac_set_irq_mask(unsigned int irq_nr, int nokicklost)
|
|||||||
if ((unsigned)irq_nr >= max_irqs)
|
if ((unsigned)irq_nr >= max_irqs)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
spin_lock_irqsave(&pmac_pic_lock, flags);
|
spin_lock_irqsave(&pmac_pic_lock, flags);
|
||||||
|
if (__test_and_clear_bit(irq_nr, ppc_lost_interrupts))
|
||||||
|
atomic_dec(&ppc_n_lost_interrupts);
|
||||||
|
out_le32(&pmac_irq_hw[i]->ack, bit);
|
||||||
|
(void)in_le32(&pmac_irq_hw[i]->ack);
|
||||||
|
spin_unlock_irqrestore(&pmac_pic_lock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __pmac_set_irq_mask(unsigned int irq_nr, int nokicklost)
|
||||||
|
{
|
||||||
|
unsigned long bit = 1UL << (irq_nr & 0x1f);
|
||||||
|
int i = irq_nr >> 5;
|
||||||
|
|
||||||
|
if ((unsigned)irq_nr >= max_irqs)
|
||||||
|
return;
|
||||||
|
|
||||||
/* enable unmasked interrupts */
|
/* enable unmasked interrupts */
|
||||||
out_le32(&pmac_irq_hw[i]->enable, ppc_cached_irq_mask[i]);
|
out_le32(&pmac_irq_hw[i]->enable, ppc_cached_irq_mask[i]);
|
||||||
|
|
||||||
@@ -135,8 +151,7 @@ static void pmac_set_irq_mask(unsigned int irq_nr, int nokicklost)
|
|||||||
* the bit in the flag register or request another interrupt.
|
* the bit in the flag register or request another interrupt.
|
||||||
*/
|
*/
|
||||||
if (bit & ppc_cached_irq_mask[i] & in_le32(&pmac_irq_hw[i]->level))
|
if (bit & ppc_cached_irq_mask[i] & in_le32(&pmac_irq_hw[i]->level))
|
||||||
__set_lost((ulong)irq_nr, nokicklost);
|
__pmac_retrigger(irq_nr);
|
||||||
spin_unlock_irqrestore(&pmac_pic_lock, flags);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* When an irq gets requested for the first client, if it's an
|
/* When an irq gets requested for the first client, if it's an
|
||||||
@@ -144,62 +159,67 @@ static void pmac_set_irq_mask(unsigned int irq_nr, int nokicklost)
|
|||||||
*/
|
*/
|
||||||
static unsigned int pmac_startup_irq(unsigned int irq_nr)
|
static unsigned int pmac_startup_irq(unsigned int irq_nr)
|
||||||
{
|
{
|
||||||
|
unsigned long flags;
|
||||||
unsigned long bit = 1UL << (irq_nr & 0x1f);
|
unsigned long bit = 1UL << (irq_nr & 0x1f);
|
||||||
int i = irq_nr >> 5;
|
int i = irq_nr >> 5;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&pmac_pic_lock, flags);
|
||||||
if ((irq_desc[irq_nr].status & IRQ_LEVEL) == 0)
|
if ((irq_desc[irq_nr].status & IRQ_LEVEL) == 0)
|
||||||
out_le32(&pmac_irq_hw[i]->ack, bit);
|
out_le32(&pmac_irq_hw[i]->ack, bit);
|
||||||
set_bit(irq_nr, ppc_cached_irq_mask);
|
__set_bit(irq_nr, ppc_cached_irq_mask);
|
||||||
pmac_set_irq_mask(irq_nr, 0);
|
__pmac_set_irq_mask(irq_nr, 0);
|
||||||
|
spin_unlock_irqrestore(&pmac_pic_lock, flags);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pmac_mask_irq(unsigned int irq_nr)
|
static void pmac_mask_irq(unsigned int irq_nr)
|
||||||
{
|
{
|
||||||
clear_bit(irq_nr, ppc_cached_irq_mask);
|
unsigned long flags;
|
||||||
pmac_set_irq_mask(irq_nr, 0);
|
|
||||||
mb();
|
spin_lock_irqsave(&pmac_pic_lock, flags);
|
||||||
|
__clear_bit(irq_nr, ppc_cached_irq_mask);
|
||||||
|
__pmac_set_irq_mask(irq_nr, 0);
|
||||||
|
spin_unlock_irqrestore(&pmac_pic_lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pmac_unmask_irq(unsigned int irq_nr)
|
static void pmac_unmask_irq(unsigned int irq_nr)
|
||||||
{
|
{
|
||||||
set_bit(irq_nr, ppc_cached_irq_mask);
|
unsigned long flags;
|
||||||
pmac_set_irq_mask(irq_nr, 0);
|
|
||||||
|
spin_lock_irqsave(&pmac_pic_lock, flags);
|
||||||
|
__set_bit(irq_nr, ppc_cached_irq_mask);
|
||||||
|
__pmac_set_irq_mask(irq_nr, 0);
|
||||||
|
spin_unlock_irqrestore(&pmac_pic_lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pmac_end_irq(unsigned int irq_nr)
|
static int pmac_retrigger(unsigned int irq_nr)
|
||||||
{
|
{
|
||||||
if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))
|
unsigned long flags;
|
||||||
&& irq_desc[irq_nr].action) {
|
|
||||||
set_bit(irq_nr, ppc_cached_irq_mask);
|
spin_lock_irqsave(&pmac_pic_lock, flags);
|
||||||
pmac_set_irq_mask(irq_nr, 1);
|
__pmac_retrigger(irq_nr);
|
||||||
}
|
spin_unlock_irqrestore(&pmac_pic_lock, flags);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct irq_chip pmac_pic = {
|
||||||
struct hw_interrupt_type pmac_pic = {
|
|
||||||
.typename = " PMAC-PIC ",
|
.typename = " PMAC-PIC ",
|
||||||
.startup = pmac_startup_irq,
|
.startup = pmac_startup_irq,
|
||||||
.enable = pmac_unmask_irq,
|
.mask = pmac_mask_irq,
|
||||||
.disable = pmac_mask_irq,
|
.ack = pmac_ack_irq,
|
||||||
.ack = pmac_mask_and_ack_irq,
|
.mask_ack = pmac_mask_and_ack_irq,
|
||||||
.end = pmac_end_irq,
|
.unmask = pmac_unmask_irq,
|
||||||
};
|
.retrigger = pmac_retrigger,
|
||||||
|
|
||||||
struct hw_interrupt_type gatwick_pic = {
|
|
||||||
.typename = " GATWICK ",
|
|
||||||
.startup = pmac_startup_irq,
|
|
||||||
.enable = pmac_unmask_irq,
|
|
||||||
.disable = pmac_mask_irq,
|
|
||||||
.ack = pmac_mask_and_ack_irq,
|
|
||||||
.end = pmac_end_irq,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static irqreturn_t gatwick_action(int cpl, void *dev_id, struct pt_regs *regs)
|
static irqreturn_t gatwick_action(int cpl, void *dev_id, struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
|
unsigned long flags;
|
||||||
int irq, bits;
|
int irq, bits;
|
||||||
|
int rc = IRQ_NONE;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&pmac_pic_lock, flags);
|
||||||
for (irq = max_irqs; (irq -= 32) >= max_real_irqs; ) {
|
for (irq = max_irqs; (irq -= 32) >= max_real_irqs; ) {
|
||||||
int i = irq >> 5;
|
int i = irq >> 5;
|
||||||
bits = in_le32(&pmac_irq_hw[i]->event) | ppc_lost_interrupts[i];
|
bits = in_le32(&pmac_irq_hw[i]->event) | ppc_lost_interrupts[i];
|
||||||
@@ -209,17 +229,20 @@ static irqreturn_t gatwick_action(int cpl, void *dev_id, struct pt_regs *regs)
|
|||||||
if (bits == 0)
|
if (bits == 0)
|
||||||
continue;
|
continue;
|
||||||
irq += __ilog2(bits);
|
irq += __ilog2(bits);
|
||||||
|
spin_unlock_irqrestore(&pmac_pic_lock, flags);
|
||||||
__do_IRQ(irq, regs);
|
__do_IRQ(irq, regs);
|
||||||
return IRQ_HANDLED;
|
spin_lock_irqsave(&pmac_pic_lock, flags);
|
||||||
|
rc = IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
printk("gatwick irq not from gatwick pic\n");
|
spin_unlock_irqrestore(&pmac_pic_lock, flags);
|
||||||
return IRQ_NONE;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pmac_get_irq(struct pt_regs *regs)
|
static int pmac_get_irq(struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
int irq;
|
int irq;
|
||||||
unsigned long bits = 0;
|
unsigned long bits = 0;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
void psurge_smp_message_recv(struct pt_regs *);
|
void psurge_smp_message_recv(struct pt_regs *);
|
||||||
@@ -230,6 +253,7 @@ static int pmac_get_irq(struct pt_regs *regs)
|
|||||||
return -2; /* ignore, already handled */
|
return -2; /* ignore, already handled */
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_SMP */
|
#endif /* CONFIG_SMP */
|
||||||
|
spin_lock_irqsave(&pmac_pic_lock, flags);
|
||||||
for (irq = max_real_irqs; (irq -= 32) >= 0; ) {
|
for (irq = max_real_irqs; (irq -= 32) >= 0; ) {
|
||||||
int i = irq >> 5;
|
int i = irq >> 5;
|
||||||
bits = in_le32(&pmac_irq_hw[i]->event) | ppc_lost_interrupts[i];
|
bits = in_le32(&pmac_irq_hw[i]->event) | ppc_lost_interrupts[i];
|
||||||
@@ -241,6 +265,7 @@ static int pmac_get_irq(struct pt_regs *regs)
|
|||||||
irq += __ilog2(bits);
|
irq += __ilog2(bits);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
spin_unlock_irqrestore(&pmac_pic_lock, flags);
|
||||||
|
|
||||||
return irq;
|
return irq;
|
||||||
}
|
}
|
||||||
@@ -389,7 +414,6 @@ static struct irqaction gatwick_cascade_action = {
|
|||||||
static void __init pmac_pic_probe_oldstyle(void)
|
static void __init pmac_pic_probe_oldstyle(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
int irq_cascade = -1;
|
|
||||||
struct device_node *master = NULL;
|
struct device_node *master = NULL;
|
||||||
struct device_node *slave = NULL;
|
struct device_node *slave = NULL;
|
||||||
u8 __iomem *addr;
|
u8 __iomem *addr;
|
||||||
@@ -443,9 +467,16 @@ static void __init pmac_pic_probe_oldstyle(void)
|
|||||||
}
|
}
|
||||||
BUG_ON(master == NULL);
|
BUG_ON(master == NULL);
|
||||||
|
|
||||||
/* Set the handler for the main PIC */
|
/* Mark level interrupts and set handlers */
|
||||||
for ( i = 0; i < max_real_irqs ; i++ )
|
for (i = 0; i < max_irqs; i++) {
|
||||||
irq_desc[i].chip = &pmac_pic;
|
int level = !!(level_mask[i >> 5] & (1UL << (i & 0x1f)));
|
||||||
|
if (level)
|
||||||
|
irq_desc[i].status |= IRQ_LEVEL;
|
||||||
|
else
|
||||||
|
irq_desc[i].status |= IRQ_DELAYED_DISABLE;
|
||||||
|
set_irq_chip_and_handler(i, &pmac_pic, level ?
|
||||||
|
handle_level_irq : handle_edge_irq);
|
||||||
|
}
|
||||||
|
|
||||||
/* Get addresses of first controller if we have a node for it */
|
/* Get addresses of first controller if we have a node for it */
|
||||||
BUG_ON(of_address_to_resource(master, 0, &r));
|
BUG_ON(of_address_to_resource(master, 0, &r));
|
||||||
@@ -472,29 +503,22 @@ static void __init pmac_pic_probe_oldstyle(void)
|
|||||||
pmac_irq_hw[i++] =
|
pmac_irq_hw[i++] =
|
||||||
(volatile struct pmac_irq_hw __iomem *)
|
(volatile struct pmac_irq_hw __iomem *)
|
||||||
(addr + 0x10);
|
(addr + 0x10);
|
||||||
irq_cascade = slave->intrs[0].line;
|
pmac_irq_cascade = slave->intrs[0].line;
|
||||||
|
|
||||||
printk(KERN_INFO "irq: Found slave Apple PIC %s for %d irqs"
|
printk(KERN_INFO "irq: Found slave Apple PIC %s for %d irqs"
|
||||||
" cascade: %d\n", slave->full_name,
|
" cascade: %d\n", slave->full_name,
|
||||||
max_irqs - max_real_irqs, irq_cascade);
|
max_irqs - max_real_irqs, pmac_irq_cascade);
|
||||||
}
|
}
|
||||||
of_node_put(slave);
|
of_node_put(slave);
|
||||||
|
|
||||||
/* disable all interrupts in all controllers */
|
/* Disable all interrupts in all controllers */
|
||||||
for (i = 0; i * 32 < max_irqs; ++i)
|
for (i = 0; i * 32 < max_irqs; ++i)
|
||||||
out_le32(&pmac_irq_hw[i]->enable, 0);
|
out_le32(&pmac_irq_hw[i]->enable, 0);
|
||||||
|
|
||||||
/* mark level interrupts */
|
/* Hookup cascade irq */
|
||||||
for (i = 0; i < max_irqs; i++)
|
if (slave)
|
||||||
if (level_mask[i >> 5] & (1UL << (i & 0x1f)))
|
setup_irq(pmac_irq_cascade, &gatwick_cascade_action);
|
||||||
irq_desc[i].status = IRQ_LEVEL;
|
|
||||||
|
|
||||||
/* Setup handlers for secondary controller and hook cascade irq*/
|
|
||||||
if (slave) {
|
|
||||||
for ( i = max_real_irqs ; i < max_irqs ; i++ )
|
|
||||||
irq_desc[i].chip = &gatwick_pic;
|
|
||||||
setup_irq(irq_cascade, &gatwick_cascade_action);
|
|
||||||
}
|
|
||||||
printk(KERN_INFO "irq: System has %d possible interrupts\n", max_irqs);
|
printk(KERN_INFO "irq: System has %d possible interrupts\n", max_irqs);
|
||||||
#ifdef CONFIG_XMON
|
#ifdef CONFIG_XMON
|
||||||
setup_irq(20, &xmon_action);
|
setup_irq(20, &xmon_action);
|
||||||
@@ -502,9 +526,20 @@ static void __init pmac_pic_probe_oldstyle(void)
|
|||||||
}
|
}
|
||||||
#endif /* CONFIG_PPC32 */
|
#endif /* CONFIG_PPC32 */
|
||||||
|
|
||||||
static int pmac_u3_cascade(struct pt_regs *regs, void *data)
|
static void pmac_u3_cascade(unsigned int irq, struct irq_desc *desc,
|
||||||
|
struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
return mpic_get_one_irq((struct mpic *)data, regs);
|
struct mpic *mpic = desc->handler_data;
|
||||||
|
unsigned int max = 100;
|
||||||
|
|
||||||
|
while(max--) {
|
||||||
|
int cascade_irq = mpic_get_one_irq(mpic, regs);
|
||||||
|
if (max == 99)
|
||||||
|
desc->chip->eoi(irq);
|
||||||
|
if (irq < 0)
|
||||||
|
break;
|
||||||
|
generic_handle_irq(cascade_irq, regs);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __init pmac_pic_setup_mpic_nmi(struct mpic *mpic)
|
static void __init pmac_pic_setup_mpic_nmi(struct mpic *mpic)
|
||||||
@@ -612,7 +647,8 @@ static int __init pmac_pic_probe_mpic(void)
|
|||||||
of_node_put(slave);
|
of_node_put(slave);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
mpic_setup_cascade(slave->intrs[0].line, pmac_u3_cascade, mpic2);
|
set_irq_data(slave->intrs[0].line, mpic2);
|
||||||
|
set_irq_chained_handler(slave->intrs[0].line, pmac_u3_cascade);
|
||||||
|
|
||||||
of_node_put(slave);
|
of_node_put(slave);
|
||||||
return 0;
|
return 0;
|
||||||
|
@@ -118,6 +118,21 @@ static void __init fwnmi_init(void)
|
|||||||
fwnmi_active = 1;
|
fwnmi_active = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void pSeries_8259_cascade(unsigned int irq, struct irq_desc *desc,
|
||||||
|
struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
unsigned int max = 100;
|
||||||
|
|
||||||
|
while(max--) {
|
||||||
|
int cascade_irq = i8259_irq(regs);
|
||||||
|
if (max == 99)
|
||||||
|
desc->chip->eoi(irq);
|
||||||
|
if (cascade_irq < 0)
|
||||||
|
break;
|
||||||
|
generic_handle_irq(cascade_irq, regs);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
static void __init pSeries_init_mpic(void)
|
static void __init pSeries_init_mpic(void)
|
||||||
{
|
{
|
||||||
unsigned int *addrp;
|
unsigned int *addrp;
|
||||||
@@ -140,7 +155,7 @@ static void __init pSeries_init_mpic(void)
|
|||||||
i8259_init(intack, 0);
|
i8259_init(intack, 0);
|
||||||
|
|
||||||
/* Hook cascade to mpic */
|
/* Hook cascade to mpic */
|
||||||
mpic_setup_cascade(NUM_ISA_INTERRUPTS, i8259_irq_cascade, NULL);
|
set_irq_chained_handler(NUM_ISA_INTERRUPTS, pSeries_8259_cascade);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __init pSeries_setup_mpic(void)
|
static void __init pSeries_setup_mpic(void)
|
||||||
@@ -201,10 +216,8 @@ static void __init pSeries_setup_arch(void)
|
|||||||
/* Allocate the mpic now, so that find_and_init_phbs() can
|
/* Allocate the mpic now, so that find_and_init_phbs() can
|
||||||
* fill the ISUs */
|
* fill the ISUs */
|
||||||
pSeries_setup_mpic();
|
pSeries_setup_mpic();
|
||||||
} else {
|
} else
|
||||||
ppc_md.init_IRQ = xics_init_IRQ;
|
ppc_md.init_IRQ = xics_init_IRQ;
|
||||||
ppc_md.get_irq = xics_get_irq;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
smp_init_pSeries();
|
smp_init_pSeries();
|
||||||
@@ -291,10 +304,7 @@ static void pSeries_mach_cpu_die(void)
|
|||||||
{
|
{
|
||||||
local_irq_disable();
|
local_irq_disable();
|
||||||
idle_task_exit();
|
idle_task_exit();
|
||||||
/* Some hardware requires clearing the CPPR, while other hardware does not
|
xics_teardown_cpu(0);
|
||||||
* it is safe either way
|
|
||||||
*/
|
|
||||||
pSeriesLP_cppr_info(0, 0);
|
|
||||||
rtas_stop_self();
|
rtas_stop_self();
|
||||||
/* Should never get here... */
|
/* Should never get here... */
|
||||||
BUG();
|
BUG();
|
||||||
|
@@ -31,23 +31,6 @@
|
|||||||
|
|
||||||
#include "xics.h"
|
#include "xics.h"
|
||||||
|
|
||||||
static unsigned int xics_startup(unsigned int irq);
|
|
||||||
static void xics_enable_irq(unsigned int irq);
|
|
||||||
static void xics_disable_irq(unsigned int irq);
|
|
||||||
static void xics_mask_and_ack_irq(unsigned int irq);
|
|
||||||
static void xics_end_irq(unsigned int irq);
|
|
||||||
static void xics_set_affinity(unsigned int irq_nr, cpumask_t cpumask);
|
|
||||||
|
|
||||||
static struct hw_interrupt_type xics_pic = {
|
|
||||||
.typename = " XICS ",
|
|
||||||
.startup = xics_startup,
|
|
||||||
.enable = xics_enable_irq,
|
|
||||||
.disable = xics_disable_irq,
|
|
||||||
.ack = xics_mask_and_ack_irq,
|
|
||||||
.end = xics_end_irq,
|
|
||||||
.set_affinity = xics_set_affinity
|
|
||||||
};
|
|
||||||
|
|
||||||
/* This is used to map real irq numbers to virtual */
|
/* This is used to map real irq numbers to virtual */
|
||||||
static struct radix_tree_root irq_map = RADIX_TREE_INIT(GFP_ATOMIC);
|
static struct radix_tree_root irq_map = RADIX_TREE_INIT(GFP_ATOMIC);
|
||||||
|
|
||||||
@@ -98,48 +81,34 @@ static int ibm_set_xive;
|
|||||||
static int ibm_int_on;
|
static int ibm_int_on;
|
||||||
static int ibm_int_off;
|
static int ibm_int_off;
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int (*xirr_info_get)(int cpu);
|
/* Direct HW low level accessors */
|
||||||
void (*xirr_info_set)(int cpu, int val);
|
|
||||||
void (*cppr_info)(int cpu, u8 val);
|
|
||||||
void (*qirr_info)(int cpu, u8 val);
|
|
||||||
} xics_ops;
|
|
||||||
|
|
||||||
|
|
||||||
/* SMP */
|
static inline int direct_xirr_info_get(int n_cpu)
|
||||||
|
|
||||||
static int pSeries_xirr_info_get(int n_cpu)
|
|
||||||
{
|
{
|
||||||
return in_be32(&xics_per_cpu[n_cpu]->xirr.word);
|
return in_be32(&xics_per_cpu[n_cpu]->xirr.word);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pSeries_xirr_info_set(int n_cpu, int value)
|
static inline void direct_xirr_info_set(int n_cpu, int value)
|
||||||
{
|
{
|
||||||
out_be32(&xics_per_cpu[n_cpu]->xirr.word, value);
|
out_be32(&xics_per_cpu[n_cpu]->xirr.word, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pSeries_cppr_info(int n_cpu, u8 value)
|
static inline void direct_cppr_info(int n_cpu, u8 value)
|
||||||
{
|
{
|
||||||
out_8(&xics_per_cpu[n_cpu]->xirr.bytes[0], value);
|
out_8(&xics_per_cpu[n_cpu]->xirr.bytes[0], value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pSeries_qirr_info(int n_cpu, u8 value)
|
static inline void direct_qirr_info(int n_cpu, u8 value)
|
||||||
{
|
{
|
||||||
out_8(&xics_per_cpu[n_cpu]->qirr.bytes[0], value);
|
out_8(&xics_per_cpu[n_cpu]->qirr.bytes[0], value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static xics_ops pSeries_ops = {
|
|
||||||
pSeries_xirr_info_get,
|
|
||||||
pSeries_xirr_info_set,
|
|
||||||
pSeries_cppr_info,
|
|
||||||
pSeries_qirr_info
|
|
||||||
};
|
|
||||||
|
|
||||||
static xics_ops *ops = &pSeries_ops;
|
/* LPAR low level accessors */
|
||||||
|
|
||||||
|
|
||||||
/* LPAR */
|
|
||||||
|
|
||||||
static inline long plpar_eoi(unsigned long xirr)
|
static inline long plpar_eoi(unsigned long xirr)
|
||||||
{
|
{
|
||||||
return plpar_hcall_norets(H_EOI, xirr);
|
return plpar_hcall_norets(H_EOI, xirr);
|
||||||
@@ -161,7 +130,7 @@ static inline long plpar_xirr(unsigned long *xirr_ret)
|
|||||||
return plpar_hcall(H_XIRR, 0, 0, 0, 0, xirr_ret, &dummy, &dummy);
|
return plpar_hcall(H_XIRR, 0, 0, 0, 0, xirr_ret, &dummy, &dummy);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pSeriesLP_xirr_info_get(int n_cpu)
|
static inline int lpar_xirr_info_get(int n_cpu)
|
||||||
{
|
{
|
||||||
unsigned long lpar_rc;
|
unsigned long lpar_rc;
|
||||||
unsigned long return_value;
|
unsigned long return_value;
|
||||||
@@ -172,7 +141,7 @@ static int pSeriesLP_xirr_info_get(int n_cpu)
|
|||||||
return (int)return_value;
|
return (int)return_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pSeriesLP_xirr_info_set(int n_cpu, int value)
|
static inline void lpar_xirr_info_set(int n_cpu, int value)
|
||||||
{
|
{
|
||||||
unsigned long lpar_rc;
|
unsigned long lpar_rc;
|
||||||
unsigned long val64 = value & 0xffffffff;
|
unsigned long val64 = value & 0xffffffff;
|
||||||
@@ -183,7 +152,7 @@ static void pSeriesLP_xirr_info_set(int n_cpu, int value)
|
|||||||
val64);
|
val64);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pSeriesLP_cppr_info(int n_cpu, u8 value)
|
static inline void lpar_cppr_info(int n_cpu, u8 value)
|
||||||
{
|
{
|
||||||
unsigned long lpar_rc;
|
unsigned long lpar_rc;
|
||||||
|
|
||||||
@@ -192,7 +161,7 @@ void pSeriesLP_cppr_info(int n_cpu, u8 value)
|
|||||||
panic("bad return code cppr - rc = %lx\n", lpar_rc);
|
panic("bad return code cppr - rc = %lx\n", lpar_rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pSeriesLP_qirr_info(int n_cpu , u8 value)
|
static inline void lpar_qirr_info(int n_cpu , u8 value)
|
||||||
{
|
{
|
||||||
unsigned long lpar_rc;
|
unsigned long lpar_rc;
|
||||||
|
|
||||||
@@ -201,36 +170,9 @@ static void pSeriesLP_qirr_info(int n_cpu , u8 value)
|
|||||||
panic("bad return code qirr - rc = %lx\n", lpar_rc);
|
panic("bad return code qirr - rc = %lx\n", lpar_rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
xics_ops pSeriesLP_ops = {
|
|
||||||
pSeriesLP_xirr_info_get,
|
|
||||||
pSeriesLP_xirr_info_set,
|
|
||||||
pSeriesLP_cppr_info,
|
|
||||||
pSeriesLP_qirr_info
|
|
||||||
};
|
|
||||||
|
|
||||||
static unsigned int xics_startup(unsigned int virq)
|
/* High level handlers and init code */
|
||||||
{
|
|
||||||
unsigned int irq;
|
|
||||||
|
|
||||||
irq = irq_offset_down(virq);
|
|
||||||
if (radix_tree_insert(&irq_map, virt_irq_to_real(irq),
|
|
||||||
&virt_irq_to_real_map[irq]) == -ENOMEM)
|
|
||||||
printk(KERN_CRIT "Out of memory creating real -> virtual"
|
|
||||||
" IRQ mapping for irq %u (real 0x%x)\n",
|
|
||||||
virq, virt_irq_to_real(irq));
|
|
||||||
xics_enable_irq(virq);
|
|
||||||
return 0; /* return value is ignored */
|
|
||||||
}
|
|
||||||
|
|
||||||
static unsigned int real_irq_to_virt(unsigned int real_irq)
|
|
||||||
{
|
|
||||||
unsigned int *ptr;
|
|
||||||
|
|
||||||
ptr = radix_tree_lookup(&irq_map, real_irq);
|
|
||||||
if (ptr == NULL)
|
|
||||||
return NO_IRQ;
|
|
||||||
return ptr - virt_irq_to_real_map;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
static int get_irq_server(unsigned int irq)
|
static int get_irq_server(unsigned int irq)
|
||||||
@@ -264,17 +206,20 @@ static int get_irq_server(unsigned int irq)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void xics_enable_irq(unsigned int virq)
|
|
||||||
|
static void xics_unmask_irq(unsigned int virq)
|
||||||
{
|
{
|
||||||
unsigned int irq;
|
unsigned int irq;
|
||||||
int call_status;
|
int call_status;
|
||||||
unsigned int server;
|
unsigned int server;
|
||||||
|
|
||||||
irq = virt_irq_to_real(irq_offset_down(virq));
|
irq = virt_irq_to_real(irq_offset_down(virq));
|
||||||
if (irq == XICS_IPI)
|
WARN_ON(irq == NO_IRQ);
|
||||||
|
if (irq == XICS_IPI || irq == NO_IRQ)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
server = get_irq_server(virq);
|
server = get_irq_server(virq);
|
||||||
|
|
||||||
call_status = rtas_call(ibm_set_xive, 3, 1, NULL, irq, server,
|
call_status = rtas_call(ibm_set_xive, 3, 1, NULL, irq, server,
|
||||||
DEFAULT_PRIORITY);
|
DEFAULT_PRIORITY);
|
||||||
if (call_status != 0) {
|
if (call_status != 0) {
|
||||||
@@ -293,7 +238,7 @@ static void xics_enable_irq(unsigned int virq)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void xics_disable_real_irq(unsigned int irq)
|
static void xics_mask_real_irq(unsigned int irq)
|
||||||
{
|
{
|
||||||
int call_status;
|
int call_status;
|
||||||
unsigned int server;
|
unsigned int server;
|
||||||
@@ -318,75 +263,104 @@ static void xics_disable_real_irq(unsigned int irq)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void xics_disable_irq(unsigned int virq)
|
static void xics_mask_irq(unsigned int virq)
|
||||||
{
|
{
|
||||||
unsigned int irq;
|
unsigned int irq;
|
||||||
|
|
||||||
irq = virt_irq_to_real(irq_offset_down(virq));
|
irq = virt_irq_to_real(irq_offset_down(virq));
|
||||||
xics_disable_real_irq(irq);
|
WARN_ON(irq == NO_IRQ);
|
||||||
|
if (irq != NO_IRQ)
|
||||||
|
xics_mask_real_irq(irq);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void xics_end_irq(unsigned int irq)
|
static void xics_set_irq_revmap(unsigned int virq)
|
||||||
|
{
|
||||||
|
unsigned int irq;
|
||||||
|
|
||||||
|
irq = irq_offset_down(virq);
|
||||||
|
if (radix_tree_insert(&irq_map, virt_irq_to_real(irq),
|
||||||
|
&virt_irq_to_real_map[irq]) == -ENOMEM)
|
||||||
|
printk(KERN_CRIT "Out of memory creating real -> virtual"
|
||||||
|
" IRQ mapping for irq %u (real 0x%x)\n",
|
||||||
|
virq, virt_irq_to_real(irq));
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int xics_startup(unsigned int virq)
|
||||||
|
{
|
||||||
|
xics_set_irq_revmap(virq);
|
||||||
|
xics_unmask_irq(virq);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int real_irq_to_virt(unsigned int real_irq)
|
||||||
|
{
|
||||||
|
unsigned int *ptr;
|
||||||
|
|
||||||
|
ptr = radix_tree_lookup(&irq_map, real_irq);
|
||||||
|
if (ptr == NULL)
|
||||||
|
return NO_IRQ;
|
||||||
|
return ptr - virt_irq_to_real_map;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void xics_eoi_direct(unsigned int irq)
|
||||||
{
|
{
|
||||||
int cpu = smp_processor_id();
|
int cpu = smp_processor_id();
|
||||||
|
|
||||||
iosync();
|
iosync();
|
||||||
ops->xirr_info_set(cpu, ((0xff << 24) |
|
direct_xirr_info_set(cpu, ((0xff << 24) |
|
||||||
|
(virt_irq_to_real(irq_offset_down(irq)))));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void xics_eoi_lpar(unsigned int irq)
|
||||||
|
{
|
||||||
|
int cpu = smp_processor_id();
|
||||||
|
|
||||||
|
iosync();
|
||||||
|
lpar_xirr_info_set(cpu, ((0xff << 24) |
|
||||||
(virt_irq_to_real(irq_offset_down(irq)))));
|
(virt_irq_to_real(irq_offset_down(irq)))));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void xics_mask_and_ack_irq(unsigned int irq)
|
static inline int xics_remap_irq(int vec)
|
||||||
{
|
{
|
||||||
int cpu = smp_processor_id();
|
|
||||||
|
|
||||||
if (irq < irq_offset_value()) {
|
|
||||||
i8259_pic.ack(irq);
|
|
||||||
iosync();
|
|
||||||
ops->xirr_info_set(cpu, ((0xff<<24) |
|
|
||||||
xics_irq_8259_cascade_real));
|
|
||||||
iosync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int xics_get_irq(struct pt_regs *regs)
|
|
||||||
{
|
|
||||||
unsigned int cpu = smp_processor_id();
|
|
||||||
unsigned int vec;
|
|
||||||
int irq;
|
int irq;
|
||||||
|
|
||||||
vec = ops->xirr_info_get(cpu);
|
|
||||||
/* (vec >> 24) == old priority */
|
|
||||||
vec &= 0x00ffffff;
|
vec &= 0x00ffffff;
|
||||||
|
|
||||||
/* for sanity, this had better be < NR_IRQS - 16 */
|
if (vec == XICS_IRQ_SPURIOUS)
|
||||||
if (vec == xics_irq_8259_cascade_real) {
|
return NO_IRQ;
|
||||||
irq = i8259_irq(regs);
|
|
||||||
xics_end_irq(irq_offset_up(xics_irq_8259_cascade));
|
irq = real_irq_to_virt(vec);
|
||||||
} else if (vec == XICS_IRQ_SPURIOUS) {
|
if (irq == NO_IRQ)
|
||||||
irq = -1;
|
irq = real_irq_to_virt_slowpath(vec);
|
||||||
} else {
|
if (likely(irq != NO_IRQ))
|
||||||
irq = real_irq_to_virt(vec);
|
return irq_offset_up(irq);
|
||||||
if (irq == NO_IRQ)
|
|
||||||
irq = real_irq_to_virt_slowpath(vec);
|
printk(KERN_ERR "Interrupt %u (real) is invalid,"
|
||||||
if (irq == NO_IRQ) {
|
" disabling it.\n", vec);
|
||||||
printk(KERN_ERR "Interrupt %u (real) is invalid,"
|
xics_mask_real_irq(vec);
|
||||||
" disabling it.\n", vec);
|
return NO_IRQ;
|
||||||
xics_disable_real_irq(vec);
|
}
|
||||||
} else
|
|
||||||
irq = irq_offset_up(irq);
|
static int xics_get_irq_direct(struct pt_regs *regs)
|
||||||
}
|
{
|
||||||
return irq;
|
unsigned int cpu = smp_processor_id();
|
||||||
|
|
||||||
|
return xics_remap_irq(direct_xirr_info_get(cpu));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int xics_get_irq_lpar(struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
unsigned int cpu = smp_processor_id();
|
||||||
|
|
||||||
|
return xics_remap_irq(lpar_xirr_info_get(cpu));
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
|
|
||||||
static irqreturn_t xics_ipi_action(int irq, void *dev_id, struct pt_regs *regs)
|
static irqreturn_t xics_ipi_dispatch(int cpu, struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
int cpu = smp_processor_id();
|
|
||||||
|
|
||||||
ops->qirr_info(cpu, 0xff);
|
|
||||||
|
|
||||||
WARN_ON(cpu_is_offline(cpu));
|
WARN_ON(cpu_is_offline(cpu));
|
||||||
|
|
||||||
while (xics_ipi_message[cpu].value) {
|
while (xics_ipi_message[cpu].value) {
|
||||||
@@ -418,18 +392,108 @@ static irqreturn_t xics_ipi_action(int irq, void *dev_id, struct pt_regs *regs)
|
|||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static irqreturn_t xics_ipi_action_direct(int irq, void *dev_id, struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
int cpu = smp_processor_id();
|
||||||
|
|
||||||
|
direct_qirr_info(cpu, 0xff);
|
||||||
|
|
||||||
|
return xics_ipi_dispatch(cpu, regs);
|
||||||
|
}
|
||||||
|
|
||||||
|
static irqreturn_t xics_ipi_action_lpar(int irq, void *dev_id, struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
int cpu = smp_processor_id();
|
||||||
|
|
||||||
|
lpar_qirr_info(cpu, 0xff);
|
||||||
|
|
||||||
|
return xics_ipi_dispatch(cpu, regs);
|
||||||
|
}
|
||||||
|
|
||||||
void xics_cause_IPI(int cpu)
|
void xics_cause_IPI(int cpu)
|
||||||
{
|
{
|
||||||
ops->qirr_info(cpu, IPI_PRIORITY);
|
if (firmware_has_feature(FW_FEATURE_LPAR))
|
||||||
|
lpar_qirr_info(cpu, IPI_PRIORITY);
|
||||||
|
else
|
||||||
|
direct_qirr_info(cpu, IPI_PRIORITY);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_SMP */
|
#endif /* CONFIG_SMP */
|
||||||
|
|
||||||
|
static void xics_set_cpu_priority(int cpu, unsigned char cppr)
|
||||||
|
{
|
||||||
|
if (firmware_has_feature(FW_FEATURE_LPAR))
|
||||||
|
lpar_cppr_info(cpu, cppr);
|
||||||
|
else
|
||||||
|
direct_cppr_info(cpu, cppr);
|
||||||
|
iosync();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void xics_set_affinity(unsigned int virq, cpumask_t cpumask)
|
||||||
|
{
|
||||||
|
unsigned int irq;
|
||||||
|
int status;
|
||||||
|
int xics_status[2];
|
||||||
|
unsigned long newmask;
|
||||||
|
cpumask_t tmp = CPU_MASK_NONE;
|
||||||
|
|
||||||
|
irq = virt_irq_to_real(irq_offset_down(virq));
|
||||||
|
if (irq == XICS_IPI || irq == NO_IRQ)
|
||||||
|
return;
|
||||||
|
|
||||||
|
status = rtas_call(ibm_get_xive, 1, 3, xics_status, irq);
|
||||||
|
|
||||||
|
if (status) {
|
||||||
|
printk(KERN_ERR "xics_set_affinity: irq=%u ibm,get-xive "
|
||||||
|
"returns %d\n", irq, status);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For the moment only implement delivery to all cpus or one cpu */
|
||||||
|
if (cpus_equal(cpumask, CPU_MASK_ALL)) {
|
||||||
|
newmask = default_distrib_server;
|
||||||
|
} else {
|
||||||
|
cpus_and(tmp, cpu_online_map, cpumask);
|
||||||
|
if (cpus_empty(tmp))
|
||||||
|
return;
|
||||||
|
newmask = get_hard_smp_processor_id(first_cpu(tmp));
|
||||||
|
}
|
||||||
|
|
||||||
|
status = rtas_call(ibm_set_xive, 3, 1, NULL,
|
||||||
|
irq, newmask, xics_status[1]);
|
||||||
|
|
||||||
|
if (status) {
|
||||||
|
printk(KERN_ERR "xics_set_affinity: irq=%u ibm,set-xive "
|
||||||
|
"returns %d\n", irq, status);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct irq_chip xics_pic_direct = {
|
||||||
|
.typename = " XICS ",
|
||||||
|
.startup = xics_startup,
|
||||||
|
.mask = xics_mask_irq,
|
||||||
|
.unmask = xics_unmask_irq,
|
||||||
|
.eoi = xics_eoi_direct,
|
||||||
|
.set_affinity = xics_set_affinity
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static struct irq_chip xics_pic_lpar = {
|
||||||
|
.typename = " XICS ",
|
||||||
|
.startup = xics_startup,
|
||||||
|
.mask = xics_mask_irq,
|
||||||
|
.unmask = xics_unmask_irq,
|
||||||
|
.eoi = xics_eoi_lpar,
|
||||||
|
.set_affinity = xics_set_affinity
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
void xics_setup_cpu(void)
|
void xics_setup_cpu(void)
|
||||||
{
|
{
|
||||||
int cpu = smp_processor_id();
|
int cpu = smp_processor_id();
|
||||||
|
|
||||||
ops->cppr_info(cpu, 0xff);
|
xics_set_cpu_priority(cpu, 0xff);
|
||||||
iosync();
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Put the calling processor into the GIQ. This is really only
|
* Put the calling processor into the GIQ. This is really only
|
||||||
@@ -453,6 +517,7 @@ void xics_init_IRQ(void)
|
|||||||
unsigned long addr;
|
unsigned long addr;
|
||||||
unsigned long size;
|
unsigned long size;
|
||||||
} intnodes[NR_CPUS];
|
} intnodes[NR_CPUS];
|
||||||
|
struct irq_chip *chip;
|
||||||
|
|
||||||
ppc64_boot_msg(0x20, "XICS Init");
|
ppc64_boot_msg(0x20, "XICS Init");
|
||||||
|
|
||||||
@@ -519,26 +584,10 @@ nextnode:
|
|||||||
intr_base = intnodes[0].addr;
|
intr_base = intnodes[0].addr;
|
||||||
intr_size = intnodes[0].size;
|
intr_size = intnodes[0].size;
|
||||||
|
|
||||||
np = of_find_node_by_type(NULL, "interrupt-controller");
|
if (firmware_has_feature(FW_FEATURE_LPAR)) {
|
||||||
if (!np) {
|
ppc_md.get_irq = xics_get_irq_lpar;
|
||||||
printk(KERN_DEBUG "xics: no ISA interrupt controller\n");
|
chip = &xics_pic_lpar;
|
||||||
xics_irq_8259_cascade_real = -1;
|
} else {
|
||||||
xics_irq_8259_cascade = -1;
|
|
||||||
} else {
|
|
||||||
ireg = (uint *) get_property(np, "interrupts", NULL);
|
|
||||||
if (!ireg)
|
|
||||||
panic("xics_init_IRQ: can't find ISA interrupts property");
|
|
||||||
|
|
||||||
xics_irq_8259_cascade_real = *ireg;
|
|
||||||
xics_irq_8259_cascade
|
|
||||||
= virt_irq_create_mapping(xics_irq_8259_cascade_real);
|
|
||||||
i8259_init(0, 0);
|
|
||||||
of_node_put(np);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (firmware_has_feature(FW_FEATURE_LPAR))
|
|
||||||
ops = &pSeriesLP_ops;
|
|
||||||
else {
|
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
for_each_possible_cpu(i) {
|
for_each_possible_cpu(i) {
|
||||||
int hard_id;
|
int hard_id;
|
||||||
@@ -554,32 +603,54 @@ nextnode:
|
|||||||
#else
|
#else
|
||||||
xics_per_cpu[0] = ioremap(intr_base, intr_size);
|
xics_per_cpu[0] = ioremap(intr_base, intr_size);
|
||||||
#endif /* CONFIG_SMP */
|
#endif /* CONFIG_SMP */
|
||||||
|
ppc_md.get_irq = xics_get_irq_direct;
|
||||||
|
chip = &xics_pic_direct;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = irq_offset_value(); i < NR_IRQS; ++i)
|
for (i = irq_offset_value(); i < NR_IRQS; ++i) {
|
||||||
get_irq_desc(i)->chip = &xics_pic;
|
/* All IRQs on XICS are level for now. MSI code may want to modify
|
||||||
|
* that for reporting purposes
|
||||||
|
*/
|
||||||
|
get_irq_desc(i)->status |= IRQ_LEVEL;
|
||||||
|
set_irq_chip_and_handler(i, chip, handle_fasteoi_irq);
|
||||||
|
}
|
||||||
|
|
||||||
xics_setup_cpu();
|
xics_setup_cpu();
|
||||||
|
|
||||||
ppc64_boot_msg(0x21, "XICS Done");
|
ppc64_boot_msg(0x21, "XICS Done");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static int xics_setup_8259_cascade(void)
|
||||||
* We cant do this in init_IRQ because we need the memory subsystem up for
|
|
||||||
* request_irq()
|
|
||||||
*/
|
|
||||||
static int __init xics_setup_i8259(void)
|
|
||||||
{
|
{
|
||||||
if (ppc64_interrupt_controller == IC_PPC_XIC &&
|
struct device_node *np;
|
||||||
xics_irq_8259_cascade != -1) {
|
uint *ireg;
|
||||||
if (request_irq(irq_offset_up(xics_irq_8259_cascade),
|
|
||||||
no_action, 0, "8259 cascade", NULL))
|
np = of_find_node_by_type(NULL, "interrupt-controller");
|
||||||
printk(KERN_ERR "xics_setup_i8259: couldn't get 8259 "
|
if (np == NULL) {
|
||||||
"cascade\n");
|
printk(KERN_WARNING "xics: no ISA interrupt controller\n");
|
||||||
|
xics_irq_8259_cascade_real = -1;
|
||||||
|
xics_irq_8259_cascade = -1;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ireg = (uint *) get_property(np, "interrupts", NULL);
|
||||||
|
if (!ireg)
|
||||||
|
panic("xics_init_IRQ: can't find ISA interrupts property");
|
||||||
|
|
||||||
|
xics_irq_8259_cascade_real = *ireg;
|
||||||
|
xics_irq_8259_cascade = irq_offset_up
|
||||||
|
(virt_irq_create_mapping(xics_irq_8259_cascade_real));
|
||||||
|
i8259_init(0, 0);
|
||||||
|
of_node_put(np);
|
||||||
|
|
||||||
|
xics_set_irq_revmap(xics_irq_8259_cascade);
|
||||||
|
set_irq_chained_handler(xics_irq_8259_cascade, pSeries_8259_cascade);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
arch_initcall(xics_setup_i8259);
|
arch_initcall(xics_setup_8259_cascade);
|
||||||
|
|
||||||
|
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
void xics_request_IPIs(void)
|
void xics_request_IPIs(void)
|
||||||
@@ -590,61 +661,22 @@ void xics_request_IPIs(void)
|
|||||||
* IPIs are marked IRQF_DISABLED as they must run with irqs
|
* IPIs are marked IRQF_DISABLED as they must run with irqs
|
||||||
* disabled
|
* disabled
|
||||||
*/
|
*/
|
||||||
request_irq(irq_offset_up(XICS_IPI), xics_ipi_action,
|
set_irq_handler(irq_offset_up(XICS_IPI), handle_percpu_irq);
|
||||||
IRQF_DISABLED, "IPI", NULL);
|
if (firmware_has_feature(FW_FEATURE_LPAR))
|
||||||
get_irq_desc(irq_offset_up(XICS_IPI))->status |= IRQ_PER_CPU;
|
request_irq(irq_offset_up(XICS_IPI), xics_ipi_action_lpar,
|
||||||
}
|
SA_INTERRUPT, "IPI", NULL);
|
||||||
#endif
|
else
|
||||||
|
request_irq(irq_offset_up(XICS_IPI), xics_ipi_action_direct,
|
||||||
static void xics_set_affinity(unsigned int virq, cpumask_t cpumask)
|
SA_INTERRUPT, "IPI", NULL);
|
||||||
{
|
|
||||||
unsigned int irq;
|
|
||||||
int status;
|
|
||||||
int xics_status[2];
|
|
||||||
unsigned long newmask;
|
|
||||||
cpumask_t tmp = CPU_MASK_NONE;
|
|
||||||
|
|
||||||
irq = virt_irq_to_real(irq_offset_down(virq));
|
|
||||||
if (irq == XICS_IPI || irq == NO_IRQ)
|
|
||||||
return;
|
|
||||||
|
|
||||||
status = rtas_call(ibm_get_xive, 1, 3, xics_status, irq);
|
|
||||||
|
|
||||||
if (status) {
|
|
||||||
printk(KERN_ERR "xics_set_affinity: irq=%u ibm,get-xive "
|
|
||||||
"returns %d\n", irq, status);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* For the moment only implement delivery to all cpus or one cpu */
|
|
||||||
if (cpus_equal(cpumask, CPU_MASK_ALL)) {
|
|
||||||
newmask = default_distrib_server;
|
|
||||||
} else {
|
|
||||||
cpus_and(tmp, cpu_online_map, cpumask);
|
|
||||||
if (cpus_empty(tmp))
|
|
||||||
return;
|
|
||||||
newmask = get_hard_smp_processor_id(first_cpu(tmp));
|
|
||||||
}
|
|
||||||
|
|
||||||
status = rtas_call(ibm_set_xive, 3, 1, NULL,
|
|
||||||
irq, newmask, xics_status[1]);
|
|
||||||
|
|
||||||
if (status) {
|
|
||||||
printk(KERN_ERR "xics_set_affinity: irq=%u ibm,set-xive "
|
|
||||||
"returns %d\n", irq, status);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
#endif /* CONFIG_SMP */
|
||||||
|
|
||||||
void xics_teardown_cpu(int secondary)
|
void xics_teardown_cpu(int secondary)
|
||||||
{
|
{
|
||||||
|
struct irq_desc *desc = get_irq_desc(irq_offset_up(XICS_IPI));
|
||||||
int cpu = smp_processor_id();
|
int cpu = smp_processor_id();
|
||||||
|
|
||||||
ops->cppr_info(cpu, 0x00);
|
xics_set_cpu_priority(cpu, 0);
|
||||||
iosync();
|
|
||||||
|
|
||||||
/* Clear IPI */
|
|
||||||
ops->qirr_info(cpu, 0xff);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* we need to EOI the IPI if we got here from kexec down IPI
|
* we need to EOI the IPI if we got here from kexec down IPI
|
||||||
@@ -653,7 +685,8 @@ void xics_teardown_cpu(int secondary)
|
|||||||
* should we be flagging idle loop instead?
|
* should we be flagging idle loop instead?
|
||||||
* or creating some task to be scheduled?
|
* or creating some task to be scheduled?
|
||||||
*/
|
*/
|
||||||
ops->xirr_info_set(cpu, XICS_IPI);
|
if (desc->chip && desc->chip->eoi)
|
||||||
|
desc->chip->eoi(XICS_IPI);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Some machines need to have at least one cpu in the GIQ,
|
* Some machines need to have at least one cpu in the GIQ,
|
||||||
@@ -674,8 +707,7 @@ void xics_migrate_irqs_away(void)
|
|||||||
unsigned int irq, virq, cpu = smp_processor_id();
|
unsigned int irq, virq, cpu = smp_processor_id();
|
||||||
|
|
||||||
/* Reject any interrupt that was queued to us... */
|
/* Reject any interrupt that was queued to us... */
|
||||||
ops->cppr_info(cpu, 0);
|
xics_set_cpu_priority(cpu, 0);
|
||||||
iosync();
|
|
||||||
|
|
||||||
/* remove ourselves from the global interrupt queue */
|
/* remove ourselves from the global interrupt queue */
|
||||||
status = rtas_set_indicator(GLOBAL_INTERRUPT_QUEUE,
|
status = rtas_set_indicator(GLOBAL_INTERRUPT_QUEUE,
|
||||||
@@ -683,11 +715,10 @@ void xics_migrate_irqs_away(void)
|
|||||||
WARN_ON(status < 0);
|
WARN_ON(status < 0);
|
||||||
|
|
||||||
/* Allow IPIs again... */
|
/* Allow IPIs again... */
|
||||||
ops->cppr_info(cpu, DEFAULT_PRIORITY);
|
xics_set_cpu_priority(cpu, DEFAULT_PRIORITY);
|
||||||
iosync();
|
|
||||||
|
|
||||||
for_each_irq(virq) {
|
for_each_irq(virq) {
|
||||||
irq_desc_t *desc;
|
struct irq_desc *desc;
|
||||||
int xics_status[2];
|
int xics_status[2];
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
|
@@ -14,13 +14,12 @@
|
|||||||
|
|
||||||
#include <linux/cache.h>
|
#include <linux/cache.h>
|
||||||
|
|
||||||
void xics_init_IRQ(void);
|
extern void xics_init_IRQ(void);
|
||||||
int xics_get_irq(struct pt_regs *);
|
extern void xics_setup_cpu(void);
|
||||||
void xics_setup_cpu(void);
|
extern void xics_teardown_cpu(int secondary);
|
||||||
void xics_teardown_cpu(int secondary);
|
extern void xics_cause_IPI(int cpu);
|
||||||
void xics_cause_IPI(int cpu);
|
extern void xics_request_IPIs(void);
|
||||||
void xics_request_IPIs(void);
|
extern void xics_migrate_irqs_away(void);
|
||||||
void xics_migrate_irqs_away(void);
|
|
||||||
|
|
||||||
/* first argument is ignored for now*/
|
/* first argument is ignored for now*/
|
||||||
void pSeriesLP_cppr_info(int n_cpu, u8 value);
|
void pSeriesLP_cppr_info(int n_cpu, u8 value);
|
||||||
@@ -31,4 +30,8 @@ struct xics_ipi_struct {
|
|||||||
|
|
||||||
extern struct xics_ipi_struct xics_ipi_message[NR_CPUS] __cacheline_aligned;
|
extern struct xics_ipi_struct xics_ipi_message[NR_CPUS] __cacheline_aligned;
|
||||||
|
|
||||||
|
struct irq_desc;
|
||||||
|
extern void pSeries_8259_cascade(unsigned int irq, struct irq_desc *desc,
|
||||||
|
struct pt_regs *regs);
|
||||||
|
|
||||||
#endif /* _POWERPC_KERNEL_XICS_H */
|
#endif /* _POWERPC_KERNEL_XICS_H */
|
||||||
|
@@ -69,11 +69,6 @@ int i8259_irq(struct pt_regs *regs)
|
|||||||
return irq + i8259_pic_irq_offset;
|
return irq + i8259_pic_irq_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
int i8259_irq_cascade(struct pt_regs *regs, void *unused)
|
|
||||||
{
|
|
||||||
return i8259_irq(regs);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void i8259_mask_and_ack_irq(unsigned int irq_nr)
|
static void i8259_mask_and_ack_irq(unsigned int irq_nr)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
@@ -129,19 +124,11 @@ static void i8259_unmask_irq(unsigned int irq_nr)
|
|||||||
spin_unlock_irqrestore(&i8259_lock, flags);
|
spin_unlock_irqrestore(&i8259_lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void i8259_end_irq(unsigned int irq)
|
static struct irq_chip i8259_pic = {
|
||||||
{
|
.typename = " i8259 ",
|
||||||
if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))
|
.mask = i8259_mask_irq,
|
||||||
&& irq_desc[irq].action)
|
.unmask = i8259_unmask_irq,
|
||||||
i8259_unmask_irq(irq);
|
.mask_ack = i8259_mask_and_ack_irq,
|
||||||
}
|
|
||||||
|
|
||||||
struct hw_interrupt_type i8259_pic = {
|
|
||||||
.typename = " i8259 ",
|
|
||||||
.enable = i8259_unmask_irq,
|
|
||||||
.disable = i8259_mask_irq,
|
|
||||||
.ack = i8259_mask_and_ack_irq,
|
|
||||||
.end = i8259_end_irq,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct resource pic1_iores = {
|
static struct resource pic1_iores = {
|
||||||
@@ -207,8 +194,11 @@ void __init i8259_init(unsigned long intack_addr, int offset)
|
|||||||
|
|
||||||
spin_unlock_irqrestore(&i8259_lock, flags);
|
spin_unlock_irqrestore(&i8259_lock, flags);
|
||||||
|
|
||||||
for (i = 0; i < NUM_ISA_INTERRUPTS; ++i)
|
for (i = 0; i < NUM_ISA_INTERRUPTS; ++i) {
|
||||||
irq_desc[offset + i].chip = &i8259_pic;
|
set_irq_chip_and_handler(offset + i, &i8259_pic,
|
||||||
|
handle_level_irq);
|
||||||
|
irq_desc[offset + i].status |= IRQ_LEVEL;
|
||||||
|
}
|
||||||
|
|
||||||
/* reserve our resources */
|
/* reserve our resources */
|
||||||
setup_irq(offset + 2, &i8259_irqaction);
|
setup_irq(offset + 2, &i8259_irqaction);
|
||||||
|
@@ -100,8 +100,8 @@ static inline u32 _mpic_cpu_read(struct mpic *mpic, unsigned int reg)
|
|||||||
|
|
||||||
if (mpic->flags & MPIC_PRIMARY)
|
if (mpic->flags & MPIC_PRIMARY)
|
||||||
cpu = hard_smp_processor_id();
|
cpu = hard_smp_processor_id();
|
||||||
|
return _mpic_read(mpic->flags & MPIC_BIG_ENDIAN,
|
||||||
return _mpic_read(mpic->flags & MPIC_BIG_ENDIAN, mpic->cpuregs[cpu], reg);
|
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)
|
||||||
@@ -378,14 +378,14 @@ static inline u32 mpic_physmask(u32 cpumask)
|
|||||||
/* Get the mpic structure from the IPI number */
|
/* Get the mpic structure from the IPI number */
|
||||||
static inline struct mpic * mpic_from_ipi(unsigned int ipi)
|
static inline struct mpic * mpic_from_ipi(unsigned int ipi)
|
||||||
{
|
{
|
||||||
return container_of(irq_desc[ipi].chip, struct mpic, hc_ipi);
|
return irq_desc[ipi].chip_data;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Get the mpic structure from the irq number */
|
/* Get the mpic structure from the irq number */
|
||||||
static inline struct mpic * mpic_from_irq(unsigned int irq)
|
static inline struct mpic * mpic_from_irq(unsigned int irq)
|
||||||
{
|
{
|
||||||
return container_of(irq_desc[irq].chip, struct mpic, hc_irq);
|
return irq_desc[irq].chip_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Send an EOI */
|
/* Send an EOI */
|
||||||
@@ -410,7 +410,7 @@ static irqreturn_t mpic_ipi_action(int irq, void *dev_id, struct pt_regs *regs)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
static void mpic_enable_irq(unsigned int irq)
|
static void mpic_unmask_irq(unsigned int irq)
|
||||||
{
|
{
|
||||||
unsigned int loops = 100000;
|
unsigned int loops = 100000;
|
||||||
struct mpic *mpic = mpic_from_irq(irq);
|
struct mpic *mpic = mpic_from_irq(irq);
|
||||||
@@ -429,35 +429,9 @@ static void mpic_enable_irq(unsigned int irq)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} while(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK);
|
} while(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK);
|
||||||
|
|
||||||
#ifdef CONFIG_MPIC_BROKEN_U3
|
|
||||||
if (mpic->flags & MPIC_BROKEN_U3) {
|
|
||||||
unsigned int src = irq - mpic->irq_offset;
|
|
||||||
if (mpic_is_ht_interrupt(mpic, src) &&
|
|
||||||
(irq_desc[irq].status & IRQ_LEVEL))
|
|
||||||
mpic_ht_end_irq(mpic, src);
|
|
||||||
}
|
|
||||||
#endif /* CONFIG_MPIC_BROKEN_U3 */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int mpic_startup_irq(unsigned int irq)
|
static void mpic_mask_irq(unsigned int irq)
|
||||||
{
|
|
||||||
#ifdef CONFIG_MPIC_BROKEN_U3
|
|
||||||
struct mpic *mpic = mpic_from_irq(irq);
|
|
||||||
unsigned int src = irq - mpic->irq_offset;
|
|
||||||
#endif /* CONFIG_MPIC_BROKEN_U3 */
|
|
||||||
|
|
||||||
mpic_enable_irq(irq);
|
|
||||||
|
|
||||||
#ifdef CONFIG_MPIC_BROKEN_U3
|
|
||||||
if (mpic_is_ht_interrupt(mpic, src))
|
|
||||||
mpic_startup_ht_interrupt(mpic, src, irq_desc[irq].status);
|
|
||||||
#endif /* CONFIG_MPIC_BROKEN_U3 */
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void mpic_disable_irq(unsigned int irq)
|
|
||||||
{
|
{
|
||||||
unsigned int loops = 100000;
|
unsigned int loops = 100000;
|
||||||
struct mpic *mpic = mpic_from_irq(irq);
|
struct mpic *mpic = mpic_from_irq(irq);
|
||||||
@@ -478,20 +452,6 @@ static void mpic_disable_irq(unsigned int irq)
|
|||||||
} while(!(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK));
|
} while(!(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mpic_shutdown_irq(unsigned int irq)
|
|
||||||
{
|
|
||||||
#ifdef CONFIG_MPIC_BROKEN_U3
|
|
||||||
struct mpic *mpic = mpic_from_irq(irq);
|
|
||||||
unsigned int src = irq - mpic->irq_offset;
|
|
||||||
|
|
||||||
if (mpic_is_ht_interrupt(mpic, src))
|
|
||||||
mpic_shutdown_ht_interrupt(mpic, src, irq_desc[irq].status);
|
|
||||||
|
|
||||||
#endif /* CONFIG_MPIC_BROKEN_U3 */
|
|
||||||
|
|
||||||
mpic_disable_irq(irq);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void mpic_end_irq(unsigned int irq)
|
static void mpic_end_irq(unsigned int irq)
|
||||||
{
|
{
|
||||||
struct mpic *mpic = mpic_from_irq(irq);
|
struct mpic *mpic = mpic_from_irq(irq);
|
||||||
@@ -504,21 +464,65 @@ static void mpic_end_irq(unsigned int irq)
|
|||||||
* latched another edge interrupt coming in anyway
|
* latched another edge interrupt coming in anyway
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef CONFIG_MPIC_BROKEN_U3
|
|
||||||
if (mpic->flags & MPIC_BROKEN_U3) {
|
|
||||||
unsigned int src = irq - mpic->irq_offset;
|
|
||||||
if (mpic_is_ht_interrupt(mpic, src) &&
|
|
||||||
(irq_desc[irq].status & IRQ_LEVEL))
|
|
||||||
mpic_ht_end_irq(mpic, src);
|
|
||||||
}
|
|
||||||
#endif /* CONFIG_MPIC_BROKEN_U3 */
|
|
||||||
|
|
||||||
mpic_eoi(mpic);
|
mpic_eoi(mpic);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_MPIC_BROKEN_U3
|
||||||
|
|
||||||
|
static void mpic_unmask_ht_irq(unsigned int irq)
|
||||||
|
{
|
||||||
|
struct mpic *mpic = mpic_from_irq(irq);
|
||||||
|
unsigned int src = irq - mpic->irq_offset;
|
||||||
|
|
||||||
|
mpic_unmask_irq(irq);
|
||||||
|
|
||||||
|
if (irq_desc[irq].status & IRQ_LEVEL)
|
||||||
|
mpic_ht_end_irq(mpic, src);
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int mpic_startup_ht_irq(unsigned int irq)
|
||||||
|
{
|
||||||
|
struct mpic *mpic = mpic_from_irq(irq);
|
||||||
|
unsigned int src = irq - mpic->irq_offset;
|
||||||
|
|
||||||
|
mpic_unmask_irq(irq);
|
||||||
|
mpic_startup_ht_interrupt(mpic, src, irq_desc[irq].status);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mpic_shutdown_ht_irq(unsigned int irq)
|
||||||
|
{
|
||||||
|
struct mpic *mpic = mpic_from_irq(irq);
|
||||||
|
unsigned int src = irq - mpic->irq_offset;
|
||||||
|
|
||||||
|
mpic_shutdown_ht_interrupt(mpic, src, irq_desc[irq].status);
|
||||||
|
mpic_mask_irq(irq);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mpic_end_ht_irq(unsigned int irq)
|
||||||
|
{
|
||||||
|
struct mpic *mpic = mpic_from_irq(irq);
|
||||||
|
unsigned int src = irq - mpic->irq_offset;
|
||||||
|
|
||||||
|
#ifdef DEBUG_IRQ
|
||||||
|
DBG("%s: end_irq: %d\n", mpic->name, irq);
|
||||||
|
#endif
|
||||||
|
/* We always EOI on end_irq() even for edge interrupts since that
|
||||||
|
* should only lower the priority, the MPIC should have properly
|
||||||
|
* latched another edge interrupt coming in anyway
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (irq_desc[irq].status & IRQ_LEVEL)
|
||||||
|
mpic_ht_end_irq(mpic, src);
|
||||||
|
mpic_eoi(mpic);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_MPIC_BROKEN_U3 */
|
||||||
|
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
|
|
||||||
static void mpic_enable_ipi(unsigned int irq)
|
static void mpic_unmask_ipi(unsigned int irq)
|
||||||
{
|
{
|
||||||
struct mpic *mpic = mpic_from_ipi(irq);
|
struct mpic *mpic = mpic_from_ipi(irq);
|
||||||
unsigned int src = irq - mpic->ipi_offset;
|
unsigned int src = irq - mpic->ipi_offset;
|
||||||
@@ -527,7 +531,7 @@ static void mpic_enable_ipi(unsigned int irq)
|
|||||||
mpic_ipi_write(src, mpic_ipi_read(src) & ~MPIC_VECPRI_MASK);
|
mpic_ipi_write(src, mpic_ipi_read(src) & ~MPIC_VECPRI_MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mpic_disable_ipi(unsigned int irq)
|
static void mpic_mask_ipi(unsigned int irq)
|
||||||
{
|
{
|
||||||
/* NEVER disable an IPI... that's just plain wrong! */
|
/* NEVER disable an IPI... that's just plain wrong! */
|
||||||
}
|
}
|
||||||
@@ -560,6 +564,30 @@ static void mpic_set_affinity(unsigned int irq, cpumask_t cpumask)
|
|||||||
mpic_physmask(cpus_addr(tmp)[0]));
|
mpic_physmask(cpus_addr(tmp)[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct irq_chip mpic_irq_chip = {
|
||||||
|
.mask = mpic_mask_irq,
|
||||||
|
.unmask = mpic_unmask_irq,
|
||||||
|
.eoi = mpic_end_irq,
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_SMP
|
||||||
|
static struct irq_chip mpic_ipi_chip = {
|
||||||
|
.mask = mpic_mask_ipi,
|
||||||
|
.unmask = mpic_unmask_ipi,
|
||||||
|
.eoi = mpic_end_ipi,
|
||||||
|
};
|
||||||
|
#endif /* CONFIG_SMP */
|
||||||
|
|
||||||
|
#ifdef CONFIG_MPIC_BROKEN_U3
|
||||||
|
static struct irq_chip mpic_irq_ht_chip = {
|
||||||
|
.startup = mpic_startup_ht_irq,
|
||||||
|
.shutdown = mpic_shutdown_ht_irq,
|
||||||
|
.mask = mpic_mask_irq,
|
||||||
|
.unmask = mpic_unmask_ht_irq,
|
||||||
|
.eoi = mpic_end_ht_irq,
|
||||||
|
};
|
||||||
|
#endif /* CONFIG_MPIC_BROKEN_U3 */
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Exported functions
|
* Exported functions
|
||||||
@@ -589,19 +617,19 @@ struct mpic * __init mpic_alloc(unsigned long phys_addr,
|
|||||||
memset(mpic, 0, sizeof(struct mpic));
|
memset(mpic, 0, sizeof(struct mpic));
|
||||||
mpic->name = name;
|
mpic->name = name;
|
||||||
|
|
||||||
|
mpic->hc_irq = mpic_irq_chip;
|
||||||
mpic->hc_irq.typename = name;
|
mpic->hc_irq.typename = name;
|
||||||
mpic->hc_irq.startup = mpic_startup_irq;
|
|
||||||
mpic->hc_irq.shutdown = mpic_shutdown_irq;
|
|
||||||
mpic->hc_irq.enable = mpic_enable_irq;
|
|
||||||
mpic->hc_irq.disable = mpic_disable_irq;
|
|
||||||
mpic->hc_irq.end = mpic_end_irq;
|
|
||||||
if (flags & MPIC_PRIMARY)
|
if (flags & MPIC_PRIMARY)
|
||||||
mpic->hc_irq.set_affinity = mpic_set_affinity;
|
mpic->hc_irq.set_affinity = mpic_set_affinity;
|
||||||
|
#ifdef CONFIG_MPIC_BROKEN_U3
|
||||||
|
mpic->hc_ht_irq = mpic_irq_ht_chip;
|
||||||
|
mpic->hc_ht_irq.typename = name;
|
||||||
|
if (flags & MPIC_PRIMARY)
|
||||||
|
mpic->hc_ht_irq.set_affinity = mpic_set_affinity;
|
||||||
|
#endif /* CONFIG_MPIC_BROKEN_U3 */
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
mpic->hc_ipi.typename = name;
|
mpic->hc_ipi.typename = name;
|
||||||
mpic->hc_ipi.enable = mpic_enable_ipi;
|
mpic->hc_ipi = mpic_ipi_chip;
|
||||||
mpic->hc_ipi.disable = mpic_disable_ipi;
|
|
||||||
mpic->hc_ipi.end = mpic_end_ipi;
|
|
||||||
#endif /* CONFIG_SMP */
|
#endif /* CONFIG_SMP */
|
||||||
|
|
||||||
mpic->flags = flags;
|
mpic->flags = flags;
|
||||||
@@ -697,28 +725,6 @@ void __init mpic_assign_isu(struct mpic *mpic, unsigned int isu_num,
|
|||||||
mpic->num_sources = isu_first + mpic->isu_size;
|
mpic->num_sources = isu_first + mpic->isu_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void __init mpic_setup_cascade(unsigned int irq, mpic_cascade_t handler,
|
|
||||||
void *data)
|
|
||||||
{
|
|
||||||
struct mpic *mpic = mpic_find(irq, NULL);
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
/* Synchronization here is a bit dodgy, so don't try to replace cascade
|
|
||||||
* interrupts on the fly too often ... but normally it's set up at boot.
|
|
||||||
*/
|
|
||||||
spin_lock_irqsave(&mpic_lock, flags);
|
|
||||||
if (mpic->cascade)
|
|
||||||
mpic_disable_irq(mpic->cascade_vec + mpic->irq_offset);
|
|
||||||
mpic->cascade = NULL;
|
|
||||||
wmb();
|
|
||||||
mpic->cascade_vec = irq - mpic->irq_offset;
|
|
||||||
mpic->cascade_data = data;
|
|
||||||
wmb();
|
|
||||||
mpic->cascade = handler;
|
|
||||||
mpic_enable_irq(irq);
|
|
||||||
spin_unlock_irqrestore(&mpic_lock, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
void __init mpic_init(struct mpic *mpic)
|
void __init mpic_init(struct mpic *mpic)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@@ -750,8 +756,10 @@ void __init mpic_init(struct mpic *mpic)
|
|||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
if (!(mpic->flags & MPIC_PRIMARY))
|
if (!(mpic->flags & MPIC_PRIMARY))
|
||||||
continue;
|
continue;
|
||||||
irq_desc[mpic->ipi_offset+i].status |= IRQ_PER_CPU;
|
set_irq_chip_data(mpic->ipi_offset+i, mpic);
|
||||||
irq_desc[mpic->ipi_offset+i].chip = &mpic->hc_ipi;
|
set_irq_chip_and_handler(mpic->ipi_offset+i,
|
||||||
|
&mpic->hc_ipi,
|
||||||
|
handle_percpu_irq);
|
||||||
#endif /* CONFIG_SMP */
|
#endif /* CONFIG_SMP */
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -763,7 +771,7 @@ void __init mpic_init(struct mpic *mpic)
|
|||||||
/* Do the HT PIC fixups on U3 broken mpic */
|
/* Do the HT PIC fixups on U3 broken mpic */
|
||||||
DBG("MPIC flags: %x\n", mpic->flags);
|
DBG("MPIC flags: %x\n", mpic->flags);
|
||||||
if ((mpic->flags & MPIC_BROKEN_U3) && (mpic->flags & MPIC_PRIMARY))
|
if ((mpic->flags & MPIC_BROKEN_U3) && (mpic->flags & MPIC_PRIMARY))
|
||||||
mpic_scan_ht_pics(mpic);
|
mpic_scan_ht_pics(mpic);
|
||||||
#endif /* CONFIG_MPIC_BROKEN_U3 */
|
#endif /* CONFIG_MPIC_BROKEN_U3 */
|
||||||
|
|
||||||
for (i = 0; i < mpic->num_sources; i++) {
|
for (i = 0; i < mpic->num_sources; i++) {
|
||||||
@@ -811,8 +819,17 @@ void __init mpic_init(struct mpic *mpic)
|
|||||||
|
|
||||||
/* init linux descriptors */
|
/* init linux descriptors */
|
||||||
if (i < mpic->irq_count) {
|
if (i < mpic->irq_count) {
|
||||||
irq_desc[mpic->irq_offset+i].status = level ? IRQ_LEVEL : 0;
|
struct irq_chip *chip = &mpic->hc_irq;
|
||||||
irq_desc[mpic->irq_offset+i].chip = &mpic->hc_irq;
|
|
||||||
|
irq_desc[mpic->irq_offset+i].status |=
|
||||||
|
level ? IRQ_LEVEL : 0;
|
||||||
|
#ifdef CONFIG_MPIC_BROKEN_U3
|
||||||
|
if (mpic_is_ht_interrupt(mpic, i))
|
||||||
|
chip = &mpic->hc_ht_irq;
|
||||||
|
#endif /* CONFIG_MPIC_BROKEN_U3 */
|
||||||
|
set_irq_chip_data(mpic->irq_offset+i, mpic);
|
||||||
|
set_irq_chip_and_handler(mpic->irq_offset+i, chip,
|
||||||
|
handle_fasteoi_irq);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -986,14 +1003,6 @@ int mpic_get_one_irq(struct mpic *mpic, struct pt_regs *regs)
|
|||||||
#ifdef DEBUG_LOW
|
#ifdef DEBUG_LOW
|
||||||
DBG("%s: get_one_irq(): %d\n", mpic->name, irq);
|
DBG("%s: get_one_irq(): %d\n", mpic->name, irq);
|
||||||
#endif
|
#endif
|
||||||
if (mpic->cascade && irq == mpic->cascade_vec) {
|
|
||||||
#ifdef DEBUG_LOW
|
|
||||||
DBG("%s: cascading ...\n", mpic->name);
|
|
||||||
#endif
|
|
||||||
irq = mpic->cascade(regs, mpic->cascade_data);
|
|
||||||
mpic_eoi(mpic);
|
|
||||||
return irq;
|
|
||||||
}
|
|
||||||
if (unlikely(irq == MPIC_VEC_SPURRIOUS))
|
if (unlikely(irq == MPIC_VEC_SPURRIOUS))
|
||||||
return -1;
|
return -1;
|
||||||
if (irq < MPIC_VEC_IPI_0) {
|
if (irq < MPIC_VEC_IPI_0) {
|
||||||
|
@@ -4,11 +4,8 @@
|
|||||||
|
|
||||||
#include <linux/irq.h>
|
#include <linux/irq.h>
|
||||||
|
|
||||||
extern struct hw_interrupt_type i8259_pic;
|
|
||||||
|
|
||||||
extern void i8259_init(unsigned long intack_addr, int offset);
|
extern void i8259_init(unsigned long intack_addr, int offset);
|
||||||
extern int i8259_irq(struct pt_regs *regs);
|
extern int i8259_irq(struct pt_regs *regs);
|
||||||
extern int i8259_irq_cascade(struct pt_regs *regs, void *unused);
|
|
||||||
|
|
||||||
#endif /* __KERNEL__ */
|
#endif /* __KERNEL__ */
|
||||||
#endif /* _ASM_POWERPC_I8259_H */
|
#endif /* _ASM_POWERPC_I8259_H */
|
||||||
|
@@ -514,9 +514,12 @@ extern u64 ppc64_interrupt_controller;
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef CONFIG_PPC_MERGE
|
||||||
#define NR_MASK_WORDS ((NR_IRQS + 31) / 32)
|
#define NR_MASK_WORDS ((NR_IRQS + 31) / 32)
|
||||||
/* pedantic: these are long because they are used with set_bit --RR */
|
/* pedantic: these are long because they are used with set_bit --RR */
|
||||||
extern unsigned long ppc_cached_irq_mask[NR_MASK_WORDS];
|
extern unsigned long ppc_cached_irq_mask[NR_MASK_WORDS];
|
||||||
|
#endif
|
||||||
|
|
||||||
extern atomic_t ppc_n_lost_interrupts;
|
extern atomic_t ppc_n_lost_interrupts;
|
||||||
|
|
||||||
#define virt_irq_create_mapping(x) (x)
|
#define virt_irq_create_mapping(x) (x)
|
||||||
@@ -579,9 +582,8 @@ extern struct thread_info *softirq_ctx[NR_CPUS];
|
|||||||
|
|
||||||
extern void irq_ctx_init(void);
|
extern void irq_ctx_init(void);
|
||||||
extern void call_do_softirq(struct thread_info *tp);
|
extern void call_do_softirq(struct thread_info *tp);
|
||||||
extern int call___do_IRQ(int irq, struct pt_regs *regs,
|
extern int call_handle_irq(int irq, void *p1, void *p2,
|
||||||
struct thread_info *tp);
|
struct thread_info *tp, void *func);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#define irq_ctx_init()
|
#define irq_ctx_init()
|
||||||
|
|
||||||
|
@@ -114,9 +114,6 @@
|
|||||||
#define MPIC_VEC_TIMER_1 248
|
#define MPIC_VEC_TIMER_1 248
|
||||||
#define MPIC_VEC_TIMER_0 247
|
#define MPIC_VEC_TIMER_0 247
|
||||||
|
|
||||||
/* Type definition of the cascade handler */
|
|
||||||
typedef int (*mpic_cascade_t)(struct pt_regs *regs, void *data);
|
|
||||||
|
|
||||||
#ifdef CONFIG_MPIC_BROKEN_U3
|
#ifdef CONFIG_MPIC_BROKEN_U3
|
||||||
/* Fixup table entry */
|
/* Fixup table entry */
|
||||||
struct mpic_irq_fixup
|
struct mpic_irq_fixup
|
||||||
@@ -133,9 +130,12 @@ struct mpic_irq_fixup
|
|||||||
struct mpic
|
struct mpic
|
||||||
{
|
{
|
||||||
/* The "linux" controller struct */
|
/* The "linux" controller struct */
|
||||||
hw_irq_controller hc_irq;
|
struct irq_chip hc_irq;
|
||||||
|
#ifdef CONFIG_MPIC_BROKEN_U3
|
||||||
|
struct irq_chip hc_ht_irq;
|
||||||
|
#endif
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
hw_irq_controller hc_ipi;
|
struct irq_chip hc_ipi;
|
||||||
#endif
|
#endif
|
||||||
const char *name;
|
const char *name;
|
||||||
/* Flags */
|
/* Flags */
|
||||||
@@ -153,10 +153,6 @@ struct mpic
|
|||||||
unsigned int num_sources;
|
unsigned int num_sources;
|
||||||
/* Number of CPUs */
|
/* Number of CPUs */
|
||||||
unsigned int num_cpus;
|
unsigned int num_cpus;
|
||||||
/* cascade handler */
|
|
||||||
mpic_cascade_t cascade;
|
|
||||||
void *cascade_data;
|
|
||||||
unsigned int cascade_vec;
|
|
||||||
/* senses array */
|
/* senses array */
|
||||||
unsigned char *senses;
|
unsigned char *senses;
|
||||||
unsigned int senses_count;
|
unsigned int senses_count;
|
||||||
@@ -237,17 +233,6 @@ extern void mpic_assign_isu(struct mpic *mpic, unsigned int isu_num,
|
|||||||
*/
|
*/
|
||||||
extern void mpic_init(struct mpic *mpic);
|
extern void mpic_init(struct mpic *mpic);
|
||||||
|
|
||||||
/* Setup a cascade. Currently, only one cascade is supported this
|
|
||||||
* way, though you can always do a normal request_irq() and add
|
|
||||||
* other cascades this way. You should call this _after_ having
|
|
||||||
* added all the ISUs
|
|
||||||
*
|
|
||||||
* @irq_no: "linux" irq number of the cascade (that is offset'ed vector)
|
|
||||||
* @handler: cascade handler function
|
|
||||||
*/
|
|
||||||
extern void mpic_setup_cascade(unsigned int irq_no, mpic_cascade_t hanlder,
|
|
||||||
void *data);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* All of the following functions must only be used after the
|
* All of the following functions must only be used after the
|
||||||
* ISUs have been assigned and the controller fully initialized
|
* ISUs have been assigned and the controller fully initialized
|
||||||
|
Reference in New Issue
Block a user