18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
38c2ecf20Sopenharmony_ci * License. See the file "COPYING" in the main directory of this archive
48c2ecf20Sopenharmony_ci * for more details.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Copyright (C) 2004-2012 Cavium Networks
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <asm/cop2.h>
108c2ecf20Sopenharmony_ci#include <linux/export.h>
118c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
128c2ecf20Sopenharmony_ci#include <linux/sched/task_stack.h>
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include "octeon-crypto.h"
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci/**
178c2ecf20Sopenharmony_ci * Enable access to Octeon's COP2 crypto hardware for kernel use. Wrap any
188c2ecf20Sopenharmony_ci * crypto operations in calls to octeon_crypto_enable/disable in order to make
198c2ecf20Sopenharmony_ci * sure the state of COP2 isn't corrupted if userspace is also performing
208c2ecf20Sopenharmony_ci * hardware crypto operations. Allocate the state parameter on the stack.
218c2ecf20Sopenharmony_ci * Returns with preemption disabled.
228c2ecf20Sopenharmony_ci *
238c2ecf20Sopenharmony_ci * @state: Pointer to state structure to store current COP2 state in.
248c2ecf20Sopenharmony_ci *
258c2ecf20Sopenharmony_ci * Returns: Flags to be passed to octeon_crypto_disable()
268c2ecf20Sopenharmony_ci */
278c2ecf20Sopenharmony_ciunsigned long octeon_crypto_enable(struct octeon_cop2_state *state)
288c2ecf20Sopenharmony_ci{
298c2ecf20Sopenharmony_ci	int status;
308c2ecf20Sopenharmony_ci	unsigned long flags;
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci	preempt_disable();
338c2ecf20Sopenharmony_ci	local_irq_save(flags);
348c2ecf20Sopenharmony_ci	status = read_c0_status();
358c2ecf20Sopenharmony_ci	write_c0_status(status | ST0_CU2);
368c2ecf20Sopenharmony_ci	if (KSTK_STATUS(current) & ST0_CU2) {
378c2ecf20Sopenharmony_ci		octeon_cop2_save(&(current->thread.cp2));
388c2ecf20Sopenharmony_ci		KSTK_STATUS(current) &= ~ST0_CU2;
398c2ecf20Sopenharmony_ci		status &= ~ST0_CU2;
408c2ecf20Sopenharmony_ci	} else if (status & ST0_CU2) {
418c2ecf20Sopenharmony_ci		octeon_cop2_save(state);
428c2ecf20Sopenharmony_ci	}
438c2ecf20Sopenharmony_ci	local_irq_restore(flags);
448c2ecf20Sopenharmony_ci	return status & ST0_CU2;
458c2ecf20Sopenharmony_ci}
468c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(octeon_crypto_enable);
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci/**
498c2ecf20Sopenharmony_ci * Disable access to Octeon's COP2 crypto hardware in the kernel. This must be
508c2ecf20Sopenharmony_ci * called after an octeon_crypto_enable() before any context switch or return to
518c2ecf20Sopenharmony_ci * userspace.
528c2ecf20Sopenharmony_ci *
538c2ecf20Sopenharmony_ci * @state:	Pointer to COP2 state to restore
548c2ecf20Sopenharmony_ci * @flags:	Return value from octeon_crypto_enable()
558c2ecf20Sopenharmony_ci */
568c2ecf20Sopenharmony_civoid octeon_crypto_disable(struct octeon_cop2_state *state,
578c2ecf20Sopenharmony_ci			   unsigned long crypto_flags)
588c2ecf20Sopenharmony_ci{
598c2ecf20Sopenharmony_ci	unsigned long flags;
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	local_irq_save(flags);
628c2ecf20Sopenharmony_ci	if (crypto_flags & ST0_CU2)
638c2ecf20Sopenharmony_ci		octeon_cop2_restore(state);
648c2ecf20Sopenharmony_ci	else
658c2ecf20Sopenharmony_ci		write_c0_status(read_c0_status() & ~ST0_CU2);
668c2ecf20Sopenharmony_ci	local_irq_restore(flags);
678c2ecf20Sopenharmony_ci	preempt_enable();
688c2ecf20Sopenharmony_ci}
698c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(octeon_crypto_disable);
70