summaryrefslogtreecommitdiff
path: root/drivers/net/ethernet/intel/ixd/ixd_virtchnl.c
blob: fc3b6d2e28c536c20e305899844787ceece84206 (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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (C) 2025 Intel Corporation */

#include "ixd.h"
#include "ixd_ctlq.h"
#include "ixd_virtchnl.h"

/**
 * ixd_vc_recv_event_msg - Handle virtchnl event message
 * @adapter: The adapter handling the message
 * @ctlq_msg: Message received
 */
void ixd_vc_recv_event_msg(struct ixd_adapter *adapter,
			   struct libie_ctlq_msg *ctlq_msg)
{
	int payload_size = ctlq_msg->data_len;
	struct virtchnl2_event *v2e;

	if (payload_size < sizeof(*v2e)) {
		dev_warn_ratelimited(ixd_to_dev(adapter),
				     "Failed to receive valid payload for event msg (op 0x%X len %u)\n",
				     ctlq_msg->chnl_opcode,
				     payload_size);
		return;
	}

	v2e = (struct virtchnl2_event *)ctlq_msg->recv_mem.iov_base;

	dev_dbg(ixd_to_dev(adapter), "Got event 0x%X from the CP\n",
		le32_to_cpu(v2e->event));
}

/**
 * ixd_vc_can_handle_msg - Decide if an event has to be handled by virtchnl code
 * @ctlq_msg: Message received
 *
 * Return: %true if virtchnl code can handle the event, %false otherwise
 */
bool ixd_vc_can_handle_msg(struct libie_ctlq_msg *ctlq_msg)
{
	return ctlq_msg->chnl_opcode == VIRTCHNL2_OP_EVENT;
}

/**
 * ixd_handle_caps - Handle VIRTCHNL2_OP_GET_CAPS response
 * @adapter: The adapter for which the capabilities are being updated
 * @recv_buff: Buffer containing the response
 * @recv_size: Response buffer size
 * @ctx: unused
 *
 * Return: %0 if the response format is correct and was handled as expected,
 * negative error otherwise.
 */
static int ixd_handle_caps(struct ixd_adapter *adapter, void *recv_buff,
			   size_t recv_size, void *ctx)
{
	if (recv_size < sizeof(adapter->caps))
		return -EBADMSG;

	adapter->caps = *(typeof(adapter->caps) *)recv_buff;

	return 0;
}

/**
 * ixd_req_vc_caps - Request and save device capability
 * @adapter: The adapter to get the capabilities for
 *
 * Return: success or error if sending the get capability message fails
 */
static int ixd_req_vc_caps(struct ixd_adapter *adapter)
{
	const struct ixd_ctlq_req req = {
		.opcode = VIRTCHNL2_OP_GET_CAPS,
		.send_size = sizeof(struct virtchnl2_get_capabilities),
		.ctx = NULL,
		.send_buff_init = NULL,
		.recv_process = ixd_handle_caps,
	};

	return ixd_ctlq_do_req(adapter, &req);
}

/**
 * ixd_get_vc_ver - Get version info from adapter
 *
 * Return: filled in virtchannel2 version info, ready for sending
 */
static struct virtchnl2_version_info ixd_get_vc_ver(void)
{
	return (struct virtchnl2_version_info) {
		.major = cpu_to_le32(VIRTCHNL2_VERSION_MAJOR_2),
		.minor = cpu_to_le32(VIRTCHNL2_VERSION_MINOR_0),
	};
}

static void ixd_fill_vc_ver(struct ixd_adapter *adapter, void *send_buff,
			    void *ctx)
{
	*(struct virtchnl2_version_info *)send_buff = ixd_get_vc_ver();
}

/**
 * ixd_handle_vc_ver - Handle VIRTCHNL2_OP_VERSION response
 * @adapter: The adapter for which the version is being updated
 * @recv_buff: Buffer containing the response
 * @recv_size: Response buffer size
 * @ctx: Unused
 *
 * Return: %0 if the response format is correct and was handled as expected,
 * negative error otherwise.
 */
static int ixd_handle_vc_ver(struct ixd_adapter *adapter, void *recv_buff,
			     size_t recv_size, void *ctx)
{
	struct virtchnl2_version_info need_ver = ixd_get_vc_ver();
	struct virtchnl2_version_info *recv_ver;

	if (recv_size < sizeof(need_ver))
		return -EBADMSG;

	recv_ver = recv_buff;
	if (le32_to_cpu(need_ver.major) != le32_to_cpu(recv_ver->major) ||
	    le32_to_cpu(need_ver.minor) != le32_to_cpu(recv_ver->minor))
		dev_warn(ixd_to_dev(adapter),
			 "Virtchnl version does not match (expected %u.%u, received %u.%u)\n",
			 le32_to_cpu(need_ver.major),
			 le32_to_cpu(need_ver.minor),
			 le32_to_cpu(recv_ver->major),
			 le32_to_cpu(recv_ver->minor));

	if (le32_to_cpu(need_ver.major) != le32_to_cpu(recv_ver->major)) {
		dev_err(ixd_to_dev(adapter),
			"Device initialization failed due to virtchnl major version mismatch\n");
		return -EOPNOTSUPP;
	}

	adapter->vc_ver.major = le32_to_cpu(recv_ver->major);
	adapter->vc_ver.minor = le32_to_cpu(recv_ver->minor);

	return 0;
}

/**
 * ixd_req_vc_version - Request and save Virtchannel2 version
 * @adapter: The adapter to get the version for
 *
 * Return: success or error if sending fails or the response was not as expected
 */
static int ixd_req_vc_version(struct ixd_adapter *adapter)
{
	const struct ixd_ctlq_req req = {
		.opcode = VIRTCHNL2_OP_VERSION,
		.send_size = sizeof(struct virtchnl2_version_info),
		.ctx = NULL,
		.send_buff_init = ixd_fill_vc_ver,
		.recv_process = ixd_handle_vc_ver,
	};

	return ixd_ctlq_do_req(adapter, &req);
}

/**
 * ixd_vc_dev_init - virtchnl device core initialization
 * @adapter: device information
 *
 * Return: %0 on success or error if any step of the initialization fails
 */
int ixd_vc_dev_init(struct ixd_adapter *adapter)
{
	int err;

	err = ixd_req_vc_version(adapter);
	if (err) {
		dev_warn(ixd_to_dev(adapter),
			 "Getting virtchnl version failed, error=%pe\n",
			 ERR_PTR(err));
		return err;
	}

	err = ixd_req_vc_caps(adapter);
	if (err) {
		dev_warn(ixd_to_dev(adapter),
			 "Getting virtchnl capabilities failed, error=%pe\n",
			 ERR_PTR(err));
		return err;
	}

	return err;
}