Skip to content

Commit dcc5c6f

Browse files
committed
Merge tag 'x86-urgent-2020-08-30' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 fixes from Thomas Gleixner: "Three interrupt related fixes for X86: - Move disabling of the local APIC after invoking fixup_irqs() to ensure that interrupts which are incoming are noted in the IRR and not ignored. - Unbreak affinity setting. The rework of the entry code reused the regular exception entry code for device interrupts. The vector number is pushed into the errorcode slot on the stack which is then lifted into an argument and set to -1 because that's regs->orig_ax which is used in quite some places to check whether the entry came from a syscall. But it was overlooked that orig_ax is used in the affinity cleanup code to validate whether the interrupt has arrived on the new target. It turned out that this vector check is pointless because interrupts are never moved from one vector to another on the same CPU. That check is a historical leftover from the time where x86 supported multi-CPU affinities, but not longer needed with the now strict single CPU affinity. Famous last words ... - Add a missing check for an empty cpumask into the matrix allocator. The affinity change added a warning to catch the case where an interrupt is moved on the same CPU to a different vector. This triggers because a condition with an empty cpumask returns an assignment from the allocator as the allocator uses for_each_cpu() without checking the cpumask for being empty. The historical inconsistent for_each_cpu() behaviour of ignoring the cpumask and unconditionally claiming that CPU0 is in the mask struck again. Sigh. plus a new entry into the MAINTAINER file for the HPE/UV platform" * tag 'x86-urgent-2020-08-30' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: genirq/matrix: Deal with the sillyness of for_each_cpu() on UP x86/irq: Unbreak interrupt affinity setting x86/hotplug: Silence APIC only after all interrupts are migrated MAINTAINERS: Add entry for HPE Superdome Flex (UV) maintainers
2 parents d2283cd + 784a083 commit dcc5c6f

File tree

4 files changed

+45
-13
lines changed

4 files changed

+45
-13
lines changed

MAINTAINERS

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18875,6 +18875,15 @@ S: Maintained
1887518875
T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86/core
1887618876
F: arch/x86/platform
1887718877

18878+
X86 PLATFORM UV HPE SUPERDOME FLEX
18879+
M: Steve Wahl <[email protected]>
18880+
R: Dimitri Sivanich <[email protected]>
18881+
R: Russ Anderson <[email protected]>
18882+
S: Supported
18883+
F: arch/x86/include/asm/uv/
18884+
F: arch/x86/kernel/apic/x2apic_uv_x.c
18885+
F: arch/x86/platform/uv/
18886+
1887818887
X86 VDSO
1887918888
M: Andy Lutomirski <[email protected]>
1888018889

arch/x86/kernel/apic/vector.c

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ static void apic_update_vector(struct irq_data *irqd, unsigned int newvec,
161161
apicd->move_in_progress = true;
162162
apicd->prev_vector = apicd->vector;
163163
apicd->prev_cpu = apicd->cpu;
164+
WARN_ON_ONCE(apicd->cpu == newcpu);
164165
} else {
165166
irq_matrix_free(vector_matrix, apicd->cpu, apicd->vector,
166167
managed);
@@ -910,23 +911,24 @@ void send_cleanup_vector(struct irq_cfg *cfg)
910911
__send_cleanup_vector(apicd);
911912
}
912913

913-
static void __irq_complete_move(struct irq_cfg *cfg, unsigned vector)
914+
void irq_complete_move(struct irq_cfg *cfg)
914915
{
915916
struct apic_chip_data *apicd;
916917

917918
apicd = container_of(cfg, struct apic_chip_data, hw_irq_cfg);
918919
if (likely(!apicd->move_in_progress))
919920
return;
920921

921-
if (vector == apicd->vector && apicd->cpu == smp_processor_id())
922+
/*
923+
* If the interrupt arrived on the new target CPU, cleanup the
924+
* vector on the old target CPU. A vector check is not required
925+
* because an interrupt can never move from one vector to another
926+
* on the same CPU.
927+
*/
928+
if (apicd->cpu == smp_processor_id())
922929
__send_cleanup_vector(apicd);
923930
}
924931

925-
void irq_complete_move(struct irq_cfg *cfg)
926-
{
927-
__irq_complete_move(cfg, ~get_irq_regs()->orig_ax);
928-
}
929-
930932
/*
931933
* Called from fixup_irqs() with @desc->lock held and interrupts disabled.
932934
*/

arch/x86/kernel/smpboot.c

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1594,14 +1594,28 @@ int native_cpu_disable(void)
15941594
if (ret)
15951595
return ret;
15961596

1597-
/*
1598-
* Disable the local APIC. Otherwise IPI broadcasts will reach
1599-
* it. It still responds normally to INIT, NMI, SMI, and SIPI
1600-
* messages.
1601-
*/
1602-
apic_soft_disable();
16031597
cpu_disable_common();
16041598

1599+
/*
1600+
* Disable the local APIC. Otherwise IPI broadcasts will reach
1601+
* it. It still responds normally to INIT, NMI, SMI, and SIPI
1602+
* messages.
1603+
*
1604+
* Disabling the APIC must happen after cpu_disable_common()
1605+
* which invokes fixup_irqs().
1606+
*
1607+
* Disabling the APIC preserves already set bits in IRR, but
1608+
* an interrupt arriving after disabling the local APIC does not
1609+
* set the corresponding IRR bit.
1610+
*
1611+
* fixup_irqs() scans IRR for set bits so it can raise a not
1612+
* yet handled interrupt on the new destination CPU via an IPI
1613+
* but obviously it can't do so for IRR bits which are not set.
1614+
* IOW, interrupts arriving after disabling the local APIC will
1615+
* be lost.
1616+
*/
1617+
apic_soft_disable();
1618+
16051619
return 0;
16061620
}
16071621

kernel/irq/matrix.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,13 @@ int irq_matrix_alloc(struct irq_matrix *m, const struct cpumask *msk,
380380
unsigned int cpu, bit;
381381
struct cpumap *cm;
382382

383+
/*
384+
* Not required in theory, but matrix_find_best_cpu() uses
385+
* for_each_cpu() which ignores the cpumask on UP .
386+
*/
387+
if (cpumask_empty(msk))
388+
return -EINVAL;
389+
383390
cpu = matrix_find_best_cpu(m, msk);
384391
if (cpu == UINT_MAX)
385392
return -ENOSPC;

0 commit comments

Comments
 (0)