Add irq_work support for LoongArch via self IPIs. This make it possible
to run works in hardware interrupt context, which is a prerequisite for
NOHZ_FULL.
Implement:
- arch_irq_work_raise()
- arch_irq_work_has_interrupt()
Signed-off-by: Huacai Chen <[email protected]>
---
arch/loongarch/include/asm/hardirq.h | 3 ++-
arch/loongarch/include/asm/irq_work.h | 10 ++++++++++
arch/loongarch/include/asm/smp.h | 2 ++
arch/loongarch/kernel/paravirt.c | 6 ++++++
arch/loongarch/kernel/smp.c | 14 ++++++++++++++
5 files changed, 34 insertions(+), 1 deletion(-)
create mode 100644 arch/loongarch/include/asm/irq_work.h
diff --git a/arch/loongarch/include/asm/hardirq.h b/arch/loongarch/include/asm/hardirq.h
index d41138abcf26..1d7feb719515 100644
--- a/arch/loongarch/include/asm/hardirq.h
+++ b/arch/loongarch/include/asm/hardirq.h
@@ -12,11 +12,12 @@
extern void ack_bad_irq(unsigned int irq);
#define ack_bad_irq ack_bad_irq
-#define NR_IPI 2
+#define NR_IPI 3
enum ipi_msg_type {
IPI_RESCHEDULE,
IPI_CALL_FUNCTION,
+ IPI_IRQ_WORK,
};
typedef struct {
diff --git a/arch/loongarch/include/asm/irq_work.h b/arch/loongarch/include/asm/irq_work.h
new file mode 100644
index 000000000000..d63076e9160d
--- /dev/null
+++ b/arch/loongarch/include/asm/irq_work.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_LOONGARCH_IRQ_WORK_H
+#define _ASM_LOONGARCH_IRQ_WORK_H
+
+static inline bool arch_irq_work_has_interrupt(void)
+{
+ return IS_ENABLED(CONFIG_SMP);
+}
+
+#endif /* _ASM_LOONGARCH_IRQ_WORK_H */
diff --git a/arch/loongarch/include/asm/smp.h b/arch/loongarch/include/asm/smp.h
index 278700cfee88..50db503f44e3 100644
--- a/arch/loongarch/include/asm/smp.h
+++ b/arch/loongarch/include/asm/smp.h
@@ -69,9 +69,11 @@ extern int __cpu_logical_map[NR_CPUS];
#define ACTION_BOOT_CPU 0
#define ACTION_RESCHEDULE 1
#define ACTION_CALL_FUNCTION 2
+#define ACTION_IRQ_WORK 3
#define SMP_BOOT_CPU BIT(ACTION_BOOT_CPU)
#define SMP_RESCHEDULE BIT(ACTION_RESCHEDULE)
#define SMP_CALL_FUNCTION BIT(ACTION_CALL_FUNCTION)
+#define SMP_IRQ_WORK BIT(ACTION_IRQ_WORK)
struct secondary_data {
unsigned long stack;
diff --git a/arch/loongarch/kernel/paravirt.c b/arch/loongarch/kernel/paravirt.c
index 1633ed4f692f..4272d2447445 100644
--- a/arch/loongarch/kernel/paravirt.c
+++ b/arch/loongarch/kernel/paravirt.c
@@ -2,6 +2,7 @@
#include <linux/export.h>
#include <linux/types.h>
#include <linux/interrupt.h>
+#include <linux/irq_work.h>
#include <linux/jump_label.h>
#include <linux/kvm_para.h>
#include <linux/static_call.h>
@@ -97,6 +98,11 @@ static irqreturn_t pv_ipi_interrupt(int irq, void *dev)
info->ipi_irqs[IPI_CALL_FUNCTION]++;
}
+ if (action & SMP_IRQ_WORK) {
+ irq_work_run();
+ info->ipi_irqs[IPI_IRQ_WORK]++;
+ }
+
return IRQ_HANDLED;
}
diff --git a/arch/loongarch/kernel/smp.c b/arch/loongarch/kernel/smp.c
index 0dfe2388ef41..7366de776f6e 100644
--- a/arch/loongarch/kernel/smp.c
+++ b/arch/loongarch/kernel/smp.c
@@ -13,6 +13,7 @@
#include <linux/cpumask.h>
#include <linux/init.h>
#include <linux/interrupt.h>
+#include <linux/irq_work.h>
#include <linux/profile.h>
#include <linux/seq_file.h>
#include <linux/smp.h>
@@ -70,6 +71,7 @@ static DEFINE_PER_CPU(int, cpu_state);
static const char *ipi_types[NR_IPI] __tracepoint_string = {
[IPI_RESCHEDULE] = "Rescheduling interrupts",
[IPI_CALL_FUNCTION] = "Function call interrupts",
+ [IPI_IRQ_WORK] = "IRQ work interrupts",
};
void show_ipi_list(struct seq_file *p, int prec)
@@ -217,6 +219,13 @@ void arch_smp_send_reschedule(int cpu)
}
EXPORT_SYMBOL_GPL(arch_smp_send_reschedule);
+#ifdef CONFIG_IRQ_WORK
+void arch_irq_work_raise(void)
+{
+ mp_ops.send_ipi_single(smp_processor_id(), ACTION_IRQ_WORK);
+}
+#endif
+
static irqreturn_t loongson_ipi_interrupt(int irq, void *dev)
{
unsigned int action;
@@ -234,6 +243,11 @@ static irqreturn_t loongson_ipi_interrupt(int irq, void *dev)
per_cpu(irq_stat, cpu).ipi_irqs[IPI_CALL_FUNCTION]++;
}
+ if (action & SMP_IRQ_WORK) {
+ irq_work_run();
+ per_cpu(irq_stat, cpu).ipi_irqs[IPI_IRQ_WORK]++;
+ }
+
return IRQ_HANDLED;
}
--
2.43.0
On Tue, May 14, 2024 at 3:32 PM Huacai Chen <[email protected]> wrote:
>
> Add irq_work support for LoongArch via self IPIs. This make it possible
> to run works in hardware interrupt context, which is a prerequisite for
> NOHZ_FULL.
>
> Implement:
> - arch_irq_work_raise()
> - arch_irq_work_has_interrupt()
>
> Signed-off-by: Huacai Chen <[email protected]>
> ---
> arch/loongarch/include/asm/hardirq.h | 3 ++-
> arch/loongarch/include/asm/irq_work.h | 10 ++++++++++
> arch/loongarch/include/asm/smp.h | 2 ++
> arch/loongarch/kernel/paravirt.c | 6 ++++++
> arch/loongarch/kernel/smp.c | 14 ++++++++++++++
> 5 files changed, 34 insertions(+), 1 deletion(-)
> create mode 100644 arch/loongarch/include/asm/irq_work.h
>
> diff --git a/arch/loongarch/include/asm/hardirq.h b/arch/loongarch/include/asm/hardirq.h
> index d41138abcf26..1d7feb719515 100644
> --- a/arch/loongarch/include/asm/hardirq.h
> +++ b/arch/loongarch/include/asm/hardirq.h
> @@ -12,11 +12,12 @@
> extern void ack_bad_irq(unsigned int irq);
> #define ack_bad_irq ack_bad_irq
>
> -#define NR_IPI 2
> +#define NR_IPI 3
>
> enum ipi_msg_type {
> IPI_RESCHEDULE,
> IPI_CALL_FUNCTION,
> + IPI_IRQ_WORK,
> };
>
> typedef struct {
> diff --git a/arch/loongarch/include/asm/irq_work.h b/arch/loongarch/include/asm/irq_work.h
> new file mode 100644
> index 000000000000..d63076e9160d
> --- /dev/null
> +++ b/arch/loongarch/include/asm/irq_work.h
> @@ -0,0 +1,10 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#ifndef _ASM_LOONGARCH_IRQ_WORK_H
> +#define _ASM_LOONGARCH_IRQ_WORK_H
> +
> +static inline bool arch_irq_work_has_interrupt(void)
> +{
> + return IS_ENABLED(CONFIG_SMP);
I think it is "return true," or it will cause the warning.
void __init tick_nohz_init(void)
{
int cpu, ret;
if (!tick_nohz_full_running)
return;
/*
* Full dynticks uses IRQ work to drive the tick rescheduling on safe
* locking contexts. But then we need IRQ work to raise its own
* interrupts to avoid circular dependency on the tick.
*/
if (!arch_irq_work_has_interrupt()) {
pr_warn("NO_HZ: Can't run full dynticks because arch
doesn't support IRQ work self-IPIs\n");
cpumask_clear(tick_nohz_full_mask);
tick_nohz_full_running = false;
return;
}
Others LGTM!
Reviewed-by: Guo Ren <[email protected]>
> +}
> +
> +#endif /* _ASM_LOONGARCH_IRQ_WORK_H */
> diff --git a/arch/loongarch/include/asm/smp.h b/arch/loongarch/include/asm/smp.h
> index 278700cfee88..50db503f44e3 100644
> --- a/arch/loongarch/include/asm/smp.h
> +++ b/arch/loongarch/include/asm/smp.h
> @@ -69,9 +69,11 @@ extern int __cpu_logical_map[NR_CPUS];
> #define ACTION_BOOT_CPU 0
> #define ACTION_RESCHEDULE 1
> #define ACTION_CALL_FUNCTION 2
> +#define ACTION_IRQ_WORK 3
> #define SMP_BOOT_CPU BIT(ACTION_BOOT_CPU)
> #define SMP_RESCHEDULE BIT(ACTION_RESCHEDULE)
> #define SMP_CALL_FUNCTION BIT(ACTION_CALL_FUNCTION)
> +#define SMP_IRQ_WORK BIT(ACTION_IRQ_WORK)
>
> struct secondary_data {
> unsigned long stack;
> diff --git a/arch/loongarch/kernel/paravirt.c b/arch/loongarch/kernel/paravirt.c
> index 1633ed4f692f..4272d2447445 100644
> --- a/arch/loongarch/kernel/paravirt.c
> +++ b/arch/loongarch/kernel/paravirt.c
> @@ -2,6 +2,7 @@
> #include <linux/export.h>
> #include <linux/types.h>
> #include <linux/interrupt.h>
> +#include <linux/irq_work.h>
> #include <linux/jump_label.h>
> #include <linux/kvm_para.h>
> #include <linux/static_call.h>
> @@ -97,6 +98,11 @@ static irqreturn_t pv_ipi_interrupt(int irq, void *dev)
> info->ipi_irqs[IPI_CALL_FUNCTION]++;
> }
>
> + if (action & SMP_IRQ_WORK) {
> + irq_work_run();
> + info->ipi_irqs[IPI_IRQ_WORK]++;
> + }
> +
> return IRQ_HANDLED;
> }
>
> diff --git a/arch/loongarch/kernel/smp.c b/arch/loongarch/kernel/smp.c
> index 0dfe2388ef41..7366de776f6e 100644
> --- a/arch/loongarch/kernel/smp.c
> +++ b/arch/loongarch/kernel/smp.c
> @@ -13,6 +13,7 @@
> #include <linux/cpumask.h>
> #include <linux/init.h>
> #include <linux/interrupt.h>
> +#include <linux/irq_work.h>
> #include <linux/profile.h>
> #include <linux/seq_file.h>
> #include <linux/smp.h>
> @@ -70,6 +71,7 @@ static DEFINE_PER_CPU(int, cpu_state);
> static const char *ipi_types[NR_IPI] __tracepoint_string = {
> [IPI_RESCHEDULE] = "Rescheduling interrupts",
> [IPI_CALL_FUNCTION] = "Function call interrupts",
> + [IPI_IRQ_WORK] = "IRQ work interrupts",
> };
>
> void show_ipi_list(struct seq_file *p, int prec)
> @@ -217,6 +219,13 @@ void arch_smp_send_reschedule(int cpu)
> }
> EXPORT_SYMBOL_GPL(arch_smp_send_reschedule);
>
> +#ifdef CONFIG_IRQ_WORK
> +void arch_irq_work_raise(void)
> +{
> + mp_ops.send_ipi_single(smp_processor_id(), ACTION_IRQ_WORK);
> +}
> +#endif
> +
> static irqreturn_t loongson_ipi_interrupt(int irq, void *dev)
> {
> unsigned int action;
> @@ -234,6 +243,11 @@ static irqreturn_t loongson_ipi_interrupt(int irq, void *dev)
> per_cpu(irq_stat, cpu).ipi_irqs[IPI_CALL_FUNCTION]++;
> }
>
> + if (action & SMP_IRQ_WORK) {
> + irq_work_run();
> + per_cpu(irq_stat, cpu).ipi_irqs[IPI_IRQ_WORK]++;
> + }
> +
> return IRQ_HANDLED;
> }
>
> --
> 2.43.0
>
--
Best Regards
Guo Ren
Hi, Ren,
On Tue, May 14, 2024 at 6:11 PM Guo Ren <[email protected]> wrote:
>
> On Tue, May 14, 2024 at 3:32 PM Huacai Chen <[email protected]> wrote:
> >
> > Add irq_work support for LoongArch via self IPIs. This make it possible
> > to run works in hardware interrupt context, which is a prerequisite for
> > NOHZ_FULL.
> >
> > Implement:
> > - arch_irq_work_raise()
> > - arch_irq_work_has_interrupt()
> >
> > Signed-off-by: Huacai Chen <[email protected]>
> > ---
> > arch/loongarch/include/asm/hardirq.h | 3 ++-
> > arch/loongarch/include/asm/irq_work.h | 10 ++++++++++
> > arch/loongarch/include/asm/smp.h | 2 ++
> > arch/loongarch/kernel/paravirt.c | 6 ++++++
> > arch/loongarch/kernel/smp.c | 14 ++++++++++++++
> > 5 files changed, 34 insertions(+), 1 deletion(-)
> > create mode 100644 arch/loongarch/include/asm/irq_work.h
> >
> > diff --git a/arch/loongarch/include/asm/hardirq.h b/arch/loongarch/include/asm/hardirq.h
> > index d41138abcf26..1d7feb719515 100644
> > --- a/arch/loongarch/include/asm/hardirq.h
> > +++ b/arch/loongarch/include/asm/hardirq.h
> > @@ -12,11 +12,12 @@
> > extern void ack_bad_irq(unsigned int irq);
> > #define ack_bad_irq ack_bad_irq
> >
> > -#define NR_IPI 2
> > +#define NR_IPI 3
> >
> > enum ipi_msg_type {
> > IPI_RESCHEDULE,
> > IPI_CALL_FUNCTION,
> > + IPI_IRQ_WORK,
> > };
> >
> > typedef struct {
> > diff --git a/arch/loongarch/include/asm/irq_work.h b/arch/loongarch/include/asm/irq_work.h
> > new file mode 100644
> > index 000000000000..d63076e9160d
> > --- /dev/null
> > +++ b/arch/loongarch/include/asm/irq_work.h
> > @@ -0,0 +1,10 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +#ifndef _ASM_LOONGARCH_IRQ_WORK_H
> > +#define _ASM_LOONGARCH_IRQ_WORK_H
> > +
> > +static inline bool arch_irq_work_has_interrupt(void)
> > +{
> > + return IS_ENABLED(CONFIG_SMP);
> I think it is "return true," or it will cause the warning.
No, HZ_FULL depends on SMP, if you force to enable it on UP, the
timekeeping will boom.
On the other hand, let the function return true will cause build
errors, see commit d2f3acde3d52b3b351db09e2e2a5e581 ("riscv: Fix
irq_work when SMP is disabled").
Huacai
>
> void __init tick_nohz_init(void)
> {
> int cpu, ret;
>
> if (!tick_nohz_full_running)
> return;
>
> /*
> * Full dynticks uses IRQ work to drive the tick rescheduling on safe
> * locking contexts. But then we need IRQ work to raise its own
> * interrupts to avoid circular dependency on the tick.
> */
> if (!arch_irq_work_has_interrupt()) {
> pr_warn("NO_HZ: Can't run full dynticks because arch
> doesn't support IRQ work self-IPIs\n");
> cpumask_clear(tick_nohz_full_mask);
> tick_nohz_full_running = false;
> return;
> }
>
> Others LGTM!
>
> Reviewed-by: Guo Ren <[email protected]>
>
> > +}
> > +
> > +#endif /* _ASM_LOONGARCH_IRQ_WORK_H */
> > diff --git a/arch/loongarch/include/asm/smp.h b/arch/loongarch/include/asm/smp.h
> > index 278700cfee88..50db503f44e3 100644
> > --- a/arch/loongarch/include/asm/smp.h
> > +++ b/arch/loongarch/include/asm/smp.h
> > @@ -69,9 +69,11 @@ extern int __cpu_logical_map[NR_CPUS];
> > #define ACTION_BOOT_CPU 0
> > #define ACTION_RESCHEDULE 1
> > #define ACTION_CALL_FUNCTION 2
> > +#define ACTION_IRQ_WORK 3
> > #define SMP_BOOT_CPU BIT(ACTION_BOOT_CPU)
> > #define SMP_RESCHEDULE BIT(ACTION_RESCHEDULE)
> > #define SMP_CALL_FUNCTION BIT(ACTION_CALL_FUNCTION)
> > +#define SMP_IRQ_WORK BIT(ACTION_IRQ_WORK)
> >
> > struct secondary_data {
> > unsigned long stack;
> > diff --git a/arch/loongarch/kernel/paravirt.c b/arch/loongarch/kernel/paravirt.c
> > index 1633ed4f692f..4272d2447445 100644
> > --- a/arch/loongarch/kernel/paravirt.c
> > +++ b/arch/loongarch/kernel/paravirt.c
> > @@ -2,6 +2,7 @@
> > #include <linux/export.h>
> > #include <linux/types.h>
> > #include <linux/interrupt.h>
> > +#include <linux/irq_work.h>
> > #include <linux/jump_label.h>
> > #include <linux/kvm_para.h>
> > #include <linux/static_call.h>
> > @@ -97,6 +98,11 @@ static irqreturn_t pv_ipi_interrupt(int irq, void *dev)
> > info->ipi_irqs[IPI_CALL_FUNCTION]++;
> > }
> >
> > + if (action & SMP_IRQ_WORK) {
> > + irq_work_run();
> > + info->ipi_irqs[IPI_IRQ_WORK]++;
> > + }
> > +
> > return IRQ_HANDLED;
> > }
> >
> > diff --git a/arch/loongarch/kernel/smp.c b/arch/loongarch/kernel/smp.c
> > index 0dfe2388ef41..7366de776f6e 100644
> > --- a/arch/loongarch/kernel/smp.c
> > +++ b/arch/loongarch/kernel/smp.c
> > @@ -13,6 +13,7 @@
> > #include <linux/cpumask.h>
> > #include <linux/init.h>
> > #include <linux/interrupt.h>
> > +#include <linux/irq_work.h>
> > #include <linux/profile.h>
> > #include <linux/seq_file.h>
> > #include <linux/smp.h>
> > @@ -70,6 +71,7 @@ static DEFINE_PER_CPU(int, cpu_state);
> > static const char *ipi_types[NR_IPI] __tracepoint_string = {
> > [IPI_RESCHEDULE] = "Rescheduling interrupts",
> > [IPI_CALL_FUNCTION] = "Function call interrupts",
> > + [IPI_IRQ_WORK] = "IRQ work interrupts",
> > };
> >
> > void show_ipi_list(struct seq_file *p, int prec)
> > @@ -217,6 +219,13 @@ void arch_smp_send_reschedule(int cpu)
> > }
> > EXPORT_SYMBOL_GPL(arch_smp_send_reschedule);
> >
> > +#ifdef CONFIG_IRQ_WORK
> > +void arch_irq_work_raise(void)
> > +{
> > + mp_ops.send_ipi_single(smp_processor_id(), ACTION_IRQ_WORK);
> > +}
> > +#endif
> > +
> > static irqreturn_t loongson_ipi_interrupt(int irq, void *dev)
> > {
> > unsigned int action;
> > @@ -234,6 +243,11 @@ static irqreturn_t loongson_ipi_interrupt(int irq, void *dev)
> > per_cpu(irq_stat, cpu).ipi_irqs[IPI_CALL_FUNCTION]++;
> > }
> >
> > + if (action & SMP_IRQ_WORK) {
> > + irq_work_run();
> > + per_cpu(irq_stat, cpu).ipi_irqs[IPI_IRQ_WORK]++;
> > + }
> > +
> > return IRQ_HANDLED;
> > }
> >
> > --
> > 2.43.0
> >
>
>
> --
> Best Regards
> Guo Ren
On Tue, May 14, 2024 at 7:14 PM Huacai Chen <[email protected]> wrote:
>
> Hi, Ren,
>
> On Tue, May 14, 2024 at 6:11 PM Guo Ren <[email protected]> wrote:
> >
> > On Tue, May 14, 2024 at 3:32 PM Huacai Chen <[email protected]> wrote:
> > >
> > > Add irq_work support for LoongArch via self IPIs. This make it possible
> > > to run works in hardware interrupt context, which is a prerequisite for
> > > NOHZ_FULL.
> > >
> > > Implement:
> > > - arch_irq_work_raise()
> > > - arch_irq_work_has_interrupt()
> > >
> > > Signed-off-by: Huacai Chen <[email protected]>
> > > ---
> > > arch/loongarch/include/asm/hardirq.h | 3 ++-
> > > arch/loongarch/include/asm/irq_work.h | 10 ++++++++++
> > > arch/loongarch/include/asm/smp.h | 2 ++
> > > arch/loongarch/kernel/paravirt.c | 6 ++++++
> > > arch/loongarch/kernel/smp.c | 14 ++++++++++++++
> > > 5 files changed, 34 insertions(+), 1 deletion(-)
> > > create mode 100644 arch/loongarch/include/asm/irq_work.h
> > >
> > > diff --git a/arch/loongarch/include/asm/hardirq.h b/arch/loongarch/include/asm/hardirq.h
> > > index d41138abcf26..1d7feb719515 100644
> > > --- a/arch/loongarch/include/asm/hardirq.h
> > > +++ b/arch/loongarch/include/asm/hardirq.h
> > > @@ -12,11 +12,12 @@
> > > extern void ack_bad_irq(unsigned int irq);
> > > #define ack_bad_irq ack_bad_irq
> > >
> > > -#define NR_IPI 2
> > > +#define NR_IPI 3
> > >
> > > enum ipi_msg_type {
> > > IPI_RESCHEDULE,
> > > IPI_CALL_FUNCTION,
> > > + IPI_IRQ_WORK,
> > > };
> > >
> > > typedef struct {
> > > diff --git a/arch/loongarch/include/asm/irq_work.h b/arch/loongarch/include/asm/irq_work.h
> > > new file mode 100644
> > > index 000000000000..d63076e9160d
> > > --- /dev/null
> > > +++ b/arch/loongarch/include/asm/irq_work.h
> > > @@ -0,0 +1,10 @@
> > > +/* SPDX-License-Identifier: GPL-2.0 */
> > > +#ifndef _ASM_LOONGARCH_IRQ_WORK_H
> > > +#define _ASM_LOONGARCH_IRQ_WORK_H
> > > +
> > > +static inline bool arch_irq_work_has_interrupt(void)
> > > +{
> > > + return IS_ENABLED(CONFIG_SMP);
> > I think it is "return true," or it will cause the warning.
> No, HZ_FULL depends on SMP, if you force to enable it on UP, the
> timekeeping will boom.
> On the other hand, let the function return true will cause build
> errors, see commit d2f3acde3d52b3b351db09e2e2a5e581 ("riscv: Fix
> irq_work when SMP is disabled").
Sorry, I misunderstood.
But it is not a build error. Quote:
This was found while bringing up cpufreq on D1. Switching cpufreq
governors was hanging on irq_work_sync().
/*
* Synchronize against the irq_work @entry, ensures the entry is not
* currently in use.
*/
void irq_work_sync(struct irq_work *work)
{
lockdep_assert_irqs_enabled();
might_sleep();
if ((IS_ENABLED(CONFIG_PREEMPT_RT) && !irq_work_is_hard(work)) ||
!arch_irq_work_has_interrupt()) {
^^^^^^^^^^^^^^^^^^^^^^^^^^^
rcuwait_wait_event(&work->irqwait, !irq_work_is_busy(work),
TASK_UNINTERRUPTIBLE);
return;
}
>
> Huacai
>
> >
> > void __init tick_nohz_init(void)
> > {
> > int cpu, ret;
> >
> > if (!tick_nohz_full_running)
> > return;
> >
> > /*
> > * Full dynticks uses IRQ work to drive the tick rescheduling on safe
> > * locking contexts. But then we need IRQ work to raise its own
> > * interrupts to avoid circular dependency on the tick.
> > */
> > if (!arch_irq_work_has_interrupt()) {
> > pr_warn("NO_HZ: Can't run full dynticks because arch
> > doesn't support IRQ work self-IPIs\n");
> > cpumask_clear(tick_nohz_full_mask);
> > tick_nohz_full_running = false;
> > return;
> > }
> >
> > Others LGTM!
> >
> > Reviewed-by: Guo Ren <[email protected]>
> >
> > > +}
> > > +
> > > +#endif /* _ASM_LOONGARCH_IRQ_WORK_H */
> > > diff --git a/arch/loongarch/include/asm/smp.h b/arch/loongarch/include/asm/smp.h
> > > index 278700cfee88..50db503f44e3 100644
> > > --- a/arch/loongarch/include/asm/smp.h
> > > +++ b/arch/loongarch/include/asm/smp.h
> > > @@ -69,9 +69,11 @@ extern int __cpu_logical_map[NR_CPUS];
> > > #define ACTION_BOOT_CPU 0
> > > #define ACTION_RESCHEDULE 1
> > > #define ACTION_CALL_FUNCTION 2
> > > +#define ACTION_IRQ_WORK 3
> > > #define SMP_BOOT_CPU BIT(ACTION_BOOT_CPU)
> > > #define SMP_RESCHEDULE BIT(ACTION_RESCHEDULE)
> > > #define SMP_CALL_FUNCTION BIT(ACTION_CALL_FUNCTION)
> > > +#define SMP_IRQ_WORK BIT(ACTION_IRQ_WORK)
> > >
> > > struct secondary_data {
> > > unsigned long stack;
> > > diff --git a/arch/loongarch/kernel/paravirt.c b/arch/loongarch/kernel/paravirt.c
> > > index 1633ed4f692f..4272d2447445 100644
> > > --- a/arch/loongarch/kernel/paravirt.c
> > > +++ b/arch/loongarch/kernel/paravirt.c
> > > @@ -2,6 +2,7 @@
> > > #include <linux/export.h>
> > > #include <linux/types.h>
> > > #include <linux/interrupt.h>
> > > +#include <linux/irq_work.h>
> > > #include <linux/jump_label.h>
> > > #include <linux/kvm_para.h>
> > > #include <linux/static_call.h>
> > > @@ -97,6 +98,11 @@ static irqreturn_t pv_ipi_interrupt(int irq, void *dev)
> > > info->ipi_irqs[IPI_CALL_FUNCTION]++;
> > > }
> > >
> > > + if (action & SMP_IRQ_WORK) {
> > > + irq_work_run();
> > > + info->ipi_irqs[IPI_IRQ_WORK]++;
> > > + }
> > > +
> > > return IRQ_HANDLED;
> > > }
> > >
> > > diff --git a/arch/loongarch/kernel/smp.c b/arch/loongarch/kernel/smp.c
> > > index 0dfe2388ef41..7366de776f6e 100644
> > > --- a/arch/loongarch/kernel/smp.c
> > > +++ b/arch/loongarch/kernel/smp.c
> > > @@ -13,6 +13,7 @@
> > > #include <linux/cpumask.h>
> > > #include <linux/init.h>
> > > #include <linux/interrupt.h>
> > > +#include <linux/irq_work.h>
> > > #include <linux/profile.h>
> > > #include <linux/seq_file.h>
> > > #include <linux/smp.h>
> > > @@ -70,6 +71,7 @@ static DEFINE_PER_CPU(int, cpu_state);
> > > static const char *ipi_types[NR_IPI] __tracepoint_string = {
> > > [IPI_RESCHEDULE] = "Rescheduling interrupts",
> > > [IPI_CALL_FUNCTION] = "Function call interrupts",
> > > + [IPI_IRQ_WORK] = "IRQ work interrupts",
> > > };
> > >
> > > void show_ipi_list(struct seq_file *p, int prec)
> > > @@ -217,6 +219,13 @@ void arch_smp_send_reschedule(int cpu)
> > > }
> > > EXPORT_SYMBOL_GPL(arch_smp_send_reschedule);
> > >
> > > +#ifdef CONFIG_IRQ_WORK
> > > +void arch_irq_work_raise(void)
> > > +{
> > > + mp_ops.send_ipi_single(smp_processor_id(), ACTION_IRQ_WORK);
> > > +}
> > > +#endif
> > > +
> > > static irqreturn_t loongson_ipi_interrupt(int irq, void *dev)
> > > {
> > > unsigned int action;
> > > @@ -234,6 +243,11 @@ static irqreturn_t loongson_ipi_interrupt(int irq, void *dev)
> > > per_cpu(irq_stat, cpu).ipi_irqs[IPI_CALL_FUNCTION]++;
> > > }
> > >
> > > + if (action & SMP_IRQ_WORK) {
> > > + irq_work_run();
> > > + per_cpu(irq_stat, cpu).ipi_irqs[IPI_IRQ_WORK]++;
> > > + }
> > > +
> > > return IRQ_HANDLED;
> > > }
> > >
> > > --
> > > 2.43.0
> > >
> >
> >
> > --
> > Best Regards
> > Guo Ren
--
Best Regards
Guo Ren
On Wed, May 15, 2024 at 11:21 AM Guo Ren <[email protected]> wrote:
>
> On Tue, May 14, 2024 at 7:14 PM Huacai Chen <[email protected]> wrote:
> >
> > Hi, Ren,
> >
> > On Tue, May 14, 2024 at 6:11 PM Guo Ren <[email protected]> wrote:
> > >
> > > On Tue, May 14, 2024 at 3:32 PM Huacai Chen <[email protected]> wrote:
> > > >
> > > > Add irq_work support for LoongArch via self IPIs. This make it possible
> > > > to run works in hardware interrupt context, which is a prerequisite for
> > > > NOHZ_FULL.
> > > >
> > > > Implement:
> > > > - arch_irq_work_raise()
> > > > - arch_irq_work_has_interrupt()
> > > >
> > > > Signed-off-by: Huacai Chen <[email protected]>
> > > > ---
> > > > arch/loongarch/include/asm/hardirq.h | 3 ++-
> > > > arch/loongarch/include/asm/irq_work.h | 10 ++++++++++
> > > > arch/loongarch/include/asm/smp.h | 2 ++
> > > > arch/loongarch/kernel/paravirt.c | 6 ++++++
> > > > arch/loongarch/kernel/smp.c | 14 ++++++++++++++
> > > > 5 files changed, 34 insertions(+), 1 deletion(-)
> > > > create mode 100644 arch/loongarch/include/asm/irq_work.h
> > > >
> > > > diff --git a/arch/loongarch/include/asm/hardirq.h b/arch/loongarch/include/asm/hardirq.h
> > > > index d41138abcf26..1d7feb719515 100644
> > > > --- a/arch/loongarch/include/asm/hardirq.h
> > > > +++ b/arch/loongarch/include/asm/hardirq.h
> > > > @@ -12,11 +12,12 @@
> > > > extern void ack_bad_irq(unsigned int irq);
> > > > #define ack_bad_irq ack_bad_irq
> > > >
> > > > -#define NR_IPI 2
> > > > +#define NR_IPI 3
> > > >
> > > > enum ipi_msg_type {
> > > > IPI_RESCHEDULE,
> > > > IPI_CALL_FUNCTION,
> > > > + IPI_IRQ_WORK,
> > > > };
> > > >
> > > > typedef struct {
> > > > diff --git a/arch/loongarch/include/asm/irq_work.h b/arch/loongarch/include/asm/irq_work.h
> > > > new file mode 100644
> > > > index 000000000000..d63076e9160d
> > > > --- /dev/null
> > > > +++ b/arch/loongarch/include/asm/irq_work.h
> > > > @@ -0,0 +1,10 @@
> > > > +/* SPDX-License-Identifier: GPL-2.0 */
> > > > +#ifndef _ASM_LOONGARCH_IRQ_WORK_H
> > > > +#define _ASM_LOONGARCH_IRQ_WORK_H
> > > > +
> > > > +static inline bool arch_irq_work_has_interrupt(void)
> > > > +{
> > > > + return IS_ENABLED(CONFIG_SMP);
> > > I think it is "return true," or it will cause the warning.
> > No, HZ_FULL depends on SMP, if you force to enable it on UP, the
> > timekeeping will boom.
> > On the other hand, let the function return true will cause build
> > errors, see commit d2f3acde3d52b3b351db09e2e2a5e581 ("riscv: Fix
> > irq_work when SMP is disabled").
> Sorry, I misunderstood.
>
> But it is not a build error. Quote:
Sorry, I misunderstood, too.
Huacai
>
> This was found while bringing up cpufreq on D1. Switching cpufreq
> governors was hanging on irq_work_sync().
>
> /*
> * Synchronize against the irq_work @entry, ensures the entry is not
> * currently in use.
> */
> void irq_work_sync(struct irq_work *work)
> {
> lockdep_assert_irqs_enabled();
> might_sleep();
>
> if ((IS_ENABLED(CONFIG_PREEMPT_RT) && !irq_work_is_hard(work)) ||
> !arch_irq_work_has_interrupt()) {
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^
> rcuwait_wait_event(&work->irqwait, !irq_work_is_busy(work),
> TASK_UNINTERRUPTIBLE);
> return;
> }
>
>
> >
> > Huacai
> >
> > >
> > > void __init tick_nohz_init(void)
> > > {
> > > int cpu, ret;
> > >
> > > if (!tick_nohz_full_running)
> > > return;
> > >
> > > /*
> > > * Full dynticks uses IRQ work to drive the tick rescheduling on safe
> > > * locking contexts. But then we need IRQ work to raise its own
> > > * interrupts to avoid circular dependency on the tick.
> > > */
> > > if (!arch_irq_work_has_interrupt()) {
> > > pr_warn("NO_HZ: Can't run full dynticks because arch
> > > doesn't support IRQ work self-IPIs\n");
> > > cpumask_clear(tick_nohz_full_mask);
> > > tick_nohz_full_running = false;
> > > return;
> > > }
> > >
> > > Others LGTM!
> > >
> > > Reviewed-by: Guo Ren <[email protected]>
> > >
> > > > +}
> > > > +
> > > > +#endif /* _ASM_LOONGARCH_IRQ_WORK_H */
> > > > diff --git a/arch/loongarch/include/asm/smp.h b/arch/loongarch/include/asm/smp.h
> > > > index 278700cfee88..50db503f44e3 100644
> > > > --- a/arch/loongarch/include/asm/smp.h
> > > > +++ b/arch/loongarch/include/asm/smp.h
> > > > @@ -69,9 +69,11 @@ extern int __cpu_logical_map[NR_CPUS];
> > > > #define ACTION_BOOT_CPU 0
> > > > #define ACTION_RESCHEDULE 1
> > > > #define ACTION_CALL_FUNCTION 2
> > > > +#define ACTION_IRQ_WORK 3
> > > > #define SMP_BOOT_CPU BIT(ACTION_BOOT_CPU)
> > > > #define SMP_RESCHEDULE BIT(ACTION_RESCHEDULE)
> > > > #define SMP_CALL_FUNCTION BIT(ACTION_CALL_FUNCTION)
> > > > +#define SMP_IRQ_WORK BIT(ACTION_IRQ_WORK)
> > > >
> > > > struct secondary_data {
> > > > unsigned long stack;
> > > > diff --git a/arch/loongarch/kernel/paravirt.c b/arch/loongarch/kernel/paravirt.c
> > > > index 1633ed4f692f..4272d2447445 100644
> > > > --- a/arch/loongarch/kernel/paravirt.c
> > > > +++ b/arch/loongarch/kernel/paravirt.c
> > > > @@ -2,6 +2,7 @@
> > > > #include <linux/export.h>
> > > > #include <linux/types.h>
> > > > #include <linux/interrupt.h>
> > > > +#include <linux/irq_work.h>
> > > > #include <linux/jump_label.h>
> > > > #include <linux/kvm_para.h>
> > > > #include <linux/static_call.h>
> > > > @@ -97,6 +98,11 @@ static irqreturn_t pv_ipi_interrupt(int irq, void *dev)
> > > > info->ipi_irqs[IPI_CALL_FUNCTION]++;
> > > > }
> > > >
> > > > + if (action & SMP_IRQ_WORK) {
> > > > + irq_work_run();
> > > > + info->ipi_irqs[IPI_IRQ_WORK]++;
> > > > + }
> > > > +
> > > > return IRQ_HANDLED;
> > > > }
> > > >
> > > > diff --git a/arch/loongarch/kernel/smp.c b/arch/loongarch/kernel/smp.c
> > > > index 0dfe2388ef41..7366de776f6e 100644
> > > > --- a/arch/loongarch/kernel/smp.c
> > > > +++ b/arch/loongarch/kernel/smp.c
> > > > @@ -13,6 +13,7 @@
> > > > #include <linux/cpumask.h>
> > > > #include <linux/init.h>
> > > > #include <linux/interrupt.h>
> > > > +#include <linux/irq_work.h>
> > > > #include <linux/profile.h>
> > > > #include <linux/seq_file.h>
> > > > #include <linux/smp.h>
> > > > @@ -70,6 +71,7 @@ static DEFINE_PER_CPU(int, cpu_state);
> > > > static const char *ipi_types[NR_IPI] __tracepoint_string = {
> > > > [IPI_RESCHEDULE] = "Rescheduling interrupts",
> > > > [IPI_CALL_FUNCTION] = "Function call interrupts",
> > > > + [IPI_IRQ_WORK] = "IRQ work interrupts",
> > > > };
> > > >
> > > > void show_ipi_list(struct seq_file *p, int prec)
> > > > @@ -217,6 +219,13 @@ void arch_smp_send_reschedule(int cpu)
> > > > }
> > > > EXPORT_SYMBOL_GPL(arch_smp_send_reschedule);
> > > >
> > > > +#ifdef CONFIG_IRQ_WORK
> > > > +void arch_irq_work_raise(void)
> > > > +{
> > > > + mp_ops.send_ipi_single(smp_processor_id(), ACTION_IRQ_WORK);
> > > > +}
> > > > +#endif
> > > > +
> > > > static irqreturn_t loongson_ipi_interrupt(int irq, void *dev)
> > > > {
> > > > unsigned int action;
> > > > @@ -234,6 +243,11 @@ static irqreturn_t loongson_ipi_interrupt(int irq, void *dev)
> > > > per_cpu(irq_stat, cpu).ipi_irqs[IPI_CALL_FUNCTION]++;
> > > > }
> > > >
> > > > + if (action & SMP_IRQ_WORK) {
> > > > + irq_work_run();
> > > > + per_cpu(irq_stat, cpu).ipi_irqs[IPI_IRQ_WORK]++;
> > > > + }
> > > > +
> > > > return IRQ_HANDLED;
> > > > }
> > > >
> > > > --
> > > > 2.43.0
> > > >
> > >
> > >
> > > --
> > > Best Regards
> > > Guo Ren
>
>
>
> --
> Best Regards
> Guo Ren
>
On 2024/5/14 下午3:32, Huacai Chen wrote:
> Add irq_work support for LoongArch via self IPIs. This make it possible
> to run works in hardware interrupt context, which is a prerequisite for
> NOHZ_FULL.
>
> Implement:
> - arch_irq_work_raise()
> - arch_irq_work_has_interrupt()
>
> Signed-off-by: Huacai Chen <[email protected]>
> ---
> arch/loongarch/include/asm/hardirq.h | 3 ++-
> arch/loongarch/include/asm/irq_work.h | 10 ++++++++++
> arch/loongarch/include/asm/smp.h | 2 ++
> arch/loongarch/kernel/paravirt.c | 6 ++++++
> arch/loongarch/kernel/smp.c | 14 ++++++++++++++
> 5 files changed, 34 insertions(+), 1 deletion(-)
> create mode 100644 arch/loongarch/include/asm/irq_work.h
>
> diff --git a/arch/loongarch/include/asm/hardirq.h b/arch/loongarch/include/asm/hardirq.h
> index d41138abcf26..1d7feb719515 100644
> --- a/arch/loongarch/include/asm/hardirq.h
> +++ b/arch/loongarch/include/asm/hardirq.h
> @@ -12,11 +12,12 @@
> extern void ack_bad_irq(unsigned int irq);
> #define ack_bad_irq ack_bad_irq
>
> -#define NR_IPI 2
> +#define NR_IPI 3
>
> enum ipi_msg_type {
> IPI_RESCHEDULE,
> IPI_CALL_FUNCTION,
> + IPI_IRQ_WORK,
> };
>
> typedef struct {
> diff --git a/arch/loongarch/include/asm/irq_work.h b/arch/loongarch/include/asm/irq_work.h
> new file mode 100644
> index 000000000000..d63076e9160d
> --- /dev/null
> +++ b/arch/loongarch/include/asm/irq_work.h
> @@ -0,0 +1,10 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#ifndef _ASM_LOONGARCH_IRQ_WORK_H
> +#define _ASM_LOONGARCH_IRQ_WORK_H
> +
> +static inline bool arch_irq_work_has_interrupt(void)
> +{
> + return IS_ENABLED(CONFIG_SMP);
> +}
> +
> +#endif /* _ASM_LOONGARCH_IRQ_WORK_H */
> diff --git a/arch/loongarch/include/asm/smp.h b/arch/loongarch/include/asm/smp.h
> index 278700cfee88..50db503f44e3 100644
> --- a/arch/loongarch/include/asm/smp.h
> +++ b/arch/loongarch/include/asm/smp.h
> @@ -69,9 +69,11 @@ extern int __cpu_logical_map[NR_CPUS];
> #define ACTION_BOOT_CPU 0
> #define ACTION_RESCHEDULE 1
> #define ACTION_CALL_FUNCTION 2
> +#define ACTION_IRQ_WORK 3
> #define SMP_BOOT_CPU BIT(ACTION_BOOT_CPU)
> #define SMP_RESCHEDULE BIT(ACTION_RESCHEDULE)
> #define SMP_CALL_FUNCTION BIT(ACTION_CALL_FUNCTION)
> +#define SMP_IRQ_WORK BIT(ACTION_IRQ_WORK)
>
> struct secondary_data {
> unsigned long stack;
> diff --git a/arch/loongarch/kernel/paravirt.c b/arch/loongarch/kernel/paravirt.c
> index 1633ed4f692f..4272d2447445 100644
> --- a/arch/loongarch/kernel/paravirt.c
> +++ b/arch/loongarch/kernel/paravirt.c
> @@ -2,6 +2,7 @@
> #include <linux/export.h>
> #include <linux/types.h>
> #include <linux/interrupt.h>
> +#include <linux/irq_work.h>
> #include <linux/jump_label.h>
> #include <linux/kvm_para.h>
> #include <linux/static_call.h>
> @@ -97,6 +98,11 @@ static irqreturn_t pv_ipi_interrupt(int irq, void *dev)
> info->ipi_irqs[IPI_CALL_FUNCTION]++;
> }
>
> + if (action & SMP_IRQ_WORK) {
> + irq_work_run();
> + info->ipi_irqs[IPI_IRQ_WORK]++;
> + }
> +
Would you mind adding common api so that pv ipi handler and hw ipi
handler can call it both? The coming avec MSI interrupt driver has the
same requirement for ipi.
void do_ipi_demux(unsigned int action)
{
irq_cpustat_t *info;
info = this_cpu_ptr(&irq_stat);
if (action & SMP_RESCHEDULE) {
scheduler_ipi();
info->ipi_irqs[IPI_RESCHEDULE]++;
}
if (action & SMP_CALL_FUNCTION) {
generic_smp_call_function_interrupt();
info->ipi_irqs[IPI_CALL_FUNCTION]++;
}
if (action & SMP_IRQ_WORK) {
irq_work_run();
info->ipi_irqs[IPI_IRQ_WORK]++;
}
Regards
Bibo Mao
> return IRQ_HANDLED;
> }
>
> diff --git a/arch/loongarch/kernel/smp.c b/arch/loongarch/kernel/smp.c
> index 0dfe2388ef41..7366de776f6e 100644
> --- a/arch/loongarch/kernel/smp.c
> +++ b/arch/loongarch/kernel/smp.c
> @@ -13,6 +13,7 @@
> #include <linux/cpumask.h>
> #include <linux/init.h>
> #include <linux/interrupt.h>
> +#include <linux/irq_work.h>
> #include <linux/profile.h>
> #include <linux/seq_file.h>
> #include <linux/smp.h>
> @@ -70,6 +71,7 @@ static DEFINE_PER_CPU(int, cpu_state);
> static const char *ipi_types[NR_IPI] __tracepoint_string = {
> [IPI_RESCHEDULE] = "Rescheduling interrupts",
> [IPI_CALL_FUNCTION] = "Function call interrupts",
> + [IPI_IRQ_WORK] = "IRQ work interrupts",
> };
>
> void show_ipi_list(struct seq_file *p, int prec)
> @@ -217,6 +219,13 @@ void arch_smp_send_reschedule(int cpu)
> }
> EXPORT_SYMBOL_GPL(arch_smp_send_reschedule);
>
> +#ifdef CONFIG_IRQ_WORK
> +void arch_irq_work_raise(void)
> +{
> + mp_ops.send_ipi_single(smp_processor_id(), ACTION_IRQ_WORK);
> +}
> +#endif
> +
> static irqreturn_t loongson_ipi_interrupt(int irq, void *dev)
> {
> unsigned int action;
> @@ -234,6 +243,11 @@ static irqreturn_t loongson_ipi_interrupt(int irq, void *dev)
> per_cpu(irq_stat, cpu).ipi_irqs[IPI_CALL_FUNCTION]++;
> }
>
> + if (action & SMP_IRQ_WORK) {
> + irq_work_run();
> + per_cpu(irq_stat, cpu).ipi_irqs[IPI_IRQ_WORK]++;
> + }
> +
> return IRQ_HANDLED;
> }
>
>
On Thu, May 16, 2024 at 8:23 PM maobibo <[email protected]> wrote:
>
>
>
> On 2024/5/14 下午3:32, Huacai Chen wrote:
> > Add irq_work support for LoongArch via self IPIs. This make it possible
> > to run works in hardware interrupt context, which is a prerequisite for
> > NOHZ_FULL.
> >
> > Implement:
> > - arch_irq_work_raise()
> > - arch_irq_work_has_interrupt()
> >
> > Signed-off-by: Huacai Chen <[email protected]>
> > ---
> > arch/loongarch/include/asm/hardirq.h | 3 ++-
> > arch/loongarch/include/asm/irq_work.h | 10 ++++++++++
> > arch/loongarch/include/asm/smp.h | 2 ++
> > arch/loongarch/kernel/paravirt.c | 6 ++++++
> > arch/loongarch/kernel/smp.c | 14 ++++++++++++++
> > 5 files changed, 34 insertions(+), 1 deletion(-)
> > create mode 100644 arch/loongarch/include/asm/irq_work.h
> >
> > diff --git a/arch/loongarch/include/asm/hardirq.h b/arch/loongarch/include/asm/hardirq.h
> > index d41138abcf26..1d7feb719515 100644
> > --- a/arch/loongarch/include/asm/hardirq.h
> > +++ b/arch/loongarch/include/asm/hardirq.h
> > @@ -12,11 +12,12 @@
> > extern void ack_bad_irq(unsigned int irq);
> > #define ack_bad_irq ack_bad_irq
> >
> > -#define NR_IPI 2
> > +#define NR_IPI 3
> >
> > enum ipi_msg_type {
> > IPI_RESCHEDULE,
> > IPI_CALL_FUNCTION,
> > + IPI_IRQ_WORK,
> > };
> >
> > typedef struct {
> > diff --git a/arch/loongarch/include/asm/irq_work.h b/arch/loongarch/include/asm/irq_work.h
> > new file mode 100644
> > index 000000000000..d63076e9160d
> > --- /dev/null
> > +++ b/arch/loongarch/include/asm/irq_work.h
> > @@ -0,0 +1,10 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +#ifndef _ASM_LOONGARCH_IRQ_WORK_H
> > +#define _ASM_LOONGARCH_IRQ_WORK_H
> > +
> > +static inline bool arch_irq_work_has_interrupt(void)
> > +{
> > + return IS_ENABLED(CONFIG_SMP);
> > +}
> > +
> > +#endif /* _ASM_LOONGARCH_IRQ_WORK_H */
> > diff --git a/arch/loongarch/include/asm/smp.h b/arch/loongarch/include/asm/smp.h
> > index 278700cfee88..50db503f44e3 100644
> > --- a/arch/loongarch/include/asm/smp.h
> > +++ b/arch/loongarch/include/asm/smp.h
> > @@ -69,9 +69,11 @@ extern int __cpu_logical_map[NR_CPUS];
> > #define ACTION_BOOT_CPU 0
> > #define ACTION_RESCHEDULE 1
> > #define ACTION_CALL_FUNCTION 2
> > +#define ACTION_IRQ_WORK 3
> > #define SMP_BOOT_CPU BIT(ACTION_BOOT_CPU)
> > #define SMP_RESCHEDULE BIT(ACTION_RESCHEDULE)
> > #define SMP_CALL_FUNCTION BIT(ACTION_CALL_FUNCTION)
> > +#define SMP_IRQ_WORK BIT(ACTION_IRQ_WORK)
> >
> > struct secondary_data {
> > unsigned long stack;
> > diff --git a/arch/loongarch/kernel/paravirt.c b/arch/loongarch/kernel/paravirt.c
> > index 1633ed4f692f..4272d2447445 100644
> > --- a/arch/loongarch/kernel/paravirt.c
> > +++ b/arch/loongarch/kernel/paravirt.c
> > @@ -2,6 +2,7 @@
> > #include <linux/export.h>
> > #include <linux/types.h>
> > #include <linux/interrupt.h>
> > +#include <linux/irq_work.h>
> > #include <linux/jump_label.h>
> > #include <linux/kvm_para.h>
> > #include <linux/static_call.h>
> > @@ -97,6 +98,11 @@ static irqreturn_t pv_ipi_interrupt(int irq, void *dev)
> > info->ipi_irqs[IPI_CALL_FUNCTION]++;
> > }
> >
> > + if (action & SMP_IRQ_WORK) {
> > + irq_work_run();
> > + info->ipi_irqs[IPI_IRQ_WORK]++;
> > + }
> > +
> Would you mind adding common api so that pv ipi handler and hw ipi
> handler can call it both? The coming avec MSI interrupt driver has the
> same requirement for ipi.
We can refactor it after AVEC upstream, if needed.
Huacai
>
> void do_ipi_demux(unsigned int action)
> {
> irq_cpustat_t *info;
>
> info = this_cpu_ptr(&irq_stat);
> if (action & SMP_RESCHEDULE) {
> scheduler_ipi();
> info->ipi_irqs[IPI_RESCHEDULE]++;
> }
>
> if (action & SMP_CALL_FUNCTION) {
> generic_smp_call_function_interrupt();
> info->ipi_irqs[IPI_CALL_FUNCTION]++;
> }
>
> if (action & SMP_IRQ_WORK) {
> irq_work_run();
> info->ipi_irqs[IPI_IRQ_WORK]++;
> }
>
> Regards
> Bibo Mao
> > return IRQ_HANDLED;
> > }
> >
> > diff --git a/arch/loongarch/kernel/smp.c b/arch/loongarch/kernel/smp.c
> > index 0dfe2388ef41..7366de776f6e 100644
> > --- a/arch/loongarch/kernel/smp.c
> > +++ b/arch/loongarch/kernel/smp.c
> > @@ -13,6 +13,7 @@
> > #include <linux/cpumask.h>
> > #include <linux/init.h>
> > #include <linux/interrupt.h>
> > +#include <linux/irq_work.h>
> > #include <linux/profile.h>
> > #include <linux/seq_file.h>
> > #include <linux/smp.h>
> > @@ -70,6 +71,7 @@ static DEFINE_PER_CPU(int, cpu_state);
> > static const char *ipi_types[NR_IPI] __tracepoint_string = {
> > [IPI_RESCHEDULE] = "Rescheduling interrupts",
> > [IPI_CALL_FUNCTION] = "Function call interrupts",
> > + [IPI_IRQ_WORK] = "IRQ work interrupts",
> > };
> >
> > void show_ipi_list(struct seq_file *p, int prec)
> > @@ -217,6 +219,13 @@ void arch_smp_send_reschedule(int cpu)
> > }
> > EXPORT_SYMBOL_GPL(arch_smp_send_reschedule);
> >
> > +#ifdef CONFIG_IRQ_WORK
> > +void arch_irq_work_raise(void)
> > +{
> > + mp_ops.send_ipi_single(smp_processor_id(), ACTION_IRQ_WORK);
> > +}
> > +#endif
> > +
> > static irqreturn_t loongson_ipi_interrupt(int irq, void *dev)
> > {
> > unsigned int action;
> > @@ -234,6 +243,11 @@ static irqreturn_t loongson_ipi_interrupt(int irq, void *dev)
> > per_cpu(irq_stat, cpu).ipi_irqs[IPI_CALL_FUNCTION]++;
> > }
> >
> > + if (action & SMP_IRQ_WORK) {
> > + irq_work_run();
> > + per_cpu(irq_stat, cpu).ipi_irqs[IPI_IRQ_WORK]++;
> > + }
> > +
> > return IRQ_HANDLED;
> > }
> >
> >
>
>