LoongArch: Provide kernel fpu functions
authorHuacai Chen <chenhuacai@loongson.cn>
Mon, 1 May 2023 09:19:27 +0000 (17:19 +0800)
committerHuacai Chen <chenhuacai@loongson.cn>
Mon, 1 May 2023 09:19:27 +0000 (17:19 +0800)
Provide kernel_fpu_begin()/kernel_fpu_end() to allow the kernel itself
to use fpu. They can be used by some other kernel components, e.g., the
AMDGPU graphic driver for DCN.

Reported-by: WANG Xuerui <kernel@xen0n.name>
Tested-by: WANG Xuerui <kernel@xen0n.name>
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
arch/loongarch/include/asm/fpu.h
arch/loongarch/kernel/Makefile
arch/loongarch/kernel/kfpu.c [new file with mode: 0644]

index 358b254..192f8e3 100644 (file)
@@ -21,6 +21,9 @@
 
 struct sigcontext;
 
+extern void kernel_fpu_begin(void);
+extern void kernel_fpu_end(void);
+
 extern void _init_fpu(unsigned int);
 extern void _save_fp(struct loongarch_fpu *);
 extern void _restore_fp(struct loongarch_fpu *);
index 78d4e33..9a72d91 100644 (file)
@@ -13,7 +13,7 @@ obj-y         += head.o cpu-probe.o cacheinfo.o env.o setup.o entry.o genex.o \
 obj-$(CONFIG_ACPI)             += acpi.o
 obj-$(CONFIG_EFI)              += efi.o
 
-obj-$(CONFIG_CPU_HAS_FPU)      += fpu.o
+obj-$(CONFIG_CPU_HAS_FPU)      += fpu.o kfpu.o
 
 obj-$(CONFIG_ARCH_STRICT_ALIGN)        += unaligned.o
 
diff --git a/arch/loongarch/kernel/kfpu.c b/arch/loongarch/kernel/kfpu.c
new file mode 100644 (file)
index 0000000..5c46ae8
--- /dev/null
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2023 Loongson Technology Corporation Limited
+ */
+
+#include <linux/cpu.h>
+#include <linux/init.h>
+#include <asm/fpu.h>
+#include <asm/smp.h>
+
+static DEFINE_PER_CPU(bool, in_kernel_fpu);
+
+void kernel_fpu_begin(void)
+{
+       preempt_disable();
+
+       WARN_ON(this_cpu_read(in_kernel_fpu));
+
+       this_cpu_write(in_kernel_fpu, true);
+
+       if (!is_fpu_owner())
+               enable_fpu();
+       else
+               _save_fp(&current->thread.fpu);
+
+       write_fcsr(LOONGARCH_FCSR0, 0);
+}
+EXPORT_SYMBOL_GPL(kernel_fpu_begin);
+
+void kernel_fpu_end(void)
+{
+       WARN_ON(!this_cpu_read(in_kernel_fpu));
+
+       if (!is_fpu_owner())
+               disable_fpu();
+       else
+               _restore_fp(&current->thread.fpu);
+
+       this_cpu_write(in_kernel_fpu, false);
+
+       preempt_enable();
+}
+EXPORT_SYMBOL_GPL(kernel_fpu_end);