aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/irq.h3
-rw-r--r--kernel/irq/chip.c67
-rw-r--r--kernel/irq/manage.c34
3 files changed, 101 insertions, 3 deletions
diff --git a/include/linux/irq.h b/include/linux/irq.h
index ce8171bc6fac..8778ee993937 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -70,6 +70,7 @@ typedef void (*irq_flow_handler_t)(unsigned int irq,
70#define IRQ_AFFINITY_SET 0x02000000 /* IRQ affinity was set from userspace*/ 70#define IRQ_AFFINITY_SET 0x02000000 /* IRQ affinity was set from userspace*/
71#define IRQ_SUSPENDED 0x04000000 /* IRQ has gone through suspend sequence */ 71#define IRQ_SUSPENDED 0x04000000 /* IRQ has gone through suspend sequence */
72#define IRQ_ONESHOT 0x08000000 /* IRQ is not unmasked after hardirq */ 72#define IRQ_ONESHOT 0x08000000 /* IRQ is not unmasked after hardirq */
73#define IRQ_NESTED_THREAD 0x10000000 /* IRQ is nested into another, no own handler thread */
73 74
74#ifdef CONFIG_IRQ_PER_CPU 75#ifdef CONFIG_IRQ_PER_CPU
75# define CHECK_IRQ_PER_CPU(var) ((var) & IRQ_PER_CPU) 76# define CHECK_IRQ_PER_CPU(var) ((var) & IRQ_PER_CPU)
@@ -386,6 +387,8 @@ set_irq_chained_handler(unsigned int irq,
386 __set_irq_handler(irq, handle, 1, NULL); 387 __set_irq_handler(irq, handle, 1, NULL);
387} 388}
388 389
390extern void set_irq_nested_thread(unsigned int irq, int nest);
391
389extern void set_irq_noprobe(unsigned int irq); 392extern void set_irq_noprobe(unsigned int irq);
390extern void set_irq_probe(unsigned int irq); 393extern void set_irq_probe(unsigned int irq);
391 394
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index f856330e684a..5765aad94998 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -222,6 +222,34 @@ int set_irq_chip_data(unsigned int irq, void *data)
222} 222}
223EXPORT_SYMBOL(set_irq_chip_data); 223EXPORT_SYMBOL(set_irq_chip_data);
224 224
225/**
226 * set_irq_nested_thread - Set/Reset the IRQ_NESTED_THREAD flag of an irq
227 *
228 * @irq: Interrupt number
229 * @nest: 0 to clear / 1 to set the IRQ_NESTED_THREAD flag
230 *
231 * The IRQ_NESTED_THREAD flag indicates that on
232 * request_threaded_irq() no separate interrupt thread should be
233 * created for the irq as the handler are called nested in the
234 * context of a demultiplexing interrupt handler thread.
235 */
236void set_irq_nested_thread(unsigned int irq, int nest)
237{
238 struct irq_desc *desc = irq_to_desc(irq);
239 unsigned long flags;
240
241 if (!desc)
242 return;
243
244 spin_lock_irqsave(&desc->lock, flags);
245 if (nest)
246 desc->status |= IRQ_NESTED_THREAD;
247 else
248 desc->status &= ~IRQ_NESTED_THREAD;
249 spin_unlock_irqrestore(&desc->lock, flags);
250}
251EXPORT_SYMBOL_GPL(set_irq_nested_thread);
252
225/* 253/*
226 * default enable function 254 * default enable function
227 */ 255 */
@@ -299,6 +327,45 @@ static inline void mask_ack_irq(struct irq_desc *desc, int irq)
299 } 327 }
300} 328}
301 329
330/*
331 * handle_nested_irq - Handle a nested irq from a irq thread
332 * @irq: the interrupt number
333 *
334 * Handle interrupts which are nested into a threaded interrupt
335 * handler. The handler function is called inside the calling
336 * threads context.
337 */
338void handle_nested_irq(unsigned int irq)
339{
340 struct irq_desc *desc = irq_to_desc(irq);
341 struct irqaction *action;
342 irqreturn_t action_ret;
343
344 might_sleep();
345
346 spin_lock_irq(&desc->lock);
347
348 kstat_incr_irqs_this_cpu(irq, desc);
349
350 action = desc->action;
351 if (unlikely(!action || (desc->status & IRQ_DISABLED)))
352 goto out_unlock;
353
354 desc->status |= IRQ_INPROGRESS;
355 spin_unlock_irq(&desc->lock);
356
357 action_ret = action->thread_fn(action->irq, action->dev_id);
358 if (!noirqdebug)
359 note_interrupt(irq, desc, action_ret);
360
361 spin_lock_irq(&desc->lock);
362 desc->status &= ~IRQ_INPROGRESS;
363
364out_unlock:
365 spin_unlock_irq(&desc->lock);
366}
367EXPORT_SYMBOL_GPL(handle_nested_irq);
368
302/** 369/**
303 * handle_simple_irq - Simple and software-decoded IRQs. 370 * handle_simple_irq - Simple and software-decoded IRQs.
304 * @irq: the interrupt number 371 * @irq: the interrupt number
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 0a3fd5b524c9..e485cea04bf1 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -451,6 +451,16 @@ static irqreturn_t irq_default_primary_handler(int irq, void *dev_id)
451 return IRQ_WAKE_THREAD; 451 return IRQ_WAKE_THREAD;
452} 452}
453 453
454/*
455 * Primary handler for nested threaded interrupts. Should never be
456 * called.
457 */
458static irqreturn_t irq_nested_primary_handler(int irq, void *dev_id)
459{
460 WARN(1, "Primary handler called for nested irq %d\n", irq);
461 return IRQ_NONE;
462}
463
454static int irq_wait_for_interrupt(struct irqaction *action) 464static int irq_wait_for_interrupt(struct irqaction *action)
455{ 465{
456 while (!kthread_should_stop()) { 466 while (!kthread_should_stop()) {
@@ -600,7 +610,7 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
600 struct irqaction *old, **old_ptr; 610 struct irqaction *old, **old_ptr;
601 const char *old_name = NULL; 611 const char *old_name = NULL;
602 unsigned long flags; 612 unsigned long flags;
603 int shared = 0; 613 int nested, shared = 0;
604 int ret; 614 int ret;
605 615
606 if (!desc) 616 if (!desc)
@@ -630,9 +640,27 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
630 return -EINVAL; 640 return -EINVAL;
631 641
632 /* 642 /*
633 * Threaded handler ? 643 * Check whether the interrupt nests into another interrupt
644 * thread.
645 */
646 nested = desc->status & IRQ_NESTED_THREAD;
647 if (nested) {
648 if (!new->thread_fn)
649 return -EINVAL;
650 /*
651 * Replace the primary handler which was provided from
652 * the driver for non nested interrupt handling by the
653 * dummy function which warns when called.
654 */
655 new->handler = irq_nested_primary_handler;
656 }
657
658 /*
659 * Create a handler thread when a thread function is supplied
660 * and the interrupt does not nest into another interrupt
661 * thread.
634 */ 662 */
635 if (new->thread_fn) { 663 if (new->thread_fn && !nested) {
636 struct task_struct *t; 664 struct task_struct *t;
637 665
638 t = kthread_create(irq_thread, new, "irq/%d-%s", irq, 666 t = kthread_create(irq_thread, new, "irq/%d-%s", irq,