[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:

zatwierdzone przez
Paul Mackerras

rodzic
5a43a066b1
commit
b9e5b4e6a9
@@ -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;
|
||||
|
Reference in New Issue
Block a user