cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

adf_pfvf_vf_proto.c (10499B)


      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 */
     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 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 */
     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 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 */
     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-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 */
    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 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
    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_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
    329bool 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 */
    349int 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}
    368EXPORT_SYMBOL_GPL(adf_enable_vf2pf_comms);