brintos

brintos / linux-shallow public Read only

0
0
Text · 10.5 KiB · dc284a0 Raw
375 lines · c
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	1015#define ADF_PFVF_MSG_ACK_DELAY			216#define ADF_PFVF_MSG_ACK_MAX_RETRY		10017 18/* How often to retry if there is no response */19#define ADF_PFVF_MSG_RESP_RETRIES	520#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 message26 * @accel_dev:	Pointer to acceleration device27 * @msg:	Message to send28 *29 * This function allows the VF to send a message to the PF.30 *31 * Return: 0 on success, error code otherwise.32 */33int 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 message44 * @accel_dev:	Pointer to acceleration device45 *46 * This function allows the VF to receive a message from the PF.47 *48 * Return: a valid message on success, zero otherwise.49 */50static 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 message60 * @accel_dev:	Pointer to acceleration device.61 * @msg:	Request message to send62 * @resp:	Returned PF response63 *64 * This function sends a message that requires a response from the VF to the PF65 * and waits for a reply.66 *67 * Return: 0 on success, error code otherwise.68 */69int 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 106static 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 162static 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 182static 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-based188	 * count to avoid overflows. Thus, a request for 0 bytes is technically189	 * 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 message210 * @accel_dev:	Pointer to acceleration VF device.211 * @type:	The block message type, see adf_pfvf_msg.h for allowed values212 * @buffer:	input buffer where to place the received data213 * @buffer_len:	buffer length as input, the amount of written bytes on output214 *215 * Request a message of type 'type' over the block message transport.216 * This function will send the required amount block message requests and217 * 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 */223int 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 a269	 * specific version. As a consequence any scenario is possible:270	 * - PF has a newer (longer) version which doesn't fit in the buffer271	 * - VF expects a newer (longer) version, so we must not ask for272	 *   bytes in excess273	 * - PF and VF share the same version, no problem274	 */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 302static 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 335bool 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 pf350 *351 * @accel_dev:	Pointer to acceleration device virtual function.352 *353 * Return: 0 on success, error code otherwise.354 */355int 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}374EXPORT_SYMBOL_GPL(adf_enable_vf2pf_comms);375