- chip = irq_data_get_irq_chip(idata);
- /* Might be lapic_chip for irq 0 */
- if (chip->irq_set_affinity)
- chip->irq_set_affinity(idata, mask, false);
+ irq_set_affinity_locked(idata, mask, false); raw_spin_unlock_irq(&desc->lock);
}
}
which essentially keeps the raw_spin_lock_irq()/raw_spin_unlock_irq() rather than raw_spin_lock_irqsave()/raw_spin_unlock_irqrestore() used by __irq_set_affinity() in kernel/irq/manage.c .
I tested both patches on top of Ubuntu-4.4.0-47.68 and they work.
They also apply cleanly to Ubuntu-4.2.0-42.49 but I didn't actually check that it builds/works.
I tried manually inlining the irq_set_affinity_locked() (which required further inlining of some helper functions and providing a declaration of irq_do_set_affinity()) and it still worked. However, forcing the "if (irq_can_move_pcntxt())" path that immediately performs "chip->irq_set_affinity(idata, mask, false)" exposes the bug.
This confirms what I expected after reading https://lkml.org/lkml/2012/3/26/392 . Basically, when the hardware says that you cannot do something right away, you really cannot. And the offending commit just ignores this.
The revert of the offending commit does not apply cleanly to the Ubuntu-4.4.0-47.68 kernel. The closest we can get to a revert is this patch:
diff --git a/arch/ x86/kernel/ apic/io_ apic.c b/arch/ x86/kernel/ apic/io_ apic.c x86/kernel/ apic/io_ apic.c x86/kernel/ apic/io_ apic.c dest(void)
index 64f233a..aec995c 100644
--- a/arch/
+++ b/arch/
@@ -2523,7 +2523,6 @@ void __init setup_ioapic_
const struct cpumask *mask;
struct irq_desc *desc;
struct irq_data *idata;
- struct irq_chip *chip;
if (skip_ioapic_setup == 1)
return; dest(void)
continue;
@@ -2538,7 +2537,6 @@ void __init setup_ioapic_
- raw_spin_
/* dest(void)
else
mask = apic->target_ cpus();
@@ -2549,11 +2547,7 @@ void __init setup_ioapic_
- chip = irq_data_ get_irq_ chip(idata) ; irq_set_ affinity) set_affinity( idata, mask, false); unlock_ irq(&desc- >lock); affinity( irq, mask);
- /* Might be lapic_chip for irq 0 */
- if (chip->
- chip->irq_
- raw_spin_
+ irq_set_
}
}
#endif
I tried this and it works. Another option is this smaller patch:
diff --git a/arch/ x86/kernel/ apic/io_ apic.c b/arch/ x86/kernel/ apic/io_ apic.c x86/kernel/ apic/io_ apic.c x86/kernel/ apic/io_ apic.c dest(void)
index 64f233a..f185a1e 100644
--- a/arch/
+++ b/arch/
@@ -2523,7 +2523,6 @@ void __init setup_ioapic_
const struct cpumask *mask;
struct irq_desc *desc;
struct irq_data *idata;
- struct irq_chip *chip;
if (skip_ioapic_setup == 1)
return; dest(void)
else
mask = apic->target_ cpus();
@@ -2549,10 +2548,7 @@ void __init setup_ioapic_
- chip = irq_data_ get_irq_ chip(idata) ; irq_set_ affinity) set_affinity( idata, mask, false); affinity_ locked( idata, mask, false);
raw_spin_ unlock_ irq(&desc- >lock);
- /* Might be lapic_chip for irq 0 */
- if (chip->
- chip->irq_
+ irq_set_
}
}
which essentially keeps the raw_spin_ lock_irq( )/raw_spin_ unlock_ irq() rather than raw_spin_ lock_irqsave( )/raw_spin_ unlock_ irqrestore( ) used by __irq_set_ affinity( ) in kernel/irq/manage.c .
I tested both patches on top of Ubuntu-4.4.0-47.68 and they work.
They also apply cleanly to Ubuntu-4.2.0-42.49 but I didn't actually check that it builds/works.
I tried manually inlining the irq_set_ affinity_ locked( ) (which required further inlining of some helper functions and providing a declaration of irq_do_ set_affinity( )) and it still worked. However, forcing the "if (irq_can_ move_pcntxt( ))" path that immediately performs "chip-> irq_set_ affinity( idata, mask, false)" exposes the bug.
This confirms what I expected after reading https:/ /lkml.org/ lkml/2012/ 3/26/392 . Basically, when the hardware says that you cannot do something right away, you really cannot. And the offending commit just ignores this.