summaryrefslogtreecommitdiffstats
path: root/drivers/crypto/qat/qat_common/adf_pfvf_pf_proto.c
blob: 9f4baa9b14fc3bd4d7739c7f90d6995960ab2427 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
// SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only)
/* Copyright(c) 2015 - 2021 Intel Corporation */
#include <linux/spinlock.h>
#include <linux/types.h>
#include "adf_accel_devices.h"
#include "adf_common_drv.h"
#include "adf_pfvf_msg.h"
#include "adf_pfvf_pf_proto.h"

/**
 * adf_send_pf2vf_msg() - send PF to VF message
 * @accel_dev:	Pointer to acceleration device
 * @vf_nr:	VF number to which the message will be sent
 * @msg:	Message to send
 *
 * This function allows the PF to send a message to a specific VF.
 *
 * Return: 0 on success, error code otherwise.
 */
int adf_send_pf2vf_msg(struct adf_accel_dev *accel_dev, u8 vf_nr, u32 msg)
{
	struct adf_pfvf_ops *pfvf_ops = GET_PFVF_OPS(accel_dev);
	u32 pfvf_offset = pfvf_ops->get_pf2vf_offset(vf_nr);

	return pfvf_ops->send_msg(accel_dev, msg, pfvf_offset,
				  &accel_dev->pf.vf_info[vf_nr].pf2vf_lock);
}

/**
 * adf_recv_vf2pf_msg() - receive a VF to PF message
 * @accel_dev:	Pointer to acceleration device
 * @vf_nr:	Number of the VF from where the message will be received
 *
 * This function allows the PF to receive a message from a specific VF.
 *
 * Return: a valid message on success, zero otherwise.
 */
static u32 adf_recv_vf2pf_msg(struct adf_accel_dev *accel_dev, u8 vf_nr)
{
	struct adf_pfvf_ops *pfvf_ops = GET_PFVF_OPS(accel_dev);
	u32 pfvf_offset = pfvf_ops->get_vf2pf_offset(vf_nr);

	return pfvf_ops->recv_msg(accel_dev, pfvf_offset);
}

static int adf_handle_vf2pf_msg(struct adf_accel_dev *accel_dev, u32 vf_nr,
				u32 msg, u32 *response)
{
	struct adf_accel_vf_info *vf_info = &accel_dev->pf.vf_info[vf_nr];
	u32 resp = 0;

	switch ((msg >> ADF_PFVF_MSGTYPE_SHIFT) & ADF_PFVF_MSGTYPE_MASK) {
	case ADF_VF2PF_MSGTYPE_COMPAT_VER_REQ:
		{
		u8 vf_compat_ver = msg >> ADF_VF2PF_COMPAT_VER_REQ_SHIFT;
		u8 compat;

		dev_dbg(&GET_DEV(accel_dev),
			"VersionRequest received from VF%d (vers %d) to PF (vers %d)\n",
			vf_nr, vf_compat_ver, ADF_PFVF_COMPAT_THIS_VERSION);

		if (vf_compat_ver <= ADF_PFVF_COMPAT_THIS_VERSION)
			compat = ADF_PF2VF_VF_COMPATIBLE;
		else
			compat = ADF_PF2VF_VF_COMPAT_UNKNOWN;

		resp |= ADF_PF2VF_MSGTYPE_VERSION_RESP <<
			ADF_PFVF_MSGTYPE_SHIFT;
		resp |= ADF_PFVF_COMPAT_THIS_VERSION <<
			ADF_PF2VF_VERSION_RESP_VERS_SHIFT;
		resp |= compat << ADF_PF2VF_VERSION_RESP_RESULT_SHIFT;
		}
		break;
	case ADF_VF2PF_MSGTYPE_VERSION_REQ:
		{
		u8 compat;

		dev_dbg(&GET_DEV(accel_dev),
			"Legacy VersionRequest received from VF%d to PF (vers 1.1)\n",
			vf_nr);

		/* PF always newer than legacy VF */
		compat = ADF_PF2VF_VF_COMPATIBLE;

		resp |= ADF_PF2VF_MSGTYPE_VERSION_RESP <<
			ADF_PFVF_MSGTYPE_SHIFT;
		/* Set legacy major and minor version num */
		resp |= 1 << ADF_PF2VF_MAJORVERSION_SHIFT |
			1 << ADF_PF2VF_MINORVERSION_SHIFT;
		resp |= compat << ADF_PF2VF_VERSION_RESP_RESULT_SHIFT;
		}
		break;
	case ADF_VF2PF_MSGTYPE_INIT:
		{
		dev_dbg(&GET_DEV(accel_dev),
			"Init message received from VF%d\n", vf_nr);
		vf_info->init = true;
		}
		break;
	case ADF_VF2PF_MSGTYPE_SHUTDOWN:
		{
		dev_dbg(&GET_DEV(accel_dev),
			"Shutdown message received from VF%d\n", vf_nr);
		vf_info->init = false;
		}
		break;
	default:
		dev_dbg(&GET_DEV(accel_dev), "Unknown message from VF%d (0x%.8x)\n",
			vf_nr, msg);
		return -ENOMSG;
	}

	*response = resp;

	return 0;
}

bool adf_recv_and_handle_vf2pf_msg(struct adf_accel_dev *accel_dev, u32 vf_nr)
{
	u32 resp = 0;
	u32 msg;

	msg = adf_recv_vf2pf_msg(accel_dev, vf_nr);
	if (!msg)
		return true;

	if (adf_handle_vf2pf_msg(accel_dev, vf_nr, msg, &resp))
		return false;

	if (resp && adf_send_pf2vf_msg(accel_dev, vf_nr, resp))
		dev_err(&GET_DEV(accel_dev),
			"Failed to send response to VF%d\n", vf_nr);

	return true;
}

/**
 * adf_enable_pf2vf_comms() - Function enables communication from pf to vf
 *
 * @accel_dev: Pointer to acceleration device virtual function.
 *
 * This function carries out the necessary steps to setup and start the PFVF
 * communication channel, if any.
 *
 * Return: 0 on success, error code otherwise.
 */
int adf_enable_pf2vf_comms(struct adf_accel_dev *accel_dev)
{
	spin_lock_init(&accel_dev->pf.vf2pf_ints_lock);

	return 0;
}
EXPORT_SYMBOL_GPL(adf_enable_pf2vf_comms);