m68k/mac: Optimize interrupts using chain handlers

Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
This commit is contained in:
Geert Uytterhoeven
2011-08-10 12:48:29 +02:00
parent ddc7fd25d0
commit 9145db564e
4 changed files with 300 additions and 65 deletions

View File

@@ -32,10 +32,11 @@
int oss_present;
volatile struct mac_oss *oss;
static irqreturn_t oss_irq(int, void *);
static irqreturn_t oss_nubus_irq(int, void *);
#ifdef CONFIG_GENERIC_HARDIRQS
extern void via1_irq(unsigned int irq, struct irq_desc *desc);
#else
extern irqreturn_t via1_irq(int, void *);
#endif
/*
* Initialize the OSS
@@ -62,23 +63,6 @@ void __init oss_init(void)
oss->irq_level[OSS_VIA1] = OSS_IRQLEV_VIA1;
}
/*
* Register the OSS and NuBus interrupt dispatchers.
*/
void __init oss_register_interrupts(void)
{
if (request_irq(OSS_IRQLEV_SCSI, oss_irq, 0, "scsi", (void *)oss))
pr_err("Couldn't register %s interrupt\n", "scsi");
if (request_irq(OSS_IRQLEV_NUBUS, oss_nubus_irq, 0, "nubus",
(void *)oss))
pr_err("Couldn't register %s interrupt\n", "nubus");
if (request_irq(OSS_IRQLEV_SOUND, oss_irq, 0, "sound", (void *)oss))
pr_err("Couldn't register %s interrupt\n", "sound");
if (request_irq(OSS_IRQLEV_VIA1, via1_irq, 0, "via1", (void *)via1))
pr_err("Couldn't register %s interrupt\n", "via1");
}
/*
* Initialize OSS for Nubus access
*/
@@ -92,6 +76,34 @@ void __init oss_nubus_init(void)
* and SCSI; everything else is routed to its own autovector IRQ.
*/
#ifdef CONFIG_GENERIC_HARDIRQS
static void oss_irq(unsigned int irq, struct irq_desc *desc)
{
int events;
events = oss->irq_pending & (OSS_IP_SOUND|OSS_IP_SCSI);
if (!events)
return;
#ifdef DEBUG_IRQS
if ((console_loglevel == 10) && !(events & OSS_IP_SCSI)) {
printk("oss_irq: irq %u events = 0x%04X\n", irq,
(int) oss->irq_pending);
}
#endif
/* FIXME: how do you clear a pending IRQ? */
if (events & OSS_IP_SOUND) {
oss->irq_pending &= ~OSS_IP_SOUND;
/* FIXME: call sound handler */
} else if (events & OSS_IP_SCSI) {
oss->irq_pending &= ~OSS_IP_SCSI;
generic_handle_irq(IRQ_MAC_SCSI);
} else {
/* FIXME: error check here? */
}
}
#else
static irqreturn_t oss_irq(int irq, void *dev_id)
{
int events;
@@ -119,6 +131,7 @@ static irqreturn_t oss_irq(int irq, void *dev_id)
}
return IRQ_HANDLED;
}
#endif
/*
* Nubus IRQ handler, OSS style
@@ -126,6 +139,34 @@ static irqreturn_t oss_irq(int irq, void *dev_id)
* Unlike the VIA/RBV this is on its own autovector interrupt level.
*/
#ifdef CONFIG_GENERIC_HARDIRQS
static void oss_nubus_irq(unsigned int irq, struct irq_desc *desc)
{
int events, irq_bit, i;
events = oss->irq_pending & OSS_IP_NUBUS;
if (!events)
return;
#ifdef DEBUG_NUBUS_INT
if (console_loglevel > 7) {
printk("oss_nubus_irq: events = 0x%04X\n", events);
}
#endif
/* There are only six slots on the OSS, not seven */
i = 6;
irq_bit = 0x40;
do {
--i;
irq_bit >>= 1;
if (events & irq_bit) {
oss->irq_pending &= ~irq_bit;
generic_handle_irq(NUBUS_SOURCE_BASE + i);
}
} while(events & (irq_bit - 1));
}
#else
static irqreturn_t oss_nubus_irq(int irq, void *dev_id)
{
int events, irq_bit, i;
@@ -153,6 +194,31 @@ static irqreturn_t oss_nubus_irq(int irq, void *dev_id)
} while(events & (irq_bit - 1));
return IRQ_HANDLED;
}
#endif
/*
* Register the OSS and NuBus interrupt dispatchers.
*/
void __init oss_register_interrupts(void)
{
#ifdef CONFIG_GENERIC_HARDIRQS
irq_set_chained_handler(OSS_IRQLEV_SCSI, oss_irq);
irq_set_chained_handler(OSS_IRQLEV_NUBUS, oss_nubus_irq);
irq_set_chained_handler(OSS_IRQLEV_SOUND, oss_irq);
irq_set_chained_handler(OSS_IRQLEV_VIA1, via1_irq);
#else /* !CONFIG_GENERIC_HARDIRQS */
if (request_irq(OSS_IRQLEV_SCSI, oss_irq, 0, "scsi", (void *)oss))
pr_err("Couldn't register %s interrupt\n", "scsi");
if (request_irq(OSS_IRQLEV_NUBUS, oss_nubus_irq, 0, "nubus",
(void *)oss))
pr_err("Couldn't register %s interrupt\n", "nubus");
if (request_irq(OSS_IRQLEV_SOUND, oss_irq, 0, "sound", (void *)oss))
pr_err("Couldn't register %s interrupt\n", "sound");
if (request_irq(OSS_IRQLEV_VIA1, via1_irq, 0, "via1", (void *)via1))
pr_err("Couldn't register %s interrupt\n", "via1");
#endif /* !CONFIG_GENERIC_HARDIRQS */
}
/*
* Enable an OSS interrupt