Loading Documentation/DocBook/genericirq.tmpl +47 −35 Original line number Diff line number Diff line Loading @@ -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"> Loading @@ -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> Loading @@ -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 Loading @@ -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) Loading Loading @@ -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> Loading @@ -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> Loading @@ -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> Loading @@ -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> Loading @@ -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> Loading Loading @@ -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> Loading @@ -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"> Loading arch/arm/mach-davinci/irq.c +20 −73 Original line number Diff line number Diff line Loading @@ -29,8 +29,6 @@ #include <mach/common.h> #include <asm/mach/irq.h> #define IRQ_BIT(irq) ((irq) & 0x1f) #define FIQ_REG0_OFFSET 0x0000 #define FIQ_REG1_OFFSET 0x0004 #define IRQ_REG0_OFFSET 0x0008 Loading @@ -42,78 +40,33 @@ #define IRQ_INTPRI0_REG_OFFSET 0x0030 #define IRQ_INTPRI7_REG_OFFSET 0x004C static inline unsigned int davinci_irq_readl(int offset) { return __raw_readl(davinci_intc_base + offset); } static inline void davinci_irq_writel(unsigned long value, int offset) { __raw_writel(value, davinci_intc_base + offset); } /* Disable interrupt */ static void davinci_mask_irq(struct irq_data *d) static __init void davinci_alloc_gc(void __iomem *base, unsigned int irq_start, unsigned int num) { unsigned int mask; u32 l; mask = 1 << IRQ_BIT(d->irq); if (d->irq > 31) { l = davinci_irq_readl(IRQ_ENT_REG1_OFFSET); l &= ~mask; davinci_irq_writel(l, IRQ_ENT_REG1_OFFSET); } else { l = davinci_irq_readl(IRQ_ENT_REG0_OFFSET); l &= ~mask; davinci_irq_writel(l, IRQ_ENT_REG0_OFFSET); } } /* Enable interrupt */ static void davinci_unmask_irq(struct irq_data *d) { unsigned int mask; u32 l; mask = 1 << IRQ_BIT(d->irq); if (d->irq > 31) { l = davinci_irq_readl(IRQ_ENT_REG1_OFFSET); l |= mask; davinci_irq_writel(l, IRQ_ENT_REG1_OFFSET); } else { l = davinci_irq_readl(IRQ_ENT_REG0_OFFSET); l |= mask; davinci_irq_writel(l, IRQ_ENT_REG0_OFFSET); } struct irq_chip_generic *gc; struct irq_chip_type *ct; gc = irq_alloc_generic_chip("AINTC", 1, irq_start, base, handle_edge_irq); ct = gc->chip_types; ct->chip.irq_ack = irq_gc_ack; ct->chip.irq_mask = irq_gc_mask_clr_bit; ct->chip.irq_unmask = irq_gc_mask_set_bit; ct->regs.ack = IRQ_REG0_OFFSET; ct->regs.mask = IRQ_ENT_REG0_OFFSET; irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE, IRQ_NOREQUEST | IRQ_NOPROBE, 0); } /* EOI interrupt */ static void davinci_ack_irq(struct irq_data *d) { unsigned int mask; mask = 1 << IRQ_BIT(d->irq); if (d->irq > 31) davinci_irq_writel(mask, IRQ_REG1_OFFSET); else davinci_irq_writel(mask, IRQ_REG0_OFFSET); } static struct irq_chip davinci_irq_chip_0 = { .name = "AINTC", .irq_ack = davinci_ack_irq, .irq_mask = davinci_mask_irq, .irq_unmask = davinci_unmask_irq, }; /* ARM Interrupt Controller Initialization */ void __init davinci_irq_init(void) { unsigned i; unsigned i, j; const u8 *davinci_def_priorities = davinci_soc_info.intc_irq_prios; davinci_intc_type = DAVINCI_INTC_TYPE_AINTC; Loading Loading @@ -144,7 +97,6 @@ void __init davinci_irq_init(void) davinci_irq_writel(~0x0, IRQ_REG1_OFFSET); for (i = IRQ_INTPRI0_REG_OFFSET; i <= IRQ_INTPRI7_REG_OFFSET; i += 4) { unsigned j; u32 pri; for (j = 0, pri = 0; j < 32; j += 4, davinci_def_priorities++) Loading @@ -152,13 +104,8 @@ void __init davinci_irq_init(void) davinci_irq_writel(pri, i); } /* set up genirq dispatch for ARM INTC */ for (i = 0; i < davinci_soc_info.intc_irq_num; i++) { irq_set_chip(i, &davinci_irq_chip_0); set_irq_flags(i, IRQF_VALID | IRQF_PROBE); if (i != IRQ_TINT1_TINT34) irq_set_handler(i, handle_edge_irq); else irq_set_handler(i, handle_level_irq); } for (i = 0, j = 0; i < davinci_soc_info.intc_irq_num; i += 32, j += 0x04) davinci_alloc_gc(davinci_intc_base + j, i, 32); irq_set_handler(IRQ_TINT1_TINT34, handle_level_irq); } include/linux/irq.h +160 −19 Original line number Diff line number Diff line Loading @@ -53,12 +53,13 @@ typedef void (*irq_preflow_handler_t)(struct irq_data *data); * Bits which can be modified via irq_set/clear/modify_status_flags() * IRQ_LEVEL - Interrupt is level type. Will be also * updated in the code when the above trigger * bits are modified via set_irq_type() * bits are modified via irq_set_irq_type() * IRQ_PER_CPU - Mark an interrupt PER_CPU. Will protect * it from affinity setting * IRQ_NOPROBE - Interrupt cannot be probed by autoprobing * IRQ_NOREQUEST - Interrupt cannot be requested via * request_irq() * IRQ_NOTHREAD - Interrupt cannot be threaded * IRQ_NOAUTOEN - Interrupt is not automatically enabled in * request/setup_irq() * IRQ_NO_BALANCING - Interrupt cannot be balanced (affinity set) Loading @@ -85,6 +86,7 @@ enum { IRQ_NO_BALANCING = (1 << 13), IRQ_MOVE_PCNTXT = (1 << 14), IRQ_NESTED_THREAD = (1 << 15), IRQ_NOTHREAD = (1 << 16), }; #define IRQF_MODIFY_MASK \ Loading Loading @@ -261,23 +263,6 @@ static inline void irqd_clr_chained_irq_inprogress(struct irq_data *d) * struct irq_chip - hardware interrupt chip descriptor * * @name: name for /proc/interrupts * @startup: deprecated, replaced by irq_startup * @shutdown: deprecated, replaced by irq_shutdown * @enable: deprecated, replaced by irq_enable * @disable: deprecated, replaced by irq_disable * @ack: deprecated, replaced by irq_ack * @mask: deprecated, replaced by irq_mask * @mask_ack: deprecated, replaced by irq_mask_ack * @unmask: deprecated, replaced by irq_unmask * @eoi: deprecated, replaced by irq_eoi * @end: deprecated, will go away with __do_IRQ() * @set_affinity: deprecated, replaced by irq_set_affinity * @retrigger: deprecated, replaced by irq_retrigger * @set_type: deprecated, replaced by irq_set_type * @set_wake: deprecated, replaced by irq_wake * @bus_lock: deprecated, replaced by irq_bus_lock * @bus_sync_unlock: deprecated, replaced by irq_bus_sync_unlock * * @irq_startup: start up the interrupt (defaults to ->enable if NULL) * @irq_shutdown: shut down the interrupt (defaults to ->disable if NULL) * @irq_enable: enable the interrupt (defaults to chip->unmask if NULL) Loading @@ -295,6 +280,9 @@ static inline void irqd_clr_chained_irq_inprogress(struct irq_data *d) * @irq_bus_sync_unlock:function to sync and unlock slow bus (i2c) chips * @irq_cpu_online: configure an interrupt source for a secondary CPU * @irq_cpu_offline: un-configure an interrupt source for a secondary CPU * @irq_suspend: function called from core code on suspend once per chip * @irq_resume: function called from core code on resume once per chip * @irq_pm_shutdown: function called from core code on shutdown once per chip * @irq_print_chip: optional to print special chip info in show_interrupts * @flags: chip specific flags * Loading Loading @@ -324,6 +312,10 @@ struct irq_chip { void (*irq_cpu_online)(struct irq_data *data); void (*irq_cpu_offline)(struct irq_data *data); void (*irq_suspend)(struct irq_data *data); void (*irq_resume)(struct irq_data *data); void (*irq_pm_shutdown)(struct irq_data *data); void (*irq_print_chip)(struct irq_data *data, struct seq_file *p); unsigned long flags; Loading Loading @@ -439,7 +431,7 @@ irq_set_handler(unsigned int irq, irq_flow_handler_t handle) /* * Set a highlevel chained flow handler for a given IRQ. * (a chained handler is automatically enabled and set to * IRQ_NOREQUEST and IRQ_NOPROBE) * IRQ_NOREQUEST, IRQ_NOPROBE, and IRQ_NOTHREAD) */ static inline void irq_set_chained_handler(unsigned int irq, irq_flow_handler_t handle) Loading Loading @@ -469,6 +461,16 @@ static inline void irq_set_probe(unsigned int irq) irq_modify_status(irq, IRQ_NOPROBE, 0); } static inline void irq_set_nothread(unsigned int irq) { irq_modify_status(irq, 0, IRQ_NOTHREAD); } static inline void irq_set_thread(unsigned int irq) { irq_modify_status(irq, IRQ_NOTHREAD, 0); } static inline void irq_set_nested_thread(unsigned int irq, bool nest) { if (nest) Loading Loading @@ -573,6 +575,145 @@ static inline int irq_reserve_irq(unsigned int irq) return irq_reserve_irqs(irq, 1); } #ifndef irq_reg_writel # define irq_reg_writel(val, addr) writel(val, addr) #endif #ifndef irq_reg_readl # define irq_reg_readl(addr) readl(addr) #endif /** * struct irq_chip_regs - register offsets for struct irq_gci * @enable: Enable register offset to reg_base * @disable: Disable register offset to reg_base * @mask: Mask register offset to reg_base * @ack: Ack register offset to reg_base * @eoi: Eoi register offset to reg_base * @type: Type configuration register offset to reg_base * @polarity: Polarity configuration register offset to reg_base */ struct irq_chip_regs { unsigned long enable; unsigned long disable; unsigned long mask; unsigned long ack; unsigned long eoi; unsigned long type; unsigned long polarity; }; /** * struct irq_chip_type - Generic interrupt chip instance for a flow type * @chip: The real interrupt chip which provides the callbacks * @regs: Register offsets for this chip * @handler: Flow handler associated with this chip * @type: Chip can handle these flow types * * A irq_generic_chip can have several instances of irq_chip_type when * it requires different functions and register offsets for different * flow types. */ struct irq_chip_type { struct irq_chip chip; struct irq_chip_regs regs; irq_flow_handler_t handler; u32 type; }; /** * struct irq_chip_generic - Generic irq chip data structure * @lock: Lock to protect register and cache data access * @reg_base: Register base address (virtual) * @irq_base: Interrupt base nr for this chip * @irq_cnt: Number of interrupts handled by this chip * @mask_cache: Cached mask register * @type_cache: Cached type register * @polarity_cache: Cached polarity register * @wake_enabled: Interrupt can wakeup from suspend * @wake_active: Interrupt is marked as an wakeup from suspend source * @num_ct: Number of available irq_chip_type instances (usually 1) * @private: Private data for non generic chip callbacks * @list: List head for keeping track of instances * @chip_types: Array of interrupt irq_chip_types * * Note, that irq_chip_generic can have multiple irq_chip_type * implementations which can be associated to a particular irq line of * an irq_chip_generic instance. That allows to share and protect * state in an irq_chip_generic instance when we need to implement * different flow mechanisms (level/edge) for it. */ struct irq_chip_generic { raw_spinlock_t lock; void __iomem *reg_base; unsigned int irq_base; unsigned int irq_cnt; u32 mask_cache; u32 type_cache; u32 polarity_cache; u32 wake_enabled; u32 wake_active; unsigned int num_ct; void *private; struct list_head list; struct irq_chip_type chip_types[0]; }; /** * enum irq_gc_flags - Initialization flags for generic irq chips * @IRQ_GC_INIT_MASK_CACHE: Initialize the mask_cache by reading mask reg * @IRQ_GC_INIT_NESTED_LOCK: Set the lock class of the irqs to nested for * irq chips which need to call irq_set_wake() on * the parent irq. Usually GPIO implementations */ enum irq_gc_flags { IRQ_GC_INIT_MASK_CACHE = 1 << 0, IRQ_GC_INIT_NESTED_LOCK = 1 << 1, }; /* Generic chip callback functions */ void irq_gc_noop(struct irq_data *d); void irq_gc_mask_disable_reg(struct irq_data *d); void irq_gc_mask_set_bit(struct irq_data *d); void irq_gc_mask_clr_bit(struct irq_data *d); void irq_gc_unmask_enable_reg(struct irq_data *d); void irq_gc_ack(struct irq_data *d); void irq_gc_mask_disable_reg_and_ack(struct irq_data *d); void irq_gc_eoi(struct irq_data *d); int irq_gc_set_wake(struct irq_data *d, unsigned int on); /* Setup functions for irq_chip_generic */ struct irq_chip_generic * irq_alloc_generic_chip(const char *name, int nr_ct, unsigned int irq_base, void __iomem *reg_base, irq_flow_handler_t handler); void irq_setup_generic_chip(struct irq_chip_generic *gc, u32 msk, enum irq_gc_flags flags, unsigned int clr, unsigned int set); int irq_setup_alt_chip(struct irq_data *d, unsigned int type); void irq_remove_generic_chip(struct irq_chip_generic *gc, u32 msk, unsigned int clr, unsigned int set); static inline struct irq_chip_type *irq_data_get_chip_type(struct irq_data *d) { return container_of(d->chip, struct irq_chip_type, chip); } #define IRQ_MSK(n) (u32)((n) < 32 ? ((1 << (n)) - 1) : UINT_MAX) #ifdef CONFIG_SMP static inline void irq_gc_lock(struct irq_chip_generic *gc) { raw_spin_lock(&gc->lock); } static inline void irq_gc_unlock(struct irq_chip_generic *gc) { raw_spin_unlock(&gc->lock); } #else static inline void irq_gc_lock(struct irq_chip_generic *gc) { } static inline void irq_gc_unlock(struct irq_chip_generic *gc) { } #endif #endif /* CONFIG_GENERIC_HARDIRQS */ #endif /* !CONFIG_S390 */ Loading include/linux/irqdesc.h +4 −2 Original line number Diff line number Diff line Loading @@ -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 Loading kernel/irq/Makefile +1 −0 Original line number Diff line number Diff line obj-y := irqdesc.o handle.o manage.o spurious.o resend.o chip.o dummychip.o devres.o obj-y += generic-chip.o obj-$(CONFIG_GENERIC_IRQ_PROBE) += autoprobe.o obj-$(CONFIG_PROC_FS) += proc.o obj-$(CONFIG_GENERIC_PENDING_IRQ) += migration.o Loading Loading
Documentation/DocBook/genericirq.tmpl +47 −35 Original line number Diff line number Diff line Loading @@ -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"> Loading @@ -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> Loading @@ -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 Loading @@ -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) Loading Loading @@ -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> Loading @@ -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> Loading @@ -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> Loading @@ -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> Loading @@ -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> Loading Loading @@ -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> Loading @@ -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"> Loading
arch/arm/mach-davinci/irq.c +20 −73 Original line number Diff line number Diff line Loading @@ -29,8 +29,6 @@ #include <mach/common.h> #include <asm/mach/irq.h> #define IRQ_BIT(irq) ((irq) & 0x1f) #define FIQ_REG0_OFFSET 0x0000 #define FIQ_REG1_OFFSET 0x0004 #define IRQ_REG0_OFFSET 0x0008 Loading @@ -42,78 +40,33 @@ #define IRQ_INTPRI0_REG_OFFSET 0x0030 #define IRQ_INTPRI7_REG_OFFSET 0x004C static inline unsigned int davinci_irq_readl(int offset) { return __raw_readl(davinci_intc_base + offset); } static inline void davinci_irq_writel(unsigned long value, int offset) { __raw_writel(value, davinci_intc_base + offset); } /* Disable interrupt */ static void davinci_mask_irq(struct irq_data *d) static __init void davinci_alloc_gc(void __iomem *base, unsigned int irq_start, unsigned int num) { unsigned int mask; u32 l; mask = 1 << IRQ_BIT(d->irq); if (d->irq > 31) { l = davinci_irq_readl(IRQ_ENT_REG1_OFFSET); l &= ~mask; davinci_irq_writel(l, IRQ_ENT_REG1_OFFSET); } else { l = davinci_irq_readl(IRQ_ENT_REG0_OFFSET); l &= ~mask; davinci_irq_writel(l, IRQ_ENT_REG0_OFFSET); } } /* Enable interrupt */ static void davinci_unmask_irq(struct irq_data *d) { unsigned int mask; u32 l; mask = 1 << IRQ_BIT(d->irq); if (d->irq > 31) { l = davinci_irq_readl(IRQ_ENT_REG1_OFFSET); l |= mask; davinci_irq_writel(l, IRQ_ENT_REG1_OFFSET); } else { l = davinci_irq_readl(IRQ_ENT_REG0_OFFSET); l |= mask; davinci_irq_writel(l, IRQ_ENT_REG0_OFFSET); } struct irq_chip_generic *gc; struct irq_chip_type *ct; gc = irq_alloc_generic_chip("AINTC", 1, irq_start, base, handle_edge_irq); ct = gc->chip_types; ct->chip.irq_ack = irq_gc_ack; ct->chip.irq_mask = irq_gc_mask_clr_bit; ct->chip.irq_unmask = irq_gc_mask_set_bit; ct->regs.ack = IRQ_REG0_OFFSET; ct->regs.mask = IRQ_ENT_REG0_OFFSET; irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE, IRQ_NOREQUEST | IRQ_NOPROBE, 0); } /* EOI interrupt */ static void davinci_ack_irq(struct irq_data *d) { unsigned int mask; mask = 1 << IRQ_BIT(d->irq); if (d->irq > 31) davinci_irq_writel(mask, IRQ_REG1_OFFSET); else davinci_irq_writel(mask, IRQ_REG0_OFFSET); } static struct irq_chip davinci_irq_chip_0 = { .name = "AINTC", .irq_ack = davinci_ack_irq, .irq_mask = davinci_mask_irq, .irq_unmask = davinci_unmask_irq, }; /* ARM Interrupt Controller Initialization */ void __init davinci_irq_init(void) { unsigned i; unsigned i, j; const u8 *davinci_def_priorities = davinci_soc_info.intc_irq_prios; davinci_intc_type = DAVINCI_INTC_TYPE_AINTC; Loading Loading @@ -144,7 +97,6 @@ void __init davinci_irq_init(void) davinci_irq_writel(~0x0, IRQ_REG1_OFFSET); for (i = IRQ_INTPRI0_REG_OFFSET; i <= IRQ_INTPRI7_REG_OFFSET; i += 4) { unsigned j; u32 pri; for (j = 0, pri = 0; j < 32; j += 4, davinci_def_priorities++) Loading @@ -152,13 +104,8 @@ void __init davinci_irq_init(void) davinci_irq_writel(pri, i); } /* set up genirq dispatch for ARM INTC */ for (i = 0; i < davinci_soc_info.intc_irq_num; i++) { irq_set_chip(i, &davinci_irq_chip_0); set_irq_flags(i, IRQF_VALID | IRQF_PROBE); if (i != IRQ_TINT1_TINT34) irq_set_handler(i, handle_edge_irq); else irq_set_handler(i, handle_level_irq); } for (i = 0, j = 0; i < davinci_soc_info.intc_irq_num; i += 32, j += 0x04) davinci_alloc_gc(davinci_intc_base + j, i, 32); irq_set_handler(IRQ_TINT1_TINT34, handle_level_irq); }
include/linux/irq.h +160 −19 Original line number Diff line number Diff line Loading @@ -53,12 +53,13 @@ typedef void (*irq_preflow_handler_t)(struct irq_data *data); * Bits which can be modified via irq_set/clear/modify_status_flags() * IRQ_LEVEL - Interrupt is level type. Will be also * updated in the code when the above trigger * bits are modified via set_irq_type() * bits are modified via irq_set_irq_type() * IRQ_PER_CPU - Mark an interrupt PER_CPU. Will protect * it from affinity setting * IRQ_NOPROBE - Interrupt cannot be probed by autoprobing * IRQ_NOREQUEST - Interrupt cannot be requested via * request_irq() * IRQ_NOTHREAD - Interrupt cannot be threaded * IRQ_NOAUTOEN - Interrupt is not automatically enabled in * request/setup_irq() * IRQ_NO_BALANCING - Interrupt cannot be balanced (affinity set) Loading @@ -85,6 +86,7 @@ enum { IRQ_NO_BALANCING = (1 << 13), IRQ_MOVE_PCNTXT = (1 << 14), IRQ_NESTED_THREAD = (1 << 15), IRQ_NOTHREAD = (1 << 16), }; #define IRQF_MODIFY_MASK \ Loading Loading @@ -261,23 +263,6 @@ static inline void irqd_clr_chained_irq_inprogress(struct irq_data *d) * struct irq_chip - hardware interrupt chip descriptor * * @name: name for /proc/interrupts * @startup: deprecated, replaced by irq_startup * @shutdown: deprecated, replaced by irq_shutdown * @enable: deprecated, replaced by irq_enable * @disable: deprecated, replaced by irq_disable * @ack: deprecated, replaced by irq_ack * @mask: deprecated, replaced by irq_mask * @mask_ack: deprecated, replaced by irq_mask_ack * @unmask: deprecated, replaced by irq_unmask * @eoi: deprecated, replaced by irq_eoi * @end: deprecated, will go away with __do_IRQ() * @set_affinity: deprecated, replaced by irq_set_affinity * @retrigger: deprecated, replaced by irq_retrigger * @set_type: deprecated, replaced by irq_set_type * @set_wake: deprecated, replaced by irq_wake * @bus_lock: deprecated, replaced by irq_bus_lock * @bus_sync_unlock: deprecated, replaced by irq_bus_sync_unlock * * @irq_startup: start up the interrupt (defaults to ->enable if NULL) * @irq_shutdown: shut down the interrupt (defaults to ->disable if NULL) * @irq_enable: enable the interrupt (defaults to chip->unmask if NULL) Loading @@ -295,6 +280,9 @@ static inline void irqd_clr_chained_irq_inprogress(struct irq_data *d) * @irq_bus_sync_unlock:function to sync and unlock slow bus (i2c) chips * @irq_cpu_online: configure an interrupt source for a secondary CPU * @irq_cpu_offline: un-configure an interrupt source for a secondary CPU * @irq_suspend: function called from core code on suspend once per chip * @irq_resume: function called from core code on resume once per chip * @irq_pm_shutdown: function called from core code on shutdown once per chip * @irq_print_chip: optional to print special chip info in show_interrupts * @flags: chip specific flags * Loading Loading @@ -324,6 +312,10 @@ struct irq_chip { void (*irq_cpu_online)(struct irq_data *data); void (*irq_cpu_offline)(struct irq_data *data); void (*irq_suspend)(struct irq_data *data); void (*irq_resume)(struct irq_data *data); void (*irq_pm_shutdown)(struct irq_data *data); void (*irq_print_chip)(struct irq_data *data, struct seq_file *p); unsigned long flags; Loading Loading @@ -439,7 +431,7 @@ irq_set_handler(unsigned int irq, irq_flow_handler_t handle) /* * Set a highlevel chained flow handler for a given IRQ. * (a chained handler is automatically enabled and set to * IRQ_NOREQUEST and IRQ_NOPROBE) * IRQ_NOREQUEST, IRQ_NOPROBE, and IRQ_NOTHREAD) */ static inline void irq_set_chained_handler(unsigned int irq, irq_flow_handler_t handle) Loading Loading @@ -469,6 +461,16 @@ static inline void irq_set_probe(unsigned int irq) irq_modify_status(irq, IRQ_NOPROBE, 0); } static inline void irq_set_nothread(unsigned int irq) { irq_modify_status(irq, 0, IRQ_NOTHREAD); } static inline void irq_set_thread(unsigned int irq) { irq_modify_status(irq, IRQ_NOTHREAD, 0); } static inline void irq_set_nested_thread(unsigned int irq, bool nest) { if (nest) Loading Loading @@ -573,6 +575,145 @@ static inline int irq_reserve_irq(unsigned int irq) return irq_reserve_irqs(irq, 1); } #ifndef irq_reg_writel # define irq_reg_writel(val, addr) writel(val, addr) #endif #ifndef irq_reg_readl # define irq_reg_readl(addr) readl(addr) #endif /** * struct irq_chip_regs - register offsets for struct irq_gci * @enable: Enable register offset to reg_base * @disable: Disable register offset to reg_base * @mask: Mask register offset to reg_base * @ack: Ack register offset to reg_base * @eoi: Eoi register offset to reg_base * @type: Type configuration register offset to reg_base * @polarity: Polarity configuration register offset to reg_base */ struct irq_chip_regs { unsigned long enable; unsigned long disable; unsigned long mask; unsigned long ack; unsigned long eoi; unsigned long type; unsigned long polarity; }; /** * struct irq_chip_type - Generic interrupt chip instance for a flow type * @chip: The real interrupt chip which provides the callbacks * @regs: Register offsets for this chip * @handler: Flow handler associated with this chip * @type: Chip can handle these flow types * * A irq_generic_chip can have several instances of irq_chip_type when * it requires different functions and register offsets for different * flow types. */ struct irq_chip_type { struct irq_chip chip; struct irq_chip_regs regs; irq_flow_handler_t handler; u32 type; }; /** * struct irq_chip_generic - Generic irq chip data structure * @lock: Lock to protect register and cache data access * @reg_base: Register base address (virtual) * @irq_base: Interrupt base nr for this chip * @irq_cnt: Number of interrupts handled by this chip * @mask_cache: Cached mask register * @type_cache: Cached type register * @polarity_cache: Cached polarity register * @wake_enabled: Interrupt can wakeup from suspend * @wake_active: Interrupt is marked as an wakeup from suspend source * @num_ct: Number of available irq_chip_type instances (usually 1) * @private: Private data for non generic chip callbacks * @list: List head for keeping track of instances * @chip_types: Array of interrupt irq_chip_types * * Note, that irq_chip_generic can have multiple irq_chip_type * implementations which can be associated to a particular irq line of * an irq_chip_generic instance. That allows to share and protect * state in an irq_chip_generic instance when we need to implement * different flow mechanisms (level/edge) for it. */ struct irq_chip_generic { raw_spinlock_t lock; void __iomem *reg_base; unsigned int irq_base; unsigned int irq_cnt; u32 mask_cache; u32 type_cache; u32 polarity_cache; u32 wake_enabled; u32 wake_active; unsigned int num_ct; void *private; struct list_head list; struct irq_chip_type chip_types[0]; }; /** * enum irq_gc_flags - Initialization flags for generic irq chips * @IRQ_GC_INIT_MASK_CACHE: Initialize the mask_cache by reading mask reg * @IRQ_GC_INIT_NESTED_LOCK: Set the lock class of the irqs to nested for * irq chips which need to call irq_set_wake() on * the parent irq. Usually GPIO implementations */ enum irq_gc_flags { IRQ_GC_INIT_MASK_CACHE = 1 << 0, IRQ_GC_INIT_NESTED_LOCK = 1 << 1, }; /* Generic chip callback functions */ void irq_gc_noop(struct irq_data *d); void irq_gc_mask_disable_reg(struct irq_data *d); void irq_gc_mask_set_bit(struct irq_data *d); void irq_gc_mask_clr_bit(struct irq_data *d); void irq_gc_unmask_enable_reg(struct irq_data *d); void irq_gc_ack(struct irq_data *d); void irq_gc_mask_disable_reg_and_ack(struct irq_data *d); void irq_gc_eoi(struct irq_data *d); int irq_gc_set_wake(struct irq_data *d, unsigned int on); /* Setup functions for irq_chip_generic */ struct irq_chip_generic * irq_alloc_generic_chip(const char *name, int nr_ct, unsigned int irq_base, void __iomem *reg_base, irq_flow_handler_t handler); void irq_setup_generic_chip(struct irq_chip_generic *gc, u32 msk, enum irq_gc_flags flags, unsigned int clr, unsigned int set); int irq_setup_alt_chip(struct irq_data *d, unsigned int type); void irq_remove_generic_chip(struct irq_chip_generic *gc, u32 msk, unsigned int clr, unsigned int set); static inline struct irq_chip_type *irq_data_get_chip_type(struct irq_data *d) { return container_of(d->chip, struct irq_chip_type, chip); } #define IRQ_MSK(n) (u32)((n) < 32 ? ((1 << (n)) - 1) : UINT_MAX) #ifdef CONFIG_SMP static inline void irq_gc_lock(struct irq_chip_generic *gc) { raw_spin_lock(&gc->lock); } static inline void irq_gc_unlock(struct irq_chip_generic *gc) { raw_spin_unlock(&gc->lock); } #else static inline void irq_gc_lock(struct irq_chip_generic *gc) { } static inline void irq_gc_unlock(struct irq_chip_generic *gc) { } #endif #endif /* CONFIG_GENERIC_HARDIRQS */ #endif /* !CONFIG_S390 */ Loading
include/linux/irqdesc.h +4 −2 Original line number Diff line number Diff line Loading @@ -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 Loading
kernel/irq/Makefile +1 −0 Original line number Diff line number Diff line obj-y := irqdesc.o handle.o manage.o spurious.o resend.o chip.o dummychip.o devres.o obj-y += generic-chip.o obj-$(CONFIG_GENERIC_IRQ_PROBE) += autoprobe.o obj-$(CONFIG_PROC_FS) += proc.o obj-$(CONFIG_GENERIC_PENDING_IRQ) += migration.o Loading