summaryrefslogtreecommitdiffstats
path: root/arch/m68k/mac/oss.c
diff options
context:
space:
mode:
authorGeert Uytterhoeven <geert@linux-m68k.org>2011-08-10 12:48:29 +0200
committerGeert Uytterhoeven <geert@linux-m68k.org>2011-11-08 22:35:50 +0100
commit9145db564eae98134de8eb8d64b47d7177eccfdd (patch)
tree7d0e25514abba33b6082f5a13963442cf390a058 /arch/m68k/mac/oss.c
parentm68k/mac: Convert Mac to genirq (diff)
downloadlinux-9145db564eae98134de8eb8d64b47d7177eccfdd.tar.xz
linux-9145db564eae98134de8eb8d64b47d7177eccfdd.zip
m68k/mac: Optimize interrupts using chain handlers
Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
Diffstat (limited to 'arch/m68k/mac/oss.c')
-rw-r--r--arch/m68k/mac/oss.c106
1 files changed, 86 insertions, 20 deletions
diff --git a/arch/m68k/mac/oss.c b/arch/m68k/mac/oss.c
index ed952704e6ee..cc784c2ff6e8 100644
--- a/arch/m68k/mac/oss.c
+++ b/arch/m68k/mac/oss.c
@@ -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
@@ -63,23 +64,6 @@ void __init oss_init(void)
}
/*
- * 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