diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2009-03-23 13:28:15 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2009-03-24 07:15:23 -0400 |
commit | 3aa551c9b4c40018f0e261a178e3d25478dc04a9 (patch) | |
tree | 2a696109273fcc421d774cc8fefa4180331a85ad /include | |
parent | 80c5520811d3805adcb15c570ea5e2d489fa5d0b (diff) |
genirq: add threaded interrupt handler support
Add support for threaded interrupt handlers:
A device driver can request that its main interrupt handler runs in a
thread. To achive this the device driver requests the interrupt with
request_threaded_irq() and provides additionally to the handler a
thread function. The handler function is called in hard interrupt
context and needs to check whether the interrupt originated from the
device. If the interrupt originated from the device then the handler
can either return IRQ_HANDLED or IRQ_WAKE_THREAD. IRQ_HANDLED is
returned when no further action is required. IRQ_WAKE_THREAD causes
the genirq code to invoke the threaded (main) handler. When
IRQ_WAKE_THREAD is returned handler must have disabled the interrupt
on the device level. This is mandatory for shared interrupt handlers,
but we need to do it as well for obscure x86 hardware where disabling
an interrupt on the IO_APIC level redirects the interrupt to the
legacy PIC interrupt lines.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'include')
-rw-r--r-- | include/linux/hardirq.h | 2 | ||||
-rw-r--r-- | include/linux/interrupt.h | 37 | ||||
-rw-r--r-- | include/linux/irq.h | 5 | ||||
-rw-r--r-- | include/linux/irqreturn.h | 2 | ||||
-rw-r--r-- | include/linux/sched.h | 5 |
5 files changed, 48 insertions, 3 deletions
diff --git a/include/linux/hardirq.h b/include/linux/hardirq.h index f83288347dda..2dfaadbdb2ac 100644 --- a/include/linux/hardirq.h +++ b/include/linux/hardirq.h | |||
@@ -105,7 +105,7 @@ | |||
105 | # define IRQ_EXIT_OFFSET HARDIRQ_OFFSET | 105 | # define IRQ_EXIT_OFFSET HARDIRQ_OFFSET |
106 | #endif | 106 | #endif |
107 | 107 | ||
108 | #ifdef CONFIG_SMP | 108 | #if defined(CONFIG_SMP) || defined(CONFIG_GENERIC_HARDIRQS) |
109 | extern void synchronize_irq(unsigned int irq); | 109 | extern void synchronize_irq(unsigned int irq); |
110 | #else | 110 | #else |
111 | # define synchronize_irq(irq) barrier() | 111 | # define synchronize_irq(irq) barrier() |
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index 0c9cb63e6895..6fc2b720c231 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h | |||
@@ -59,6 +59,16 @@ | |||
59 | #define IRQF_NOBALANCING 0x00000800 | 59 | #define IRQF_NOBALANCING 0x00000800 |
60 | #define IRQF_IRQPOLL 0x00001000 | 60 | #define IRQF_IRQPOLL 0x00001000 |
61 | 61 | ||
62 | /* | ||
63 | * Bits used by threaded handlers: | ||
64 | * IRQTF_RUNTHREAD - signals that the interrupt handler thread should run | ||
65 | * IRQTF_DIED - handler thread died | ||
66 | */ | ||
67 | enum { | ||
68 | IRQTF_RUNTHREAD, | ||
69 | IRQTF_DIED, | ||
70 | }; | ||
71 | |||
62 | typedef irqreturn_t (*irq_handler_t)(int, void *); | 72 | typedef irqreturn_t (*irq_handler_t)(int, void *); |
63 | 73 | ||
64 | /** | 74 | /** |
@@ -71,6 +81,9 @@ typedef irqreturn_t (*irq_handler_t)(int, void *); | |||
71 | * @next: pointer to the next irqaction for shared interrupts | 81 | * @next: pointer to the next irqaction for shared interrupts |
72 | * @irq: interrupt number | 82 | * @irq: interrupt number |
73 | * @dir: pointer to the proc/irq/NN/name entry | 83 | * @dir: pointer to the proc/irq/NN/name entry |
84 | * @thread_fn: interupt handler function for threaded interrupts | ||
85 | * @thread: thread pointer for threaded interrupts | ||
86 | * @thread_flags: flags related to @thread | ||
74 | */ | 87 | */ |
75 | struct irqaction { | 88 | struct irqaction { |
76 | irq_handler_t handler; | 89 | irq_handler_t handler; |
@@ -81,11 +94,31 @@ struct irqaction { | |||
81 | struct irqaction *next; | 94 | struct irqaction *next; |
82 | int irq; | 95 | int irq; |
83 | struct proc_dir_entry *dir; | 96 | struct proc_dir_entry *dir; |
97 | irq_handler_t thread_fn; | ||
98 | struct task_struct *thread; | ||
99 | unsigned long thread_flags; | ||
84 | }; | 100 | }; |
85 | 101 | ||
86 | extern irqreturn_t no_action(int cpl, void *dev_id); | 102 | extern irqreturn_t no_action(int cpl, void *dev_id); |
87 | extern int __must_check request_irq(unsigned int, irq_handler_t handler, | 103 | |
88 | unsigned long, const char *, void *); | 104 | extern int __must_check |
105 | request_threaded_irq(unsigned int irq, irq_handler_t handler, | ||
106 | irq_handler_t thread_fn, | ||
107 | unsigned long flags, const char *name, void *dev); | ||
108 | |||
109 | static inline int __must_check | ||
110 | request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, | ||
111 | const char *name, void *dev) | ||
112 | { | ||
113 | return request_threaded_irq(irq, handler, NULL, flags, name, dev); | ||
114 | } | ||
115 | |||
116 | #ifdef CONFIG_GENERIC_HARDIRQS | ||
117 | extern void exit_irq_thread(void); | ||
118 | #else | ||
119 | static inline void exit_irq_thread(void) { } | ||
120 | #endif | ||
121 | |||
89 | extern void free_irq(unsigned int, void *); | 122 | extern void free_irq(unsigned int, void *); |
90 | 123 | ||
91 | struct device; | 124 | struct device; |
diff --git a/include/linux/irq.h b/include/linux/irq.h index 873e4ac11b81..8b1cf0630210 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/irqreturn.h> | 20 | #include <linux/irqreturn.h> |
21 | #include <linux/irqnr.h> | 21 | #include <linux/irqnr.h> |
22 | #include <linux/errno.h> | 22 | #include <linux/errno.h> |
23 | #include <linux/wait.h> | ||
23 | 24 | ||
24 | #include <asm/irq.h> | 25 | #include <asm/irq.h> |
25 | #include <asm/ptrace.h> | 26 | #include <asm/ptrace.h> |
@@ -155,6 +156,8 @@ struct irq_2_iommu; | |||
155 | * @affinity: IRQ affinity on SMP | 156 | * @affinity: IRQ affinity on SMP |
156 | * @cpu: cpu index useful for balancing | 157 | * @cpu: cpu index useful for balancing |
157 | * @pending_mask: pending rebalanced interrupts | 158 | * @pending_mask: pending rebalanced interrupts |
159 | * @threads_active: number of irqaction threads currently running | ||
160 | * @wait_for_threads: wait queue for sync_irq to wait for threaded handlers | ||
158 | * @dir: /proc/irq/ procfs entry | 161 | * @dir: /proc/irq/ procfs entry |
159 | * @name: flow handler name for /proc/interrupts output | 162 | * @name: flow handler name for /proc/interrupts output |
160 | */ | 163 | */ |
@@ -186,6 +189,8 @@ struct irq_desc { | |||
186 | cpumask_var_t pending_mask; | 189 | cpumask_var_t pending_mask; |
187 | #endif | 190 | #endif |
188 | #endif | 191 | #endif |
192 | atomic_t threads_active; | ||
193 | wait_queue_head_t wait_for_threads; | ||
189 | #ifdef CONFIG_PROC_FS | 194 | #ifdef CONFIG_PROC_FS |
190 | struct proc_dir_entry *dir; | 195 | struct proc_dir_entry *dir; |
191 | #endif | 196 | #endif |
diff --git a/include/linux/irqreturn.h b/include/linux/irqreturn.h index c5584ca5b8c9..819acaaac3f5 100644 --- a/include/linux/irqreturn.h +++ b/include/linux/irqreturn.h | |||
@@ -5,10 +5,12 @@ | |||
5 | * enum irqreturn | 5 | * enum irqreturn |
6 | * @IRQ_NONE interrupt was not from this device | 6 | * @IRQ_NONE interrupt was not from this device |
7 | * @IRQ_HANDLED interrupt was handled by this device | 7 | * @IRQ_HANDLED interrupt was handled by this device |
8 | * @IRQ_WAKE_THREAD handler requests to wake the handler thread | ||
8 | */ | 9 | */ |
9 | enum irqreturn { | 10 | enum irqreturn { |
10 | IRQ_NONE, | 11 | IRQ_NONE, |
11 | IRQ_HANDLED, | 12 | IRQ_HANDLED, |
13 | IRQ_WAKE_THREAD, | ||
12 | }; | 14 | }; |
13 | 15 | ||
14 | typedef enum irqreturn irqreturn_t; | 16 | typedef enum irqreturn irqreturn_t; |
diff --git a/include/linux/sched.h b/include/linux/sched.h index 46d680643f89..38b77b0f56e5 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
@@ -1292,6 +1292,11 @@ struct task_struct { | |||
1292 | /* Protection of (de-)allocation: mm, files, fs, tty, keyrings */ | 1292 | /* Protection of (de-)allocation: mm, files, fs, tty, keyrings */ |
1293 | spinlock_t alloc_lock; | 1293 | spinlock_t alloc_lock; |
1294 | 1294 | ||
1295 | #ifdef CONFIG_GENERIC_HARDIRQS | ||
1296 | /* IRQ handler threads */ | ||
1297 | struct irqaction *irqaction; | ||
1298 | #endif | ||
1299 | |||
1295 | /* Protection of the PI data structures: */ | 1300 | /* Protection of the PI data structures: */ |
1296 | spinlock_t pi_lock; | 1301 | spinlock_t pi_lock; |
1297 | 1302 | ||