Commit ae731f8d0785ccd3380f511bae888933b6562e45

Authored by Marc Zyngier
Committed by Thomas Gleixner
1 parent 7c7145f6ac

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) { }
... ... @@ -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);