162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
362306a36Sopenharmony_ci * License.  See the file "COPYING" in the main directory of this archive
462306a36Sopenharmony_ci * for more details.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright (C) 2009 Wind River Systems,
762306a36Sopenharmony_ci *   written by Ralf Baechle <ralf@linux-mips.org>
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci#include <linux/init.h>
1062306a36Sopenharmony_ci#include <linux/irqflags.h>
1162306a36Sopenharmony_ci#include <linux/notifier.h>
1262306a36Sopenharmony_ci#include <linux/prefetch.h>
1362306a36Sopenharmony_ci#include <linux/ptrace.h>
1462306a36Sopenharmony_ci#include <linux/sched.h>
1562306a36Sopenharmony_ci#include <linux/sched/task_stack.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include <asm/cop2.h>
1862306a36Sopenharmony_ci#include <asm/current.h>
1962306a36Sopenharmony_ci#include <asm/mipsregs.h>
2062306a36Sopenharmony_ci#include <asm/page.h>
2162306a36Sopenharmony_ci#include <asm/octeon/octeon.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_cistatic int cnmips_cu2_call(struct notifier_block *nfb, unsigned long action,
2462306a36Sopenharmony_ci	void *data)
2562306a36Sopenharmony_ci{
2662306a36Sopenharmony_ci	unsigned long flags;
2762306a36Sopenharmony_ci	unsigned int status;
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci	switch (action) {
3062306a36Sopenharmony_ci	case CU2_EXCEPTION:
3162306a36Sopenharmony_ci		prefetch(&current->thread.cp2);
3262306a36Sopenharmony_ci		local_irq_save(flags);
3362306a36Sopenharmony_ci		KSTK_STATUS(current) |= ST0_CU2;
3462306a36Sopenharmony_ci		status = read_c0_status();
3562306a36Sopenharmony_ci		write_c0_status(status | ST0_CU2);
3662306a36Sopenharmony_ci		octeon_cop2_restore(&(current->thread.cp2));
3762306a36Sopenharmony_ci		write_c0_status(status & ~ST0_CU2);
3862306a36Sopenharmony_ci		local_irq_restore(flags);
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci		return NOTIFY_BAD;	/* Don't call default notifier */
4162306a36Sopenharmony_ci	}
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	return NOTIFY_OK;		/* Let default notifier send signals */
4462306a36Sopenharmony_ci}
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_cistatic int __init cnmips_cu2_setup(void)
4762306a36Sopenharmony_ci{
4862306a36Sopenharmony_ci	return cu2_notifier(cnmips_cu2_call, 0);
4962306a36Sopenharmony_ci}
5062306a36Sopenharmony_ciearly_initcall(cnmips_cu2_setup);
51