Browse Source

arch/x86: Make irq_offload SMP-safe on x86_64

The irq_offload mechanism was using the same entry of the IDT vector for
all CPUs on SMP systems. This caused race conditions when two CPUs were
doing irq_offload() calls.

This patch addresses that by adding one indirection layer: the
irq_offload() now sets a per CPU entry with the routine and parameter to
be run. Then a software interrupt is generated, and a default handler
will do the appropriate dispatching.

Finally, test "kernel/smp_abort" is enabled for x86 as it should work
now.

Fixes #72172.

Signed-off-by: Ederson de Souza <ederson.desouza@intel.com>
pull/73698/head
Ederson de Souza 1 year ago committed by Henrik Brix Andersen
parent
commit
7f0b5edd8c
  1. 32
      arch/x86/core/intel64/irq_offload.c
  2. 1
      tests/kernel/smp_abort/testcase.yaml

32
arch/x86/core/intel64/irq_offload.c

@ -9,6 +9,7 @@ @@ -9,6 +9,7 @@
*/
#include <zephyr/kernel.h>
#include <zephyr/init.h>
#include <zephyr/irq_offload.h>
#include <kernel_arch_data.h>
@ -17,12 +18,37 @@ @@ -17,12 +18,37 @@
extern void (*x86_irq_funcs[NR_IRQ_VECTORS])(const void *arg);
extern const void *x86_irq_args[NR_IRQ_VECTORS];
static void (*irq_offload_funcs[CONFIG_MP_NUM_CPUS])(const void *arg);
static const void *irq_offload_args[CONFIG_MP_NUM_CPUS];
static void dispatcher(const void *arg)
{
uint8_t cpu_id = _current_cpu->id;
if (irq_offload_funcs[cpu_id] != NULL) {
irq_offload_funcs[cpu_id](irq_offload_args[cpu_id]);
}
}
void arch_irq_offload(irq_offload_routine_t routine, const void *parameter)
{
x86_irq_funcs[CONFIG_IRQ_OFFLOAD_VECTOR - IV_IRQS] = routine;
x86_irq_args[CONFIG_IRQ_OFFLOAD_VECTOR - IV_IRQS] = parameter;
int key = arch_irq_lock();
uint8_t cpu_id = _current_cpu->id;
irq_offload_funcs[cpu_id] = routine;
irq_offload_args[cpu_id] = parameter;
__asm__ volatile("int %0" : : "i" (CONFIG_IRQ_OFFLOAD_VECTOR)
: "memory");
x86_irq_funcs[CONFIG_IRQ_OFFLOAD_VECTOR - IV_IRQS] = NULL;
arch_irq_unlock(key);
}
int irq_offload_init(void)
{
x86_irq_funcs[CONFIG_IRQ_OFFLOAD_VECTOR - IV_IRQS] = dispatcher;
return 0;
}
SYS_INIT(irq_offload_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);

1
tests/kernel/smp_abort/testcase.yaml

@ -1,6 +1,5 @@ @@ -1,6 +1,5 @@
tests:
kernel.smp_abort:
arch_exclude: x86 # Buggy irq_offload(), see #71172
tags:
- kernel
- smp

Loading…
Cancel
Save