Commit ae731f8d0785ccd3380f511bae888933b6562e45
Committed by
Thomas Gleixner
1 parent
7c7145f6ac
Exists in
master
and in
7 other branches
genirq: Introduce request_any_context_irq()
Now that we enjoy threaded interrupts, we're starting to see irq_chip implementations (wm831x, pca953x) that make use of threaded interrupts for the controller, and nested interrupts for the client interrupt. It all works very well, with one drawback: Drivers requesting an IRQ must now know whether the handler will run in a thread context or not, and call request_threaded_irq() or request_irq() accordingly. The problem is that the requesting driver sometimes doesn't know about the nature of the interrupt, specially when the interrupt controller is a discrete chip (typically a GPIO expander connected over I2C) that can be connected to a wide variety of otherwise perfectly supported hardware. This patch introduces the request_any_context_irq() function that mostly mimics the usual request_irq(), except that it checks whether the irq level is configured as nested or not, and calls the right backend. On success, it also returns either IRQC_IS_HARDIRQ or IRQC_IS_NESTED. [ tglx: Made return value an enum, simplified code and made the export of request_any_context_irq GPL ] Signed-off-by: Marc Zyngier <maz@misterjones.org> Cc: <joachim.eastwood@jotron.com> LKML-Reference: <927ea285bd0c68934ddae1a47e44a9ba@localhost> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Showing 2 changed files with 60 additions and 0 deletions Side-by-side Diff
include/linux/interrupt.h
... | ... | @@ -77,6 +77,18 @@ |
77 | 77 | IRQTF_AFFINITY, |
78 | 78 | }; |
79 | 79 | |
80 | +/** | |
81 | + * These values can be returned by request_any_context_irq() and | |
82 | + * describe the context the interrupt will be run in. | |
83 | + * | |
84 | + * IRQC_IS_HARDIRQ - interrupt runs in hardirq context | |
85 | + * IRQC_IS_NESTED - interrupt runs in a nested threaded context | |
86 | + */ | |
87 | +enum { | |
88 | + IRQC_IS_HARDIRQ = 0, | |
89 | + IRQC_IS_NESTED, | |
90 | +}; | |
91 | + | |
80 | 92 | typedef irqreturn_t (*irq_handler_t)(int, void *); |
81 | 93 | |
82 | 94 | /** |
... | ... | @@ -120,6 +132,10 @@ |
120 | 132 | return request_threaded_irq(irq, handler, NULL, flags, name, dev); |
121 | 133 | } |
122 | 134 | |
135 | +extern int __must_check | |
136 | +request_any_context_irq(unsigned int irq, irq_handler_t handler, | |
137 | + unsigned long flags, const char *name, void *dev_id); | |
138 | + | |
123 | 139 | extern void exit_irq_thread(void); |
124 | 140 | #else |
125 | 141 | |
... | ... | @@ -139,6 +155,13 @@ |
139 | 155 | unsigned long flags, const char *name, void *dev) |
140 | 156 | { |
141 | 157 | return request_irq(irq, handler, flags, name, dev); |
158 | +} | |
159 | + | |
160 | +static inline int __must_check | |
161 | +request_any_context_irq(unsigned int irq, irq_handler_t handler, | |
162 | + unsigned long flags, const char *name, void *dev_id) | |
163 | +{ | |
164 | + return request_irq(irq, handler, flags, name, dev_id); | |
142 | 165 | } |
143 | 166 | |
144 | 167 | static inline void exit_irq_thread(void) { } |
kernel/irq/manage.c
... | ... | @@ -1120,4 +1120,41 @@ |
1120 | 1120 | return retval; |
1121 | 1121 | } |
1122 | 1122 | EXPORT_SYMBOL(request_threaded_irq); |
1123 | + | |
1124 | +/** | |
1125 | + * request_any_context_irq - allocate an interrupt line | |
1126 | + * @irq: Interrupt line to allocate | |
1127 | + * @handler: Function to be called when the IRQ occurs. | |
1128 | + * Threaded handler for threaded interrupts. | |
1129 | + * @flags: Interrupt type flags | |
1130 | + * @name: An ascii name for the claiming device | |
1131 | + * @dev_id: A cookie passed back to the handler function | |
1132 | + * | |
1133 | + * This call allocates interrupt resources and enables the | |
1134 | + * interrupt line and IRQ handling. It selects either a | |
1135 | + * hardirq or threaded handling method depending on the | |
1136 | + * context. | |
1137 | + * | |
1138 | + * On failure, it returns a negative value. On success, | |
1139 | + * it returns either IRQC_IS_HARDIRQ or IRQC_IS_NESTED. | |
1140 | + */ | |
1141 | +int request_any_context_irq(unsigned int irq, irq_handler_t handler, | |
1142 | + unsigned long flags, const char *name, void *dev_id) | |
1143 | +{ | |
1144 | + struct irq_desc *desc = irq_to_desc(irq); | |
1145 | + int ret; | |
1146 | + | |
1147 | + if (!desc) | |
1148 | + return -EINVAL; | |
1149 | + | |
1150 | + if (desc->status & IRQ_NESTED_THREAD) { | |
1151 | + ret = request_threaded_irq(irq, NULL, handler, | |
1152 | + flags, name, dev_id); | |
1153 | + return !ret ? IRQC_IS_NESTED : ret; | |
1154 | + } | |
1155 | + | |
1156 | + ret = request_irq(irq, handler, flags, name, dev_id); | |
1157 | + return !ret ? IRQC_IS_HARDIRQ : ret; | |
1158 | +} | |
1159 | +EXPORT_SYMBOL_GPL(request_any_context_irq); |