diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/mips/cavium-octeon/Makefile | 2 | ||||
-rw-r--r-- | arch/mips/cavium-octeon/cpu.c | 52 | ||||
-rw-r--r-- | arch/mips/include/asm/cop2.h | 23 | ||||
-rw-r--r-- | arch/mips/include/asm/octeon/octeon.h | 1 | ||||
-rw-r--r-- | arch/mips/kernel/traps.c | 60 | ||||
-rw-r--r-- | arch/mips/kernel/unaligned.c | 25 |
6 files changed, 140 insertions, 23 deletions
diff --git a/arch/mips/cavium-octeon/Makefile b/arch/mips/cavium-octeon/Makefile index 139436280520..3e9876317e61 100644 --- a/arch/mips/cavium-octeon/Makefile +++ b/arch/mips/cavium-octeon/Makefile | |||
@@ -9,7 +9,7 @@ | |||
9 | # Copyright (C) 2005-2009 Cavium Networks | 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 | obj-y += dma-octeon.o flash_setup.o | 13 | obj-y += dma-octeon.o flash_setup.o |
14 | obj-y += octeon-memcpy.o | 14 | obj-y += octeon-memcpy.o |
15 | 15 | ||
diff --git a/arch/mips/cavium-octeon/cpu.c b/arch/mips/cavium-octeon/cpu.c new file mode 100644 index 000000000000..b6df5387e855 --- /dev/null +++ b/arch/mips/cavium-octeon/cpu.c | |||
@@ -0,0 +1,52 @@ | |||
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); | ||
diff --git a/arch/mips/include/asm/cop2.h b/arch/mips/include/asm/cop2.h new file mode 100644 index 000000000000..6b04c98b7fad --- /dev/null +++ b/arch/mips/include/asm/cop2.h | |||
@@ -0,0 +1,23 @@ | |||
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 */ | ||
diff --git a/arch/mips/include/asm/octeon/octeon.h b/arch/mips/include/asm/octeon/octeon.h index cac9b1a206fc..4d0a8c61fc3e 100644 --- a/arch/mips/include/asm/octeon/octeon.h +++ b/arch/mips/include/asm/octeon/octeon.h | |||
@@ -47,6 +47,7 @@ struct octeon_cop2_state; | |||
47 | extern unsigned long octeon_crypto_enable(struct octeon_cop2_state *state); | 47 | extern unsigned long octeon_crypto_enable(struct octeon_cop2_state *state); |
48 | extern void octeon_crypto_disable(struct octeon_cop2_state *state, | 48 | extern void octeon_crypto_disable(struct octeon_cop2_state *state, |
49 | unsigned long flags); | 49 | unsigned long flags); |
50 | extern asmlinkage void octeon_cop2_restore(struct octeon_cop2_state *task); | ||
50 | 51 | ||
51 | extern void octeon_init_cvmcount(void); | 52 | extern void octeon_init_cvmcount(void); |
52 | 53 | ||
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 0a18b4c62afb..9fe21fb65305 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c | |||
@@ -25,10 +25,12 @@ | |||
25 | #include <linux/ptrace.h> | 25 | #include <linux/ptrace.h> |
26 | #include <linux/kgdb.h> | 26 | #include <linux/kgdb.h> |
27 | #include <linux/kdebug.h> | 27 | #include <linux/kdebug.h> |
28 | #include <linux/notifier.h> | ||
28 | 29 | ||
29 | #include <asm/bootinfo.h> | 30 | #include <asm/bootinfo.h> |
30 | #include <asm/branch.h> | 31 | #include <asm/branch.h> |
31 | #include <asm/break.h> | 32 | #include <asm/break.h> |
33 | #include <asm/cop2.h> | ||
32 | #include <asm/cpu.h> | 34 | #include <asm/cpu.h> |
33 | #include <asm/dsp.h> | 35 | #include <asm/dsp.h> |
34 | #include <asm/fpu.h> | 36 | #include <asm/fpu.h> |
@@ -79,10 +81,6 @@ extern asmlinkage void handle_reserved(void); | |||
79 | extern int fpu_emulator_cop1Handler(struct pt_regs *xcp, | 81 | extern int fpu_emulator_cop1Handler(struct pt_regs *xcp, |
80 | struct mips_fpu_struct *ctx, int has_fpu); | 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 | void (*board_be_init)(void); | 84 | void (*board_be_init)(void); |
87 | int (*board_be_handler)(struct pt_regs *regs, int is_fixup); | 85 | int (*board_be_handler)(struct pt_regs *regs, int is_fixup); |
88 | void (*board_nmi_handler_setup)(void); | 86 | void (*board_nmi_handler_setup)(void); |
@@ -857,6 +855,44 @@ static void mt_ase_fp_affinity(void) | |||
857 | #endif /* CONFIG_MIPS_MT_FPAFF */ | 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 | asmlinkage void do_cpu(struct pt_regs *regs) | 896 | asmlinkage void do_cpu(struct pt_regs *regs) |
861 | { | 897 | { |
862 | unsigned int __user *epc; | 898 | unsigned int __user *epc; |
@@ -920,17 +956,9 @@ asmlinkage void do_cpu(struct pt_regs *regs) | |||
920 | return; | 956 | return; |
921 | 957 | ||
922 | case 2: | 958 | case 2: |
923 | #ifdef CONFIG_CPU_CAVIUM_OCTEON | 959 | raw_notifier_call_chain(&cu2_chain, CU2_EXCEPTION, regs); |
924 | prefetch(¤t->thread.cp2); | 960 | break; |
925 | local_irq_save(flags); | 961 | |
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 | ||
934 | case 3: | 962 | case 3: |
935 | break; | 963 | break; |
936 | } | 964 | } |
@@ -1760,4 +1788,6 @@ void __init trap_init(void) | |||
1760 | flush_tlb_handlers(); | 1788 | flush_tlb_handlers(); |
1761 | 1789 | ||
1762 | sort_extable(__start___dbe_table, __stop___dbe_table); | 1790 | sort_extable(__start___dbe_table, __stop___dbe_table); |
1791 | |||
1792 | register_cu2_notifier(&default_cu2_notifier); | ||
1763 | } | 1793 | } |
diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c index 67bd626942ab..69b039ca8d83 100644 --- a/arch/mips/kernel/unaligned.c +++ b/arch/mips/kernel/unaligned.c | |||
@@ -81,6 +81,7 @@ | |||
81 | #include <asm/asm.h> | 81 | #include <asm/asm.h> |
82 | #include <asm/branch.h> | 82 | #include <asm/branch.h> |
83 | #include <asm/byteorder.h> | 83 | #include <asm/byteorder.h> |
84 | #include <asm/cop2.h> | ||
84 | #include <asm/inst.h> | 85 | #include <asm/inst.h> |
85 | #include <asm/uaccess.h> | 86 | #include <asm/uaccess.h> |
86 | #include <asm/system.h> | 87 | #include <asm/system.h> |
@@ -451,17 +452,27 @@ static void emulate_load_store_insn(struct pt_regs *regs, | |||
451 | */ | 452 | */ |
452 | goto sigbus; | 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 | case lwc2_op: | 460 | case lwc2_op: |
461 | cu2_notifier_call_chain(CU2_LWC2_OP, regs); | ||
462 | break; | ||
463 | |||
455 | case ldc2_op: | 464 | case ldc2_op: |
465 | cu2_notifier_call_chain(CU2_LDC2_OP, regs); | ||
466 | break; | ||
467 | |||
456 | case swc2_op: | 468 | case swc2_op: |
469 | cu2_notifier_call_chain(CU2_SWC2_OP, regs); | ||
470 | break; | ||
471 | |||
457 | case sdc2_op: | 472 | case sdc2_op: |
458 | /* | 473 | cu2_notifier_call_chain(CU2_SDC2_OP, regs); |
459 | * These are the coprocessor 2 load/stores. The current | 474 | break; |
460 | * implementations don't use cp2 and cp2 should always be | 475 | |
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 | */ | ||
465 | default: | 476 | default: |
466 | /* | 477 | /* |
467 | * Pheeee... We encountered an yet unknown instruction or | 478 | * Pheeee... We encountered an yet unknown instruction or |