From a8717c6453d2bb32f399bbcfe30f6c722783d0c7 Mon Sep 17 00:00:00 2001 From: hujun5 Date: Fri, 26 Apr 2024 12:26:53 +0800 Subject: [PATCH] arch: We can use an independent SIG interrupt to handle async pause, which can save processing time. Signed-off-by: hujun5 --- arch/arm/src/armv7-a/arm_cpupause.c | 34 +++++++++++++++++--- arch/arm/src/armv7-a/arm_gicv2.c | 2 ++ arch/arm/src/armv7-a/gic.h | 25 +++++++++++++++ arch/arm/src/armv7-r/arm_cpupause.c | 34 +++++++++++++++++--- arch/arm/src/armv7-r/arm_gicv2.c | 2 ++ arch/arm/src/armv7-r/gic.h | 26 +++++++++++++++ arch/arm/src/armv8-r/arm_gic.h | 6 ++++ arch/arm/src/armv8-r/arm_gicv3.c | 3 ++ arch/arm64/src/common/arm64_cpupause.c | 35 +++++++++++++++++--- arch/arm64/src/common/arm64_gic.h | 24 ++++++++++++++ arch/arm64/src/common/arm64_gicv2.c | 2 ++ arch/arm64/src/common/arm64_gicv3.c | 3 ++ arch/x86_64/include/intel64/irq.h | 3 +- arch/x86_64/src/intel64/intel64_cpupause.c | 37 ++++++++++++++++++++-- arch/x86_64/src/intel64/intel64_cpustart.c | 3 ++ 15 files changed, 223 insertions(+), 16 deletions(-) diff --git a/arch/arm/src/armv7-a/arm_cpupause.c b/arch/arm/src/armv7-a/arm_cpupause.c index 0a25b9af5d..81dc1a534e 100644 --- a/arch/arm/src/armv7-a/arm_cpupause.c +++ b/arch/arm/src/armv7-a/arm_cpupause.c @@ -208,6 +208,34 @@ int up_cpu_paused_restore(void) return OK; } +/**************************************************************************** + * Name: arm_pause_async_handler + * + * Description: + * This is the handler for async pause. + * + * 1. It saves the current task state at the head of the current assigned + * task list. + * 2. It porcess g_delivertasks + * 3. Returns from interrupt, restoring the state of the new task at the + * head of the ready to run list. + * + * Input Parameters: + * Standard interrupt handling + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +int arm_pause_async_handler(int irq, void *context, void *arg) +{ + int cpu = this_cpu(); + + nxsched_process_delivered(cpu); + return OK; +} + /**************************************************************************** * Name: arm_pause_handler * @@ -256,8 +284,6 @@ int arm_pause_handler(int irq, void *context, void *arg) leave_critical_section(flags); } - nxsched_process_delivered(cpu); - return OK; } @@ -282,7 +308,7 @@ int arm_pause_handler(int irq, void *context, void *arg) inline_function int up_cpu_pause_async(int cpu) { - arm_cpu_sgi(GIC_SMP_CPUPAUSE, (1 << cpu)); + arm_cpu_sgi(GIC_SMP_CPUPAUSE_ASYNC, (1 << cpu)); return OK; } @@ -331,7 +357,7 @@ int up_cpu_pause(int cpu) spin_lock(&g_cpu_wait[cpu]); spin_lock(&g_cpu_paused[cpu]); - up_cpu_pause_async(cpu); + arm_cpu_sgi(GIC_SMP_CPUPAUSE, (1 << cpu)); /* Wait for the other CPU to unlock g_cpu_paused meaning that * it is fully paused and ready for up_cpu_resume(); diff --git a/arch/arm/src/armv7-a/arm_gicv2.c b/arch/arm/src/armv7-a/arm_gicv2.c index 87c5aa19e3..47a132fbc6 100644 --- a/arch/arm/src/armv7-a/arm_gicv2.c +++ b/arch/arm/src/armv7-a/arm_gicv2.c @@ -215,6 +215,8 @@ void arm_gic0_initialize(void) DEBUGVERIFY(irq_attach(GIC_SMP_CPUSTART, arm_start_handler, NULL)); DEBUGVERIFY(irq_attach(GIC_SMP_CPUPAUSE, arm_pause_handler, NULL)); + DEBUGVERIFY(irq_attach(GIC_SMP_CPUPAUSE_ASYNC, + arm_pause_async_handler, NULL)); DEBUGVERIFY(irq_attach(GIC_SMP_CPUCALL, nxsched_smp_call_handler, NULL)); #endif diff --git a/arch/arm/src/armv7-a/gic.h b/arch/arm/src/armv7-a/gic.h index 29359e12dd..b652dea0a1 100644 --- a/arch/arm/src/armv7-a/gic.h +++ b/arch/arm/src/armv7-a/gic.h @@ -619,10 +619,12 @@ # define GIC_SMP_CPUSTART GIC_IRQ_SGI9 # define GIC_SMP_CPUPAUSE GIC_IRQ_SGI10 # define GIC_SMP_CPUCALL GIC_IRQ_SGI11 +# define GIC_SMP_CPUPAUSE_ASYNC GIC_IRQ_SGI12 #else # define GIC_SMP_CPUSTART GIC_IRQ_SGI1 # define GIC_SMP_CPUPAUSE GIC_IRQ_SGI2 # define GIC_SMP_CPUCALL GIC_IRQ_SGI3 +# define GIC_SMP_CPUPAUSE_ASYNC GIC_IRQ_SGI4 #endif /**************************************************************************** @@ -839,6 +841,29 @@ int arm_start_handler(int irq, void *context, void *arg); int arm_pause_handler(int irq, void *context, void *arg); #endif +/**************************************************************************** + * Name: arm_pause_async_handler + * + * Description: + * This is the handler for async pause. + * + * 1. It saves the current task state at the head of the current assigned + * task list. + * 2. It porcess g_delivertasks + * 3. Returns from interrupt, restoring the state of the new task at the + * head of the ready to run list. + * + * Input Parameters: + * Standard interrupt handling + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +#ifdef CONFIG_SMP +int arm_pause_async_handler(int irq, void *context, void *arg); +#endif /**************************************************************************** * Name: arm_gic_dump * diff --git a/arch/arm/src/armv7-r/arm_cpupause.c b/arch/arm/src/armv7-r/arm_cpupause.c index f68f418216..c7d1ebe38e 100644 --- a/arch/arm/src/armv7-r/arm_cpupause.c +++ b/arch/arm/src/armv7-r/arm_cpupause.c @@ -230,8 +230,6 @@ int up_cpu_paused_restore(void) int arm_pause_handler(int irq, void *context, void *arg) { - int cpu = this_cpu(); - /* Check for false alarms. Such false could occur as a consequence of * some deadlock breaking logic that might have already serviced the SG2 * interrupt by calling up_cpu_paused(). If the pause event has already @@ -256,8 +254,34 @@ int arm_pause_handler(int irq, void *context, void *arg) leave_critical_section(flags); } - nxsched_process_delivered(cpu); + return OK; +} +/**************************************************************************** + * Name: arm_pause_async_handler + * + * Description: + * This is the handler for async pause. + * + * 1. It saves the current task state at the head of the current assigned + * task list. + * 2. It porcess g_delivertasks + * 3. Returns from interrupt, restoring the state of the new task at the + * head of the ready to run list. + * + * Input Parameters: + * Standard interrupt handling + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +int arm_pause_async_handler(int irq, void *context, void *arg) +{ + int cpu = this_cpu(); + + nxsched_process_delivered(cpu); return OK; } @@ -282,7 +306,7 @@ int arm_pause_handler(int irq, void *context, void *arg) inline_function int up_cpu_pause_async(int cpu) { - arm_cpu_sgi(GIC_SMP_CPUPAUSE, (1 << cpu)); + arm_cpu_sgi(GIC_SMP_CPUPAUSE_ASYNC, (1 << cpu)); return OK; } @@ -331,7 +355,7 @@ int up_cpu_pause(int cpu) spin_lock(&g_cpu_wait[cpu]); spin_lock(&g_cpu_paused[cpu]); - up_cpu_pause_async(cpu); + arm_cpu_sgi(GIC_SMP_CPUPAUSE, (1 << cpu)); /* Wait for the other CPU to unlock g_cpu_paused meaning that * it is fully paused and ready for up_cpu_resume(); diff --git a/arch/arm/src/armv7-r/arm_gicv2.c b/arch/arm/src/armv7-r/arm_gicv2.c index d7513d252d..431ace37a4 100644 --- a/arch/arm/src/armv7-r/arm_gicv2.c +++ b/arch/arm/src/armv7-r/arm_gicv2.c @@ -161,6 +161,8 @@ void arm_gic0_initialize(void) DEBUGVERIFY(irq_attach(GIC_SMP_CPUSTART, arm_start_handler, NULL)); DEBUGVERIFY(irq_attach(GIC_SMP_CPUPAUSE, arm_pause_handler, NULL)); + DEBUGVERIFY(irq_attach(GIC_SMP_CPUPAUSE_ASYNC, + arm_pause_async_handler, NULL)); DEBUGVERIFY(irq_attach(GIC_SMP_CPUCALL, nxsched_smp_call_handler, NULL)); #endif diff --git a/arch/arm/src/armv7-r/gic.h b/arch/arm/src/armv7-r/gic.h index ecee23563d..d863233056 100644 --- a/arch/arm/src/armv7-r/gic.h +++ b/arch/arm/src/armv7-r/gic.h @@ -610,10 +610,12 @@ # define GIC_SMP_CPUSTART GIC_IRQ_SGI9 # define GIC_SMP_CPUPAUSE GIC_IRQ_SGI10 # define GIC_SMP_CPUCALL GIC_IRQ_SGI11 +# define GIC_SMP_CPUPAUSE_ASYNC GIC_IRQ_SGI12 #else # define GIC_SMP_CPUSTART GIC_IRQ_SGI1 # define GIC_SMP_CPUPAUSE GIC_IRQ_SGI2 # define GIC_SMP_CPUCALL GIC_IRQ_SGI3 +# define GIC_SMP_CPUPAUSE_ASYNC GIC_IRQ_SGI4 #endif /**************************************************************************** @@ -827,6 +829,30 @@ int arm_start_handler(int irq, void *context, void *arg); int arm_pause_handler(int irq, void *context, void *arg); #endif +/**************************************************************************** + * Name: arm_pause_async_handler + * + * Description: + * This is the handler for async pause. + * + * 1. It saves the current task state at the head of the current assigned + * task list. + * 2. It porcess g_delivertasks + * 3. Returns from interrupt, restoring the state of the new task at the + * head of the ready to run list. + * + * Input Parameters: + * Standard interrupt handling + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +#ifdef CONFIG_SMP +int arm_pause_async_handler(int irq, void *context, void *arg); +#endif + /**************************************************************************** * Name: arm_gic_dump * diff --git a/arch/arm/src/armv8-r/arm_gic.h b/arch/arm/src/armv8-r/arm_gic.h index e43ccff8d0..717e3660d2 100644 --- a/arch/arm/src/armv8-r/arm_gic.h +++ b/arch/arm/src/armv8-r/arm_gic.h @@ -313,10 +313,12 @@ # define GIC_SMP_CPUSTART GIC_IRQ_SGI9 # define GIC_SMP_CPUPAUSE GIC_IRQ_SGI10 # define GIC_SMP_CPUCALL GIC_IRQ_SGI11 +# define GIC_SMP_CPUPAUSE_ASYNC GIC_IRQ_SGI12 #else # define GIC_SMP_CPUSTART GIC_IRQ_SGI1 # define GIC_SMP_CPUPAUSE GIC_IRQ_SGI2 # define GIC_SMP_CPUCALL GIC_IRQ_SGI3 +# define GIC_SMP_CPUPAUSE_ASYNC GIC_IRQ_SGI4 #endif /**************************************************************************** @@ -355,6 +357,10 @@ int arm_gic_raise_sgi(unsigned int sgi_id, uint16_t target_list); int arm_pause_handler(int irq, void *context, void *arg); +#ifdef CONFIG_SMP +int arm_pause_async_handler(int irq, void *context, void *arg); +#endif + void arm_gic_secondary_init(void); #endif diff --git a/arch/arm/src/armv8-r/arm_gicv3.c b/arch/arm/src/armv8-r/arm_gicv3.c index 7ff1d35582..d32db05ac7 100644 --- a/arch/arm/src/armv8-r/arm_gicv3.c +++ b/arch/arm/src/armv8-r/arm_gicv3.c @@ -568,6 +568,8 @@ static void gicv3_dist_init(void) /* Attach SGI interrupt handlers. This attaches the handler to all CPUs. */ DEBUGVERIFY(irq_attach(GIC_SMP_CPUPAUSE, arm64_pause_handler, NULL)); + DEBUGVERIFY(irq_attach(GIC_SMP_CPUPAUSE_ASYNC, + arm64_pause_async_handler, NULL)); DEBUGVERIFY(irq_attach(GIC_SMP_CPUCALL, nxsched_smp_call_handler, NULL)); #endif @@ -814,6 +816,7 @@ static void arm_gic_init(void) #ifdef CONFIG_SMP up_enable_irq(GIC_SMP_CPUPAUSE); + up_enable_irq(GIC_SMP_CPUPAUSE_ASYNC); #endif } diff --git a/arch/arm64/src/common/arm64_cpupause.c b/arch/arm64/src/common/arm64_cpupause.c index f6579ba3b7..da81259d8d 100644 --- a/arch/arm64/src/common/arm64_cpupause.c +++ b/arch/arm64/src/common/arm64_cpupause.c @@ -211,6 +211,35 @@ int up_cpu_paused_restore(void) return OK; } +/**************************************************************************** + * Name: arm64_pause_async_handler + * + * Description: + * This is the handler for async pause. + * + * 1. It saves the current task state at the head of the current assigned + * task list. + * 2. It porcess g_delivertasks + * 3. Returns from interrupt, restoring the state of the new task at the + * head of the ready to run list. + * + * Input Parameters: + * Standard interrupt handling + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +int arm64_pause_async_handler(int irq, void *context, void *arg) +{ + int cpu = this_cpu(); + + nxsched_process_delivered(cpu); + + return OK; +} + /**************************************************************************** * Name: arm64_pause_handler * @@ -259,8 +288,6 @@ int arm64_pause_handler(int irq, void *context, void *arg) leave_critical_section(flags); } - nxsched_process_delivered(cpu); - return OK; } @@ -287,7 +314,7 @@ inline_function int up_cpu_pause_async(int cpu) { /* Execute SGI2 */ - arm64_gic_raise_sgi(GIC_SMP_CPUPAUSE, (1 << cpu)); + arm64_gic_raise_sgi(GIC_SMP_CPUPAUSE_ASYNC, (1 << cpu)); return OK; } @@ -336,7 +363,7 @@ int up_cpu_pause(int cpu) spin_lock(&g_cpu_wait[cpu]); spin_lock(&g_cpu_paused[cpu]); - up_cpu_pause_async(cpu); + arm64_gic_raise_sgi(GIC_SMP_CPUPAUSE, (1 << cpu)); /* Wait for the other CPU to unlock g_cpu_paused meaning that * it is fully paused and ready for up_cpu_resume(); diff --git a/arch/arm64/src/common/arm64_gic.h b/arch/arm64/src/common/arm64_gic.h index 5b81e6ebde..de66d61696 100644 --- a/arch/arm64/src/common/arm64_gic.h +++ b/arch/arm64/src/common/arm64_gic.h @@ -281,10 +281,12 @@ #define GIC_IRQ_SGI15 15 #ifdef CONFIG_ARCH_TRUSTZONE_SECURE +# define GIC_SMP_CPUPAUSE_ASYNC GIC_IRQ_SGI8 # define GIC_SMP_CPUSTART GIC_IRQ_SGI9 # define GIC_SMP_CPUPAUSE GIC_IRQ_SGI10 # define GIC_SMP_CPUCALL GIC_IRQ_SGI11 #else +# define GIC_SMP_CPUPAUSE_ASYNC GIC_IRQ_SGI0 # define GIC_SMP_CPUSTART GIC_IRQ_SGI1 # define GIC_SMP_CPUPAUSE GIC_IRQ_SGI2 # define GIC_SMP_CPUCALL GIC_IRQ_SGI3 @@ -343,6 +345,28 @@ void arm64_gic_raise_sgi(unsigned int sgi_id, uint16_t target_list); int arm64_pause_handler(int irq, void *context, void *arg); +/**************************************************************************** + * Name: arm64_pause_async_handler + * + * Description: + * This is the handler for async pause. + * + * 1. It saves the current task state at the head of the current assigned + * task list. + * 2. It porcess g_delivertasks + * 3. Returns from interrupt, restoring the state of the new task at the + * head of the ready to run list. + * + * Input Parameters: + * Standard interrupt handling + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +int arm64_pause_async_handler(int irq, void *context, void *arg); + void arm64_gic_secondary_init(void); #endif diff --git a/arch/arm64/src/common/arm64_gicv2.c b/arch/arm64/src/common/arm64_gicv2.c index 3f019bfd9a..525298b185 100644 --- a/arch/arm64/src/common/arm64_gicv2.c +++ b/arch/arm64/src/common/arm64_gicv2.c @@ -911,6 +911,8 @@ static void arm_gic0_initialize(void) /* Attach SGI interrupt handlers. This attaches the handler to all CPUs. */ DEBUGVERIFY(irq_attach(GIC_SMP_CPUPAUSE, arm64_pause_handler, NULL)); + DEBUGVERIFY(irq_attach(GIC_SMP_CPUPAUSE_ASYNC, + arm64_pause_async_handler, NULL)); DEBUGVERIFY(irq_attach(GIC_SMP_CPUCALL, nxsched_smp_call_handler, NULL)); #endif diff --git a/arch/arm64/src/common/arm64_gicv3.c b/arch/arm64/src/common/arm64_gicv3.c index 59b300cbf2..49b9d51335 100644 --- a/arch/arm64/src/common/arm64_gicv3.c +++ b/arch/arm64/src/common/arm64_gicv3.c @@ -654,6 +654,8 @@ static void gicv3_dist_init(void) /* Attach SGI interrupt handlers. This attaches the handler to all CPUs. */ DEBUGVERIFY(irq_attach(GIC_SMP_CPUPAUSE, arm64_pause_handler, NULL)); + DEBUGVERIFY(irq_attach(GIC_SMP_CPUPAUSE_ASYNC, + arm64_pause_async_handler, NULL)); DEBUGVERIFY(irq_attach(GIC_SMP_CPUCALL, nxsched_smp_call_handler, NULL)); #endif @@ -952,6 +954,7 @@ static void arm64_gic_init(void) #ifdef CONFIG_SMP up_enable_irq(GIC_SMP_CPUPAUSE); + up_enable_irq(GIC_SMP_CPUPAUSE_ASYNC); up_enable_irq(GIC_SMP_CPUCALL); #endif } diff --git a/arch/x86_64/include/intel64/irq.h b/arch/x86_64/include/intel64/irq.h index 676458020d..fbcdf54500 100644 --- a/arch/x86_64/include/intel64/irq.h +++ b/arch/x86_64/include/intel64/irq.h @@ -346,9 +346,10 @@ #define HPET0_IRQ IRQ2 #define HPET1_IRQ IRQ8 -/* Use IRQ15 for SMP */ +/* Use IRQ15 IRQ16 for SMP */ #define SMP_IPI_IRQ IRQ15 +#define SMP_IPI_ASYNC_IRQ IRQ16 /* Common register save structure created by up_saveusercontext() and by * ISR/IRQ interrupt processing. diff --git a/arch/x86_64/src/intel64/intel64_cpupause.c b/arch/x86_64/src/intel64/intel64_cpupause.c index 44e3220c2a..7f6891d24c 100644 --- a/arch/x86_64/src/intel64/intel64_cpupause.c +++ b/arch/x86_64/src/intel64/intel64_cpupause.c @@ -264,6 +264,35 @@ int up_pause_handler(int irq, void *c, void *arg) return OK; } +/**************************************************************************** + * Name: up_pause_async_handler + * + * Description: + * This is the handler for async pause. + * + * 1. It saves the current task state at the head of the current assigned + * task list. + * 2. It porcess g_delivertasks + * 3. Returns from interrupt, restoring the state of the new task at the + * head of the ready to run list. + * + * Input Parameters: + * Standard interrupt handling + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +int up_pause_async_handler(int irq, void *c, void *arg) +{ + int cpu = this_cpu(); + + nxsched_process_delivered(cpu); + + return OK; +} + /**************************************************************************** * Name: up_cpu_pause_async * @@ -290,7 +319,7 @@ inline_function int up_cpu_pause_async(int cpu) CPU_ZERO(&cpuset); CPU_SET(cpu, &cpuset); - up_trigger_irq(SMP_IPI_IRQ, cpuset); + up_trigger_irq(SMP_IPI_ASYNC_IRQ, cpuset); return OK; } @@ -336,6 +365,7 @@ void up_send_smp_call(cpu_set_t cpuset) int up_cpu_pause(int cpu) { + cpu_set_t cpuset; sinfo("cpu=%d\n", cpu); #ifdef CONFIG_SCHED_INSTRUMENTATION @@ -362,7 +392,10 @@ int up_cpu_pause(int cpu) /* Execute Pause IRQ to CPU(cpu) */ - up_cpu_pause_async(cpu); + CPU_ZERO(&cpuset); + CPU_SET(cpu, &cpuset); + + up_trigger_irq(SMP_IPI_IRQ, cpuset); /* Wait for the other CPU to unlock g_cpu_paused meaning that * it is fully paused and ready for up_cpu_resume(); diff --git a/arch/x86_64/src/intel64/intel64_cpustart.c b/arch/x86_64/src/intel64/intel64_cpustart.c index c766ebfe1c..2fe404349a 100644 --- a/arch/x86_64/src/intel64/intel64_cpustart.c +++ b/arch/x86_64/src/intel64/intel64_cpustart.c @@ -47,6 +47,7 @@ extern void __ap_entry(void); extern int up_pause_handler(int irq, void *c, void *arg); +extern int up_pause_async_handler(int irq, void *c, void *arg); /**************************************************************************** * Private Functions @@ -160,7 +161,9 @@ void x86_64_ap_boot(void) /* Connect Pause IRQ to CPU */ irq_attach(SMP_IPI_IRQ, up_pause_handler, NULL); + irq_attach(SMP_IPI_ASYNC_IRQ, up_pause_async_handler, NULL); up_enable_irq(SMP_IPI_IRQ); + up_enable_irq(SMP_IPI_ASYNC_IRQ); /* CPU ready */