summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorHuacai Chen <chenhuacai@loongson.cn>2024-07-20 17:40:58 +0300
committerHuacai Chen <chenhuacai@loongson.cn>2024-07-20 17:40:58 +0300
commit08f417db702c5b05150b3851af7186fee96ddd46 (patch)
tree7268a740e178602b1854e2480a9a8fc1fd602184 /arch
parent12d3b559b85e75640b79995e1320588d6f0d5630 (diff)
downloadlinux-08f417db702c5b05150b3851af7186fee96ddd46.tar.xz
LoongArch: Add irq_work support via self IPIs
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() Reviewed-by: Guo Ren <guoren@kernel.org> Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
Diffstat (limited to 'arch')
-rw-r--r--arch/loongarch/include/asm/hardirq.h3
-rw-r--r--arch/loongarch/include/asm/irq_work.h10
-rw-r--r--arch/loongarch/include/asm/smp.h2
-rw-r--r--arch/loongarch/kernel/paravirt.c6
-rw-r--r--arch/loongarch/kernel/smp.c14
5 files changed, 34 insertions, 1 deletions
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 03b2b7669cf5..ca405ab86aae 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;
}