arch/x86: Fix sending ICIs to more than one cluster, send one at a time.

The structure of a logical APIC destination is made up of a 16-bit
bitfield of cluster-local IDs, as well as a 16-bit cluster ID. When
sending an ICI to multiple cores in different clusters, these cannot simply be ORed together.
Fixes #17233

Change-Id: Ifa84da51eccd85c1eff529749ffa00bc2159899e
Reviewed-on: https://review.haiku-os.org/c/haiku/+/6919
Tested-by: Commit checker robot <no-reply+buildbot@haiku-os.org>
Reviewed-by: Jérôme Duval <jerome.duval@gmail.com>
This commit is contained in:
Puck Meerburg 2023-09-28 13:49:05 +00:00 committed by Jérôme Duval
parent 908afdaae4
commit 46b8479173

View File

@ -1,4 +1,5 @@
/*
* Copyright 2023, Puck Meerburg, puck@puckipedia.com.
* Copyright 2013, Paweł Dziepak, pdziepak@quarnos.org.
* Copyright 2002-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Distributed under the terms of the MIT License.
@ -132,42 +133,14 @@ arch_smp_per_cpu_init(kernel_args *args, int32 cpu)
}
void
arch_smp_send_multicast_ici(CPUSet& cpuSet)
static void
send_multicast_ici_physical(CPUSet& cpuSet)
{
#if KDEBUG
if (are_interrupts_enabled())
panic("arch_smp_send_multicast_ici: called with interrupts enabled");
#endif
memory_write_barrier();
int32 i = 0;
int32 cpuCount = smp_get_num_cpus();
int32 currentCpu = smp_get_current_cpu();
int32 logicalModeCPUs;
if (x2apic_available())
logicalModeCPUs = cpuCount;
else
logicalModeCPUs = std::min(cpuCount, int32(8));
uint32 destination = 0;
for (; i < logicalModeCPUs; i++) {
if (cpuSet.GetBit(i) && i != smp_get_current_cpu())
destination |= gCPU[i].arch.logical_apic_id;
}
uint32 mode = ICI_VECTOR | APIC_DELIVERY_MODE_FIXED
| APIC_INTR_COMMAND_1_ASSERT
| APIC_INTR_COMMAND_1_DEST_MODE_LOGICAL
| APIC_INTR_COMMAND_1_DEST_FIELD;
while (!apic_interrupt_delivered())
cpu_pause();
apic_set_interrupt_command(destination, mode);
for (; i < cpuCount; i++) {
if (cpuSet.GetBit(i)) {
for (int32 i = 0; i < cpuCount; i++) {
if (cpuSet.GetBit(i) && i != currentCpu) {
uint32 destination = sCPUAPICIds[i];
uint32 mode = ICI_VECTOR | APIC_DELIVERY_MODE_FIXED
| APIC_INTR_COMMAND_1_ASSERT
@ -182,6 +155,44 @@ arch_smp_send_multicast_ici(CPUSet& cpuSet)
}
void
arch_smp_send_multicast_ici(CPUSet& cpuSet)
{
#if KDEBUG
if (are_interrupts_enabled())
panic("arch_smp_send_multicast_ici: called with interrupts enabled");
#endif
memory_write_barrier();
if (!x2apic_available()) {
send_multicast_ici_physical(cpuSet);
return;
}
// WRMSR on the x2APIC MSRs is neither serializing, nor a load-store
// operation, requiring both memory serialization *and* a load fence, which is
// the only way to ensure the MSR doesn't get executed before the write
// barrier.
memory_read_barrier();
int32 cpuCount = smp_get_num_cpus();
int32 currentCpu = smp_get_current_cpu();
uint32 mode = ICI_VECTOR | APIC_DELIVERY_MODE_FIXED
| APIC_INTR_COMMAND_1_ASSERT
| APIC_INTR_COMMAND_1_DEST_MODE_LOGICAL
| APIC_INTR_COMMAND_1_DEST_FIELD;
for (int32 i = 0; i < cpuCount; i++) {
if (!cpuSet.GetBit(i) || i == currentCpu)
continue;
apic_set_interrupt_command(gCPU[i].arch.logical_apic_id, mode);
}
}
void
arch_smp_send_broadcast_ici(void)
{