From 46b84791737448e1e3668c31c9caa30fa707ad41 Mon Sep 17 00:00:00 2001 From: Puck Meerburg Date: Thu, 28 Sep 2023 13:49:05 +0000 Subject: [PATCH] arch/x86: Fix sending ICIs to more than one cluster, send one at a time. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Reviewed-by: Jérôme Duval --- src/system/kernel/arch/x86/arch_smp.cpp | 77 ++++++++++++++----------- 1 file changed, 44 insertions(+), 33 deletions(-) diff --git a/src/system/kernel/arch/x86/arch_smp.cpp b/src/system/kernel/arch/x86/arch_smp.cpp index fd5535157f..be77fe0db8 100644 --- a/src/system/kernel/arch/x86/arch_smp.cpp +++ b/src/system/kernel/arch/x86/arch_smp.cpp @@ -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) {