m68k/amiga: Optimize interrupts using chain handlers

Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
diff --git a/arch/m68k/amiga/amiints.c b/arch/m68k/amiga/amiints.c
index c3da534..a8da471 100644
--- a/arch/m68k/amiga/amiints.c
+++ b/arch/m68k/amiga/amiints.c
@@ -48,6 +48,99 @@
  * The builtin Amiga hardware interrupt handlers.
  */
 
+#ifdef CONFIG_GENERIC_HARDIRQS
+static void ami_int1(unsigned int irq, struct irq_desc *desc)
+{
+	unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;
+
+	/* if serial transmit buffer empty, interrupt */
+	if (ints & IF_TBE) {
+		amiga_custom.intreq = IF_TBE;
+		generic_handle_irq(IRQ_AMIGA_TBE);
+	}
+
+	/* if floppy disk transfer complete, interrupt */
+	if (ints & IF_DSKBLK) {
+		amiga_custom.intreq = IF_DSKBLK;
+		generic_handle_irq(IRQ_AMIGA_DSKBLK);
+	}
+
+	/* if software interrupt set, interrupt */
+	if (ints & IF_SOFT) {
+		amiga_custom.intreq = IF_SOFT;
+		generic_handle_irq(IRQ_AMIGA_SOFT);
+	}
+}
+
+static void ami_int3(unsigned int irq, struct irq_desc *desc)
+{
+	unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;
+
+	/* if a blitter interrupt */
+	if (ints & IF_BLIT) {
+		amiga_custom.intreq = IF_BLIT;
+		generic_handle_irq(IRQ_AMIGA_BLIT);
+	}
+
+	/* if a copper interrupt */
+	if (ints & IF_COPER) {
+		amiga_custom.intreq = IF_COPER;
+		generic_handle_irq(IRQ_AMIGA_COPPER);
+	}
+
+	/* if a vertical blank interrupt */
+	if (ints & IF_VERTB) {
+		amiga_custom.intreq = IF_VERTB;
+		generic_handle_irq(IRQ_AMIGA_VERTB);
+	}
+}
+
+static void ami_int4(unsigned int irq, struct irq_desc *desc)
+{
+	unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;
+
+	/* if audio 0 interrupt */
+	if (ints & IF_AUD0) {
+		amiga_custom.intreq = IF_AUD0;
+		generic_handle_irq(IRQ_AMIGA_AUD0);
+	}
+
+	/* if audio 1 interrupt */
+	if (ints & IF_AUD1) {
+		amiga_custom.intreq = IF_AUD1;
+		generic_handle_irq(IRQ_AMIGA_AUD1);
+	}
+
+	/* if audio 2 interrupt */
+	if (ints & IF_AUD2) {
+		amiga_custom.intreq = IF_AUD2;
+		generic_handle_irq(IRQ_AMIGA_AUD2);
+	}
+
+	/* if audio 3 interrupt */
+	if (ints & IF_AUD3) {
+		amiga_custom.intreq = IF_AUD3;
+		generic_handle_irq(IRQ_AMIGA_AUD3);
+	}
+}
+
+static void ami_int5(unsigned int irq, struct irq_desc *desc)
+{
+	unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;
+
+	/* if serial receive buffer full interrupt */
+	if (ints & IF_RBF) {
+		/* acknowledge of IF_RBF must be done by the serial interrupt */
+		generic_handle_irq(IRQ_AMIGA_RBF);
+	}
+
+	/* if a disk sync interrupt */
+	if (ints & IF_DSKSYN) {
+		amiga_custom.intreq = IF_DSKSYN;
+		generic_handle_irq(IRQ_AMIGA_DSKSYN);
+	}
+}
+#else /* !CONFIG_GENERIC_HARDIRQS */
 static irqreturn_t ami_int1(int irq, void *dev_id)
 {
 	unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;
@@ -143,6 +236,7 @@
 	}
 	return IRQ_HANDLED;
 }
+#endif /* !CONFIG_GENERIC_HARDIRQS */
 
 
 /*
@@ -158,6 +252,15 @@
 
 void __init amiga_init_IRQ(void)
 {
+#ifdef CONFIG_GENERIC_HARDIRQS
+	m68k_setup_irq_controller(&amiga_irq_chip, handle_simple_irq, IRQ_USER,
+				  AMI_STD_IRQS);
+
+	irq_set_chained_handler(IRQ_AUTO_1, ami_int1);
+	irq_set_chained_handler(IRQ_AUTO_3, ami_int3);
+	irq_set_chained_handler(IRQ_AUTO_4, ami_int4);
+	irq_set_chained_handler(IRQ_AUTO_5, ami_int5);
+#else /* !CONFIG_GENERIC_HARDIRQS */
 	if (request_irq(IRQ_AUTO_1, ami_int1, 0, "int1", NULL))
 		pr_err("Couldn't register int%d\n", 1);
 	if (request_irq(IRQ_AUTO_3, ami_int3, 0, "int3", NULL))
@@ -169,6 +272,7 @@
 
 	m68k_setup_irq_controller(&amiga_irq_chip, handle_simple_irq, IRQ_USER,
 				  AMI_STD_IRQS);
+#endif /* !CONFIG_GENERIC_HARDIRQS */
 
 	/* turn off PCMCIA interrupts */
 	if (AMIGAHW_PRESENT(PCMCIA))