| 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 | */ |
| 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 | */ |
| 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 | */ |
| 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(x: &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(x: &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 | |
| 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, msg: req, resp: &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 | |
| 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, crc: false, type: &type, data: &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 | |
| 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, crc: true, type: &type, data: &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 | */ |
| 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 | data: &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 | data: &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 | data: &buffer[index]); |
| 282 | if (unlikely(ret)) |
| 283 | return ret; |
| 284 | } |
| 285 | |
| 286 | ret = adf_vf2pf_blkmsg_get_crc(accel_dev, type, bytes: msg_len, crc: &remote_crc); |
| 287 | if (unlikely(ret)) |
| 288 | return ret; |
| 289 | |
| 290 | local_crc = adf_pfvf_calc_blkmsg_crc(buf: buffer, buf_len: 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 | |
| 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 | |
| 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 | */ |
| 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 | |