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/
This commit is contained in:
parent
4dd92e15b3
commit
69f3a7de1f
|
@ -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
|
||||
|
||||
|
|
|
@ -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(¤t->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);
|
|
@ -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 */
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -25,10 +25,12 @@
|
|||
#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(¤t->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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue