Linus,

please pull the latest irq-urgent-for-linus git tree from:

   git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git 
irq-urgent-for-linus

This update contains:

  - Prevent double activation of interrupt lines, which causes problems on
    certain interrupt controllers

  - Handle the fallout of the above because x86 (ab)uses the activation
    function to reconfigure interrupts under the hood. 

Thanks,

        tglx

------------------>
Marc Zyngier (1):
      irqdomain: Avoid activating interrupts more than once

Thomas Gleixner (1):
      x86/irq: Make irq activate operations symmetric


 arch/x86/kernel/apic/io_apic.c |  2 ++
 arch/x86/kernel/hpet.c         |  1 +
 include/linux/irq.h            | 17 ++++++++++++++++
 kernel/irq/irqdomain.c         | 44 ++++++++++++++++++++++++++++--------------
 4 files changed, 50 insertions(+), 14 deletions(-)

diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
index 1e35dd06b090..52f352b063fd 100644
--- a/arch/x86/kernel/apic/io_apic.c
+++ b/arch/x86/kernel/apic/io_apic.c
@@ -2117,6 +2117,7 @@ static inline void __init check_timer(void)
                        if (idx != -1 && irq_trigger(idx))
                                unmask_ioapic_irq(irq_get_chip_data(0));
                }
+               irq_domain_deactivate_irq(irq_data);
                irq_domain_activate_irq(irq_data);
                if (timer_irq_works()) {
                        if (disable_timer_pin_1 > 0)
@@ -2138,6 +2139,7 @@ static inline void __init check_timer(void)
                 * legacy devices should be connected to IO APIC #0
                 */
                replace_pin_at_irq_node(data, node, apic1, pin1, apic2, pin2);
+               irq_domain_deactivate_irq(irq_data);
                irq_domain_activate_irq(irq_data);
                legacy_pic->unmask(0);
                if (timer_irq_works()) {
diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c
index 85e87b46c318..dc6ba5bda9fc 100644
--- a/arch/x86/kernel/hpet.c
+++ b/arch/x86/kernel/hpet.c
@@ -352,6 +352,7 @@ static int hpet_resume(struct clock_event_device *evt, int 
timer)
        } else {
                struct hpet_dev *hdev = EVT_TO_HPET_DEV(evt);
 
+               irq_domain_deactivate_irq(irq_get_irq_data(hdev->irq));
                irq_domain_activate_irq(irq_get_irq_data(hdev->irq));
                disable_irq(hdev->irq);
                irq_set_affinity(hdev->irq, cpumask_of(hdev->cpu));
diff --git a/include/linux/irq.h b/include/linux/irq.h
index e79875574b39..39e3254e5769 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -184,6 +184,7 @@ struct irq_data {
  *
  * IRQD_TRIGGER_MASK           - Mask for the trigger type bits
  * IRQD_SETAFFINITY_PENDING    - Affinity setting is pending
+ * IRQD_ACTIVATED              - Interrupt has already been activated
  * IRQD_NO_BALANCING           - Balancing disabled for this IRQ
  * IRQD_PER_CPU                        - Interrupt is per cpu
  * IRQD_AFFINITY_SET           - Interrupt affinity was set
@@ -202,6 +203,7 @@ struct irq_data {
 enum {
        IRQD_TRIGGER_MASK               = 0xf,
        IRQD_SETAFFINITY_PENDING        = (1 <<  8),
+       IRQD_ACTIVATED                  = (1 <<  9),
        IRQD_NO_BALANCING               = (1 << 10),
        IRQD_PER_CPU                    = (1 << 11),
        IRQD_AFFINITY_SET               = (1 << 12),
@@ -312,6 +314,21 @@ static inline bool irqd_affinity_is_managed(struct 
irq_data *d)
        return __irqd_to_state(d) & IRQD_AFFINITY_MANAGED;
 }
 
+static inline bool irqd_is_activated(struct irq_data *d)
+{
+       return __irqd_to_state(d) & IRQD_ACTIVATED;
+}
+
+static inline void irqd_set_activated(struct irq_data *d)
+{
+       __irqd_to_state(d) |= IRQD_ACTIVATED;
+}
+
+static inline void irqd_clr_activated(struct irq_data *d)
+{
+       __irqd_to_state(d) &= ~IRQD_ACTIVATED;
+}
+
 #undef __irqd_to_state
 
 static inline irq_hw_number_t irqd_to_hwirq(struct irq_data *d)
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index 8c0a0ae43521..b59e6768c5e9 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -1346,6 +1346,30 @@ void irq_domain_free_irqs_parent(struct irq_domain 
*domain,
 }
 EXPORT_SYMBOL_GPL(irq_domain_free_irqs_parent);
 
+static void __irq_domain_activate_irq(struct irq_data *irq_data)
+{
+       if (irq_data && irq_data->domain) {
+               struct irq_domain *domain = irq_data->domain;
+
+               if (irq_data->parent_data)
+                       __irq_domain_activate_irq(irq_data->parent_data);
+               if (domain->ops->activate)
+                       domain->ops->activate(domain, irq_data);
+       }
+}
+
+static void __irq_domain_deactivate_irq(struct irq_data *irq_data)
+{
+       if (irq_data && irq_data->domain) {
+               struct irq_domain *domain = irq_data->domain;
+
+               if (domain->ops->deactivate)
+                       domain->ops->deactivate(domain, irq_data);
+               if (irq_data->parent_data)
+                       __irq_domain_deactivate_irq(irq_data->parent_data);
+       }
+}
+
 /**
  * irq_domain_activate_irq - Call domain_ops->activate recursively to activate
  *                          interrupt
@@ -1356,13 +1380,9 @@ EXPORT_SYMBOL_GPL(irq_domain_free_irqs_parent);
  */
 void irq_domain_activate_irq(struct irq_data *irq_data)
 {
-       if (irq_data && irq_data->domain) {
-               struct irq_domain *domain = irq_data->domain;
-
-               if (irq_data->parent_data)
-                       irq_domain_activate_irq(irq_data->parent_data);
-               if (domain->ops->activate)
-                       domain->ops->activate(domain, irq_data);
+       if (!irqd_is_activated(irq_data)) {
+               __irq_domain_activate_irq(irq_data);
+               irqd_set_activated(irq_data);
        }
 }
 
@@ -1376,13 +1396,9 @@ void irq_domain_activate_irq(struct irq_data *irq_data)
  */
 void irq_domain_deactivate_irq(struct irq_data *irq_data)
 {
-       if (irq_data && irq_data->domain) {
-               struct irq_domain *domain = irq_data->domain;
-
-               if (domain->ops->deactivate)
-                       domain->ops->deactivate(domain, irq_data);
-               if (irq_data->parent_data)
-                       irq_domain_deactivate_irq(irq_data->parent_data);
+       if (irqd_is_activated(irq_data)) {
+               __irq_domain_deactivate_irq(irq_data);
+               irqd_clr_activated(irq_data);
        }
 }
 

Reply via email to