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

delta-ipc.c (14853B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (C) STMicroelectronics SA 2015
      4 * Author: Hugues Fruchet <hugues.fruchet@st.com> for STMicroelectronics.
      5 */
      6
      7#include <linux/rpmsg.h>
      8
      9#include "delta.h"
     10#include "delta-ipc.h"
     11#include "delta-mem.h"
     12
     13#define IPC_TIMEOUT 100
     14#define IPC_SANITY_TAG 0xDEADBEEF
     15
     16enum delta_ipc_fw_command {
     17	DELTA_IPC_OPEN,
     18	DELTA_IPC_SET_STREAM,
     19	DELTA_IPC_DECODE,
     20	DELTA_IPC_CLOSE
     21};
     22
     23#define to_rpmsg_driver(__drv) container_of(__drv, struct rpmsg_driver, drv)
     24#define to_delta(__d) container_of(__d, struct delta_dev, rpmsg_driver)
     25
     26#define to_ctx(hdl) ((struct delta_ipc_ctx *)hdl)
     27#define to_pctx(ctx) container_of(ctx, struct delta_ctx, ipc_ctx)
     28
     29struct delta_ipc_header_msg {
     30	u32 tag;
     31	void *host_hdl;
     32	u32 copro_hdl;
     33	u32 command;
     34};
     35
     36#define to_host_hdl(ctx) ((void *)ctx)
     37
     38#define msg_to_ctx(msg) ((struct delta_ipc_ctx *)(msg)->header.host_hdl)
     39#define msg_to_copro_hdl(msg) ((msg)->header.copro_hdl)
     40
     41static inline dma_addr_t to_paddr(struct delta_ipc_ctx *ctx, void *vaddr)
     42{
     43	return (ctx->ipc_buf->paddr + (vaddr - ctx->ipc_buf->vaddr));
     44}
     45
     46static inline bool is_valid_data(struct delta_ipc_ctx *ctx,
     47				 void *data, u32 size)
     48{
     49	return ((data >= ctx->ipc_buf->vaddr) &&
     50		((data + size) <= (ctx->ipc_buf->vaddr + ctx->ipc_buf->size)));
     51}
     52
     53/*
     54 * IPC shared memory (@ipc_buf_size, @ipc_buf_paddr) is sent to copro
     55 * at each instance opening. This memory is allocated by IPC client
     56 * and given through delta_ipc_open(). All messages parameters
     57 * (open, set_stream, decode) will have their phy address within
     58 * this IPC shared memory, avoiding de-facto recopies inside delta-ipc.
     59 * All the below messages structures are used on both host and firmware
     60 * side and are packed (use only of 32 bits size fields in messages
     61 * structures to ensure packing):
     62 * - struct delta_ipc_open_msg
     63 * - struct delta_ipc_set_stream_msg
     64 * - struct delta_ipc_decode_msg
     65 * - struct delta_ipc_close_msg
     66 * - struct delta_ipc_cb_msg
     67 */
     68struct delta_ipc_open_msg {
     69	struct delta_ipc_header_msg header;
     70	u32 ipc_buf_size;
     71	dma_addr_t ipc_buf_paddr;
     72	char name[32];
     73	u32 param_size;
     74	dma_addr_t param_paddr;
     75};
     76
     77struct delta_ipc_set_stream_msg {
     78	struct delta_ipc_header_msg header;
     79	u32 param_size;
     80	dma_addr_t param_paddr;
     81};
     82
     83struct delta_ipc_decode_msg {
     84	struct delta_ipc_header_msg header;
     85	u32 param_size;
     86	dma_addr_t param_paddr;
     87	u32 status_size;
     88	dma_addr_t status_paddr;
     89};
     90
     91struct delta_ipc_close_msg {
     92	struct delta_ipc_header_msg header;
     93};
     94
     95struct delta_ipc_cb_msg {
     96	struct delta_ipc_header_msg header;
     97	int err;
     98};
     99
    100static void build_msg_header(struct delta_ipc_ctx *ctx,
    101			     enum delta_ipc_fw_command command,
    102			     struct delta_ipc_header_msg *header)
    103{
    104	header->tag = IPC_SANITY_TAG;
    105	header->host_hdl = to_host_hdl(ctx);
    106	header->copro_hdl = ctx->copro_hdl;
    107	header->command = command;
    108}
    109
    110int delta_ipc_open(struct delta_ctx *pctx, const char *name,
    111		   struct delta_ipc_param *param, u32 ipc_buf_size,
    112		   struct delta_buf **ipc_buf, void **hdl)
    113{
    114	struct delta_dev *delta = pctx->dev;
    115	struct rpmsg_device *rpmsg_device = delta->rpmsg_device;
    116	struct delta_ipc_ctx *ctx = &pctx->ipc_ctx;
    117	struct delta_ipc_open_msg msg;
    118	struct delta_buf *buf = &ctx->ipc_buf_struct;
    119	int ret;
    120
    121	if (!rpmsg_device) {
    122		dev_err(delta->dev,
    123			"%s   ipc: failed to open, rpmsg is not initialized\n",
    124			pctx->name);
    125		pctx->sys_errors++;
    126		return -EINVAL;
    127	}
    128
    129	if (!name) {
    130		dev_err(delta->dev,
    131			"%s   ipc: failed to open, no name given\n",
    132			pctx->name);
    133		return -EINVAL;
    134	}
    135
    136	if (!param || !param->data || !param->size) {
    137		dev_err(delta->dev,
    138			"%s  ipc: failed to open, empty parameter\n",
    139			pctx->name);
    140		return -EINVAL;
    141	}
    142
    143	if (!ipc_buf_size) {
    144		dev_err(delta->dev,
    145			"%s   ipc: failed to open, no size given for ipc buffer\n",
    146			pctx->name);
    147		return -EINVAL;
    148	}
    149
    150	if (param->size > ipc_buf_size) {
    151		dev_err(delta->dev,
    152			"%s   ipc: failed to open, too large ipc parameter (%d bytes while max %d expected)\n",
    153			pctx->name,
    154			param->size, ctx->ipc_buf->size);
    155		return -EINVAL;
    156	}
    157
    158	/* init */
    159	init_completion(&ctx->done);
    160
    161	/*
    162	 * allocation of contiguous buffer for
    163	 * data of commands exchanged between
    164	 * host and firmware coprocessor
    165	 */
    166	ret = hw_alloc(pctx, ipc_buf_size,
    167		       "ipc data buffer", buf);
    168	if (ret)
    169		return ret;
    170	ctx->ipc_buf = buf;
    171
    172	/* build rpmsg message */
    173	build_msg_header(ctx, DELTA_IPC_OPEN, &msg.header);
    174
    175	msg.ipc_buf_size = ipc_buf_size;
    176	msg.ipc_buf_paddr = ctx->ipc_buf->paddr;
    177
    178	strscpy(msg.name, name, sizeof(msg.name));
    179
    180	msg.param_size = param->size;
    181	memcpy(ctx->ipc_buf->vaddr, param->data, msg.param_size);
    182	msg.param_paddr = ctx->ipc_buf->paddr;
    183
    184	/* send it */
    185	ret = rpmsg_send(rpmsg_device->ept, &msg, sizeof(msg));
    186	if (ret) {
    187		dev_err(delta->dev,
    188			"%s   ipc: failed to open, rpmsg_send failed (%d) for DELTA_IPC_OPEN (name=%s, size=%d, data=%p)\n",
    189			pctx->name,
    190			ret, name, param->size, param->data);
    191		goto err;
    192	}
    193
    194	/* wait for acknowledge */
    195	if (!wait_for_completion_timeout
    196	    (&ctx->done, msecs_to_jiffies(IPC_TIMEOUT))) {
    197		dev_err(delta->dev,
    198			"%s   ipc: failed to open, timeout waiting for DELTA_IPC_OPEN callback (name=%s, size=%d, data=%p)\n",
    199			pctx->name,
    200			name, param->size, param->data);
    201		ret = -ETIMEDOUT;
    202		goto err;
    203	}
    204
    205	/* command completed, check error */
    206	if (ctx->cb_err) {
    207		dev_err(delta->dev,
    208			"%s   ipc: failed to open, DELTA_IPC_OPEN completed but with error (%d) (name=%s, size=%d, data=%p)\n",
    209			pctx->name,
    210			ctx->cb_err, name, param->size, param->data);
    211		ret = -EIO;
    212		goto err;
    213	}
    214
    215	*ipc_buf = ctx->ipc_buf;
    216	*hdl = (void *)ctx;
    217
    218	return 0;
    219
    220err:
    221	pctx->sys_errors++;
    222	hw_free(pctx, ctx->ipc_buf);
    223	ctx->ipc_buf = NULL;
    224
    225	return ret;
    226};
    227
    228int delta_ipc_set_stream(void *hdl, struct delta_ipc_param *param)
    229{
    230	struct delta_ipc_ctx *ctx = to_ctx(hdl);
    231	struct delta_ctx *pctx = to_pctx(ctx);
    232	struct delta_dev *delta = pctx->dev;
    233	struct rpmsg_device *rpmsg_device = delta->rpmsg_device;
    234	struct delta_ipc_set_stream_msg msg;
    235	int ret;
    236
    237	if (!hdl) {
    238		dev_err(delta->dev,
    239			"%s   ipc: failed to set stream, invalid ipc handle\n",
    240			pctx->name);
    241		return -EINVAL;
    242	}
    243
    244	if (!rpmsg_device) {
    245		dev_err(delta->dev,
    246			"%s   ipc: failed to set stream, rpmsg is not initialized\n",
    247			pctx->name);
    248		return -EINVAL;
    249	}
    250
    251	if (!param || !param->data || !param->size) {
    252		dev_err(delta->dev,
    253			"%s  ipc: failed to set stream, empty parameter\n",
    254			pctx->name);
    255		return -EINVAL;
    256	}
    257
    258	if (param->size > ctx->ipc_buf->size) {
    259		dev_err(delta->dev,
    260			"%s   ipc: failed to set stream, too large ipc parameter(%d bytes while max %d expected)\n",
    261			pctx->name,
    262			param->size, ctx->ipc_buf->size);
    263		return -EINVAL;
    264	}
    265
    266	if (!is_valid_data(ctx, param->data, param->size)) {
    267		dev_err(delta->dev,
    268			"%s   ipc: failed to set stream, parameter is not in expected address range (size=%d, data=%p not in %p..%p)\n",
    269			pctx->name,
    270			param->size,
    271			param->data,
    272			ctx->ipc_buf->vaddr,
    273			ctx->ipc_buf->vaddr + ctx->ipc_buf->size - 1);
    274		return -EINVAL;
    275	}
    276
    277	/* build rpmsg message */
    278	build_msg_header(ctx, DELTA_IPC_SET_STREAM, &msg.header);
    279
    280	msg.param_size = param->size;
    281	msg.param_paddr = to_paddr(ctx, param->data);
    282
    283	/* send it */
    284	ret = rpmsg_send(rpmsg_device->ept, &msg, sizeof(msg));
    285	if (ret) {
    286		dev_err(delta->dev,
    287			"%s   ipc: failed to set stream, rpmsg_send failed (%d) for DELTA_IPC_SET_STREAM (size=%d, data=%p)\n",
    288			pctx->name,
    289			ret, param->size, param->data);
    290		pctx->sys_errors++;
    291		return ret;
    292	}
    293
    294	/* wait for acknowledge */
    295	if (!wait_for_completion_timeout
    296	    (&ctx->done, msecs_to_jiffies(IPC_TIMEOUT))) {
    297		dev_err(delta->dev,
    298			"%s   ipc: failed to set stream, timeout waiting for DELTA_IPC_SET_STREAM callback (size=%d, data=%p)\n",
    299			pctx->name,
    300			param->size, param->data);
    301		pctx->sys_errors++;
    302		return -ETIMEDOUT;
    303	}
    304
    305	/* command completed, check status */
    306	if (ctx->cb_err) {
    307		dev_err(delta->dev,
    308			"%s   ipc: failed to set stream, DELTA_IPC_SET_STREAM completed but with error (%d) (size=%d, data=%p)\n",
    309			pctx->name,
    310			ctx->cb_err, param->size, param->data);
    311		pctx->sys_errors++;
    312		return -EIO;
    313	}
    314
    315	return 0;
    316}
    317
    318int delta_ipc_decode(void *hdl, struct delta_ipc_param *param,
    319		     struct delta_ipc_param *status)
    320{
    321	struct delta_ipc_ctx *ctx = to_ctx(hdl);
    322	struct delta_ctx *pctx = to_pctx(ctx);
    323	struct delta_dev *delta = pctx->dev;
    324	struct rpmsg_device *rpmsg_device = delta->rpmsg_device;
    325	struct delta_ipc_decode_msg msg;
    326	int ret;
    327
    328	if (!hdl) {
    329		dev_err(delta->dev,
    330			"%s   ipc: failed to decode, invalid ipc handle\n",
    331			pctx->name);
    332		return -EINVAL;
    333	}
    334
    335	if (!rpmsg_device) {
    336		dev_err(delta->dev,
    337			"%s   ipc: failed to decode, rpmsg is not initialized\n",
    338			pctx->name);
    339		return -EINVAL;
    340	}
    341
    342	if (!param || !param->data || !param->size) {
    343		dev_err(delta->dev,
    344			"%s  ipc: failed to decode, empty parameter\n",
    345			pctx->name);
    346		return -EINVAL;
    347	}
    348
    349	if (!status || !status->data || !status->size) {
    350		dev_err(delta->dev,
    351			"%s  ipc: failed to decode, empty status\n",
    352			pctx->name);
    353		return -EINVAL;
    354	}
    355
    356	if (param->size + status->size > ctx->ipc_buf->size) {
    357		dev_err(delta->dev,
    358			"%s   ipc: failed to decode, too large ipc parameter (%d bytes (param) + %d bytes (status) while max %d expected)\n",
    359			pctx->name,
    360			param->size,
    361			status->size,
    362			ctx->ipc_buf->size);
    363		return -EINVAL;
    364	}
    365
    366	if (!is_valid_data(ctx, param->data, param->size)) {
    367		dev_err(delta->dev,
    368			"%s   ipc: failed to decode, parameter is not in expected address range (size=%d, data=%p not in %p..%p)\n",
    369			pctx->name,
    370			param->size,
    371			param->data,
    372			ctx->ipc_buf->vaddr,
    373			ctx->ipc_buf->vaddr + ctx->ipc_buf->size - 1);
    374		return -EINVAL;
    375	}
    376
    377	if (!is_valid_data(ctx, status->data, status->size)) {
    378		dev_err(delta->dev,
    379			"%s   ipc: failed to decode, status is not in expected address range (size=%d, data=%p not in %p..%p)\n",
    380			pctx->name,
    381			status->size,
    382			status->data,
    383			ctx->ipc_buf->vaddr,
    384			ctx->ipc_buf->vaddr + ctx->ipc_buf->size - 1);
    385		return -EINVAL;
    386	}
    387
    388	/* build rpmsg message */
    389	build_msg_header(ctx, DELTA_IPC_DECODE, &msg.header);
    390
    391	msg.param_size = param->size;
    392	msg.param_paddr = to_paddr(ctx, param->data);
    393
    394	msg.status_size = status->size;
    395	msg.status_paddr = to_paddr(ctx, status->data);
    396
    397	/* send it */
    398	ret = rpmsg_send(rpmsg_device->ept, &msg, sizeof(msg));
    399	if (ret) {
    400		dev_err(delta->dev,
    401			"%s   ipc: failed to decode, rpmsg_send failed (%d) for DELTA_IPC_DECODE (size=%d, data=%p)\n",
    402			pctx->name,
    403			ret, param->size, param->data);
    404		pctx->sys_errors++;
    405		return ret;
    406	}
    407
    408	/* wait for acknowledge */
    409	if (!wait_for_completion_timeout
    410	    (&ctx->done, msecs_to_jiffies(IPC_TIMEOUT))) {
    411		dev_err(delta->dev,
    412			"%s   ipc: failed to decode, timeout waiting for DELTA_IPC_DECODE callback (size=%d, data=%p)\n",
    413			pctx->name,
    414			param->size, param->data);
    415		pctx->sys_errors++;
    416		return -ETIMEDOUT;
    417	}
    418
    419	/* command completed, check status */
    420	if (ctx->cb_err) {
    421		dev_err(delta->dev,
    422			"%s   ipc: failed to decode, DELTA_IPC_DECODE completed but with error (%d) (size=%d, data=%p)\n",
    423			pctx->name,
    424			ctx->cb_err, param->size, param->data);
    425		pctx->sys_errors++;
    426		return -EIO;
    427	}
    428
    429	return 0;
    430};
    431
    432void delta_ipc_close(void *hdl)
    433{
    434	struct delta_ipc_ctx *ctx = to_ctx(hdl);
    435	struct delta_ctx *pctx = to_pctx(ctx);
    436	struct delta_dev *delta = pctx->dev;
    437	struct rpmsg_device *rpmsg_device = delta->rpmsg_device;
    438	struct delta_ipc_close_msg msg;
    439	int ret;
    440
    441	if (!hdl) {
    442		dev_err(delta->dev,
    443			"%s   ipc: failed to close, invalid ipc handle\n",
    444			pctx->name);
    445		return;
    446	}
    447
    448	if (ctx->ipc_buf) {
    449		hw_free(pctx, ctx->ipc_buf);
    450		ctx->ipc_buf = NULL;
    451	}
    452
    453	if (!rpmsg_device) {
    454		dev_err(delta->dev,
    455			"%s   ipc: failed to close, rpmsg is not initialized\n",
    456			pctx->name);
    457		return;
    458	}
    459
    460	/* build rpmsg message */
    461	build_msg_header(ctx, DELTA_IPC_CLOSE, &msg.header);
    462
    463	/* send it */
    464	ret = rpmsg_send(rpmsg_device->ept, &msg, sizeof(msg));
    465	if (ret) {
    466		dev_err(delta->dev,
    467			"%s   ipc: failed to close, rpmsg_send failed (%d) for DELTA_IPC_CLOSE\n",
    468			pctx->name, ret);
    469		pctx->sys_errors++;
    470		return;
    471	}
    472
    473	/* wait for acknowledge */
    474	if (!wait_for_completion_timeout
    475	    (&ctx->done, msecs_to_jiffies(IPC_TIMEOUT))) {
    476		dev_err(delta->dev,
    477			"%s   ipc: failed to close, timeout waiting for DELTA_IPC_CLOSE callback\n",
    478			pctx->name);
    479		pctx->sys_errors++;
    480		return;
    481	}
    482
    483	/* command completed, check status */
    484	if (ctx->cb_err) {
    485		dev_err(delta->dev,
    486			"%s   ipc: failed to close, DELTA_IPC_CLOSE completed but with error (%d)\n",
    487			pctx->name, ctx->cb_err);
    488		pctx->sys_errors++;
    489	}
    490};
    491
    492static int delta_ipc_cb(struct rpmsg_device *rpdev, void *data,
    493			int len, void *priv, u32 src)
    494{
    495	struct delta_ipc_ctx *ctx;
    496	struct delta_ipc_cb_msg *msg;
    497
    498	/* sanity check */
    499	if (!rpdev) {
    500		dev_err(NULL, "rpdev is NULL\n");
    501		return -EINVAL;
    502	}
    503
    504	if (!data || !len) {
    505		dev_err(&rpdev->dev,
    506			"unexpected empty message received from src=%d\n", src);
    507		return -EINVAL;
    508	}
    509
    510	if (len != sizeof(*msg)) {
    511		dev_err(&rpdev->dev,
    512			"unexpected message length received from src=%d (received %d bytes while %zu bytes expected)\n",
    513			len, src, sizeof(*msg));
    514		return -EINVAL;
    515	}
    516
    517	msg = (struct delta_ipc_cb_msg *)data;
    518	if (msg->header.tag != IPC_SANITY_TAG) {
    519		dev_err(&rpdev->dev,
    520			"unexpected message tag received from src=%d (received %x tag while %x expected)\n",
    521			src, msg->header.tag, IPC_SANITY_TAG);
    522		return -EINVAL;
    523	}
    524
    525	ctx = msg_to_ctx(msg);
    526	if (!ctx) {
    527		dev_err(&rpdev->dev,
    528			"unexpected message with NULL host_hdl received from src=%d\n",
    529			src);
    530		return -EINVAL;
    531	}
    532
    533	/*
    534	 * if not already known, save copro instance context
    535	 * to ensure re-entrance on copro side
    536	 */
    537	if (!ctx->copro_hdl)
    538		ctx->copro_hdl = msg_to_copro_hdl(msg);
    539
    540	/*
    541	 * all is fine,
    542	 * update status & complete command
    543	 */
    544	ctx->cb_err = msg->err;
    545	complete(&ctx->done);
    546
    547	return 0;
    548}
    549
    550static int delta_ipc_probe(struct rpmsg_device *rpmsg_device)
    551{
    552	struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpmsg_device->dev.driver);
    553	struct delta_dev *delta = to_delta(rpdrv);
    554
    555	delta->rpmsg_device = rpmsg_device;
    556
    557	return 0;
    558}
    559
    560static void delta_ipc_remove(struct rpmsg_device *rpmsg_device)
    561{
    562	struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpmsg_device->dev.driver);
    563	struct delta_dev *delta = to_delta(rpdrv);
    564
    565	delta->rpmsg_device = NULL;
    566}
    567
    568static struct rpmsg_device_id delta_ipc_device_id_table[] = {
    569	{.name = "rpmsg-delta"},
    570	{},
    571};
    572
    573static struct rpmsg_driver delta_rpmsg_driver = {
    574	.drv = {.name = KBUILD_MODNAME},
    575	.id_table = delta_ipc_device_id_table,
    576	.probe = delta_ipc_probe,
    577	.callback = delta_ipc_cb,
    578	.remove = delta_ipc_remove,
    579};
    580
    581int delta_ipc_init(struct delta_dev *delta)
    582{
    583	delta->rpmsg_driver = delta_rpmsg_driver;
    584
    585	return register_rpmsg_driver(&delta->rpmsg_driver);
    586}
    587
    588void delta_ipc_exit(struct delta_dev *delta)
    589{
    590	unregister_rpmsg_driver(&delta->rpmsg_driver);
    591}