Commit 69f3a7de1f1ec935924b1b13f83812f8b30e92ce
1 parent
4dd92e15b3
Exists in
master
and in
7 other branches
MIPS: Modularize COP2 handling
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/
Showing 6 changed files with 140 additions and 23 deletions Side-by-side Diff
arch/mips/cavium-octeon/Makefile
... | ... | @@ -9,7 +9,7 @@ |
9 | 9 | # Copyright (C) 2005-2009 Cavium Networks |
10 | 10 | # |
11 | 11 | |
12 | -obj-y := setup.o serial.o octeon-platform.o octeon-irq.o csrc-octeon.o | |
12 | +obj-y := cpu.o setup.o serial.o octeon-platform.o octeon-irq.o csrc-octeon.o | |
13 | 13 | obj-y += dma-octeon.o flash_setup.o |
14 | 14 | obj-y += octeon-memcpy.o |
15 | 15 |
arch/mips/cavium-octeon/cpu.c
1 | +/* | |
2 | + * This file is subject to the terms and conditions of the GNU General Public | |
3 | + * License. See the file "COPYING" in the main directory of this archive | |
4 | + * for more details. | |
5 | + * | |
6 | + * Copyright (C) 2009 Wind River Systems, | |
7 | + * written by Ralf Baechle <ralf@linux-mips.org> | |
8 | + */ | |
9 | +#include <linux/init.h> | |
10 | +#include <linux/irqflags.h> | |
11 | +#include <linux/notifier.h> | |
12 | +#include <linux/prefetch.h> | |
13 | +#include <linux/sched.h> | |
14 | + | |
15 | +#include <asm/cop2.h> | |
16 | +#include <asm/current.h> | |
17 | +#include <asm/mipsregs.h> | |
18 | +#include <asm/page.h> | |
19 | +#include <asm/octeon/octeon.h> | |
20 | + | |
21 | +static int cnmips_cu2_call(struct notifier_block *nfb, unsigned long action, | |
22 | + void *data) | |
23 | +{ | |
24 | + unsigned long flags; | |
25 | + unsigned int status; | |
26 | + | |
27 | + switch (action) { | |
28 | + case CU2_EXCEPTION: | |
29 | + prefetch(¤t->thread.cp2); | |
30 | + local_irq_save(flags); | |
31 | + KSTK_STATUS(current) |= ST0_CU2; | |
32 | + status = read_c0_status(); | |
33 | + write_c0_status(status | ST0_CU2); | |
34 | + octeon_cop2_restore(&(current->thread.cp2)); | |
35 | + write_c0_status(status & ~ST0_CU2); | |
36 | + local_irq_restore(flags); | |
37 | + | |
38 | + return NOTIFY_BAD; /* Don't call default notifier */ | |
39 | + } | |
40 | + | |
41 | + return NOTIFY_OK; /* Let default notifier send signals */ | |
42 | +} | |
43 | + | |
44 | +static struct notifier_block cnmips_cu2_notifier = { | |
45 | + .notifier_call = cnmips_cu2_call, | |
46 | +}; | |
47 | + | |
48 | +static int cnmips_cu2_setup(void) | |
49 | +{ | |
50 | + return register_cu2_notifier(&cnmips_cu2_notifier); | |
51 | +} | |
52 | +early_initcall(cnmips_cu2_setup); |
arch/mips/include/asm/cop2.h
1 | +/* | |
2 | + * This file is subject to the terms and conditions of the GNU General Public | |
3 | + * License. See the file "COPYING" in the main directory of this archive | |
4 | + * for more details. | |
5 | + * | |
6 | + * Copyright (C) 2009 Wind River Systems, | |
7 | + * written by Ralf Baechle <ralf@linux-mips.org> | |
8 | + */ | |
9 | +#ifndef __ASM_COP2_H | |
10 | +#define __ASM_COP2_H | |
11 | + | |
12 | +enum cu2_ops { | |
13 | + CU2_EXCEPTION, | |
14 | + CU2_LWC2_OP, | |
15 | + CU2_LDC2_OP, | |
16 | + CU2_SWC2_OP, | |
17 | + CU2_SDC2_OP, | |
18 | +}; | |
19 | + | |
20 | +extern int register_cu2_notifier(struct notifier_block *nb); | |
21 | +extern int cu2_notifier_call_chain(unsigned long val, void *v); | |
22 | + | |
23 | +#endif /* __ASM_COP2_H */ |
arch/mips/include/asm/octeon/octeon.h
... | ... | @@ -47,6 +47,7 @@ |
47 | 47 | extern unsigned long octeon_crypto_enable(struct octeon_cop2_state *state); |
48 | 48 | extern void octeon_crypto_disable(struct octeon_cop2_state *state, |
49 | 49 | unsigned long flags); |
50 | +extern asmlinkage void octeon_cop2_restore(struct octeon_cop2_state *task); | |
50 | 51 | |
51 | 52 | extern void octeon_init_cvmcount(void); |
52 | 53 |
arch/mips/kernel/traps.c
... | ... | @@ -25,10 +25,12 @@ |
25 | 25 | #include <linux/ptrace.h> |
26 | 26 | #include <linux/kgdb.h> |
27 | 27 | #include <linux/kdebug.h> |
28 | +#include <linux/notifier.h> | |
28 | 29 | |
29 | 30 | #include <asm/bootinfo.h> |
30 | 31 | #include <asm/branch.h> |
31 | 32 | #include <asm/break.h> |
33 | +#include <asm/cop2.h> | |
32 | 34 | #include <asm/cpu.h> |
33 | 35 | #include <asm/dsp.h> |
34 | 36 | #include <asm/fpu.h> |
... | ... | @@ -79,10 +81,6 @@ |
79 | 81 | extern int fpu_emulator_cop1Handler(struct pt_regs *xcp, |
80 | 82 | struct mips_fpu_struct *ctx, int has_fpu); |
81 | 83 | |
82 | -#ifdef CONFIG_CPU_CAVIUM_OCTEON | |
83 | -extern asmlinkage void octeon_cop2_restore(struct octeon_cop2_state *task); | |
84 | -#endif | |
85 | - | |
86 | 84 | void (*board_be_init)(void); |
87 | 85 | int (*board_be_handler)(struct pt_regs *regs, int is_fixup); |
88 | 86 | void (*board_nmi_handler_setup)(void); |
... | ... | @@ -857,6 +855,44 @@ |
857 | 855 | #endif /* CONFIG_MIPS_MT_FPAFF */ |
858 | 856 | } |
859 | 857 | |
858 | +/* | |
859 | + * No lock; only written during early bootup by CPU 0. | |
860 | + */ | |
861 | +static RAW_NOTIFIER_HEAD(cu2_chain); | |
862 | + | |
863 | +int __ref register_cu2_notifier(struct notifier_block *nb) | |
864 | +{ | |
865 | + return raw_notifier_chain_register(&cu2_chain, nb); | |
866 | +} | |
867 | + | |
868 | +int cu2_notifier_call_chain(unsigned long val, void *v) | |
869 | +{ | |
870 | + return raw_notifier_call_chain(&cu2_chain, val, v); | |
871 | +} | |
872 | + | |
873 | +static int default_cu2_call(struct notifier_block *nfb, unsigned long action, | |
874 | + void *data) | |
875 | +{ | |
876 | + struct pt_regs *regs = data; | |
877 | + | |
878 | + switch (action) { | |
879 | + default: | |
880 | + die_if_kernel("Unhandled kernel unaligned access or invalid " | |
881 | + "instruction", regs); | |
882 | + /* Fall through */ | |
883 | + | |
884 | + case CU2_EXCEPTION: | |
885 | + force_sig(SIGILL, current); | |
886 | + } | |
887 | + | |
888 | + return NOTIFY_OK; | |
889 | +} | |
890 | + | |
891 | +static struct notifier_block default_cu2_notifier = { | |
892 | + .notifier_call = default_cu2_call, | |
893 | + .priority = 0x80000000, /* Run last */ | |
894 | +}; | |
895 | + | |
860 | 896 | asmlinkage void do_cpu(struct pt_regs *regs) |
861 | 897 | { |
862 | 898 | unsigned int __user *epc; |
... | ... | @@ -920,17 +956,9 @@ |
920 | 956 | return; |
921 | 957 | |
922 | 958 | case 2: |
923 | -#ifdef CONFIG_CPU_CAVIUM_OCTEON | |
924 | - prefetch(¤t->thread.cp2); | |
925 | - local_irq_save(flags); | |
926 | - KSTK_STATUS(current) |= ST0_CU2; | |
927 | - status = read_c0_status(); | |
928 | - write_c0_status(status | ST0_CU2); | |
929 | - octeon_cop2_restore(&(current->thread.cp2)); | |
930 | - write_c0_status(status & ~ST0_CU2); | |
931 | - local_irq_restore(flags); | |
932 | - return; | |
933 | -#endif | |
959 | + raw_notifier_call_chain(&cu2_chain, CU2_EXCEPTION, regs); | |
960 | + break; | |
961 | + | |
934 | 962 | case 3: |
935 | 963 | break; |
936 | 964 | } |
... | ... | @@ -1760,5 +1788,7 @@ |
1760 | 1788 | flush_tlb_handlers(); |
1761 | 1789 | |
1762 | 1790 | sort_extable(__start___dbe_table, __stop___dbe_table); |
1791 | + | |
1792 | + register_cu2_notifier(&default_cu2_notifier); | |
1763 | 1793 | } |
arch/mips/kernel/unaligned.c
... | ... | @@ -81,6 +81,7 @@ |
81 | 81 | #include <asm/asm.h> |
82 | 82 | #include <asm/branch.h> |
83 | 83 | #include <asm/byteorder.h> |
84 | +#include <asm/cop2.h> | |
84 | 85 | #include <asm/inst.h> |
85 | 86 | #include <asm/uaccess.h> |
86 | 87 | #include <asm/system.h> |
87 | 88 | |
88 | 89 | |
89 | 90 | |
90 | 91 | |
... | ... | @@ -451,17 +452,27 @@ |
451 | 452 | */ |
452 | 453 | goto sigbus; |
453 | 454 | |
455 | + /* | |
456 | + * COP2 is available to implementor for application specific use. | |
457 | + * It's up to applications to register a notifier chain and do | |
458 | + * whatever they have to do, including possible sending of signals. | |
459 | + */ | |
454 | 460 | case lwc2_op: |
461 | + cu2_notifier_call_chain(CU2_LWC2_OP, regs); | |
462 | + break; | |
463 | + | |
455 | 464 | case ldc2_op: |
465 | + cu2_notifier_call_chain(CU2_LDC2_OP, regs); | |
466 | + break; | |
467 | + | |
456 | 468 | case swc2_op: |
469 | + cu2_notifier_call_chain(CU2_SWC2_OP, regs); | |
470 | + break; | |
471 | + | |
457 | 472 | case sdc2_op: |
458 | - /* | |
459 | - * These are the coprocessor 2 load/stores. The current | |
460 | - * implementations don't use cp2 and cp2 should always be | |
461 | - * disabled in c0_status. So send SIGILL. | |
462 | - * (No longer true: The Sony Praystation uses cp2 for | |
463 | - * 3D matrix operations. Dunno if that thingy has a MMU ...) | |
464 | - */ | |
473 | + cu2_notifier_call_chain(CU2_SDC2_OP, regs); | |
474 | + break; | |
475 | + | |
465 | 476 | default: |
466 | 477 | /* |
467 | 478 | * Pheeee... We encountered an yet unknown instruction or |