arch: We can use an independent SIG interrupt to handle async pause, which can save processing time.

Signed-off-by: hujun5 <hujun5@xiaomi.com>
This commit is contained in:
hujun5 2024-04-26 12:26:53 +08:00 committed by Xiang Xiao
parent ed998c08c4
commit a8717c6453
15 changed files with 223 additions and 16 deletions

View File

@ -208,6 +208,34 @@ int up_cpu_paused_restore(void)
return OK; 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 * Name: arm_pause_handler
* *
@ -256,8 +284,6 @@ int arm_pause_handler(int irq, void *context, void *arg)
leave_critical_section(flags); leave_critical_section(flags);
} }
nxsched_process_delivered(cpu);
return OK; 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) 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; return OK;
} }
@ -331,7 +357,7 @@ int up_cpu_pause(int cpu)
spin_lock(&g_cpu_wait[cpu]); spin_lock(&g_cpu_wait[cpu]);
spin_lock(&g_cpu_paused[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 /* Wait for the other CPU to unlock g_cpu_paused meaning that
* it is fully paused and ready for up_cpu_resume(); * it is fully paused and ready for up_cpu_resume();

View File

@ -215,6 +215,8 @@ void arm_gic0_initialize(void)
DEBUGVERIFY(irq_attach(GIC_SMP_CPUSTART, arm_start_handler, NULL)); 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, arm_pause_handler, NULL));
DEBUGVERIFY(irq_attach(GIC_SMP_CPUPAUSE_ASYNC,
arm_pause_async_handler, NULL));
DEBUGVERIFY(irq_attach(GIC_SMP_CPUCALL, DEBUGVERIFY(irq_attach(GIC_SMP_CPUCALL,
nxsched_smp_call_handler, NULL)); nxsched_smp_call_handler, NULL));
#endif #endif

View File

@ -619,10 +619,12 @@
# define GIC_SMP_CPUSTART GIC_IRQ_SGI9 # define GIC_SMP_CPUSTART GIC_IRQ_SGI9
# define GIC_SMP_CPUPAUSE GIC_IRQ_SGI10 # define GIC_SMP_CPUPAUSE GIC_IRQ_SGI10
# define GIC_SMP_CPUCALL GIC_IRQ_SGI11 # define GIC_SMP_CPUCALL GIC_IRQ_SGI11
# define GIC_SMP_CPUPAUSE_ASYNC GIC_IRQ_SGI12
#else #else
# define GIC_SMP_CPUSTART GIC_IRQ_SGI1 # define GIC_SMP_CPUSTART GIC_IRQ_SGI1
# define GIC_SMP_CPUPAUSE GIC_IRQ_SGI2 # define GIC_SMP_CPUPAUSE GIC_IRQ_SGI2
# define GIC_SMP_CPUCALL GIC_IRQ_SGI3 # define GIC_SMP_CPUCALL GIC_IRQ_SGI3
# define GIC_SMP_CPUPAUSE_ASYNC GIC_IRQ_SGI4
#endif #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); int arm_pause_handler(int irq, void *context, void *arg);
#endif #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 * Name: arm_gic_dump
* *

View File

@ -230,8 +230,6 @@ int up_cpu_paused_restore(void)
int arm_pause_handler(int irq, void *context, void *arg) 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 /* Check for false alarms. Such false could occur as a consequence of
* some deadlock breaking logic that might have already serviced the SG2 * some deadlock breaking logic that might have already serviced the SG2
* interrupt by calling up_cpu_paused(). If the pause event has already * 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); 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; 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) 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; return OK;
} }
@ -331,7 +355,7 @@ int up_cpu_pause(int cpu)
spin_lock(&g_cpu_wait[cpu]); spin_lock(&g_cpu_wait[cpu]);
spin_lock(&g_cpu_paused[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 /* Wait for the other CPU to unlock g_cpu_paused meaning that
* it is fully paused and ready for up_cpu_resume(); * it is fully paused and ready for up_cpu_resume();

View File

@ -161,6 +161,8 @@ void arm_gic0_initialize(void)
DEBUGVERIFY(irq_attach(GIC_SMP_CPUSTART, arm_start_handler, NULL)); 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, arm_pause_handler, NULL));
DEBUGVERIFY(irq_attach(GIC_SMP_CPUPAUSE_ASYNC,
arm_pause_async_handler, NULL));
DEBUGVERIFY(irq_attach(GIC_SMP_CPUCALL, DEBUGVERIFY(irq_attach(GIC_SMP_CPUCALL,
nxsched_smp_call_handler, NULL)); nxsched_smp_call_handler, NULL));
#endif #endif

View File

@ -610,10 +610,12 @@
# define GIC_SMP_CPUSTART GIC_IRQ_SGI9 # define GIC_SMP_CPUSTART GIC_IRQ_SGI9
# define GIC_SMP_CPUPAUSE GIC_IRQ_SGI10 # define GIC_SMP_CPUPAUSE GIC_IRQ_SGI10
# define GIC_SMP_CPUCALL GIC_IRQ_SGI11 # define GIC_SMP_CPUCALL GIC_IRQ_SGI11
# define GIC_SMP_CPUPAUSE_ASYNC GIC_IRQ_SGI12
#else #else
# define GIC_SMP_CPUSTART GIC_IRQ_SGI1 # define GIC_SMP_CPUSTART GIC_IRQ_SGI1
# define GIC_SMP_CPUPAUSE GIC_IRQ_SGI2 # define GIC_SMP_CPUPAUSE GIC_IRQ_SGI2
# define GIC_SMP_CPUCALL GIC_IRQ_SGI3 # define GIC_SMP_CPUCALL GIC_IRQ_SGI3
# define GIC_SMP_CPUPAUSE_ASYNC GIC_IRQ_SGI4
#endif #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); int arm_pause_handler(int irq, void *context, void *arg);
#endif #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 * Name: arm_gic_dump
* *

View File

@ -313,10 +313,12 @@
# define GIC_SMP_CPUSTART GIC_IRQ_SGI9 # define GIC_SMP_CPUSTART GIC_IRQ_SGI9
# define GIC_SMP_CPUPAUSE GIC_IRQ_SGI10 # define GIC_SMP_CPUPAUSE GIC_IRQ_SGI10
# define GIC_SMP_CPUCALL GIC_IRQ_SGI11 # define GIC_SMP_CPUCALL GIC_IRQ_SGI11
# define GIC_SMP_CPUPAUSE_ASYNC GIC_IRQ_SGI12
#else #else
# define GIC_SMP_CPUSTART GIC_IRQ_SGI1 # define GIC_SMP_CPUSTART GIC_IRQ_SGI1
# define GIC_SMP_CPUPAUSE GIC_IRQ_SGI2 # define GIC_SMP_CPUPAUSE GIC_IRQ_SGI2
# define GIC_SMP_CPUCALL GIC_IRQ_SGI3 # define GIC_SMP_CPUCALL GIC_IRQ_SGI3
# define GIC_SMP_CPUPAUSE_ASYNC GIC_IRQ_SGI4
#endif #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); 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); void arm_gic_secondary_init(void);
#endif #endif

View File

@ -568,6 +568,8 @@ static void gicv3_dist_init(void)
/* Attach SGI interrupt handlers. This attaches the handler to all CPUs. */ /* 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, arm64_pause_handler, NULL));
DEBUGVERIFY(irq_attach(GIC_SMP_CPUPAUSE_ASYNC,
arm64_pause_async_handler, NULL));
DEBUGVERIFY(irq_attach(GIC_SMP_CPUCALL, DEBUGVERIFY(irq_attach(GIC_SMP_CPUCALL,
nxsched_smp_call_handler, NULL)); nxsched_smp_call_handler, NULL));
#endif #endif
@ -814,6 +816,7 @@ static void arm_gic_init(void)
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
up_enable_irq(GIC_SMP_CPUPAUSE); up_enable_irq(GIC_SMP_CPUPAUSE);
up_enable_irq(GIC_SMP_CPUPAUSE_ASYNC);
#endif #endif
} }

View File

@ -211,6 +211,35 @@ int up_cpu_paused_restore(void)
return OK; 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 * Name: arm64_pause_handler
* *
@ -259,8 +288,6 @@ int arm64_pause_handler(int irq, void *context, void *arg)
leave_critical_section(flags); leave_critical_section(flags);
} }
nxsched_process_delivered(cpu);
return OK; return OK;
} }
@ -287,7 +314,7 @@ inline_function int up_cpu_pause_async(int cpu)
{ {
/* Execute SGI2 */ /* Execute SGI2 */
arm64_gic_raise_sgi(GIC_SMP_CPUPAUSE, (1 << cpu)); arm64_gic_raise_sgi(GIC_SMP_CPUPAUSE_ASYNC, (1 << cpu));
return OK; return OK;
} }
@ -336,7 +363,7 @@ int up_cpu_pause(int cpu)
spin_lock(&g_cpu_wait[cpu]); spin_lock(&g_cpu_wait[cpu]);
spin_lock(&g_cpu_paused[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 /* Wait for the other CPU to unlock g_cpu_paused meaning that
* it is fully paused and ready for up_cpu_resume(); * it is fully paused and ready for up_cpu_resume();

View File

@ -281,10 +281,12 @@
#define GIC_IRQ_SGI15 15 #define GIC_IRQ_SGI15 15
#ifdef CONFIG_ARCH_TRUSTZONE_SECURE #ifdef CONFIG_ARCH_TRUSTZONE_SECURE
# define GIC_SMP_CPUPAUSE_ASYNC GIC_IRQ_SGI8
# define GIC_SMP_CPUSTART GIC_IRQ_SGI9 # define GIC_SMP_CPUSTART GIC_IRQ_SGI9
# define GIC_SMP_CPUPAUSE GIC_IRQ_SGI10 # define GIC_SMP_CPUPAUSE GIC_IRQ_SGI10
# define GIC_SMP_CPUCALL GIC_IRQ_SGI11 # define GIC_SMP_CPUCALL GIC_IRQ_SGI11
#else #else
# define GIC_SMP_CPUPAUSE_ASYNC GIC_IRQ_SGI0
# define GIC_SMP_CPUSTART GIC_IRQ_SGI1 # define GIC_SMP_CPUSTART GIC_IRQ_SGI1
# define GIC_SMP_CPUPAUSE GIC_IRQ_SGI2 # define GIC_SMP_CPUPAUSE GIC_IRQ_SGI2
# define GIC_SMP_CPUCALL GIC_IRQ_SGI3 # 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); 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); void arm64_gic_secondary_init(void);
#endif #endif

View File

@ -911,6 +911,8 @@ static void arm_gic0_initialize(void)
/* Attach SGI interrupt handlers. This attaches the handler to all CPUs. */ /* 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, arm64_pause_handler, NULL));
DEBUGVERIFY(irq_attach(GIC_SMP_CPUPAUSE_ASYNC,
arm64_pause_async_handler, NULL));
DEBUGVERIFY(irq_attach(GIC_SMP_CPUCALL, DEBUGVERIFY(irq_attach(GIC_SMP_CPUCALL,
nxsched_smp_call_handler, NULL)); nxsched_smp_call_handler, NULL));
#endif #endif

View File

@ -654,6 +654,8 @@ static void gicv3_dist_init(void)
/* Attach SGI interrupt handlers. This attaches the handler to all CPUs. */ /* 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, arm64_pause_handler, NULL));
DEBUGVERIFY(irq_attach(GIC_SMP_CPUPAUSE_ASYNC,
arm64_pause_async_handler, NULL));
DEBUGVERIFY(irq_attach(GIC_SMP_CPUCALL, DEBUGVERIFY(irq_attach(GIC_SMP_CPUCALL,
nxsched_smp_call_handler, NULL)); nxsched_smp_call_handler, NULL));
#endif #endif
@ -952,6 +954,7 @@ static void arm64_gic_init(void)
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
up_enable_irq(GIC_SMP_CPUPAUSE); up_enable_irq(GIC_SMP_CPUPAUSE);
up_enable_irq(GIC_SMP_CPUPAUSE_ASYNC);
up_enable_irq(GIC_SMP_CPUCALL); up_enable_irq(GIC_SMP_CPUCALL);
#endif #endif
} }

View File

@ -346,9 +346,10 @@
#define HPET0_IRQ IRQ2 #define HPET0_IRQ IRQ2
#define HPET1_IRQ IRQ8 #define HPET1_IRQ IRQ8
/* Use IRQ15 for SMP */ /* Use IRQ15 IRQ16 for SMP */
#define SMP_IPI_IRQ IRQ15 #define SMP_IPI_IRQ IRQ15
#define SMP_IPI_ASYNC_IRQ IRQ16
/* Common register save structure created by up_saveusercontext() and by /* Common register save structure created by up_saveusercontext() and by
* ISR/IRQ interrupt processing. * ISR/IRQ interrupt processing.

View File

@ -264,6 +264,35 @@ int up_pause_handler(int irq, void *c, void *arg)
return OK; 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 * Name: up_cpu_pause_async
* *
@ -290,7 +319,7 @@ inline_function int up_cpu_pause_async(int cpu)
CPU_ZERO(&cpuset); CPU_ZERO(&cpuset);
CPU_SET(cpu, &cpuset); CPU_SET(cpu, &cpuset);
up_trigger_irq(SMP_IPI_IRQ, cpuset); up_trigger_irq(SMP_IPI_ASYNC_IRQ, cpuset);
return OK; return OK;
} }
@ -336,6 +365,7 @@ void up_send_smp_call(cpu_set_t cpuset)
int up_cpu_pause(int cpu) int up_cpu_pause(int cpu)
{ {
cpu_set_t cpuset;
sinfo("cpu=%d\n", cpu); sinfo("cpu=%d\n", cpu);
#ifdef CONFIG_SCHED_INSTRUMENTATION #ifdef CONFIG_SCHED_INSTRUMENTATION
@ -362,7 +392,10 @@ int up_cpu_pause(int cpu)
/* Execute Pause IRQ to CPU(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 /* Wait for the other CPU to unlock g_cpu_paused meaning that
* it is fully paused and ready for up_cpu_resume(); * it is fully paused and ready for up_cpu_resume();

View File

@ -47,6 +47,7 @@
extern void __ap_entry(void); extern void __ap_entry(void);
extern int up_pause_handler(int irq, void *c, void *arg); 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 * Private Functions
@ -160,7 +161,9 @@ void x86_64_ap_boot(void)
/* Connect Pause IRQ to CPU */ /* Connect Pause IRQ to CPU */
irq_attach(SMP_IPI_IRQ, up_pause_handler, NULL); 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_IRQ);
up_enable_irq(SMP_IPI_ASYNC_IRQ);
/* CPU ready */ /* CPU ready */