[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:
Benjamin Herrenschmidt
2006-07-03 19:32:51 +10:00
zatwierdzone przez Paul Mackerras
rodzic 5a43a066b1
commit b9e5b4e6a9
17 zmienionych plików z 692 dodań i 635 usunięć

Wyświetl plik

@@ -70,18 +70,19 @@ static struct interrupt_info gatwick_int_pool[GATWICK_IRQ_POOL_SIZE];
#define NR_MASK_WORDS ((NR_IRQS + 31) / 32)
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;
/*
* 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)
static void __pmac_retrigger(unsigned int irq_nr)
{
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);
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)
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);
__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]->ack, bit);
do {
@@ -109,7 +110,7 @@ static void pmac_mask_and_ack_irq(unsigned int irq_nr)
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);
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)
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 */
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.
*/
if (bit & ppc_cached_irq_mask[i] & in_le32(&pmac_irq_hw[i]->level))
__set_lost((ulong)irq_nr, nokicklost);
spin_unlock_irqrestore(&pmac_pic_lock, flags);
__pmac_retrigger(irq_nr);
}
/* 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)
{
unsigned long flags;
unsigned long bit = 1UL << (irq_nr & 0x1f);
int i = irq_nr >> 5;
spin_lock_irqsave(&pmac_pic_lock, flags);
if ((irq_desc[irq_nr].status & IRQ_LEVEL) == 0)
out_le32(&pmac_irq_hw[i]->ack, bit);
set_bit(irq_nr, ppc_cached_irq_mask);
pmac_set_irq_mask(irq_nr, 0);
__set_bit(irq_nr, ppc_cached_irq_mask);
__pmac_set_irq_mask(irq_nr, 0);
spin_unlock_irqrestore(&pmac_pic_lock, flags);
return 0;
}
static void pmac_mask_irq(unsigned int irq_nr)
{
clear_bit(irq_nr, ppc_cached_irq_mask);
pmac_set_irq_mask(irq_nr, 0);
mb();
unsigned long flags;
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)
{
set_bit(irq_nr, ppc_cached_irq_mask);
pmac_set_irq_mask(irq_nr, 0);
unsigned long flags;
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))
&& irq_desc[irq_nr].action) {
set_bit(irq_nr, ppc_cached_irq_mask);
pmac_set_irq_mask(irq_nr, 1);
}
unsigned long flags;
spin_lock_irqsave(&pmac_pic_lock, flags);
__pmac_retrigger(irq_nr);
spin_unlock_irqrestore(&pmac_pic_lock, flags);
return 1;
}
struct hw_interrupt_type pmac_pic = {
static struct irq_chip pmac_pic = {
.typename = " PMAC-PIC ",
.startup = pmac_startup_irq,
.enable = pmac_unmask_irq,
.disable = pmac_mask_irq,
.ack = pmac_mask_and_ack_irq,
.end = pmac_end_irq,
};
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,
.mask = pmac_mask_irq,
.ack = pmac_ack_irq,
.mask_ack = pmac_mask_and_ack_irq,
.unmask = pmac_unmask_irq,
.retrigger = pmac_retrigger,
};
static irqreturn_t gatwick_action(int cpl, void *dev_id, struct pt_regs *regs)
{
unsigned long flags;
int irq, bits;
int rc = IRQ_NONE;
spin_lock_irqsave(&pmac_pic_lock, flags);
for (irq = max_irqs; (irq -= 32) >= max_real_irqs; ) {
int i = irq >> 5;
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)
continue;
irq += __ilog2(bits);
spin_unlock_irqrestore(&pmac_pic_lock, flags);
__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");
return IRQ_NONE;
spin_unlock_irqrestore(&pmac_pic_lock, flags);
return rc;
}
static int pmac_get_irq(struct pt_regs *regs)
{
int irq;
unsigned long bits = 0;
unsigned long flags;
#ifdef CONFIG_SMP
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 */
}
#endif /* CONFIG_SMP */
spin_lock_irqsave(&pmac_pic_lock, flags);
for (irq = max_real_irqs; (irq -= 32) >= 0; ) {
int i = irq >> 5;
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);
break;
}
spin_unlock_irqrestore(&pmac_pic_lock, flags);
return irq;
}
@@ -389,7 +414,6 @@ static struct irqaction gatwick_cascade_action = {
static void __init pmac_pic_probe_oldstyle(void)
{
int i;
int irq_cascade = -1;
struct device_node *master = NULL;
struct device_node *slave = NULL;
u8 __iomem *addr;
@@ -443,9 +467,16 @@ static void __init pmac_pic_probe_oldstyle(void)
}
BUG_ON(master == NULL);
/* Set the handler for the main PIC */
for ( i = 0; i < max_real_irqs ; i++ )
irq_desc[i].chip = &pmac_pic;
/* Mark level interrupts and set handlers */
for (i = 0; i < max_irqs; i++) {
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 */
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++] =
(volatile struct pmac_irq_hw __iomem *)
(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"
" 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);
/* disable all interrupts in all controllers */
/* Disable all interrupts in all controllers */
for (i = 0; i * 32 < max_irqs; ++i)
out_le32(&pmac_irq_hw[i]->enable, 0);
/* mark level interrupts */
for (i = 0; i < max_irqs; i++)
if (level_mask[i >> 5] & (1UL << (i & 0x1f)))
irq_desc[i].status = IRQ_LEVEL;
/* Hookup cascade irq */
if (slave)
setup_irq(pmac_irq_cascade, &gatwick_cascade_action);
/* 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);
#ifdef CONFIG_XMON
setup_irq(20, &xmon_action);
@@ -502,9 +526,20 @@ static void __init pmac_pic_probe_oldstyle(void)
}
#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)
@@ -612,7 +647,8 @@ static int __init pmac_pic_probe_mpic(void)
of_node_put(slave);
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);
return 0;