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_RESTARTED:
312 dev_dbg(&GET_DEV(accel_dev), "Restarted message received from PF\n");
313 return true;
314 case ADF_PF2VF_MSGTYPE_FATAL_ERROR:
315 dev_err(&GET_DEV(accel_dev), "Fatal error received from PF\n");
316 return true;
317 case ADF_PF2VF_MSGTYPE_VERSION_RESP:
318 case ADF_PF2VF_MSGTYPE_BLKMSG_RESP:
319 case ADF_PF2VF_MSGTYPE_RP_RESET_RESP:
320 dev_dbg(&GET_DEV(accel_dev),
321 "Response Message received from PF (type 0x%.4x, data 0x%.4x)\n",
322 msg.type, msg.data);
323 accel_dev->vf.response = msg;
324 complete(&accel_dev->vf.msg_received);
325 return true;
326 default:
327 dev_err(&GET_DEV(accel_dev),
328 "Unknown message from PF (type 0x%.4x, data: 0x%.4x)\n",
329 msg.type, msg.data);
330 }
331
332 return false;
333 }
334
adf_recv_and_handle_pf2vf_msg(struct adf_accel_dev * accel_dev)335 bool adf_recv_and_handle_pf2vf_msg(struct adf_accel_dev *accel_dev)
336 {
337 struct pfvf_message msg;
338
339 msg = adf_recv_pf2vf_msg(accel_dev);
340 if (msg.type) /* Invalid or no message */
341 return adf_handle_pf2vf_msg(accel_dev, msg);
342
343 /* No replies for PF->VF messages at present */
344
345 return true;
346 }
347
348 /**
349 * adf_enable_vf2pf_comms() - Function enables communication from vf to pf
350 *
351 * @accel_dev: Pointer to acceleration device virtual function.
352 *
353 * Return: 0 on success, error code otherwise.
354 */
adf_enable_vf2pf_comms(struct adf_accel_dev * accel_dev)355 int adf_enable_vf2pf_comms(struct adf_accel_dev *accel_dev)
356 {
357 int ret;
358
359 adf_pfvf_crc_init();
360 adf_enable_pf2vf_interrupts(accel_dev);
361
362 ret = adf_vf2pf_request_version(accel_dev);
363 if (ret)
364 return ret;
365
366 ret = adf_vf2pf_get_capabilities(accel_dev);
367 if (ret)
368 return ret;
369
370 ret = adf_vf2pf_get_ring_to_svc(accel_dev);
371
372 return ret;
373 }
374 EXPORT_SYMBOL_GPL(adf_enable_vf2pf_comms);
375