aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2009-08-13 06:17:22 -0400
committerThomas Gleixner <tglx@linutronix.de>2009-08-17 04:54:05 -0400
commitb25c340c195447afb1860da580fe2a85a6b652c5 (patch)
tree99578092c1e6100f50786e44a1a4fe9cfdb11662
parentb2add73dbf93fd50f00564d7abc3e2b9aa9dd20c (diff)
genirq: Add oneshot support
For threaded interrupt handlers we expect the hard interrupt handler part to mask the interrupt on the originating device. The interrupt line itself is reenabled after the hard interrupt handler has executed. This requires access to the originating device from hard interrupt context which is not always possible. There are devices which can only be accessed via a bus (i2c, spi, ...). The bus access requires thread context. For such devices we need to keep the interrupt line masked until the threaded handler has executed. Add a new flag IRQF_ONESHOT which allows drivers to request that the interrupt is not unmasked after the hard interrupt context handler has been executed and the thread has been woken. The interrupt line is unmasked after the thread handler function has been executed. Note that for now IRQF_ONESHOT cannot be used with IRQF_SHARED to avoid complex accounting mechanisms. For oneshot interrupts the primary handler simply returns IRQ_WAKE_THREAD and does nothing else. A generic implementation irq_default_primary_handler() is provided to avoid useless copies all over the place. It is automatically installed when request_threaded_irq() is called with handler=NULL and thread_fn!=NULL. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Cc: Mark Brown <broonie@opensource.wolfsonmicro.com> Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com> Cc: Trilok Soni <soni.trilok@gmail.com> Cc: Pavel Machek <pavel@ucw.cz> Cc: Brian Swetland <swetland@google.com> Cc: Joonyoung Shim <jy0922.shim@samsung.com> Cc: m.szyprowski@samsung.com Cc: t.fujak@samsung.com Cc: kyungmin.park@samsung.com, Cc: David Brownell <david-b@pacbell.net> Cc: Daniel Ribeiro <drwyrm@gmail.com> Cc: arve@android.com Cc: Barry Song <21cnbao@gmail.com>
-rw-r--r--include/linux/interrupt.h4
-rw-r--r--include/linux/irq.h1
-rw-r--r--kernel/irq/chip.c14
-rw-r--r--kernel/irq/manage.c49
4 files changed, 61 insertions, 7 deletions
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index 35e7df1e9f30..1ac57e522a1f 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -50,6 +50,9 @@
50 * IRQF_IRQPOLL - Interrupt is used for polling (only the interrupt that is 50 * IRQF_IRQPOLL - Interrupt is used for polling (only the interrupt that is
51 * registered first in an shared interrupt is considered for 51 * registered first in an shared interrupt is considered for
52 * performance reasons) 52 * performance reasons)
53 * IRQF_ONESHOT - Interrupt is not reenabled after the hardirq handler finished.
54 * Used by threaded interrupts which need to keep the
55 * irq line disabled until the threaded handler has been run.
53 */ 56 */
54#define IRQF_DISABLED 0x00000020 57#define IRQF_DISABLED 0x00000020
55#define IRQF_SAMPLE_RANDOM 0x00000040 58#define IRQF_SAMPLE_RANDOM 0x00000040
@@ -59,6 +62,7 @@
59#define IRQF_PERCPU 0x00000400 62#define IRQF_PERCPU 0x00000400
60#define IRQF_NOBALANCING 0x00000800 63#define IRQF_NOBALANCING 0x00000800
61#define IRQF_IRQPOLL 0x00001000 64#define IRQF_IRQPOLL 0x00001000
65#define IRQF_ONESHOT 0x00002000
62 66
63/* 67/*
64 * Bits used by threaded handlers: 68 * Bits used by threaded handlers:
diff --git a/include/linux/irq.h b/include/linux/irq.h
index cb2e77a3f7f7..5e7c6ee8c35c 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -69,6 +69,7 @@ typedef void (*irq_flow_handler_t)(unsigned int irq,
69#define IRQ_MOVE_PCNTXT 0x01000000 /* IRQ migration from process context */ 69#define IRQ_MOVE_PCNTXT 0x01000000 /* IRQ migration from process context */
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 73
73#ifdef CONFIG_IRQ_PER_CPU 74#ifdef CONFIG_IRQ_PER_CPU
74# define CHECK_IRQ_PER_CPU(var) ((var) & IRQ_PER_CPU) 75# define CHECK_IRQ_PER_CPU(var) ((var) & IRQ_PER_CPU)
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index 13c68e71b726..b08c0d24f202 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -382,7 +382,10 @@ handle_level_irq(unsigned int irq, struct irq_desc *desc)
382 382
383 spin_lock(&desc->lock); 383 spin_lock(&desc->lock);
384 desc->status &= ~IRQ_INPROGRESS; 384 desc->status &= ~IRQ_INPROGRESS;
385 if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask) 385
386 if (unlikely(desc->status & IRQ_ONESHOT))
387 desc->status |= IRQ_MASKED;
388 else if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask)
386 desc->chip->unmask(irq); 389 desc->chip->unmask(irq);
387out_unlock: 390out_unlock:
388 spin_unlock(&desc->lock); 391 spin_unlock(&desc->lock);
@@ -478,8 +481,13 @@ handle_edge_irq(unsigned int irq, struct irq_desc *desc)
478 kstat_incr_irqs_this_cpu(irq, desc); 481 kstat_incr_irqs_this_cpu(irq, desc);
479 482
480 /* Start handling the irq */ 483 /* Start handling the irq */
481 if (desc->chip->ack) 484 if (unlikely(desc->status & IRQ_ONESHOT)) {
482 desc->chip->ack(irq); 485 desc->status |= IRQ_MASKED;
486 mask_ack_irq(desc, irq);
487 } else {
488 if (desc->chip->ack)
489 desc->chip->ack(irq);
490 }
483 491
484 /* Mark the IRQ currently in progress.*/ 492 /* Mark the IRQ currently in progress.*/
485 desc->status |= IRQ_INPROGRESS; 493 desc->status |= IRQ_INPROGRESS;
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index d222515a5a06..d7f7b5fd2476 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -436,6 +436,16 @@ int __irq_set_trigger(struct irq_desc *desc, unsigned int irq,
436 return ret; 436 return ret;
437} 437}
438 438
439/*
440 * Default primary interrupt handler for threaded interrupts. Is
441 * assigned as primary handler when request_threaded_irq is called
442 * with handler == NULL. Useful for oneshot interrupts.
443 */
444static irqreturn_t irq_default_primary_handler(int irq, void *dev_id)
445{
446 return IRQ_WAKE_THREAD;
447}
448
439static int irq_wait_for_interrupt(struct irqaction *action) 449static int irq_wait_for_interrupt(struct irqaction *action)
440{ 450{
441 while (!kthread_should_stop()) { 451 while (!kthread_should_stop()) {
@@ -451,6 +461,21 @@ static int irq_wait_for_interrupt(struct irqaction *action)
451 return -1; 461 return -1;
452} 462}
453 463
464/*
465 * Oneshot interrupts keep the irq line masked until the threaded
466 * handler finished. unmask if the interrupt has not been disabled and
467 * is marked MASKED.
468 */
469static void irq_finalize_oneshot(unsigned int irq, struct irq_desc *desc)
470{
471 spin_lock_irq(&desc->lock);
472 if (!(desc->status & IRQ_DISABLED) && (desc->status & IRQ_MASKED)) {
473 desc->status &= ~IRQ_MASKED;
474 desc->chip->unmask(irq);
475 }
476 spin_unlock_irq(&desc->lock);
477}
478
454#ifdef CONFIG_SMP 479#ifdef CONFIG_SMP
455/* 480/*
456 * Check whether we need to change the affinity of the interrupt thread. 481 * Check whether we need to change the affinity of the interrupt thread.
@@ -492,7 +517,7 @@ static int irq_thread(void *data)
492 struct sched_param param = { .sched_priority = MAX_USER_RT_PRIO/2, }; 517 struct sched_param param = { .sched_priority = MAX_USER_RT_PRIO/2, };
493 struct irqaction *action = data; 518 struct irqaction *action = data;
494 struct irq_desc *desc = irq_to_desc(action->irq); 519 struct irq_desc *desc = irq_to_desc(action->irq);
495 int wake; 520 int wake, oneshot = desc->status & IRQ_ONESHOT;
496 521
497 sched_setscheduler(current, SCHED_FIFO, &param); 522 sched_setscheduler(current, SCHED_FIFO, &param);
498 current->irqaction = action; 523 current->irqaction = action;
@@ -518,6 +543,9 @@ static int irq_thread(void *data)
518 spin_unlock_irq(&desc->lock); 543 spin_unlock_irq(&desc->lock);
519 544
520 action->thread_fn(action->irq, action->dev_id); 545 action->thread_fn(action->irq, action->dev_id);
546
547 if (oneshot)
548 irq_finalize_oneshot(action->irq, desc);
521 } 549 }
522 550
523 wake = atomic_dec_and_test(&desc->threads_active); 551 wake = atomic_dec_and_test(&desc->threads_active);
@@ -590,6 +618,10 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
590 rand_initialize_irq(irq); 618 rand_initialize_irq(irq);
591 } 619 }
592 620
621 /* Oneshot interrupts are not allowed with shared */
622 if ((new->flags & IRQF_ONESHOT) && (new->flags & IRQF_SHARED))
623 return -EINVAL;
624
593 /* 625 /*
594 * Threaded handler ? 626 * Threaded handler ?
595 */ 627 */
@@ -663,9 +695,12 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
663 desc->status |= IRQ_PER_CPU; 695 desc->status |= IRQ_PER_CPU;
664#endif 696#endif
665 697
666 desc->status &= ~(IRQ_AUTODETECT | IRQ_WAITING | 698 desc->status &= ~(IRQ_AUTODETECT | IRQ_WAITING | IRQ_ONESHOT |
667 IRQ_INPROGRESS | IRQ_SPURIOUS_DISABLED); 699 IRQ_INPROGRESS | IRQ_SPURIOUS_DISABLED);
668 700
701 if (new->flags & IRQF_ONESHOT)
702 desc->status |= IRQ_ONESHOT;
703
669 if (!(desc->status & IRQ_NOAUTOEN)) { 704 if (!(desc->status & IRQ_NOAUTOEN)) {
670 desc->depth = 0; 705 desc->depth = 0;
671 desc->status &= ~IRQ_DISABLED; 706 desc->status &= ~IRQ_DISABLED;
@@ -878,6 +913,8 @@ EXPORT_SYMBOL(free_irq);
878 * @irq: Interrupt line to allocate 913 * @irq: Interrupt line to allocate
879 * @handler: Function to be called when the IRQ occurs. 914 * @handler: Function to be called when the IRQ occurs.
880 * Primary handler for threaded interrupts 915 * Primary handler for threaded interrupts
916 * If NULL and thread_fn != NULL the default
917 * primary handler is installed
881 * @thread_fn: Function called from the irq handler thread 918 * @thread_fn: Function called from the irq handler thread
882 * If NULL, no irq thread is created 919 * If NULL, no irq thread is created
883 * @irqflags: Interrupt type flags 920 * @irqflags: Interrupt type flags
@@ -957,8 +994,12 @@ int request_threaded_irq(unsigned int irq, irq_handler_t handler,
957 994
958 if (desc->status & IRQ_NOREQUEST) 995 if (desc->status & IRQ_NOREQUEST)
959 return -EINVAL; 996 return -EINVAL;
960 if (!handler) 997
961 return -EINVAL; 998 if (!handler) {
999 if (!thread_fn)
1000 return -EINVAL;
1001 handler = irq_default_primary_handler;
1002 }
962 1003
963 action = kzalloc(sizeof(struct irqaction), GFP_KERNEL); 1004 action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);
964 if (!action) 1005 if (!action)