MIPS: Modularize COP2 handling
authorRalf Baechle <ralf@linux-mips.org>
Tue, 24 Nov 2009 01:24:58 +0000 (01:24 +0000)
committerRalf Baechle <ralf@linux-mips.org>
Thu, 17 Dec 2009 01:57:30 +0000 (01:57 +0000)
Away with the daemons of ifdef; get ready for future COP2 users.

Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Patchwork: http://patchwork.linux-mips.org/patch/708/

arch/mips/cavium-octeon/Makefile
arch/mips/cavium-octeon/cpu.c [new file with mode: 0644]
arch/mips/include/asm/cop2.h [new file with mode: 0644]
arch/mips/include/asm/octeon/octeon.h
arch/mips/kernel/traps.c
arch/mips/kernel/unaligned.c

index 1394362..3e98763 100644 (file)
@@ -9,7 +9,7 @@
 # Copyright (C) 2005-2009 Cavium Networks
 #
 
-obj-y := setup.o serial.o octeon-platform.o octeon-irq.o csrc-octeon.o
+obj-y := cpu.o setup.o serial.o octeon-platform.o octeon-irq.o csrc-octeon.o
 obj-y += dma-octeon.o flash_setup.o
 obj-y += octeon-memcpy.o
 
diff --git a/arch/mips/cavium-octeon/cpu.c b/arch/mips/cavium-octeon/cpu.c
new file mode 100644 (file)
index 0000000..b6df538
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2009 Wind River Systems,
+ *   written by Ralf Baechle <ralf@linux-mips.org>
+ */
+#include <linux/init.h>
+#include <linux/irqflags.h>
+#include <linux/notifier.h>
+#include <linux/prefetch.h>
+#include <linux/sched.h>
+
+#include <asm/cop2.h>
+#include <asm/current.h>
+#include <asm/mipsregs.h>
+#include <asm/page.h>
+#include <asm/octeon/octeon.h>
+
+static int cnmips_cu2_call(struct notifier_block *nfb, unsigned long action,
+       void *data)
+{
+       unsigned long flags;
+       unsigned int status;
+
+       switch (action) {
+       case CU2_EXCEPTION:
+               prefetch(&current->thread.cp2);
+               local_irq_save(flags);
+               KSTK_STATUS(current) |= ST0_CU2;
+               status = read_c0_status();
+               write_c0_status(status | ST0_CU2);
+               octeon_cop2_restore(&(current->thread.cp2));
+               write_c0_status(status & ~ST0_CU2);
+               local_irq_restore(flags);
+
+               return NOTIFY_BAD;      /* Don't call default notifier */
+       }
+
+       return NOTIFY_OK;               /* Let default notifier send signals */
+}
+
+static struct notifier_block cnmips_cu2_notifier = {
+       .notifier_call = cnmips_cu2_call,
+};
+
+static int cnmips_cu2_setup(void)
+{
+       return register_cu2_notifier(&cnmips_cu2_notifier);
+}
+early_initcall(cnmips_cu2_setup);
diff --git a/arch/mips/include/asm/cop2.h b/arch/mips/include/asm/cop2.h
new file mode 100644 (file)
index 0000000..6b04c98
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2009 Wind River Systems,
+ *   written by Ralf Baechle <ralf@linux-mips.org>
+ */
+#ifndef __ASM_COP2_H
+#define __ASM_COP2_H
+
+enum cu2_ops {
+       CU2_EXCEPTION,
+       CU2_LWC2_OP,
+       CU2_LDC2_OP,
+       CU2_SWC2_OP,
+       CU2_SDC2_OP,
+};
+
+extern int register_cu2_notifier(struct notifier_block *nb);
+extern int cu2_notifier_call_chain(unsigned long val, void *v);
+
+#endif /* __ASM_COP2_H */
index cac9b1a..4d0a8c6 100644 (file)
@@ -47,6 +47,7 @@ struct octeon_cop2_state;
 extern unsigned long octeon_crypto_enable(struct octeon_cop2_state *state);
 extern void octeon_crypto_disable(struct octeon_cop2_state *state,
                                  unsigned long flags);
+extern asmlinkage void octeon_cop2_restore(struct octeon_cop2_state *task);
 
 extern void octeon_init_cvmcount(void);
 
index 0a18b4c..9fe21fb 100644 (file)
 #include <linux/ptrace.h>
 #include <linux/kgdb.h>
 #include <linux/kdebug.h>
+#include <linux/notifier.h>
 
 #include <asm/bootinfo.h>
 #include <asm/branch.h>
 #include <asm/break.h>
+#include <asm/cop2.h>
 #include <asm/cpu.h>
 #include <asm/dsp.h>
 #include <asm/fpu.h>
@@ -79,10 +81,6 @@ extern asmlinkage void handle_reserved(void);
 extern int fpu_emulator_cop1Handler(struct pt_regs *xcp,
        struct mips_fpu_struct *ctx, int has_fpu);
 
-#ifdef CONFIG_CPU_CAVIUM_OCTEON
-extern asmlinkage void octeon_cop2_restore(struct octeon_cop2_state *task);
-#endif
-
 void (*board_be_init)(void);
 int (*board_be_handler)(struct pt_regs *regs, int is_fixup);
 void (*board_nmi_handler_setup)(void);
@@ -857,6 +855,44 @@ static void mt_ase_fp_affinity(void)
 #endif /* CONFIG_MIPS_MT_FPAFF */
 }
 
+/*
+ * No lock; only written during early bootup by CPU 0.
+ */
+static RAW_NOTIFIER_HEAD(cu2_chain);
+
+int __ref register_cu2_notifier(struct notifier_block *nb)
+{
+       return raw_notifier_chain_register(&cu2_chain, nb);
+}
+
+int cu2_notifier_call_chain(unsigned long val, void *v)
+{
+       return raw_notifier_call_chain(&cu2_chain, val, v);
+}
+
+static int default_cu2_call(struct notifier_block *nfb, unsigned long action,
+        void *data)
+{
+       struct pt_regs *regs = data;
+
+       switch (action) {
+       default:
+               die_if_kernel("Unhandled kernel unaligned access or invalid "
+                             "instruction", regs);
+               /* Fall through  */
+
+       case CU2_EXCEPTION:
+               force_sig(SIGILL, current);
+       }
+
+       return NOTIFY_OK;
+}
+
+static struct notifier_block default_cu2_notifier = {
+       .notifier_call  = default_cu2_call,
+       .priority       = 0x80000000,           /* Run last  */
+};
+
 asmlinkage void do_cpu(struct pt_regs *regs)
 {
        unsigned int __user *epc;
@@ -920,17 +956,9 @@ asmlinkage void do_cpu(struct pt_regs *regs)
                return;
 
        case 2:
-#ifdef CONFIG_CPU_CAVIUM_OCTEON
-               prefetch(&current->thread.cp2);
-               local_irq_save(flags);
-               KSTK_STATUS(current) |= ST0_CU2;
-               status = read_c0_status();
-               write_c0_status(status | ST0_CU2);
-               octeon_cop2_restore(&(current->thread.cp2));
-               write_c0_status(status & ~ST0_CU2);
-               local_irq_restore(flags);
-               return;
-#endif
+               raw_notifier_call_chain(&cu2_chain, CU2_EXCEPTION, regs);
+               break;
+
        case 3:
                break;
        }
@@ -1760,4 +1788,6 @@ void __init trap_init(void)
        flush_tlb_handlers();
 
        sort_extable(__start___dbe_table, __stop___dbe_table);
+
+       register_cu2_notifier(&default_cu2_notifier);
 }
index 67bd626..69b039c 100644 (file)
@@ -81,6 +81,7 @@
 #include <asm/asm.h>
 #include <asm/branch.h>
 #include <asm/byteorder.h>
+#include <asm/cop2.h>
 #include <asm/inst.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -451,17 +452,27 @@ static void emulate_load_store_insn(struct pt_regs *regs,
                 */
                goto sigbus;
 
+       /*
+        * COP2 is available to implementor for application specific use.
+        * It's up to applications to register a notifier chain and do
+        * whatever they have to do, including possible sending of signals.
+        */
        case lwc2_op:
+               cu2_notifier_call_chain(CU2_LWC2_OP, regs);
+               break;
+
        case ldc2_op:
+               cu2_notifier_call_chain(CU2_LDC2_OP, regs);
+               break;
+
        case swc2_op:
+               cu2_notifier_call_chain(CU2_SWC2_OP, regs);
+               break;
+
        case sdc2_op:
-               /*
-                * These are the coprocessor 2 load/stores.  The current
-                * implementations don't use cp2 and cp2 should always be
-                * disabled in c0_status.  So send SIGILL.
-                 * (No longer true: The Sony Praystation uses cp2 for
-                 * 3D matrix operations.  Dunno if that thingy has a MMU ...)
-                */
+               cu2_notifier_call_chain(CU2_SDC2_OP, regs);
+               break;
+
        default:
                /*
                 * Pheeee...  We encountered an yet unknown instruction or