Skip to content

Commit

Permalink
MIPS: Modularize COP2 handling
Browse files Browse the repository at this point in the history
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/
  • Loading branch information
Ralf Baechle committed Dec 17, 2009
1 parent 4dd92e1 commit 69f3a7d
Show file tree
Hide file tree
Showing 6 changed files with 140 additions and 23 deletions.
2 changes: 1 addition & 1 deletion arch/mips/cavium-octeon/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
52 changes: 52 additions & 0 deletions arch/mips/cavium-octeon/cpu.c
Original file line number Diff line number Diff line change
@@ -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);
23 changes: 23 additions & 0 deletions arch/mips/include/asm/cop2.h
Original file line number Diff line number Diff line change
@@ -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 */
1 change: 1 addition & 0 deletions arch/mips/include/asm/octeon/octeon.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
60 changes: 45 additions & 15 deletions arch/mips/kernel/traps.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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);
}
25 changes: 18 additions & 7 deletions arch/mips/kernel/unaligned.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 69f3a7d

Please sign in to comment.