• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only)
2 /* Copyright(c) 2015 - 2021 Intel Corporation */
3 #include <linux/bitfield.h>
4 #include <linux/completion.h>
5 #include <linux/minmax.h>
6 #include <linux/types.h>
7 #include "adf_accel_devices.h"
8 #include "adf_common_drv.h"
9 #include "adf_pfvf_msg.h"
10 #include "adf_pfvf_utils.h"
11 #include "adf_pfvf_vf_msg.h"
12 #include "adf_pfvf_vf_proto.h"
13 
14 #define ADF_PFVF_MSG_COLLISION_DETECT_DELAY	10
15 #define ADF_PFVF_MSG_ACK_DELAY			2
16 #define ADF_PFVF_MSG_ACK_MAX_RETRY		100
17 
18 /* How often to retry if there is no response */
19 #define ADF_PFVF_MSG_RESP_RETRIES	5
20 #define ADF_PFVF_MSG_RESP_TIMEOUT	(ADF_PFVF_MSG_ACK_DELAY * \
21 					 ADF_PFVF_MSG_ACK_MAX_RETRY + \
22 					 ADF_PFVF_MSG_COLLISION_DETECT_DELAY)
23 
24 /**
25  * adf_send_vf2pf_msg() - send VF to PF message
26  * @accel_dev:	Pointer to acceleration device
27  * @msg:	Message to send
28  *
29  * This function allows the VF to send a message to the PF.
30  *
31  * Return: 0 on success, error code otherwise.
32  */
adf_send_vf2pf_msg(struct adf_accel_dev * accel_dev,struct pfvf_message msg)33 int adf_send_vf2pf_msg(struct adf_accel_dev *accel_dev, struct pfvf_message msg)
34 {
35 	struct adf_pfvf_ops *pfvf_ops = GET_PFVF_OPS(accel_dev);
36 	u32 pfvf_offset = pfvf_ops->get_vf2pf_offset(0);
37 
38 	return pfvf_ops->send_msg(accel_dev, msg, pfvf_offset,
39 				  &accel_dev->vf.vf2pf_lock);
40 }
41 
42 /**
43  * adf_recv_pf2vf_msg() - receive a PF to VF message
44  * @accel_dev:	Pointer to acceleration device
45  *
46  * This function allows the VF to receive a message from the PF.
47  *
48  * Return: a valid message on success, zero otherwise.
49  */
adf_recv_pf2vf_msg(struct adf_accel_dev * accel_dev)50 static struct pfvf_message adf_recv_pf2vf_msg(struct adf_accel_dev *accel_dev)
51 {
52 	struct adf_pfvf_ops *pfvf_ops = GET_PFVF_OPS(accel_dev);
53 	u32 pfvf_offset = pfvf_ops->get_pf2vf_offset(0);
54 
55 	return pfvf_ops->recv_msg(accel_dev, pfvf_offset, accel_dev->vf.pf_compat_ver);
56 }
57 
58 /**
59  * adf_send_vf2pf_req() - send VF2PF request message
60  * @accel_dev:	Pointer to acceleration device.
61  * @msg:	Request message to send
62  * @resp:	Returned PF response
63  *
64  * This function sends a message that requires a response from the VF to the PF
65  * and waits for a reply.
66  *
67  * Return: 0 on success, error code otherwise.
68  */
adf_send_vf2pf_req(struct adf_accel_dev * accel_dev,struct pfvf_message msg,struct pfvf_message * resp)69 int adf_send_vf2pf_req(struct adf_accel_dev *accel_dev, struct pfvf_message msg,
70 		       struct pfvf_message *resp)
71 {
72 	unsigned long timeout = msecs_to_jiffies(ADF_PFVF_MSG_RESP_TIMEOUT);
73 	unsigned int retries = ADF_PFVF_MSG_RESP_RETRIES;
74 	int ret;
75 
76 	reinit_completion(&accel_dev->vf.msg_received);
77 
78 	/* Send request from VF to PF */
79 	do {
80 		ret = adf_send_vf2pf_msg(accel_dev, msg);
81 		if (ret) {
82 			dev_err(&GET_DEV(accel_dev),
83 				"Failed to send request msg to PF\n");
84 			return ret;
85 		}
86 
87 		/* Wait for response, if it times out retry */
88 		ret = wait_for_completion_timeout(&accel_dev->vf.msg_received,
89 						  timeout);
90 		if (ret) {
91 			if (likely(resp))
92 				*resp = accel_dev->vf.response;
93 
94 			/* Once copied, set to an invalid value */
95 			accel_dev->vf.response.type = 0;
96 
97 			return 0;
98 		}
99 
100 		dev_err(&GET_DEV(accel_dev), "PFVF response message timeout\n");
101 	} while (--retries);
102 
103 	return -EIO;
104 }
105 
adf_vf2pf_blkmsg_data_req(struct adf_accel_dev * accel_dev,bool crc,u8 * type,u8 * data)106 static int adf_vf2pf_blkmsg_data_req(struct adf_accel_dev *accel_dev, bool crc,
107 				     u8 *type, u8 *data)
108 {
109 	struct pfvf_message req = { 0 };
110 	struct pfvf_message resp = { 0 };
111 	u8 blk_type;
112 	u8 blk_byte;
113 	u8 msg_type;
114 	u8 max_data;
115 	int err;
116 
117 	/* Convert the block type to {small, medium, large} size category */
118 	if (*type <= ADF_VF2PF_SMALL_BLOCK_TYPE_MAX) {
119 		msg_type = ADF_VF2PF_MSGTYPE_SMALL_BLOCK_REQ;
120 		blk_type = FIELD_PREP(ADF_VF2PF_SMALL_BLOCK_TYPE_MASK, *type);
121 		blk_byte = FIELD_PREP(ADF_VF2PF_SMALL_BLOCK_BYTE_MASK, *data);
122 		max_data = ADF_VF2PF_SMALL_BLOCK_BYTE_MAX;
123 	} else if (*type <= ADF_VF2PF_MEDIUM_BLOCK_TYPE_MAX) {
124 		msg_type = ADF_VF2PF_MSGTYPE_MEDIUM_BLOCK_REQ;
125 		blk_type = FIELD_PREP(ADF_VF2PF_MEDIUM_BLOCK_TYPE_MASK,
126 				      *type - ADF_VF2PF_SMALL_BLOCK_TYPE_MAX);
127 		blk_byte = FIELD_PREP(ADF_VF2PF_MEDIUM_BLOCK_BYTE_MASK, *data);
128 		max_data = ADF_VF2PF_MEDIUM_BLOCK_BYTE_MAX;
129 	} else if (*type <= ADF_VF2PF_LARGE_BLOCK_TYPE_MAX) {
130 		msg_type = ADF_VF2PF_MSGTYPE_LARGE_BLOCK_REQ;
131 		blk_type = FIELD_PREP(ADF_VF2PF_LARGE_BLOCK_TYPE_MASK,
132 				      *type - ADF_VF2PF_MEDIUM_BLOCK_TYPE_MAX);
133 		blk_byte = FIELD_PREP(ADF_VF2PF_LARGE_BLOCK_BYTE_MASK, *data);
134 		max_data = ADF_VF2PF_LARGE_BLOCK_BYTE_MAX;
135 	} else {
136 		dev_err(&GET_DEV(accel_dev), "Invalid message type %u\n", *type);
137 		return -EINVAL;
138 	}
139 
140 	/* Sanity check */
141 	if (*data > max_data) {
142 		dev_err(&GET_DEV(accel_dev),
143 			"Invalid byte %s %u for message type %u\n",
144 			crc ? "count" : "index", *data, *type);
145 		return -EINVAL;
146 	}
147 
148 	/* Build the block message */
149 	req.type = msg_type;
150 	req.data = blk_type | blk_byte | FIELD_PREP(ADF_VF2PF_BLOCK_CRC_REQ_MASK, crc);
151 
152 	err = adf_send_vf2pf_req(accel_dev, req, &resp);
153 	if (err)
154 		return err;
155 
156 	*type = FIELD_GET(ADF_PF2VF_BLKMSG_RESP_TYPE_MASK, resp.data);
157 	*data = FIELD_GET(ADF_PF2VF_BLKMSG_RESP_DATA_MASK, resp.data);
158 
159 	return 0;
160 }
161 
adf_vf2pf_blkmsg_get_byte(struct adf_accel_dev * accel_dev,u8 type,u8 index,u8 * data)162 static int adf_vf2pf_blkmsg_get_byte(struct adf_accel_dev *accel_dev, u8 type,
163 				     u8 index, u8 *data)
164 {
165 	int ret;
166 
167 	ret = adf_vf2pf_blkmsg_data_req(accel_dev, false, &type, &index);
168 	if (ret < 0)
169 		return ret;
170 
171 	if (unlikely(type != ADF_PF2VF_BLKMSG_RESP_TYPE_DATA)) {
172 		dev_err(&GET_DEV(accel_dev),
173 			"Unexpected BLKMSG response type %u, byte 0x%x\n",
174 			type, index);
175 		return -EFAULT;
176 	}
177 
178 	*data = index;
179 	return 0;
180 }
181 
adf_vf2pf_blkmsg_get_crc(struct adf_accel_dev * accel_dev,u8 type,u8 bytes,u8 * crc)182 static int adf_vf2pf_blkmsg_get_crc(struct adf_accel_dev *accel_dev, u8 type,
183 				    u8 bytes, u8 *crc)
184 {
185 	int ret;
186 
187 	/* The count of bytes refers to a length, however shift it to a 0-based
188 	 * count to avoid overflows. Thus, a request for 0 bytes is technically
189 	 * valid.
190 	 */
191 	--bytes;
192 
193 	ret = adf_vf2pf_blkmsg_data_req(accel_dev, true, &type, &bytes);
194 	if (ret < 0)
195 		return ret;
196 
197 	if (unlikely(type != ADF_PF2VF_BLKMSG_RESP_TYPE_CRC)) {
198 		dev_err(&GET_DEV(accel_dev),
199 			"Unexpected CRC BLKMSG response type %u, crc 0x%x\n",
200 			type, bytes);
201 		return  -EFAULT;
202 	}
203 
204 	*crc = bytes;
205 	return 0;
206 }
207 
208 /**
209  * adf_send_vf2pf_blkmsg_req() - retrieve block message
210  * @accel_dev:	Pointer to acceleration VF device.
211  * @type:	The block message type, see adf_pfvf_msg.h for allowed values
212  * @buffer:	input buffer where to place the received data
213  * @buffer_len:	buffer length as input, the amount of written bytes on output
214  *
215  * Request a message of type 'type' over the block message transport.
216  * This function will send the required amount block message requests and
217  * return the overall content back to the caller through the provided buffer.
218  * The buffer should be large enough to contain the requested message type,
219  * otherwise the response will be truncated.
220  *
221  * Return: 0 on success, error code otherwise.
222  */
adf_send_vf2pf_blkmsg_req(struct adf_accel_dev * accel_dev,u8 type,u8 * buffer,unsigned int * buffer_len)223 int adf_send_vf2pf_blkmsg_req(struct adf_accel_dev *accel_dev, u8 type,
224 			      u8 *buffer, unsigned int *buffer_len)
225 {
226 	unsigned int index;
227 	unsigned int msg_len;
228 	int ret;
229 	u8 remote_crc;
230 	u8 local_crc;
231 
232 	if (unlikely(type > ADF_VF2PF_LARGE_BLOCK_TYPE_MAX)) {
233 		dev_err(&GET_DEV(accel_dev), "Invalid block message type %d\n",
234 			type);
235 		return -EINVAL;
236 	}
237 
238 	if (unlikely(*buffer_len < ADF_PFVF_BLKMSG_HEADER_SIZE)) {
239 		dev_err(&GET_DEV(accel_dev),
240 			"Buffer size too small for a block message\n");
241 		return -EINVAL;
242 	}
243 
244 	ret = adf_vf2pf_blkmsg_get_byte(accel_dev, type,
245 					ADF_PFVF_BLKMSG_VER_BYTE,
246 					&buffer[ADF_PFVF_BLKMSG_VER_BYTE]);
247 	if (unlikely(ret))
248 		return ret;
249 
250 	if (unlikely(!buffer[ADF_PFVF_BLKMSG_VER_BYTE])) {
251 		dev_err(&GET_DEV(accel_dev),
252 			"Invalid version 0 received for block request %u", type);
253 		return -EFAULT;
254 	}
255 
256 	ret = adf_vf2pf_blkmsg_get_byte(accel_dev, type,
257 					ADF_PFVF_BLKMSG_LEN_BYTE,
258 					&buffer[ADF_PFVF_BLKMSG_LEN_BYTE]);
259 	if (unlikely(ret))
260 		return ret;
261 
262 	if (unlikely(!buffer[ADF_PFVF_BLKMSG_LEN_BYTE])) {
263 		dev_err(&GET_DEV(accel_dev),
264 			"Invalid size 0 received for block request %u", type);
265 		return -EFAULT;
266 	}
267 
268 	/* We need to pick the minimum since there is no way to request a
269 	 * specific version. As a consequence any scenario is possible:
270 	 * - PF has a newer (longer) version which doesn't fit in the buffer
271 	 * - VF expects a newer (longer) version, so we must not ask for
272 	 *   bytes in excess
273 	 * - PF and VF share the same version, no problem
274 	 */
275 	msg_len = ADF_PFVF_BLKMSG_HEADER_SIZE + buffer[ADF_PFVF_BLKMSG_LEN_BYTE];
276 	msg_len = min(*buffer_len, msg_len);
277 
278 	/* Get the payload */
279 	for (index = ADF_PFVF_BLKMSG_HEADER_SIZE; index < msg_len; index++) {
280 		ret = adf_vf2pf_blkmsg_get_byte(accel_dev, type, index,
281 						&buffer[index]);
282 		if (unlikely(ret))
283 			return ret;
284 	}
285 
286 	ret = adf_vf2pf_blkmsg_get_crc(accel_dev, type, msg_len, &remote_crc);
287 	if (unlikely(ret))
288 		return ret;
289 
290 	local_crc = adf_pfvf_calc_blkmsg_crc(buffer, msg_len);
291 	if (unlikely(local_crc != remote_crc)) {
292 		dev_err(&GET_DEV(accel_dev),
293 			"CRC error on msg type %d. Local %02X, remote %02X\n",
294 			type, local_crc, remote_crc);
295 		return -EIO;
296 	}
297 
298 	*buffer_len = msg_len;
299 	return 0;
300 }
301 
adf_handle_pf2vf_msg(struct adf_accel_dev * accel_dev,struct pfvf_message msg)302 static bool adf_handle_pf2vf_msg(struct adf_accel_dev *accel_dev,
303 				 struct pfvf_message msg)
304 {
305 	switch (msg.type) {
306 	case ADF_PF2VF_MSGTYPE_RESTARTING:
307 		dev_dbg(&GET_DEV(accel_dev), "Restarting message received from PF\n");
308 
309 		adf_pf2vf_handle_pf_restarting(accel_dev);
310 		return false;
311 	case ADF_PF2VF_MSGTYPE_VERSION_RESP:
312 	case ADF_PF2VF_MSGTYPE_BLKMSG_RESP:
313 	case ADF_PF2VF_MSGTYPE_RP_RESET_RESP:
314 		dev_dbg(&GET_DEV(accel_dev),
315 			"Response Message received from PF (type 0x%.4x, data 0x%.4x)\n",
316 			msg.type, msg.data);
317 		accel_dev->vf.response = msg;
318 		complete(&accel_dev->vf.msg_received);
319 		return true;
320 	default:
321 		dev_err(&GET_DEV(accel_dev),
322 			"Unknown message from PF (type 0x%.4x, data: 0x%.4x)\n",
323 			msg.type, msg.data);
324 	}
325 
326 	return false;
327 }
328 
adf_recv_and_handle_pf2vf_msg(struct adf_accel_dev * accel_dev)329 bool adf_recv_and_handle_pf2vf_msg(struct adf_accel_dev *accel_dev)
330 {
331 	struct pfvf_message msg;
332 
333 	msg = adf_recv_pf2vf_msg(accel_dev);
334 	if (msg.type)  /* Invalid or no message */
335 		return adf_handle_pf2vf_msg(accel_dev, msg);
336 
337 	/* No replies for PF->VF messages at present */
338 
339 	return true;
340 }
341 
342 /**
343  * adf_enable_vf2pf_comms() - Function enables communication from vf to pf
344  *
345  * @accel_dev:	Pointer to acceleration device virtual function.
346  *
347  * Return: 0 on success, error code otherwise.
348  */
adf_enable_vf2pf_comms(struct adf_accel_dev * accel_dev)349 int adf_enable_vf2pf_comms(struct adf_accel_dev *accel_dev)
350 {
351 	int ret;
352 
353 	adf_pfvf_crc_init();
354 	adf_enable_pf2vf_interrupts(accel_dev);
355 
356 	ret = adf_vf2pf_request_version(accel_dev);
357 	if (ret)
358 		return ret;
359 
360 	ret = adf_vf2pf_get_capabilities(accel_dev);
361 	if (ret)
362 		return ret;
363 
364 	ret = adf_vf2pf_get_ring_to_svc(accel_dev);
365 
366 	return ret;
367 }
368 EXPORT_SYMBOL_GPL(adf_enable_vf2pf_comms);
369