|
@@ -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">
|