/* How often to retry if there is no response */ #define ADF_PFVF_MSG_RESP_RETRIES 5 #define ADF_PFVF_MSG_RESP_TIMEOUT (ADF_PFVF_MSG_ACK_DELAY * \
ADF_PFVF_MSG_ACK_MAX_RETRY + \
ADF_PFVF_MSG_COLLISION_DETECT_DELAY)
/** * adf_send_vf2pf_msg() - send VF to PF message * @accel_dev: Pointer to acceleration device * @msg: Message to send * * This function allows the VF to send a message to the PF. * * Return: 0 on success, error code otherwise.
*/ int adf_send_vf2pf_msg(struct adf_accel_dev *accel_dev, struct pfvf_message msg)
{ struct adf_pfvf_ops *pfvf_ops = GET_PFVF_OPS(accel_dev);
u32 pfvf_offset = pfvf_ops->get_vf2pf_offset(0);
/** * adf_recv_pf2vf_msg() - receive a PF to VF message * @accel_dev: Pointer to acceleration device * * This function allows the VF to receive a message from the PF. * * Return: a valid message on success, zero otherwise.
*/ staticstruct pfvf_message adf_recv_pf2vf_msg(struct adf_accel_dev *accel_dev)
{ struct adf_pfvf_ops *pfvf_ops = GET_PFVF_OPS(accel_dev);
u32 pfvf_offset = pfvf_ops->get_pf2vf_offset(0);
/** * adf_send_vf2pf_req() - send VF2PF request message * @accel_dev: Pointer to acceleration device. * @msg: Request message to send * @resp: Returned PF response * * This function sends a message that requires a response from the VF to the PF * and waits for a reply. * * Return: 0 on success, error code otherwise.
*/ int adf_send_vf2pf_req(struct adf_accel_dev *accel_dev, struct pfvf_message msg, struct pfvf_message *resp)
{ unsignedlong timeout = msecs_to_jiffies(ADF_PFVF_MSG_RESP_TIMEOUT); unsignedint retries = ADF_PFVF_MSG_RESP_RETRIES; int ret;
reinit_completion(&accel_dev->vf.msg_received);
/* Send request from VF to PF */ do {
ret = adf_send_vf2pf_msg(accel_dev, msg); if (ret) {
dev_err(&GET_DEV(accel_dev), "Failed to send request msg to PF\n"); return ret;
}
/* Wait for response, if it times out retry */
ret = wait_for_completion_timeout(&accel_dev->vf.msg_received,
timeout); if (ret) { if (likely(resp))
*resp = accel_dev->vf.response;
/* Once copied, set to an invalid value */
accel_dev->vf.response.type = 0;
return 0;
}
dev_err(&GET_DEV(accel_dev), "PFVF response message timeout\n");
} while (--retries);
/* The count of bytes refers to a length, however shift it to a 0-based * count to avoid overflows. Thus, a request for 0 bytes is technically * valid.
*/
--bytes;
ret = adf_vf2pf_blkmsg_data_req(accel_dev, true, &type, &bytes); if (ret < 0) return ret;
if (unlikely(type != ADF_PF2VF_BLKMSG_RESP_TYPE_CRC)) {
dev_err(&GET_DEV(accel_dev), "Unexpected CRC BLKMSG response type %u, crc 0x%x\n",
type, bytes); return -EFAULT;
}
*crc = bytes; return 0;
}
/** * adf_send_vf2pf_blkmsg_req() - retrieve block message * @accel_dev: Pointer to acceleration VF device. * @type: The block message type, see adf_pfvf_msg.h for allowed values * @buffer: input buffer where to place the received data * @buffer_len: buffer length as input, the amount of written bytes on output * * Request a message of type 'type' over the block message transport. * This function will send the required amount block message requests and * return the overall content back to the caller through the provided buffer. * The buffer should be large enough to contain the requested message type, * otherwise the response will be truncated. * * Return: 0 on success, error code otherwise.
*/ int adf_send_vf2pf_blkmsg_req(struct adf_accel_dev *accel_dev, u8 type,
u8 *buffer, unsignedint *buffer_len)
{ unsignedint index; unsignedint msg_len; int ret;
u8 remote_crc;
u8 local_crc;
if (unlikely(type > ADF_VF2PF_LARGE_BLOCK_TYPE_MAX)) {
dev_err(&GET_DEV(accel_dev), "Invalid block message type %d\n",
type); return -EINVAL;
}
if (unlikely(*buffer_len < ADF_PFVF_BLKMSG_HEADER_SIZE)) {
dev_err(&GET_DEV(accel_dev), "Buffer size too small for a block message\n"); return -EINVAL;
}
ret = adf_vf2pf_blkmsg_get_byte(accel_dev, type,
ADF_PFVF_BLKMSG_VER_BYTE,
&buffer[ADF_PFVF_BLKMSG_VER_BYTE]); if (unlikely(ret)) return ret;
if (unlikely(!buffer[ADF_PFVF_BLKMSG_VER_BYTE])) {
dev_err(&GET_DEV(accel_dev), "Invalid version 0 received for block request %u", type); return -EFAULT;
}
ret = adf_vf2pf_blkmsg_get_byte(accel_dev, type,
ADF_PFVF_BLKMSG_LEN_BYTE,
&buffer[ADF_PFVF_BLKMSG_LEN_BYTE]); if (unlikely(ret)) return ret;
if (unlikely(!buffer[ADF_PFVF_BLKMSG_LEN_BYTE])) {
dev_err(&GET_DEV(accel_dev), "Invalid size 0 received for block request %u", type); return -EFAULT;
}
/* We need to pick the minimum since there is no way to request a * specific version. As a consequence any scenario is possible: * - PF has a newer (longer) version which doesn't fit in the buffer * - VF expects a newer (longer) version, so we must not ask for * bytes in excess * - PF and VF share the same version, no problem
*/
msg_len = ADF_PFVF_BLKMSG_HEADER_SIZE + buffer[ADF_PFVF_BLKMSG_LEN_BYTE];
msg_len = min(*buffer_len, msg_len);
/* Get the payload */ for (index = ADF_PFVF_BLKMSG_HEADER_SIZE; index < msg_len; index++) {
ret = adf_vf2pf_blkmsg_get_byte(accel_dev, type, index,
&buffer[index]); if (unlikely(ret)) return ret;
}
ret = adf_vf2pf_blkmsg_get_crc(accel_dev, type, msg_len, &remote_crc); if (unlikely(ret)) return ret;
local_crc = adf_pfvf_calc_blkmsg_crc(buffer, msg_len); if (unlikely(local_crc != remote_crc)) {
dev_err(&GET_DEV(accel_dev), "CRC error on msg type %d. Local %02X, remote %02X\n",
type, local_crc, remote_crc); return -EIO;
}
*buffer_len = msg_len; return 0;
}
staticbool adf_handle_pf2vf_msg(struct adf_accel_dev *accel_dev, struct pfvf_message msg)
{ switch (msg.type) { case ADF_PF2VF_MSGTYPE_RESTARTING:
dev_dbg(&GET_DEV(accel_dev), "Restarting message received from PF\n");
adf_pf2vf_handle_pf_restarting(accel_dev); returnfalse; case ADF_PF2VF_MSGTYPE_RESTARTED:
dev_dbg(&GET_DEV(accel_dev), "Restarted message received from PF\n"); returntrue; case ADF_PF2VF_MSGTYPE_FATAL_ERROR:
dev_err(&GET_DEV(accel_dev), "Fatal error received from PF\n"); returntrue; case ADF_PF2VF_MSGTYPE_VERSION_RESP: case ADF_PF2VF_MSGTYPE_BLKMSG_RESP: case ADF_PF2VF_MSGTYPE_RP_RESET_RESP:
dev_dbg(&GET_DEV(accel_dev), "Response Message received from PF (type 0x%.4x, data 0x%.4x)\n",
msg.type, msg.data);
accel_dev->vf.response = msg;
complete(&accel_dev->vf.msg_received); returntrue; default:
dev_err(&GET_DEV(accel_dev), "Unknown message from PF (type 0x%.4x, data: 0x%.4x)\n",
msg.type, msg.data);
}
msg = adf_recv_pf2vf_msg(accel_dev); if (msg.type) /* Invalid or no message */ return adf_handle_pf2vf_msg(accel_dev, msg);
/* No replies for PF->VF messages at present */
returntrue;
}
/** * adf_enable_vf2pf_comms() - Function enables communication from vf to pf * * @accel_dev: Pointer to acceleration device virtual function. * * Return: 0 on success, error code otherwise.
*/ int adf_enable_vf2pf_comms(struct adf_accel_dev *accel_dev)
{ int ret;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.