From 9145db564eae98134de8eb8d64b47d7177eccfdd Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 10 Aug 2011 12:48:29 +0200 Subject: m68k/mac: Optimize interrupts using chain handlers Signed-off-by: Geert Uytterhoeven --- arch/m68k/mac/via.c | 143 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 117 insertions(+), 26 deletions(-) (limited to 'arch/m68k/mac/via.c') diff --git a/arch/m68k/mac/via.c b/arch/m68k/mac/via.c index bde156caa46..b8156ac496a 100644 --- a/arch/m68k/mac/via.c +++ b/arch/m68k/mac/via.c @@ -80,9 +80,6 @@ static int gIER,gIFR,gBufA,gBufB; static u8 nubus_disabled; void via_debug_dump(void); -irqreturn_t via1_irq(int, void *); -irqreturn_t via2_irq(int, void *); -irqreturn_t via_nubus_irq(int, void *); void via_irq_enable(int irq); void via_irq_disable(int irq); void via_irq_clear(int irq); @@ -288,29 +285,6 @@ void __init via_init_clock(irq_handler_t func) pr_err("Couldn't register %s interrupt\n", "timer"); } -/* - * Register the interrupt dispatchers for VIA or RBV machines only. - */ - -void __init via_register_interrupts(void) -{ - if (via_alt_mapping) { - if (request_irq(IRQ_AUTO_1, via1_irq, 0, "software", - (void *)via1)) - pr_err("Couldn't register %s interrupt\n", "software"); - if (request_irq(IRQ_AUTO_6, via1_irq, 0, "via1", (void *)via1)) - pr_err("Couldn't register %s interrupt\n", "via1"); - } else { - if (request_irq(IRQ_AUTO_1, via1_irq, 0, "via1", (void *)via1)) - pr_err("Couldn't register %s interrupt\n", "via1"); - } - if (request_irq(IRQ_AUTO_2, via2_irq, 0, "via2", (void *)via2)) - pr_err("Couldn't register %s interrupt\n", "via2"); - if (request_irq(IRQ_MAC_NUBUS, via_nubus_irq, 0, "nubus", - (void *)via2)) - pr_err("Couldn't register %s interrupt\n", "nubus"); -} - /* * Debugging dump, used in various places to see what's going on. */ @@ -443,6 +417,49 @@ void __init via_nubus_init(void) * via6522.c :-), disable/pending masks added. */ +#ifdef CONFIG_GENERIC_HARDIRQS +void via1_irq(unsigned int irq, struct irq_desc *desc) +{ + int irq_num; + unsigned char irq_bit, events; + + events = via1[vIFR] & via1[vIER] & 0x7F; + if (!events) + return; + + irq_num = VIA1_SOURCE_BASE; + irq_bit = 1; + do { + if (events & irq_bit) { + via1[vIFR] = irq_bit; + generic_handle_irq(irq_num); + } + ++irq_num; + irq_bit <<= 1; + } while (events >= irq_bit); +} + +static void via2_irq(unsigned int irq, struct irq_desc *desc) +{ + int irq_num; + unsigned char irq_bit, events; + + events = via2[gIFR] & via2[gIER] & 0x7F; + if (!events) + return; + + irq_num = VIA2_SOURCE_BASE; + irq_bit = 1; + do { + if (events & irq_bit) { + via2[gIFR] = irq_bit | rbv_clear; + generic_handle_irq(irq_num); + } + ++irq_num; + irq_bit <<= 1; + } while (events >= irq_bit); +} +#else irqreturn_t via1_irq(int irq, void *dev_id) { int irq_num; @@ -486,12 +503,49 @@ irqreturn_t via2_irq(int irq, void *dev_id) } while (events >= irq_bit); return IRQ_HANDLED; } +#endif /* * Dispatch Nubus interrupts. We are called as a secondary dispatch by the * VIA2 dispatcher as a fast interrupt handler. */ +#ifdef CONFIG_GENERIC_HARDIRQS +void via_nubus_irq(unsigned int irq, struct irq_desc *desc) +{ + int slot_irq; + unsigned char slot_bit, events; + + events = ~via2[gBufA] & 0x7F; + if (rbv_present) + events &= via2[rSIER]; + else + events &= ~via2[vDirA]; + if (!events) + return; + + do { + slot_irq = IRQ_NUBUS_F; + slot_bit = 0x40; + do { + if (events & slot_bit) { + events &= ~slot_bit; + generic_handle_irq(slot_irq); + } + --slot_irq; + slot_bit >>= 1; + } while (events); + + /* clear the CA1 interrupt and make certain there's no more. */ + via2[gIFR] = 0x02 | rbv_clear; + events = ~via2[gBufA] & 0x7F; + if (rbv_present) + events &= via2[rSIER]; + else + events &= ~via2[vDirA]; + } while (events); +} +#else irqreturn_t via_nubus_irq(int irq, void *dev_id) { int slot_irq; @@ -527,6 +581,43 @@ irqreturn_t via_nubus_irq(int irq, void *dev_id) } while (events); return IRQ_HANDLED; } +#endif + +/* + * Register the interrupt dispatchers for VIA or RBV machines only. + */ + +void __init via_register_interrupts(void) +{ +#ifdef CONFIG_GENERIC_HARDIRQS + if (via_alt_mapping) { + /* software interrupt */ + irq_set_chained_handler(IRQ_AUTO_1, via1_irq); + /* via1 interrupt */ + irq_set_chained_handler(IRQ_AUTO_6, via1_irq); + } else { + irq_set_chained_handler(IRQ_AUTO_1, via1_irq); + } + irq_set_chained_handler(IRQ_AUTO_2, via2_irq); + irq_set_chained_handler(IRQ_MAC_NUBUS, via_nubus_irq); +#else + if (via_alt_mapping) { + if (request_irq(IRQ_AUTO_1, via1_irq, 0, "software", + (void *)via1)) + pr_err("Couldn't register %s interrupt\n", "software"); + if (request_irq(IRQ_AUTO_6, via1_irq, 0, "via1", (void *)via1)) + pr_err("Couldn't register %s interrupt\n", "via1"); + } else { + if (request_irq(IRQ_AUTO_1, via1_irq, 0, "via1", (void *)via1)) + pr_err("Couldn't register %s interrupt\n", "via1"); + } + if (request_irq(IRQ_AUTO_2, via2_irq, 0, "via2", (void *)via2)) + pr_err("Couldn't register %s interrupt\n", "via2"); + if (request_irq(IRQ_MAC_NUBUS, via_nubus_irq, 0, "nubus", + (void *)via2)) + pr_err("Couldn't register %s interrupt\n", "nubus"); +#endif +} void via_irq_enable(int irq) { int irq_src = IRQ_SRC(irq); -- cgit v1.2.3