diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2006-07-03 05:32:51 -0400 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2006-07-03 05:55:12 -0400 |
commit | b9e5b4e6a991a5a6d521f2e20a65835404b4169f (patch) | |
tree | a0ac972faae4bf9133f576d842667bb134190341 /arch/powerpc/platforms/powermac | |
parent | 5a43a066b11ac2fe84cf67307f20b83bea390f83 (diff) |
[POWERPC] Use the genirq framework
This adapts the generic powerpc interrupt handling code, and all of
the platforms except for the embedded 6xx machines, to use the new
genirq framework.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/platforms/powermac')
-rw-r--r-- | arch/powerpc/platforms/powermac/pic.c | 170 |
1 files changed, 103 insertions, 67 deletions
diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c index c9b09a9e6050..58a4c7b90b8b 100644 --- a/arch/powerpc/platforms/powermac/pic.c +++ b/arch/powerpc/platforms/powermac/pic.c | |||
@@ -70,18 +70,19 @@ static struct interrupt_info gatwick_int_pool[GATWICK_IRQ_POOL_SIZE]; | |||
70 | 70 | ||
71 | #define NR_MASK_WORDS ((NR_IRQS + 31) / 32) | 71 | #define NR_MASK_WORDS ((NR_IRQS + 31) / 32) |
72 | static unsigned long ppc_lost_interrupts[NR_MASK_WORDS]; | 72 | static unsigned long ppc_lost_interrupts[NR_MASK_WORDS]; |
73 | static unsigned long ppc_cached_irq_mask[NR_MASK_WORDS]; | ||
74 | static int pmac_irq_cascade = -1; | ||
73 | 75 | ||
74 | /* | 76 | static void __pmac_retrigger(unsigned int irq_nr) |
75 | * Mark an irq as "lost". This is only used on the pmac | ||
76 | * since it can lose interrupts (see pmac_set_irq_mask). | ||
77 | * -- Cort | ||
78 | */ | ||
79 | void __set_lost(unsigned long irq_nr, int nokick) | ||
80 | { | 77 | { |
81 | if (!test_and_set_bit(irq_nr, ppc_lost_interrupts)) { | 78 | if (irq_nr >= max_real_irqs && pmac_irq_cascade > 0) { |
79 | __set_bit(irq_nr, ppc_lost_interrupts); | ||
80 | irq_nr = pmac_irq_cascade; | ||
81 | mb(); | ||
82 | } | ||
83 | if (!__test_and_set_bit(irq_nr, ppc_lost_interrupts)) { | ||
82 | atomic_inc(&ppc_n_lost_interrupts); | 84 | atomic_inc(&ppc_n_lost_interrupts); |
83 | if (!nokick) | 85 | set_dec(1); |
84 | set_dec(1); | ||
85 | } | 86 | } |
86 | } | 87 | } |
87 | 88 | ||
@@ -94,10 +95,10 @@ static void pmac_mask_and_ack_irq(unsigned int irq_nr) | |||
94 | if ((unsigned)irq_nr >= max_irqs) | 95 | if ((unsigned)irq_nr >= max_irqs) |
95 | return; | 96 | return; |
96 | 97 | ||
97 | clear_bit(irq_nr, ppc_cached_irq_mask); | ||
98 | if (test_and_clear_bit(irq_nr, ppc_lost_interrupts)) | ||
99 | atomic_dec(&ppc_n_lost_interrupts); | ||
100 | spin_lock_irqsave(&pmac_pic_lock, flags); | 98 | spin_lock_irqsave(&pmac_pic_lock, flags); |
99 | __clear_bit(irq_nr, ppc_cached_irq_mask); | ||
100 | if (__test_and_clear_bit(irq_nr, ppc_lost_interrupts)) | ||
101 | atomic_dec(&ppc_n_lost_interrupts); | ||
101 | out_le32(&pmac_irq_hw[i]->enable, ppc_cached_irq_mask[i]); | 102 | out_le32(&pmac_irq_hw[i]->enable, ppc_cached_irq_mask[i]); |
102 | out_le32(&pmac_irq_hw[i]->ack, bit); | 103 | out_le32(&pmac_irq_hw[i]->ack, bit); |
103 | do { | 104 | do { |
@@ -109,7 +110,7 @@ static void pmac_mask_and_ack_irq(unsigned int irq_nr) | |||
109 | spin_unlock_irqrestore(&pmac_pic_lock, flags); | 110 | spin_unlock_irqrestore(&pmac_pic_lock, flags); |
110 | } | 111 | } |
111 | 112 | ||
112 | static void pmac_set_irq_mask(unsigned int irq_nr, int nokicklost) | 113 | static void pmac_ack_irq(unsigned int irq_nr) |
113 | { | 114 | { |
114 | unsigned long bit = 1UL << (irq_nr & 0x1f); | 115 | unsigned long bit = 1UL << (irq_nr & 0x1f); |
115 | int i = irq_nr >> 5; | 116 | int i = irq_nr >> 5; |
@@ -118,7 +119,22 @@ static void pmac_set_irq_mask(unsigned int irq_nr, int nokicklost) | |||
118 | if ((unsigned)irq_nr >= max_irqs) | 119 | if ((unsigned)irq_nr >= max_irqs) |
119 | return; | 120 | return; |
120 | 121 | ||
121 | spin_lock_irqsave(&pmac_pic_lock, flags); | 122 | spin_lock_irqsave(&pmac_pic_lock, flags); |
123 | if (__test_and_clear_bit(irq_nr, ppc_lost_interrupts)) | ||
124 | atomic_dec(&ppc_n_lost_interrupts); | ||
125 | out_le32(&pmac_irq_hw[i]->ack, bit); | ||
126 | (void)in_le32(&pmac_irq_hw[i]->ack); | ||
127 | spin_unlock_irqrestore(&pmac_pic_lock, flags); | ||
128 | } | ||
129 | |||
130 | static void __pmac_set_irq_mask(unsigned int irq_nr, int nokicklost) | ||
131 | { | ||
132 | unsigned long bit = 1UL << (irq_nr & 0x1f); | ||
133 | int i = irq_nr >> 5; | ||
134 | |||
135 | if ((unsigned)irq_nr >= max_irqs) | ||
136 | return; | ||
137 | |||
122 | /* enable unmasked interrupts */ | 138 | /* enable unmasked interrupts */ |
123 | out_le32(&pmac_irq_hw[i]->enable, ppc_cached_irq_mask[i]); | 139 | out_le32(&pmac_irq_hw[i]->enable, ppc_cached_irq_mask[i]); |
124 | 140 | ||
@@ -135,8 +151,7 @@ static void pmac_set_irq_mask(unsigned int irq_nr, int nokicklost) | |||
135 | * the bit in the flag register or request another interrupt. | 151 | * the bit in the flag register or request another interrupt. |
136 | */ | 152 | */ |
137 | if (bit & ppc_cached_irq_mask[i] & in_le32(&pmac_irq_hw[i]->level)) | 153 | if (bit & ppc_cached_irq_mask[i] & in_le32(&pmac_irq_hw[i]->level)) |
138 | __set_lost((ulong)irq_nr, nokicklost); | 154 | __pmac_retrigger(irq_nr); |
139 | spin_unlock_irqrestore(&pmac_pic_lock, flags); | ||
140 | } | 155 | } |
141 | 156 | ||
142 | /* When an irq gets requested for the first client, if it's an | 157 | /* When an irq gets requested for the first client, if it's an |
@@ -144,62 +159,67 @@ static void pmac_set_irq_mask(unsigned int irq_nr, int nokicklost) | |||
144 | */ | 159 | */ |
145 | static unsigned int pmac_startup_irq(unsigned int irq_nr) | 160 | static unsigned int pmac_startup_irq(unsigned int irq_nr) |
146 | { | 161 | { |
162 | unsigned long flags; | ||
147 | unsigned long bit = 1UL << (irq_nr & 0x1f); | 163 | unsigned long bit = 1UL << (irq_nr & 0x1f); |
148 | int i = irq_nr >> 5; | 164 | int i = irq_nr >> 5; |
149 | 165 | ||
166 | spin_lock_irqsave(&pmac_pic_lock, flags); | ||
150 | if ((irq_desc[irq_nr].status & IRQ_LEVEL) == 0) | 167 | if ((irq_desc[irq_nr].status & IRQ_LEVEL) == 0) |
151 | out_le32(&pmac_irq_hw[i]->ack, bit); | 168 | out_le32(&pmac_irq_hw[i]->ack, bit); |
152 | set_bit(irq_nr, ppc_cached_irq_mask); | 169 | __set_bit(irq_nr, ppc_cached_irq_mask); |
153 | pmac_set_irq_mask(irq_nr, 0); | 170 | __pmac_set_irq_mask(irq_nr, 0); |
171 | spin_unlock_irqrestore(&pmac_pic_lock, flags); | ||
154 | 172 | ||
155 | return 0; | 173 | return 0; |
156 | } | 174 | } |
157 | 175 | ||
158 | static void pmac_mask_irq(unsigned int irq_nr) | 176 | static void pmac_mask_irq(unsigned int irq_nr) |
159 | { | 177 | { |
160 | clear_bit(irq_nr, ppc_cached_irq_mask); | 178 | unsigned long flags; |
161 | pmac_set_irq_mask(irq_nr, 0); | 179 | |
162 | mb(); | 180 | spin_lock_irqsave(&pmac_pic_lock, flags); |
181 | __clear_bit(irq_nr, ppc_cached_irq_mask); | ||
182 | __pmac_set_irq_mask(irq_nr, 0); | ||
183 | spin_unlock_irqrestore(&pmac_pic_lock, flags); | ||
163 | } | 184 | } |
164 | 185 | ||
165 | static void pmac_unmask_irq(unsigned int irq_nr) | 186 | static void pmac_unmask_irq(unsigned int irq_nr) |
166 | { | 187 | { |
167 | set_bit(irq_nr, ppc_cached_irq_mask); | 188 | unsigned long flags; |
168 | pmac_set_irq_mask(irq_nr, 0); | 189 | |
190 | spin_lock_irqsave(&pmac_pic_lock, flags); | ||
191 | __set_bit(irq_nr, ppc_cached_irq_mask); | ||
192 | __pmac_set_irq_mask(irq_nr, 0); | ||
193 | spin_unlock_irqrestore(&pmac_pic_lock, flags); | ||
169 | } | 194 | } |
170 | 195 | ||
171 | static void pmac_end_irq(unsigned int irq_nr) | 196 | static int pmac_retrigger(unsigned int irq_nr) |
172 | { | 197 | { |
173 | if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS)) | 198 | unsigned long flags; |
174 | && irq_desc[irq_nr].action) { | ||
175 | set_bit(irq_nr, ppc_cached_irq_mask); | ||
176 | pmac_set_irq_mask(irq_nr, 1); | ||
177 | } | ||
178 | } | ||
179 | 199 | ||
200 | spin_lock_irqsave(&pmac_pic_lock, flags); | ||
201 | __pmac_retrigger(irq_nr); | ||
202 | spin_unlock_irqrestore(&pmac_pic_lock, flags); | ||
203 | return 1; | ||
204 | } | ||
180 | 205 | ||
181 | struct hw_interrupt_type pmac_pic = { | 206 | static struct irq_chip pmac_pic = { |
182 | .typename = " PMAC-PIC ", | 207 | .typename = " PMAC-PIC ", |
183 | .startup = pmac_startup_irq, | 208 | .startup = pmac_startup_irq, |
184 | .enable = pmac_unmask_irq, | 209 | .mask = pmac_mask_irq, |
185 | .disable = pmac_mask_irq, | 210 | .ack = pmac_ack_irq, |
186 | .ack = pmac_mask_and_ack_irq, | 211 | .mask_ack = pmac_mask_and_ack_irq, |
187 | .end = pmac_end_irq, | 212 | .unmask = pmac_unmask_irq, |
188 | }; | 213 | .retrigger = pmac_retrigger, |
189 | |||
190 | struct hw_interrupt_type gatwick_pic = { | ||
191 | .typename = " GATWICK ", | ||
192 | .startup = pmac_startup_irq, | ||
193 | .enable = pmac_unmask_irq, | ||
194 | .disable = pmac_mask_irq, | ||
195 | .ack = pmac_mask_and_ack_irq, | ||
196 | .end = pmac_end_irq, | ||
197 | }; | 214 | }; |
198 | 215 | ||
199 | static irqreturn_t gatwick_action(int cpl, void *dev_id, struct pt_regs *regs) | 216 | static irqreturn_t gatwick_action(int cpl, void *dev_id, struct pt_regs *regs) |
200 | { | 217 | { |
218 | unsigned long flags; | ||
201 | int irq, bits; | 219 | int irq, bits; |
220 | int rc = IRQ_NONE; | ||
202 | 221 | ||
222 | spin_lock_irqsave(&pmac_pic_lock, flags); | ||
203 | for (irq = max_irqs; (irq -= 32) >= max_real_irqs; ) { | 223 | for (irq = max_irqs; (irq -= 32) >= max_real_irqs; ) { |
204 | int i = irq >> 5; | 224 | int i = irq >> 5; |
205 | bits = in_le32(&pmac_irq_hw[i]->event) | ppc_lost_interrupts[i]; | 225 | bits = in_le32(&pmac_irq_hw[i]->event) | ppc_lost_interrupts[i]; |
@@ -209,17 +229,20 @@ static irqreturn_t gatwick_action(int cpl, void *dev_id, struct pt_regs *regs) | |||
209 | if (bits == 0) | 229 | if (bits == 0) |
210 | continue; | 230 | continue; |
211 | irq += __ilog2(bits); | 231 | irq += __ilog2(bits); |
232 | spin_unlock_irqrestore(&pmac_pic_lock, flags); | ||
212 | __do_IRQ(irq, regs); | 233 | __do_IRQ(irq, regs); |
213 | return IRQ_HANDLED; | 234 | spin_lock_irqsave(&pmac_pic_lock, flags); |
235 | rc = IRQ_HANDLED; | ||
214 | } | 236 | } |
215 | printk("gatwick irq not from gatwick pic\n"); | 237 | spin_unlock_irqrestore(&pmac_pic_lock, flags); |
216 | return IRQ_NONE; | 238 | return rc; |
217 | } | 239 | } |
218 | 240 | ||
219 | static int pmac_get_irq(struct pt_regs *regs) | 241 | static int pmac_get_irq(struct pt_regs *regs) |
220 | { | 242 | { |
221 | int irq; | 243 | int irq; |
222 | unsigned long bits = 0; | 244 | unsigned long bits = 0; |
245 | unsigned long flags; | ||
223 | 246 | ||
224 | #ifdef CONFIG_SMP | 247 | #ifdef CONFIG_SMP |
225 | void psurge_smp_message_recv(struct pt_regs *); | 248 | void psurge_smp_message_recv(struct pt_regs *); |
@@ -230,6 +253,7 @@ static int pmac_get_irq(struct pt_regs *regs) | |||
230 | return -2; /* ignore, already handled */ | 253 | return -2; /* ignore, already handled */ |
231 | } | 254 | } |
232 | #endif /* CONFIG_SMP */ | 255 | #endif /* CONFIG_SMP */ |
256 | spin_lock_irqsave(&pmac_pic_lock, flags); | ||
233 | for (irq = max_real_irqs; (irq -= 32) >= 0; ) { | 257 | for (irq = max_real_irqs; (irq -= 32) >= 0; ) { |
234 | int i = irq >> 5; | 258 | int i = irq >> 5; |
235 | bits = in_le32(&pmac_irq_hw[i]->event) | ppc_lost_interrupts[i]; | 259 | bits = in_le32(&pmac_irq_hw[i]->event) | ppc_lost_interrupts[i]; |
@@ -241,6 +265,7 @@ static int pmac_get_irq(struct pt_regs *regs) | |||
241 | irq += __ilog2(bits); | 265 | irq += __ilog2(bits); |
242 | break; | 266 | break; |
243 | } | 267 | } |
268 | spin_unlock_irqrestore(&pmac_pic_lock, flags); | ||
244 | 269 | ||
245 | return irq; | 270 | return irq; |
246 | } | 271 | } |
@@ -389,7 +414,6 @@ static struct irqaction gatwick_cascade_action = { | |||
389 | static void __init pmac_pic_probe_oldstyle(void) | 414 | static void __init pmac_pic_probe_oldstyle(void) |
390 | { | 415 | { |
391 | int i; | 416 | int i; |
392 | int irq_cascade = -1; | ||
393 | struct device_node *master = NULL; | 417 | struct device_node *master = NULL; |
394 | struct device_node *slave = NULL; | 418 | struct device_node *slave = NULL; |
395 | u8 __iomem *addr; | 419 | u8 __iomem *addr; |
@@ -443,9 +467,16 @@ static void __init pmac_pic_probe_oldstyle(void) | |||
443 | } | 467 | } |
444 | BUG_ON(master == NULL); | 468 | BUG_ON(master == NULL); |
445 | 469 | ||
446 | /* Set the handler for the main PIC */ | 470 | /* Mark level interrupts and set handlers */ |
447 | for ( i = 0; i < max_real_irqs ; i++ ) | 471 | for (i = 0; i < max_irqs; i++) { |
448 | irq_desc[i].chip = &pmac_pic; | 472 | int level = !!(level_mask[i >> 5] & (1UL << (i & 0x1f))); |
473 | if (level) | ||
474 | irq_desc[i].status |= IRQ_LEVEL; | ||
475 | else | ||
476 | irq_desc[i].status |= IRQ_DELAYED_DISABLE; | ||
477 | set_irq_chip_and_handler(i, &pmac_pic, level ? | ||
478 | handle_level_irq : handle_edge_irq); | ||
479 | } | ||
449 | 480 | ||
450 | /* Get addresses of first controller if we have a node for it */ | 481 | /* Get addresses of first controller if we have a node for it */ |
451 | BUG_ON(of_address_to_resource(master, 0, &r)); | 482 | BUG_ON(of_address_to_resource(master, 0, &r)); |
@@ -472,29 +503,22 @@ static void __init pmac_pic_probe_oldstyle(void) | |||
472 | pmac_irq_hw[i++] = | 503 | pmac_irq_hw[i++] = |
473 | (volatile struct pmac_irq_hw __iomem *) | 504 | (volatile struct pmac_irq_hw __iomem *) |
474 | (addr + 0x10); | 505 | (addr + 0x10); |
475 | irq_cascade = slave->intrs[0].line; | 506 | pmac_irq_cascade = slave->intrs[0].line; |
476 | 507 | ||
477 | printk(KERN_INFO "irq: Found slave Apple PIC %s for %d irqs" | 508 | printk(KERN_INFO "irq: Found slave Apple PIC %s for %d irqs" |
478 | " cascade: %d\n", slave->full_name, | 509 | " cascade: %d\n", slave->full_name, |
479 | max_irqs - max_real_irqs, irq_cascade); | 510 | max_irqs - max_real_irqs, pmac_irq_cascade); |
480 | } | 511 | } |
481 | of_node_put(slave); | 512 | of_node_put(slave); |
482 | 513 | ||
483 | /* disable all interrupts in all controllers */ | 514 | /* Disable all interrupts in all controllers */ |
484 | for (i = 0; i * 32 < max_irqs; ++i) | 515 | for (i = 0; i * 32 < max_irqs; ++i) |
485 | out_le32(&pmac_irq_hw[i]->enable, 0); | 516 | out_le32(&pmac_irq_hw[i]->enable, 0); |
486 | 517 | ||
487 | /* mark level interrupts */ | 518 | /* Hookup cascade irq */ |
488 | for (i = 0; i < max_irqs; i++) | 519 | if (slave) |
489 | if (level_mask[i >> 5] & (1UL << (i & 0x1f))) | 520 | setup_irq(pmac_irq_cascade, &gatwick_cascade_action); |
490 | irq_desc[i].status = IRQ_LEVEL; | ||
491 | 521 | ||
492 | /* Setup handlers for secondary controller and hook cascade irq*/ | ||
493 | if (slave) { | ||
494 | for ( i = max_real_irqs ; i < max_irqs ; i++ ) | ||
495 | irq_desc[i].chip = &gatwick_pic; | ||
496 | setup_irq(irq_cascade, &gatwick_cascade_action); | ||
497 | } | ||
498 | printk(KERN_INFO "irq: System has %d possible interrupts\n", max_irqs); | 522 | printk(KERN_INFO "irq: System has %d possible interrupts\n", max_irqs); |
499 | #ifdef CONFIG_XMON | 523 | #ifdef CONFIG_XMON |
500 | setup_irq(20, &xmon_action); | 524 | setup_irq(20, &xmon_action); |
@@ -502,9 +526,20 @@ static void __init pmac_pic_probe_oldstyle(void) | |||
502 | } | 526 | } |
503 | #endif /* CONFIG_PPC32 */ | 527 | #endif /* CONFIG_PPC32 */ |
504 | 528 | ||
505 | static int pmac_u3_cascade(struct pt_regs *regs, void *data) | 529 | static void pmac_u3_cascade(unsigned int irq, struct irq_desc *desc, |
530 | struct pt_regs *regs) | ||
506 | { | 531 | { |
507 | return mpic_get_one_irq((struct mpic *)data, regs); | 532 | struct mpic *mpic = desc->handler_data; |
533 | unsigned int max = 100; | ||
534 | |||
535 | while(max--) { | ||
536 | int cascade_irq = mpic_get_one_irq(mpic, regs); | ||
537 | if (max == 99) | ||
538 | desc->chip->eoi(irq); | ||
539 | if (irq < 0) | ||
540 | break; | ||
541 | generic_handle_irq(cascade_irq, regs); | ||
542 | }; | ||
508 | } | 543 | } |
509 | 544 | ||
510 | static void __init pmac_pic_setup_mpic_nmi(struct mpic *mpic) | 545 | static void __init pmac_pic_setup_mpic_nmi(struct mpic *mpic) |
@@ -612,7 +647,8 @@ static int __init pmac_pic_probe_mpic(void) | |||
612 | of_node_put(slave); | 647 | of_node_put(slave); |
613 | return 0; | 648 | return 0; |
614 | } | 649 | } |
615 | mpic_setup_cascade(slave->intrs[0].line, pmac_u3_cascade, mpic2); | 650 | set_irq_data(slave->intrs[0].line, mpic2); |
651 | set_irq_chained_handler(slave->intrs[0].line, pmac_u3_cascade); | ||
616 | 652 | ||
617 | of_node_put(slave); | 653 | of_node_put(slave); |
618 | return 0; | 654 | return 0; |