aboutsummaryrefslogtreecommitdiffstats
path: root/arch/m68k
diff options
context:
space:
mode:
authorGeert Uytterhoeven <geert@linux-m68k.org>2011-08-10 06:48:29 -0400
committerGeert Uytterhoeven <geert@linux-m68k.org>2011-11-08 16:35:50 -0500
commit9145db564eae98134de8eb8d64b47d7177eccfdd (patch)
tree7d0e25514abba33b6082f5a13963442cf390a058 /arch/m68k
parentddc7fd25d09678f8252c0321ef4b66e8451abe7d (diff)
m68k/mac: Optimize interrupts using chain handlers
Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
Diffstat (limited to 'arch/m68k')
-rw-r--r--arch/m68k/mac/baboon.c38
-rw-r--r--arch/m68k/mac/oss.c106
-rw-r--r--arch/m68k/mac/psc.c74
-rw-r--r--arch/m68k/mac/via.c143
4 files changed, 298 insertions, 63 deletions
diff --git a/arch/m68k/mac/baboon.c b/arch/m68k/mac/baboon.c
index ff11746b0621..425144cbfa7d 100644
--- a/arch/m68k/mac/baboon.c
+++ b/arch/m68k/mac/baboon.c
@@ -56,6 +56,39 @@ void __init baboon_init(void)
56 * Baboon interrupt handler. This works a lot like a VIA. 56 * Baboon interrupt handler. This works a lot like a VIA.
57 */ 57 */
58 58
59#ifdef CONFIG_GENERIC_HARDIRQS
60static void baboon_irq(unsigned int irq, struct irq_desc *desc)
61{
62 int irq_bit, irq_num;
63 unsigned char events;
64
65#ifdef DEBUG_IRQS
66 printk("baboon_irq: mb_control %02X mb_ifr %02X mb_status %02X\n",
67 (uint) baboon->mb_control, (uint) baboon->mb_ifr,
68 (uint) baboon->mb_status);
69#endif
70
71 events = baboon->mb_ifr & 0x07;
72 if (!events)
73 return;
74
75 irq_num = IRQ_BABOON_0;
76 irq_bit = 1;
77 do {
78 if (events & irq_bit) {
79 baboon->mb_ifr &= ~irq_bit;
80 generic_handle_irq(irq_num);
81 }
82 irq_bit <<= 1;
83 irq_num++;
84 } while(events >= irq_bit);
85#if 0
86 if (baboon->mb_ifr & 0x02) macide_ack_intr(NULL);
87 /* for now we need to smash all interrupts */
88 baboon->mb_ifr &= ~events;
89#endif
90}
91#else
59static irqreturn_t baboon_irq(int irq, void *dev_id) 92static irqreturn_t baboon_irq(int irq, void *dev_id)
60{ 93{
61 int irq_bit, irq_num; 94 int irq_bit, irq_num;
@@ -87,6 +120,7 @@ static irqreturn_t baboon_irq(int irq, void *dev_id)
87#endif 120#endif
88 return IRQ_HANDLED; 121 return IRQ_HANDLED;
89} 122}
123#endif
90 124
91/* 125/*
92 * Register the Baboon interrupt dispatcher on nubus slot $C. 126 * Register the Baboon interrupt dispatcher on nubus slot $C.
@@ -95,8 +129,12 @@ static irqreturn_t baboon_irq(int irq, void *dev_id)
95void __init baboon_register_interrupts(void) 129void __init baboon_register_interrupts(void)
96{ 130{
97 baboon_disabled = 0; 131 baboon_disabled = 0;
132#ifdef CONFIG_GENERIC_HARDIRQS
133 irq_set_chained_handler(IRQ_NUBUS_C, baboon_irq);
134#else
98 if (request_irq(IRQ_NUBUS_C, baboon_irq, 0, "baboon", (void *)baboon)) 135 if (request_irq(IRQ_NUBUS_C, baboon_irq, 0, "baboon", (void *)baboon))
99 pr_err("Couldn't register baboon interrupt\n"); 136 pr_err("Couldn't register baboon interrupt\n");
137#endif
100} 138}
101 139
102/* 140/*
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 @@
32int oss_present; 32int oss_present;
33volatile struct mac_oss *oss; 33volatile struct mac_oss *oss;
34 34
35static irqreturn_t oss_irq(int, void *); 35#ifdef CONFIG_GENERIC_HARDIRQS
36static irqreturn_t oss_nubus_irq(int, void *); 36extern void via1_irq(unsigned int irq, struct irq_desc *desc);
37 37#else
38extern irqreturn_t via1_irq(int, void *); 38extern irqreturn_t via1_irq(int, void *);
39#endif
39 40
40/* 41/*
41 * Initialize the OSS 42 * Initialize the OSS
@@ -63,23 +64,6 @@ void __init oss_init(void)
63} 64}
64 65
65/* 66/*
66 * Register the OSS and NuBus interrupt dispatchers.
67 */
68
69void __init oss_register_interrupts(void)
70{
71 if (request_irq(OSS_IRQLEV_SCSI, oss_irq, 0, "scsi", (void *)oss))
72 pr_err("Couldn't register %s interrupt\n", "scsi");
73 if (request_irq(OSS_IRQLEV_NUBUS, oss_nubus_irq, 0, "nubus",
74 (void *)oss))
75 pr_err("Couldn't register %s interrupt\n", "nubus");
76 if (request_irq(OSS_IRQLEV_SOUND, oss_irq, 0, "sound", (void *)oss))
77 pr_err("Couldn't register %s interrupt\n", "sound");
78 if (request_irq(OSS_IRQLEV_VIA1, via1_irq, 0, "via1", (void *)via1))
79 pr_err("Couldn't register %s interrupt\n", "via1");
80}
81
82/*
83 * Initialize OSS for Nubus access 67 * Initialize OSS for Nubus access
84 */ 68 */
85 69
@@ -92,6 +76,34 @@ void __init oss_nubus_init(void)
92 * and SCSI; everything else is routed to its own autovector IRQ. 76 * and SCSI; everything else is routed to its own autovector IRQ.
93 */ 77 */
94 78
79#ifdef CONFIG_GENERIC_HARDIRQS
80static void oss_irq(unsigned int irq, struct irq_desc *desc)
81{
82 int events;
83
84 events = oss->irq_pending & (OSS_IP_SOUND|OSS_IP_SCSI);
85 if (!events)
86 return;
87
88#ifdef DEBUG_IRQS
89 if ((console_loglevel == 10) && !(events & OSS_IP_SCSI)) {
90 printk("oss_irq: irq %u events = 0x%04X\n", irq,
91 (int) oss->irq_pending);
92 }
93#endif
94 /* FIXME: how do you clear a pending IRQ? */
95
96 if (events & OSS_IP_SOUND) {
97 oss->irq_pending &= ~OSS_IP_SOUND;
98 /* FIXME: call sound handler */
99 } else if (events & OSS_IP_SCSI) {
100 oss->irq_pending &= ~OSS_IP_SCSI;
101 generic_handle_irq(IRQ_MAC_SCSI);
102 } else {
103 /* FIXME: error check here? */
104 }
105}
106#else
95static irqreturn_t oss_irq(int irq, void *dev_id) 107static irqreturn_t oss_irq(int irq, void *dev_id)
96{ 108{
97 int events; 109 int events;
@@ -119,6 +131,7 @@ static irqreturn_t oss_irq(int irq, void *dev_id)
119 } 131 }
120 return IRQ_HANDLED; 132 return IRQ_HANDLED;
121} 133}
134#endif
122 135
123/* 136/*
124 * Nubus IRQ handler, OSS style 137 * Nubus IRQ handler, OSS style
@@ -126,6 +139,34 @@ static irqreturn_t oss_irq(int irq, void *dev_id)
126 * Unlike the VIA/RBV this is on its own autovector interrupt level. 139 * Unlike the VIA/RBV this is on its own autovector interrupt level.
127 */ 140 */
128 141
142#ifdef CONFIG_GENERIC_HARDIRQS
143static void oss_nubus_irq(unsigned int irq, struct irq_desc *desc)
144{
145 int events, irq_bit, i;
146
147 events = oss->irq_pending & OSS_IP_NUBUS;
148 if (!events)
149 return;
150
151#ifdef DEBUG_NUBUS_INT
152 if (console_loglevel > 7) {
153 printk("oss_nubus_irq: events = 0x%04X\n", events);
154 }
155#endif
156 /* There are only six slots on the OSS, not seven */
157
158 i = 6;
159 irq_bit = 0x40;
160 do {
161 --i;
162 irq_bit >>= 1;
163 if (events & irq_bit) {
164 oss->irq_pending &= ~irq_bit;
165 generic_handle_irq(NUBUS_SOURCE_BASE + i);
166 }
167 } while(events & (irq_bit - 1));
168}
169#else
129static irqreturn_t oss_nubus_irq(int irq, void *dev_id) 170static irqreturn_t oss_nubus_irq(int irq, void *dev_id)
130{ 171{
131 int events, irq_bit, i; 172 int events, irq_bit, i;
@@ -153,6 +194,31 @@ static irqreturn_t oss_nubus_irq(int irq, void *dev_id)
153 } while(events & (irq_bit - 1)); 194 } while(events & (irq_bit - 1));
154 return IRQ_HANDLED; 195 return IRQ_HANDLED;
155} 196}
197#endif
198
199/*
200 * Register the OSS and NuBus interrupt dispatchers.
201 */
202
203void __init oss_register_interrupts(void)
204{
205#ifdef CONFIG_GENERIC_HARDIRQS
206 irq_set_chained_handler(OSS_IRQLEV_SCSI, oss_irq);
207 irq_set_chained_handler(OSS_IRQLEV_NUBUS, oss_nubus_irq);
208 irq_set_chained_handler(OSS_IRQLEV_SOUND, oss_irq);
209 irq_set_chained_handler(OSS_IRQLEV_VIA1, via1_irq);
210#else /* !CONFIG_GENERIC_HARDIRQS */
211 if (request_irq(OSS_IRQLEV_SCSI, oss_irq, 0, "scsi", (void *)oss))
212 pr_err("Couldn't register %s interrupt\n", "scsi");
213 if (request_irq(OSS_IRQLEV_NUBUS, oss_nubus_irq, 0, "nubus",
214 (void *)oss))
215 pr_err("Couldn't register %s interrupt\n", "nubus");
216 if (request_irq(OSS_IRQLEV_SOUND, oss_irq, 0, "sound", (void *)oss))
217 pr_err("Couldn't register %s interrupt\n", "sound");
218 if (request_irq(OSS_IRQLEV_VIA1, via1_irq, 0, "via1", (void *)via1))
219 pr_err("Couldn't register %s interrupt\n", "via1");
220#endif /* !CONFIG_GENERIC_HARDIRQS */
221}
156 222
157/* 223/*
158 * Enable an OSS interrupt 224 * Enable an OSS interrupt
diff --git a/arch/m68k/mac/psc.c b/arch/m68k/mac/psc.c
index 0a34b7afc376..52840b8c03b8 100644
--- a/arch/m68k/mac/psc.c
+++ b/arch/m68k/mac/psc.c
@@ -33,8 +33,6 @@
33int psc_present; 33int psc_present;
34volatile __u8 *psc; 34volatile __u8 *psc;
35 35
36irqreturn_t psc_irq(int, void *);
37
38/* 36/*
39 * Debugging dump, used in various places to see what's going on. 37 * Debugging dump, used in various places to see what's going on.
40 */ 38 */
@@ -115,26 +113,40 @@ void __init psc_init(void)
115} 113}
116 114
117/* 115/*
118 * Register the PSC interrupt dispatchers for autovector interrupts 3-6. 116 * PSC interrupt handler. It's a lot like the VIA interrupt handler.
119 */ 117 */
120 118
121void __init psc_register_interrupts(void) 119#ifdef CONFIG_GENERIC_HARDIRQS
120static void psc_irq(unsigned int irq, struct irq_desc *desc)
122{ 121{
123 if (request_irq(IRQ_AUTO_3, psc_irq, 0, "psc3", (void *) 0x30)) 122 unsigned int offset = (unsigned int)irq_desc_get_handler_data(desc);
124 pr_err("Couldn't register psc%d interrupt\n", 3); 123 int pIFR = pIFRbase + offset;
125 if (request_irq(IRQ_AUTO_4, psc_irq, 0, "psc4", (void *) 0x40)) 124 int pIER = pIERbase + offset;
126 pr_err("Couldn't register psc%d interrupt\n", 4); 125 int irq_num;
127 if (request_irq(IRQ_AUTO_5, psc_irq, 0, "psc5", (void *) 0x50)) 126 unsigned char irq_bit, events;
128 pr_err("Couldn't register psc%d interrupt\n", 5);
129 if (request_irq(IRQ_AUTO_6, psc_irq, 0, "psc6", (void *) 0x60))
130 pr_err("Couldn't register psc%d interrupt\n", 6);
131}
132 127
133/* 128#ifdef DEBUG_IRQS
134 * PSC interrupt handler. It's a lot like the VIA interrupt handler. 129 printk("psc_irq: irq %u pIFR = 0x%02X pIER = 0x%02X\n",
135 */ 130 irq, (int) psc_read_byte(pIFR), (int) psc_read_byte(pIER));
131#endif
136 132
137irqreturn_t psc_irq(int irq, void *dev_id) 133 events = psc_read_byte(pIFR) & psc_read_byte(pIER) & 0xF;
134 if (!events)
135 return;
136
137 irq_num = irq << 3;
138 irq_bit = 1;
139 do {
140 if (events & irq_bit) {
141 psc_write_byte(pIFR, irq_bit);
142 generic_handle_irq(irq_num);
143 }
144 irq_num++;
145 irq_bit <<= 1;
146 } while (events >= irq_bit);
147}
148#else
149static irqreturn_t psc_irq(int irq, void *dev_id)
138{ 150{
139 int pIFR = pIFRbase + ((int) dev_id); 151 int pIFR = pIFRbase + ((int) dev_id);
140 int pIER = pIERbase + ((int) dev_id); 152 int pIER = pIERbase + ((int) dev_id);
@@ -162,6 +174,34 @@ irqreturn_t psc_irq(int irq, void *dev_id)
162 } while (events >= irq_bit); 174 } while (events >= irq_bit);
163 return IRQ_HANDLED; 175 return IRQ_HANDLED;
164} 176}
177#endif
178
179/*
180 * Register the PSC interrupt dispatchers for autovector interrupts 3-6.
181 */
182
183void __init psc_register_interrupts(void)
184{
185#ifdef CONFIG_GENERIC_HARDIRQS
186 irq_set_chained_handler(IRQ_AUTO_3, psc_irq);
187 irq_set_handler_data(IRQ_AUTO_3, (void *)0x30);
188 irq_set_chained_handler(IRQ_AUTO_4, psc_irq);
189 irq_set_handler_data(IRQ_AUTO_4, (void *)0x40);
190 irq_set_chained_handler(IRQ_AUTO_5, psc_irq);
191 irq_set_handler_data(IRQ_AUTO_5, (void *)0x50);
192 irq_set_chained_handler(IRQ_AUTO_6, psc_irq);
193 irq_set_handler_data(IRQ_AUTO_6, (void *)0x60);
194#else /* !CONFIG_GENERIC_HARDIRQS */
195 if (request_irq(IRQ_AUTO_3, psc_irq, 0, "psc3", (void *) 0x30))
196 pr_err("Couldn't register psc%d interrupt\n", 3);
197 if (request_irq(IRQ_AUTO_4, psc_irq, 0, "psc4", (void *) 0x40))
198 pr_err("Couldn't register psc%d interrupt\n", 4);
199 if (request_irq(IRQ_AUTO_5, psc_irq, 0, "psc5", (void *) 0x50))
200 pr_err("Couldn't register psc%d interrupt\n", 5);
201 if (request_irq(IRQ_AUTO_6, psc_irq, 0, "psc6", (void *) 0x60))
202 pr_err("Couldn't register psc%d interrupt\n", 6);
203#endif /* !CONFIG_GENERIC_HARDIRQS */
204}
165 205
166void psc_irq_enable(int irq) { 206void psc_irq_enable(int irq) {
167 int irq_src = IRQ_SRC(irq); 207 int irq_src = IRQ_SRC(irq);
diff --git a/arch/m68k/mac/via.c b/arch/m68k/mac/via.c
index bde156caa46d..b8156ac496a0 100644
--- a/arch/m68k/mac/via.c
+++ b/arch/m68k/mac/via.c
@@ -80,9 +80,6 @@ static int gIER,gIFR,gBufA,gBufB;
80static u8 nubus_disabled; 80static u8 nubus_disabled;
81 81
82void via_debug_dump(void); 82void via_debug_dump(void);
83irqreturn_t via1_irq(int, void *);
84irqreturn_t via2_irq(int, void *);
85irqreturn_t via_nubus_irq(int, void *);
86void via_irq_enable(int irq); 83void via_irq_enable(int irq);
87void via_irq_disable(int irq); 84void via_irq_disable(int irq);
88void via_irq_clear(int irq); 85void via_irq_clear(int irq);
@@ -289,29 +286,6 @@ void __init via_init_clock(irq_handler_t func)
289} 286}
290 287
291/* 288/*
292 * Register the interrupt dispatchers for VIA or RBV machines only.
293 */
294
295void __init via_register_interrupts(void)
296{
297 if (via_alt_mapping) {
298 if (request_irq(IRQ_AUTO_1, via1_irq, 0, "software",
299 (void *)via1))
300 pr_err("Couldn't register %s interrupt\n", "software");
301 if (request_irq(IRQ_AUTO_6, via1_irq, 0, "via1", (void *)via1))
302 pr_err("Couldn't register %s interrupt\n", "via1");
303 } else {
304 if (request_irq(IRQ_AUTO_1, via1_irq, 0, "via1", (void *)via1))
305 pr_err("Couldn't register %s interrupt\n", "via1");
306 }
307 if (request_irq(IRQ_AUTO_2, via2_irq, 0, "via2", (void *)via2))
308 pr_err("Couldn't register %s interrupt\n", "via2");
309 if (request_irq(IRQ_MAC_NUBUS, via_nubus_irq, 0, "nubus",
310 (void *)via2))
311 pr_err("Couldn't register %s interrupt\n", "nubus");
312}
313
314/*
315 * Debugging dump, used in various places to see what's going on. 289 * Debugging dump, used in various places to see what's going on.
316 */ 290 */
317 291
@@ -443,6 +417,49 @@ void __init via_nubus_init(void)
443 * via6522.c :-), disable/pending masks added. 417 * via6522.c :-), disable/pending masks added.
444 */ 418 */
445 419
420#ifdef CONFIG_GENERIC_HARDIRQS
421void via1_irq(unsigned int irq, struct irq_desc *desc)
422{
423 int irq_num;
424 unsigned char irq_bit, events;
425
426 events = via1[vIFR] & via1[vIER] & 0x7F;
427 if (!events)
428 return;
429
430 irq_num = VIA1_SOURCE_BASE;
431 irq_bit = 1;
432 do {
433 if (events & irq_bit) {
434 via1[vIFR] = irq_bit;
435 generic_handle_irq(irq_num);
436 }
437 ++irq_num;
438 irq_bit <<= 1;
439 } while (events >= irq_bit);
440}
441
442static void via2_irq(unsigned int irq, struct irq_desc *desc)
443{
444 int irq_num;
445 unsigned char irq_bit, events;
446
447 events = via2[gIFR] & via2[gIER] & 0x7F;
448 if (!events)
449 return;
450
451 irq_num = VIA2_SOURCE_BASE;
452 irq_bit = 1;
453 do {
454 if (events & irq_bit) {
455 via2[gIFR] = irq_bit | rbv_clear;
456 generic_handle_irq(irq_num);
457 }
458 ++irq_num;
459 irq_bit <<= 1;
460 } while (events >= irq_bit);
461}
462#else
446irqreturn_t via1_irq(int irq, void *dev_id) 463irqreturn_t via1_irq(int irq, void *dev_id)
447{ 464{
448 int irq_num; 465 int irq_num;
@@ -486,12 +503,49 @@ irqreturn_t via2_irq(int irq, void *dev_id)
486 } while (events >= irq_bit); 503 } while (events >= irq_bit);
487 return IRQ_HANDLED; 504 return IRQ_HANDLED;
488} 505}
506#endif
489 507
490/* 508/*
491 * Dispatch Nubus interrupts. We are called as a secondary dispatch by the 509 * Dispatch Nubus interrupts. We are called as a secondary dispatch by the
492 * VIA2 dispatcher as a fast interrupt handler. 510 * VIA2 dispatcher as a fast interrupt handler.
493 */ 511 */
494 512
513#ifdef CONFIG_GENERIC_HARDIRQS
514void via_nubus_irq(unsigned int irq, struct irq_desc *desc)
515{
516 int slot_irq;
517 unsigned char slot_bit, events;
518
519 events = ~via2[gBufA] & 0x7F;
520 if (rbv_present)
521 events &= via2[rSIER];
522 else
523 events &= ~via2[vDirA];
524 if (!events)
525 return;
526
527 do {
528 slot_irq = IRQ_NUBUS_F;
529 slot_bit = 0x40;
530 do {
531 if (events & slot_bit) {
532 events &= ~slot_bit;
533 generic_handle_irq(slot_irq);
534 }
535 --slot_irq;
536 slot_bit >>= 1;
537 } while (events);
538
539 /* clear the CA1 interrupt and make certain there's no more. */
540 via2[gIFR] = 0x02 | rbv_clear;
541 events = ~via2[gBufA] & 0x7F;
542 if (rbv_present)
543 events &= via2[rSIER];
544 else
545 events &= ~via2[vDirA];
546 } while (events);
547}
548#else
495irqreturn_t via_nubus_irq(int irq, void *dev_id) 549irqreturn_t via_nubus_irq(int irq, void *dev_id)
496{ 550{
497 int slot_irq; 551 int slot_irq;
@@ -527,6 +581,43 @@ irqreturn_t via_nubus_irq(int irq, void *dev_id)
527 } while (events); 581 } while (events);
528 return IRQ_HANDLED; 582 return IRQ_HANDLED;
529} 583}
584#endif
585
586/*
587 * Register the interrupt dispatchers for VIA or RBV machines only.
588 */
589
590void __init via_register_interrupts(void)
591{
592#ifdef CONFIG_GENERIC_HARDIRQS
593 if (via_alt_mapping) {
594 /* software interrupt */
595 irq_set_chained_handler(IRQ_AUTO_1, via1_irq);
596 /* via1 interrupt */
597 irq_set_chained_handler(IRQ_AUTO_6, via1_irq);
598 } else {
599 irq_set_chained_handler(IRQ_AUTO_1, via1_irq);
600 }
601 irq_set_chained_handler(IRQ_AUTO_2, via2_irq);
602 irq_set_chained_handler(IRQ_MAC_NUBUS, via_nubus_irq);
603#else
604 if (via_alt_mapping) {
605 if (request_irq(IRQ_AUTO_1, via1_irq, 0, "software",
606 (void *)via1))
607 pr_err("Couldn't register %s interrupt\n", "software");
608 if (request_irq(IRQ_AUTO_6, via1_irq, 0, "via1", (void *)via1))
609 pr_err("Couldn't register %s interrupt\n", "via1");
610 } else {
611 if (request_irq(IRQ_AUTO_1, via1_irq, 0, "via1", (void *)via1))
612 pr_err("Couldn't register %s interrupt\n", "via1");
613 }
614 if (request_irq(IRQ_AUTO_2, via2_irq, 0, "via2", (void *)via2))
615 pr_err("Couldn't register %s interrupt\n", "via2");
616 if (request_irq(IRQ_MAC_NUBUS, via_nubus_irq, 0, "nubus",
617 (void *)via2))
618 pr_err("Couldn't register %s interrupt\n", "nubus");
619#endif
620}
530 621
531void via_irq_enable(int irq) { 622void via_irq_enable(int irq) {
532 int irq_src = IRQ_SRC(irq); 623 int irq_src = IRQ_SRC(irq);