diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-06-15 12:32:52 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-06-15 12:32:52 -0400 |
commit | 0fa213310cd8fa7a51071cdcf130e26fa56e9549 (patch) | |
tree | 2a7e5cc33c8938ec82604a99c3797a3132fd91ec /arch/powerpc/kernel/irq.c | |
parent | d3bf80bff13597004b5724ee4549cd68eb0badf0 (diff) | |
parent | bc47ab0241c7c86da4f5e5f82fbca7d45387c18d (diff) |
Merge branch 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc
* 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc: (103 commits)
powerpc: Fix bug in move of altivec code to vector.S
powerpc: Add support for swiotlb on 32-bit
powerpc/spufs: Remove unused error path
powerpc: Fix warning when printing a resource_size_t
powerpc/xmon: Remove unused variable in xmon.c
powerpc/pseries: Fix warnings when printing resource_size_t
powerpc: Shield code specific to 64-bit server processors
powerpc: Separate PACA fields for server CPUs
powerpc: Split exception handling out of head_64.S
powerpc: Introduce CONFIG_PPC_BOOK3S
powerpc: Move VMX and VSX asm code to vector.S
powerpc: Set init_bootmem_done on NUMA platforms as well
powerpc/mm: Fix a AB->BA deadlock scenario with nohash MMU context lock
powerpc/mm: Fix some SMP issues with MMU context handling
powerpc: Add PTRACE_SINGLEBLOCK support
fbdev: Add PLB support and cleanup DCR in xilinxfb driver.
powerpc/virtex: Add ml510 reference design device tree
powerpc/virtex: Add Xilinx ML510 reference design support
powerpc/virtex: refactor intc driver and add support for i8259 cascading
powerpc/virtex: Add support for Xilinx PCI host bridge
...
Diffstat (limited to 'arch/powerpc/kernel/irq.c')
-rw-r--r-- | arch/powerpc/kernel/irq.c | 123 |
1 files changed, 66 insertions, 57 deletions
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 844d3f882a15..f7f376ea7b17 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c | |||
@@ -118,6 +118,7 @@ notrace void raw_local_irq_restore(unsigned long en) | |||
118 | if (!en) | 118 | if (!en) |
119 | return; | 119 | return; |
120 | 120 | ||
121 | #ifdef CONFIG_PPC_STD_MMU_64 | ||
121 | if (firmware_has_feature(FW_FEATURE_ISERIES)) { | 122 | if (firmware_has_feature(FW_FEATURE_ISERIES)) { |
122 | /* | 123 | /* |
123 | * Do we need to disable preemption here? Not really: in the | 124 | * Do we need to disable preemption here? Not really: in the |
@@ -135,6 +136,7 @@ notrace void raw_local_irq_restore(unsigned long en) | |||
135 | if (local_paca->lppaca_ptr->int_dword.any_int) | 136 | if (local_paca->lppaca_ptr->int_dword.any_int) |
136 | iseries_handle_interrupts(); | 137 | iseries_handle_interrupts(); |
137 | } | 138 | } |
139 | #endif /* CONFIG_PPC_STD_MMU_64 */ | ||
138 | 140 | ||
139 | if (test_perf_counter_pending()) { | 141 | if (test_perf_counter_pending()) { |
140 | clear_perf_counter_pending(); | 142 | clear_perf_counter_pending(); |
@@ -254,77 +256,84 @@ void fixup_irqs(cpumask_t map) | |||
254 | } | 256 | } |
255 | #endif | 257 | #endif |
256 | 258 | ||
257 | void do_IRQ(struct pt_regs *regs) | ||
258 | { | ||
259 | struct pt_regs *old_regs = set_irq_regs(regs); | ||
260 | unsigned int irq; | ||
261 | #ifdef CONFIG_IRQSTACKS | 259 | #ifdef CONFIG_IRQSTACKS |
260 | static inline void handle_one_irq(unsigned int irq) | ||
261 | { | ||
262 | struct thread_info *curtp, *irqtp; | 262 | struct thread_info *curtp, *irqtp; |
263 | #endif | 263 | unsigned long saved_sp_limit; |
264 | struct irq_desc *desc; | ||
264 | 265 | ||
265 | irq_enter(); | 266 | /* Switch to the irq stack to handle this */ |
267 | curtp = current_thread_info(); | ||
268 | irqtp = hardirq_ctx[smp_processor_id()]; | ||
269 | |||
270 | if (curtp == irqtp) { | ||
271 | /* We're already on the irq stack, just handle it */ | ||
272 | generic_handle_irq(irq); | ||
273 | return; | ||
274 | } | ||
275 | |||
276 | desc = irq_desc + irq; | ||
277 | saved_sp_limit = current->thread.ksp_limit; | ||
278 | |||
279 | irqtp->task = curtp->task; | ||
280 | irqtp->flags = 0; | ||
281 | |||
282 | /* Copy the softirq bits in preempt_count so that the | ||
283 | * softirq checks work in the hardirq context. */ | ||
284 | irqtp->preempt_count = (irqtp->preempt_count & ~SOFTIRQ_MASK) | | ||
285 | (curtp->preempt_count & SOFTIRQ_MASK); | ||
286 | |||
287 | current->thread.ksp_limit = (unsigned long)irqtp + | ||
288 | _ALIGN_UP(sizeof(struct thread_info), 16); | ||
289 | |||
290 | call_handle_irq(irq, desc, irqtp, desc->handle_irq); | ||
291 | current->thread.ksp_limit = saved_sp_limit; | ||
292 | irqtp->task = NULL; | ||
293 | |||
294 | /* Set any flag that may have been set on the | ||
295 | * alternate stack | ||
296 | */ | ||
297 | if (irqtp->flags) | ||
298 | set_bits(irqtp->flags, &curtp->flags); | ||
299 | } | ||
300 | #else | ||
301 | static inline void handle_one_irq(unsigned int irq) | ||
302 | { | ||
303 | generic_handle_irq(irq); | ||
304 | } | ||
305 | #endif | ||
266 | 306 | ||
307 | static inline void check_stack_overflow(void) | ||
308 | { | ||
267 | #ifdef CONFIG_DEBUG_STACKOVERFLOW | 309 | #ifdef CONFIG_DEBUG_STACKOVERFLOW |
268 | /* Debugging check for stack overflow: is there less than 2KB free? */ | 310 | long sp; |
269 | { | ||
270 | long sp; | ||
271 | 311 | ||
272 | sp = __get_SP() & (THREAD_SIZE-1); | 312 | sp = __get_SP() & (THREAD_SIZE-1); |
273 | 313 | ||
274 | if (unlikely(sp < (sizeof(struct thread_info) + 2048))) { | 314 | /* check for stack overflow: is there less than 2KB free? */ |
275 | printk("do_IRQ: stack overflow: %ld\n", | 315 | if (unlikely(sp < (sizeof(struct thread_info) + 2048))) { |
276 | sp - sizeof(struct thread_info)); | 316 | printk("do_IRQ: stack overflow: %ld\n", |
277 | dump_stack(); | 317 | sp - sizeof(struct thread_info)); |
278 | } | 318 | dump_stack(); |
279 | } | 319 | } |
280 | #endif | 320 | #endif |
321 | } | ||
281 | 322 | ||
282 | /* | 323 | void do_IRQ(struct pt_regs *regs) |
283 | * Every platform is required to implement ppc_md.get_irq. | 324 | { |
284 | * This function will either return an irq number or NO_IRQ to | 325 | struct pt_regs *old_regs = set_irq_regs(regs); |
285 | * indicate there are no more pending. | 326 | unsigned int irq; |
286 | * The value NO_IRQ_IGNORE is for buggy hardware and means that this | ||
287 | * IRQ has already been handled. -- Tom | ||
288 | */ | ||
289 | irq = ppc_md.get_irq(); | ||
290 | 327 | ||
291 | if (irq != NO_IRQ && irq != NO_IRQ_IGNORE) { | 328 | irq_enter(); |
292 | #ifdef CONFIG_IRQSTACKS | ||
293 | /* Switch to the irq stack to handle this */ | ||
294 | curtp = current_thread_info(); | ||
295 | irqtp = hardirq_ctx[smp_processor_id()]; | ||
296 | if (curtp != irqtp) { | ||
297 | struct irq_desc *desc = irq_desc + irq; | ||
298 | void *handler = desc->handle_irq; | ||
299 | unsigned long saved_sp_limit = current->thread.ksp_limit; | ||
300 | if (handler == NULL) | ||
301 | handler = &__do_IRQ; | ||
302 | irqtp->task = curtp->task; | ||
303 | irqtp->flags = 0; | ||
304 | |||
305 | /* Copy the softirq bits in preempt_count so that the | ||
306 | * softirq checks work in the hardirq context. | ||
307 | */ | ||
308 | irqtp->preempt_count = | ||
309 | (irqtp->preempt_count & ~SOFTIRQ_MASK) | | ||
310 | (curtp->preempt_count & SOFTIRQ_MASK); | ||
311 | 329 | ||
312 | current->thread.ksp_limit = (unsigned long)irqtp + | 330 | check_stack_overflow(); |
313 | _ALIGN_UP(sizeof(struct thread_info), 16); | ||
314 | call_handle_irq(irq, desc, irqtp, handler); | ||
315 | current->thread.ksp_limit = saved_sp_limit; | ||
316 | irqtp->task = NULL; | ||
317 | 331 | ||
332 | irq = ppc_md.get_irq(); | ||
318 | 333 | ||
319 | /* Set any flag that may have been set on the | 334 | if (irq != NO_IRQ && irq != NO_IRQ_IGNORE) |
320 | * alternate stack | 335 | handle_one_irq(irq); |
321 | */ | 336 | else if (irq != NO_IRQ_IGNORE) |
322 | if (irqtp->flags) | ||
323 | set_bits(irqtp->flags, &curtp->flags); | ||
324 | } else | ||
325 | #endif | ||
326 | generic_handle_irq(irq); | ||
327 | } else if (irq != NO_IRQ_IGNORE) | ||
328 | /* That's not SMP safe ... but who cares ? */ | 337 | /* That's not SMP safe ... but who cares ? */ |
329 | ppc_spurious_interrupts++; | 338 | ppc_spurious_interrupts++; |
330 | 339 | ||