irq/core changes for v2.6.40
Subsystems (2)
Linus,
Please pull the latest irq-core-for-linus git tree from:
git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip.git irq-core-for-linus
Thanks,
Ingo
------------------>
Geert Uytterhoeven (3):
genirq: Forgotten updates/deletions after removal of compat code
genirq: Update DocBook comments
genirq: irq_desc: Document preflow_handler and affinity_hint
Jonathan Cameron (1):
irq: Export functions to allow modular irq drivers
Paul Mundt (1):
genirq: Support per-IRQ thread disabling.
Thomas Gleixner (5):
genirq: Implement a generic interrupt chip
genirq: Add chip suspend and resume callbacks
genirq: Make generic irq chip depend on CONFIG_GENERIC_IRQ_CHIP
genirq: Remove pointless ifdefs
genirq: Uninline and sanity check generic_handle_irq()
Documentation/DocBook/genericirq.tmpl | 82 +++++---- include/linux/irq.h | 179 +++++++++++++++-- include/linux/irqdesc.h | 11 +- kernel/irq/Kconfig | 4 + kernel/irq/Makefile | 1 + kernel/irq/chip.c | 3 + kernel/irq/debug.h | 1 + kernel/irq/generic-chip.c | 354 +++++++++++++++++++++++++++++++++ kernel/irq/irqdesc.c | 22 ++- kernel/irq/manage.c | 3 +- kernel/irq/settings.h | 17 ++ 11 files changed, 613 insertions(+), 64 deletions(-) create mode 100644 kernel/irq/generic-chip.c
Documentation/DocBook/genericirq.tmpl +47 -35
@@ -191,8 +191,8 @@ <para> Whenever an interrupt triggers, the lowlevel arch code calls into the generic interrupt code by calling desc->handle_irq(). - This highlevel IRQ handling function only uses desc->chip primitives - referenced by the assigned chip descriptor structure. + This highlevel IRQ handling function only uses desc->irq_data.chip + primitives referenced by the assigned chip descriptor structure. </para> </sect1> <sect1 id="Highlevel_Driver_API">
@@ -206,11 +206,11 @@ <listitem><para>enable_irq()</para></listitem> <listitem><para>disable_irq_nosync() (SMP only)</para></listitem> <listitem><para>synchronize_irq() (SMP only)</para></listitem> - <listitem><para>set_irq_type()</para></listitem> - <listitem><para>set_irq_wake()</para></listitem> - <listitem><para>set_irq_data()</para></listitem> - <listitem><para>set_irq_chip()</para></listitem> - <listitem><para>set_irq_chip_data()</para></listitem> + <listitem><para>irq_set_irq_type()</para></listitem> + <listitem><para>irq_set_irq_wake()</para></listitem> + <listitem><para>irq_set_handler_data()</para></listitem> + <listitem><para>irq_set_chip()</para></listitem> + <listitem><para>irq_set_chip_data()</para></listitem> </itemizedlist> See the autogenerated function documentation for details. </para>
@@ -225,6 +225,8 @@ <listitem><para>handle_fasteoi_irq</para></listitem> <listitem><para>handle_simple_irq</para></listitem> <listitem><para>handle_percpu_irq</para></listitem> + <listitem><para>handle_edge_eoi_irq</para></listitem> + <listitem><para>handle_bad_irq</para></listitem> </itemizedlist> The interrupt flow handlers (either predefined or architecture specific) are assigned to specific interrupts by the architecture
@@ -241,13 +243,13 @@ <programlisting> default_enable(struct irq_data *data) { - desc->chip->irq_unmask(data); + desc->irq_data.chip->irq_unmask(data); } default_disable(struct irq_data *data) { if (!delay_disable(data)) - desc->chip->irq_mask(data); + desc->irq_data.chip->irq_mask(data); } default_ack(struct irq_data *data)
@@ -284,9 +286,9 @@ noop(struct irq_data *data)) <para> The following control flow is implemented (simplified excerpt): <programlisting> -desc->chip->irq_mask(); -handle_IRQ_event(desc->action); -desc->chip->irq_unmask(); +desc->irq_data.chip->irq_mask_ack(); +handle_irq_event(desc->action); +desc->irq_data.chip->irq_unmask(); </programlisting> </para> </sect3>
@@ -300,8 +302,8 @@ desc->chip->irq_unmask(); <para> The following control flow is implemented (simplified excerpt): <programlisting> -handle_IRQ_event(desc->action); -desc->chip->irq_eoi(); +handle_irq_event(desc->action); +desc->irq_data.chip->irq_eoi(); </programlisting> </para> </sect3>
@@ -315,17 +317,17 @@ desc->chip->irq_eoi(); The following control flow is implemented (simplified excerpt): <programlisting> if (desc->status & running) { - desc->chip->irq_mask(); + desc->irq_data.chip->irq_mask_ack(); desc->status |= pending | masked; return; } -desc->chip->irq_ack(); +desc->irq_data.chip->irq_ack(); desc->status |= running; do { if (desc->status & masked) - desc->chip->irq_unmask(); + desc->irq_data.chip->irq_unmask(); desc->status &= ~pending; - handle_IRQ_event(desc->action); + handle_irq_event(desc->action); } while (status & pending); desc->status &= ~running; </programlisting>
@@ -344,7 +346,7 @@ desc->status &= ~running; <para> The following control flow is implemented (simplified excerpt): <programlisting> -handle_IRQ_event(desc->action); +handle_irq_event(desc->action); </programlisting> </para> </sect3>
@@ -362,12 +364,29 @@ handle_IRQ_event(desc->action); <para> The following control flow is implemented (simplified excerpt): <programlisting> -handle_IRQ_event(desc->action); -if (desc->chip->irq_eoi) - desc->chip->irq_eoi(); +if (desc->irq_data.chip->irq_ack) + desc->irq_data.chip->irq_ack(); +handle_irq_event(desc->action); +if (desc->irq_data.chip->irq_eoi) + desc->irq_data.chip->irq_eoi(); </programlisting> </para> </sect3> + <sect3 id="EOI_Edge_IRQ_flow_handler"> + <title>EOI Edge IRQ flow handler</title> + <para> + handle_edge_eoi_irq provides an abnomination of the edge + handler which is solely used to tame a badly wreckaged + irq controller on powerpc/cell. + </para> + </sect3> + <sect3 id="BAD_IRQ_flow_handler"> + <title>Bad IRQ flow handler</title> + <para> + handle_bad_irq is used for spurious interrupts which + have no real handler assigned.. + </para> + </sect3> </sect2> <sect2 id="Quirks_and_optimizations"> <title>Quirks and optimizations</title>
@@ -410,6 +429,7 @@ if (desc->chip->irq_eoi) <listitem><para>irq_mask_ack() - Optional, recommended for performance</para></listitem> <listitem><para>irq_mask()</para></listitem> <listitem><para>irq_unmask()</para></listitem> + <listitem><para>irq_eoi() - Optional, required for eoi flow handlers</para></listitem> <listitem><para>irq_retrigger() - Optional</para></listitem> <listitem><para>irq_set_type() - Optional</para></listitem> <listitem><para>irq_set_wake() - Optional</para></listitem>
@@ -424,32 +444,24 @@ if (desc->chip->irq_eoi) <chapter id="doirq"> <title>__do_IRQ entry point</title> <para> - The original implementation __do_IRQ() is an alternative entry - point for all types of interrupts. + The original implementation __do_IRQ() was an alternative entry + point for all types of interrupts. It not longer exists. </para> <para> This handler turned out to be not suitable for all interrupt hardware and was therefore reimplemented with split - functionality for egde/level/simple/percpu interrupts. This is not + functionality for edge/level/simple/percpu interrupts. This is not only a functional optimization. It also shortens code paths for interrupts. </para> - <para> - To make use of the split implementation, replace the call to - __do_IRQ by a call to desc->handle_irq() and associate - the appropriate handler function to desc->handle_irq(). - In most cases the generic handler implementations should - be sufficient. - </para> </chapter> <chapter id="locking"> <title>Locking on SMP</title> <para> The locking of chip registers is up to the architecture that - defines the chip primitives. There is a chip->lock field that can be used - for serialization, but the generic layer does not touch it. The per-irq - structure is protected via desc->lock, by the generic layer. + defines the chip primitives. The per-irq structure is + protected via desc->lock, by the generic layer. </para> </chapter> <chapter id="structs">
include/linux/irq.h +160 -19
232 lines not on this page · raw message
include/linux/irqdesc.h +5 -6
@@ -16,16 +16,18 @@ struct timer_rand_state;* @irq_data: per irq and chip data passed down to chip functions * @timer_rand_state: pointer to timer rand state struct * @kstat_irqs: irq stats per cpu -* @handle_irq: highlevel irq-events handler [if NULL, __do_IRQ()] +* @handle_irq: highlevel irq-events handler +* @preflow_handler: handler called before the flow handler (currently used by sparc) * @action: the irq action chain * @status: status information * @core_internal_state__do_not_mess_with_it: core internal status information * @depth: disable-depth, for nested irq_disable() calls -* @wake_depth: enable depth, for multiple set_irq_wake() callers +* @wake_depth: enable depth, for multiple irq_set_irq_wake() callers * @irq_count: stats field to detect stalled irqs * @last_unhandled: aging timer for unhandled count * @irqs_unhandled: stats field for spurious unhandled interrupts * @lock: locking for SMP +* @affinity_hint: hint to user space for preferred irq affinity * @affinity_notify: context for notification of affinity changes * @pending_mask: pending rebalanced interrupts * @threads_oneshot: bitfield to handle shared oneshot threads
@@ -109,10 +111,7 @@ static inline void generic_handle_irq_desc(unsigned int irq, struct irq_desc *de desc->handle_irq (irq, desc); } -static inline void generic_handle_irq (unsigned int irq) -{ -generic_handle_irq_desc (irq,irq_to_desc (irq)); -} +int generic_handle_irq (unsigned int irq);/* Test to see if a driver has successfully requested an irq */ static inline int irq_has_action (unsigned int irq)
kernel/irq/Kconfig +4 -0
@@ -48,6 +48,10 @@ config IRQ_PREFLOW_FASTEOI config IRQ_EDGE_EOI_HANDLER bool +# Generic configurable interrupt chip implementation +config GENERIC_IRQ_CHIP + bool + # Support forced irq threading config IRQ_FORCED_THREADING bool
kernel/irq/Makefile +1 -0
@@ -1,5 +1,6 @@ obj-y := irqdesc.o handle.o manage.o spurious.o resend.o chip.o dummychip.o devres.o +obj-$(CONFIG_GENERIC_IRQ_CHIP) += generic-chip.o obj-$(CONFIG_GENERIC_IRQ_PROBE) += autoprobe.o obj-$(CONFIG_PROC_FS) += proc.o obj-$(CONFIG_GENERIC_PENDING_IRQ) += migration.o
kernel/irq/chip.c +3 -0
@@ -310,6 +310,7 @@ handle_simple_irq(unsigned int irq, struct irq_desc *desc) out_unlock:raw_spin_unlock (&desc->lock); } +EXPORT_SYMBOL_GPL (handle_simple_irq);/** * handle_level_irq - Level type irq handler
@@ -573,6 +574,7 @@ __irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,if (handle != handle_bad_irq && is_chained) {irq_settings_set_noprobe (desc);irq_settings_set_norequest (desc); +irq_settings_set_nothread (desc);irq_startup (desc); } out:
@@ -612,6 +614,7 @@ void irq_modify_status(unsigned int irq, unsigned long clr, unsigned long set)irq_put_desc_unlock (desc, flags); } +EXPORT_SYMBOL_GPL (irq_modify_status);/** * irq_cpu_online - Invoke all irq_cpu_online functions.
kernel/irq/debug.h +1 -0
@@ -27,6 +27,7 @@ static inline void print_irq_desc(unsigned int irq, struct irq_desc *desc)P (IRQ_PER_CPU );P (IRQ_NOPROBE );P (IRQ_NOREQUEST ); +P (IRQ_NOTHREAD );P (IRQ_NOAUTOEN );PS (IRQS_AUTODETECT );
kernel/irq/generic-chip.c new file +354 -0
354 lines not on this page · raw message
kernel/irq/irqdesc.c +19 -3
@@ -22,7 +22,7 @@*/ static struct lock_class_key irq_desc_lock_class; -#if defined(CONFIG_SMP ) && defined(CONFIG_GENERIC_HARDIRQS ) +#if defined(CONFIG_SMP )static void __init init_irq_default_affinity (void ) {alloc_cpumask_var (&irq_default_affinity,GFP_NOWAIT );
@@ -290,6 +290,22 @@ static int irq_expand_nr_irqs(unsigned int nr)#endif /* !CONFIG_SPARSE_IRQ */ +/** +* generic_handle_irq - Invoke the handler for a particular irq +* @irq: The irq number to handle +* +*/ +int generic_handle_irq (unsigned int irq) +{ +struct irq_desc *desc =irq_to_desc (irq); + +if (!desc) +return -EINVAL ; +generic_handle_irq_desc (irq, desc); +return 0 ; +} +EXPORT_SYMBOL_GPL (generic_handle_irq); +/* Dynamic interrupt handling */ /**
@@ -311,6 +327,7 @@ void irq_free_descs(unsigned int from, unsigned int cnt)bitmap_clear (allocated_irqs, from, cnt);mutex_unlock (&sparse_irq_lock); } +EXPORT_SYMBOL_GPL (irq_free_descs);/** * irq_alloc_descs - allocate and initialize a range of irq descriptors
@@ -351,6 +368,7 @@ err:mutex_unlock (&sparse_irq_lock);return ret; } +EXPORT_SYMBOL_GPL (irq_alloc_descs);/** * irq_reserve_irqs - mark irqs allocated
@@ -430,7 +448,6 @@ unsigned int kstat_irqs_cpu(unsigned int irq, int cpu) *per_cpu_ptr(desc->kstat_irqs, cpu) : 0; } -#ifdef CONFIG_GENERIC_HARDIRQS unsigned int kstat_irqs (unsigned int irq) {struct irq_desc *desc =irq_to_desc (irq);
@@ -443,4 +460,3 @@ unsigned int kstat_irqs(unsigned int irq) sum += *per_cpu_ptr (desc->kstat_irqs, cpu);return sum; } -#endif /* CONFIG_GENERIC_HARDIRQS */
kernel/irq/manage.c +2 -1
@@ -900,7 +900,8 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)*/ new->handler = irq_nested_primary_handler; }else { -irq_setup_forced_threading (new); +if (irq_settings_can_thread (desc)) +irq_setup_forced_threading (new); }/*
kernel/irq/settings.h +17 -0
@@ -8,6 +8,7 @@ enum { _IRQ_LEVEL =IRQ_LEVEL , _IRQ_NOPROBE =IRQ_NOPROBE , _IRQ_NOREQUEST =IRQ_NOREQUEST , + _IRQ_NOTHREAD =IRQ_NOTHREAD , _IRQ_NOAUTOEN =IRQ_NOAUTOEN , _IRQ_MOVE_PCNTXT =IRQ_MOVE_PCNTXT , _IRQ_NO_BALANCING = IRQ_NO_BALANCING,
@@ -20,6 +21,7 @@ enum {#define IRQ_LEVEL GOT_YOU_MORON#define IRQ_NOPROBE GOT_YOU_MORON#define IRQ_NOREQUEST GOT_YOU_MORON +#define IRQ_NOTHREAD GOT_YOU_MORON#define IRQ_NOAUTOEN GOT_YOU_MORON#define IRQ_NESTED_THREAD GOT_YOU_MORON#undef IRQF_MODIFY_MASK
@@ -94,6 +96,21 @@ static inline void irq_settings_set_norequest(struct irq_desc *desc) desc->status_use_accessors |= _IRQ_NOREQUEST; } +static inline bool irq_settings_can_thread (struct irq_desc *desc) +{ +return !(desc->status_use_accessors & _IRQ_NOTHREAD); +} + +static inline void irq_settings_clr_nothread (struct irq_desc *desc) +{ + desc->status_use_accessors &= ~_IRQ_NOTHREAD; +} + +static inline void irq_settings_set_nothread (struct irq_desc *desc) +{ + desc->status_use_accessors |= _IRQ_NOTHREAD; +} +static inline bool irq_settings_can_probe (struct irq_desc *desc) {return !(desc->status_use_accessors & _IRQ_NOPROBE);