root/drivers/media/platform/sti/delta/delta-ipc.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. to_paddr
  2. is_valid_data
  3. build_msg_header
  4. delta_ipc_open
  5. delta_ipc_set_stream
  6. delta_ipc_decode
  7. delta_ipc_close
  8. delta_ipc_cb
  9. delta_ipc_probe
  10. delta_ipc_remove
  11. delta_ipc_init
  12. delta_ipc_exit

   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 
  16 enum 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 
  29 struct 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 
  41 static 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 
  46 static 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  */
  68 struct 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 
  77 struct delta_ipc_set_stream_msg {
  78         struct delta_ipc_header_msg header;
  79         u32 param_size;
  80         dma_addr_t param_paddr;
  81 };
  82 
  83 struct 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 
  91 struct delta_ipc_close_msg {
  92         struct delta_ipc_header_msg header;
  93 };
  94 
  95 struct delta_ipc_cb_msg {
  96         struct delta_ipc_header_msg header;
  97         int err;
  98 };
  99 
 100 static 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 
 110 int 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         memcpy(msg.name, name, sizeof(msg.name));
 179         msg.name[sizeof(msg.name) - 1] = 0;
 180 
 181         msg.param_size = param->size;
 182         memcpy(ctx->ipc_buf->vaddr, param->data, msg.param_size);
 183         msg.param_paddr = ctx->ipc_buf->paddr;
 184 
 185         /* send it */
 186         ret = rpmsg_send(rpmsg_device->ept, &msg, sizeof(msg));
 187         if (ret) {
 188                 dev_err(delta->dev,
 189                         "%s   ipc: failed to open, rpmsg_send failed (%d) for DELTA_IPC_OPEN (name=%s, size=%d, data=%p)\n",
 190                         pctx->name,
 191                         ret, name, param->size, param->data);
 192                 goto err;
 193         }
 194 
 195         /* wait for acknowledge */
 196         if (!wait_for_completion_timeout
 197             (&ctx->done, msecs_to_jiffies(IPC_TIMEOUT))) {
 198                 dev_err(delta->dev,
 199                         "%s   ipc: failed to open, timeout waiting for DELTA_IPC_OPEN callback (name=%s, size=%d, data=%p)\n",
 200                         pctx->name,
 201                         name, param->size, param->data);
 202                 ret = -ETIMEDOUT;
 203                 goto err;
 204         }
 205 
 206         /* command completed, check error */
 207         if (ctx->cb_err) {
 208                 dev_err(delta->dev,
 209                         "%s   ipc: failed to open, DELTA_IPC_OPEN completed but with error (%d) (name=%s, size=%d, data=%p)\n",
 210                         pctx->name,
 211                         ctx->cb_err, name, param->size, param->data);
 212                 ret = -EIO;
 213                 goto err;
 214         }
 215 
 216         *ipc_buf = ctx->ipc_buf;
 217         *hdl = (void *)ctx;
 218 
 219         return 0;
 220 
 221 err:
 222         pctx->sys_errors++;
 223         hw_free(pctx, ctx->ipc_buf);
 224         ctx->ipc_buf = NULL;
 225 
 226         return ret;
 227 };
 228 
 229 int delta_ipc_set_stream(void *hdl, struct delta_ipc_param *param)
 230 {
 231         struct delta_ipc_ctx *ctx = to_ctx(hdl);
 232         struct delta_ctx *pctx = to_pctx(ctx);
 233         struct delta_dev *delta = pctx->dev;
 234         struct rpmsg_device *rpmsg_device = delta->rpmsg_device;
 235         struct delta_ipc_set_stream_msg msg;
 236         int ret;
 237 
 238         if (!hdl) {
 239                 dev_err(delta->dev,
 240                         "%s   ipc: failed to set stream, invalid ipc handle\n",
 241                         pctx->name);
 242                 return -EINVAL;
 243         }
 244 
 245         if (!rpmsg_device) {
 246                 dev_err(delta->dev,
 247                         "%s   ipc: failed to set stream, rpmsg is not initialized\n",
 248                         pctx->name);
 249                 return -EINVAL;
 250         }
 251 
 252         if (!param || !param->data || !param->size) {
 253                 dev_err(delta->dev,
 254                         "%s  ipc: failed to set stream, empty parameter\n",
 255                         pctx->name);
 256                 return -EINVAL;
 257         }
 258 
 259         if (param->size > ctx->ipc_buf->size) {
 260                 dev_err(delta->dev,
 261                         "%s   ipc: failed to set stream, too large ipc parameter(%d bytes while max %d expected)\n",
 262                         pctx->name,
 263                         param->size, ctx->ipc_buf->size);
 264                 return -EINVAL;
 265         }
 266 
 267         if (!is_valid_data(ctx, param->data, param->size)) {
 268                 dev_err(delta->dev,
 269                         "%s   ipc: failed to set stream, parameter is not in expected address range (size=%d, data=%p not in %p..%p)\n",
 270                         pctx->name,
 271                         param->size,
 272                         param->data,
 273                         ctx->ipc_buf->vaddr,
 274                         ctx->ipc_buf->vaddr + ctx->ipc_buf->size - 1);
 275                 return -EINVAL;
 276         }
 277 
 278         /* build rpmsg message */
 279         build_msg_header(ctx, DELTA_IPC_SET_STREAM, &msg.header);
 280 
 281         msg.param_size = param->size;
 282         msg.param_paddr = to_paddr(ctx, param->data);
 283 
 284         /* send it */
 285         ret = rpmsg_send(rpmsg_device->ept, &msg, sizeof(msg));
 286         if (ret) {
 287                 dev_err(delta->dev,
 288                         "%s   ipc: failed to set stream, rpmsg_send failed (%d) for DELTA_IPC_SET_STREAM (size=%d, data=%p)\n",
 289                         pctx->name,
 290                         ret, param->size, param->data);
 291                 pctx->sys_errors++;
 292                 return ret;
 293         }
 294 
 295         /* wait for acknowledge */
 296         if (!wait_for_completion_timeout
 297             (&ctx->done, msecs_to_jiffies(IPC_TIMEOUT))) {
 298                 dev_err(delta->dev,
 299                         "%s   ipc: failed to set stream, timeout waiting for DELTA_IPC_SET_STREAM callback (size=%d, data=%p)\n",
 300                         pctx->name,
 301                         param->size, param->data);
 302                 pctx->sys_errors++;
 303                 return -ETIMEDOUT;
 304         }
 305 
 306         /* command completed, check status */
 307         if (ctx->cb_err) {
 308                 dev_err(delta->dev,
 309                         "%s   ipc: failed to set stream, DELTA_IPC_SET_STREAM completed but with error (%d) (size=%d, data=%p)\n",
 310                         pctx->name,
 311                         ctx->cb_err, param->size, param->data);
 312                 pctx->sys_errors++;
 313                 return -EIO;
 314         }
 315 
 316         return 0;
 317 }
 318 
 319 int delta_ipc_decode(void *hdl, struct delta_ipc_param *param,
 320                      struct delta_ipc_param *status)
 321 {
 322         struct delta_ipc_ctx *ctx = to_ctx(hdl);
 323         struct delta_ctx *pctx = to_pctx(ctx);
 324         struct delta_dev *delta = pctx->dev;
 325         struct rpmsg_device *rpmsg_device = delta->rpmsg_device;
 326         struct delta_ipc_decode_msg msg;
 327         int ret;
 328 
 329         if (!hdl) {
 330                 dev_err(delta->dev,
 331                         "%s   ipc: failed to decode, invalid ipc handle\n",
 332                         pctx->name);
 333                 return -EINVAL;
 334         }
 335 
 336         if (!rpmsg_device) {
 337                 dev_err(delta->dev,
 338                         "%s   ipc: failed to decode, rpmsg is not initialized\n",
 339                         pctx->name);
 340                 return -EINVAL;
 341         }
 342 
 343         if (!param || !param->data || !param->size) {
 344                 dev_err(delta->dev,
 345                         "%s  ipc: failed to decode, empty parameter\n",
 346                         pctx->name);
 347                 return -EINVAL;
 348         }
 349 
 350         if (!status || !status->data || !status->size) {
 351                 dev_err(delta->dev,
 352                         "%s  ipc: failed to decode, empty status\n",
 353                         pctx->name);
 354                 return -EINVAL;
 355         }
 356 
 357         if (param->size + status->size > ctx->ipc_buf->size) {
 358                 dev_err(delta->dev,
 359                         "%s   ipc: failed to decode, too large ipc parameter (%d bytes (param) + %d bytes (status) while max %d expected)\n",
 360                         pctx->name,
 361                         param->size,
 362                         status->size,
 363                         ctx->ipc_buf->size);
 364                 return -EINVAL;
 365         }
 366 
 367         if (!is_valid_data(ctx, param->data, param->size)) {
 368                 dev_err(delta->dev,
 369                         "%s   ipc: failed to decode, parameter is not in expected address range (size=%d, data=%p not in %p..%p)\n",
 370                         pctx->name,
 371                         param->size,
 372                         param->data,
 373                         ctx->ipc_buf->vaddr,
 374                         ctx->ipc_buf->vaddr + ctx->ipc_buf->size - 1);
 375                 return -EINVAL;
 376         }
 377 
 378         if (!is_valid_data(ctx, status->data, status->size)) {
 379                 dev_err(delta->dev,
 380                         "%s   ipc: failed to decode, status is not in expected address range (size=%d, data=%p not in %p..%p)\n",
 381                         pctx->name,
 382                         status->size,
 383                         status->data,
 384                         ctx->ipc_buf->vaddr,
 385                         ctx->ipc_buf->vaddr + ctx->ipc_buf->size - 1);
 386                 return -EINVAL;
 387         }
 388 
 389         /* build rpmsg message */
 390         build_msg_header(ctx, DELTA_IPC_DECODE, &msg.header);
 391 
 392         msg.param_size = param->size;
 393         msg.param_paddr = to_paddr(ctx, param->data);
 394 
 395         msg.status_size = status->size;
 396         msg.status_paddr = to_paddr(ctx, status->data);
 397 
 398         /* send it */
 399         ret = rpmsg_send(rpmsg_device->ept, &msg, sizeof(msg));
 400         if (ret) {
 401                 dev_err(delta->dev,
 402                         "%s   ipc: failed to decode, rpmsg_send failed (%d) for DELTA_IPC_DECODE (size=%d, data=%p)\n",
 403                         pctx->name,
 404                         ret, param->size, param->data);
 405                 pctx->sys_errors++;
 406                 return ret;
 407         }
 408 
 409         /* wait for acknowledge */
 410         if (!wait_for_completion_timeout
 411             (&ctx->done, msecs_to_jiffies(IPC_TIMEOUT))) {
 412                 dev_err(delta->dev,
 413                         "%s   ipc: failed to decode, timeout waiting for DELTA_IPC_DECODE callback (size=%d, data=%p)\n",
 414                         pctx->name,
 415                         param->size, param->data);
 416                 pctx->sys_errors++;
 417                 return -ETIMEDOUT;
 418         }
 419 
 420         /* command completed, check status */
 421         if (ctx->cb_err) {
 422                 dev_err(delta->dev,
 423                         "%s   ipc: failed to decode, DELTA_IPC_DECODE completed but with error (%d) (size=%d, data=%p)\n",
 424                         pctx->name,
 425                         ctx->cb_err, param->size, param->data);
 426                 pctx->sys_errors++;
 427                 return -EIO;
 428         }
 429 
 430         return 0;
 431 };
 432 
 433 void delta_ipc_close(void *hdl)
 434 {
 435         struct delta_ipc_ctx *ctx = to_ctx(hdl);
 436         struct delta_ctx *pctx = to_pctx(ctx);
 437         struct delta_dev *delta = pctx->dev;
 438         struct rpmsg_device *rpmsg_device = delta->rpmsg_device;
 439         struct delta_ipc_close_msg msg;
 440         int ret;
 441 
 442         if (!hdl) {
 443                 dev_err(delta->dev,
 444                         "%s   ipc: failed to close, invalid ipc handle\n",
 445                         pctx->name);
 446                 return;
 447         }
 448 
 449         if (ctx->ipc_buf) {
 450                 hw_free(pctx, ctx->ipc_buf);
 451                 ctx->ipc_buf = NULL;
 452         }
 453 
 454         if (!rpmsg_device) {
 455                 dev_err(delta->dev,
 456                         "%s   ipc: failed to close, rpmsg is not initialized\n",
 457                         pctx->name);
 458                 return;
 459         }
 460 
 461         /* build rpmsg message */
 462         build_msg_header(ctx, DELTA_IPC_CLOSE, &msg.header);
 463 
 464         /* send it */
 465         ret = rpmsg_send(rpmsg_device->ept, &msg, sizeof(msg));
 466         if (ret) {
 467                 dev_err(delta->dev,
 468                         "%s   ipc: failed to close, rpmsg_send failed (%d) for DELTA_IPC_CLOSE\n",
 469                         pctx->name, ret);
 470                 pctx->sys_errors++;
 471                 return;
 472         }
 473 
 474         /* wait for acknowledge */
 475         if (!wait_for_completion_timeout
 476             (&ctx->done, msecs_to_jiffies(IPC_TIMEOUT))) {
 477                 dev_err(delta->dev,
 478                         "%s   ipc: failed to close, timeout waiting for DELTA_IPC_CLOSE callback\n",
 479                         pctx->name);
 480                 pctx->sys_errors++;
 481                 return;
 482         }
 483 
 484         /* command completed, check status */
 485         if (ctx->cb_err) {
 486                 dev_err(delta->dev,
 487                         "%s   ipc: failed to close, DELTA_IPC_CLOSE completed but with error (%d)\n",
 488                         pctx->name, ctx->cb_err);
 489                 pctx->sys_errors++;
 490         }
 491 };
 492 
 493 static int delta_ipc_cb(struct rpmsg_device *rpdev, void *data,
 494                         int len, void *priv, u32 src)
 495 {
 496         struct delta_ipc_ctx *ctx;
 497         struct delta_ipc_cb_msg *msg;
 498 
 499         /* sanity check */
 500         if (!rpdev) {
 501                 dev_err(NULL, "rpdev is NULL\n");
 502                 return -EINVAL;
 503         }
 504 
 505         if (!data || !len) {
 506                 dev_err(&rpdev->dev,
 507                         "unexpected empty message received from src=%d\n", src);
 508                 return -EINVAL;
 509         }
 510 
 511         if (len != sizeof(*msg)) {
 512                 dev_err(&rpdev->dev,
 513                         "unexpected message length received from src=%d (received %d bytes while %zu bytes expected)\n",
 514                         len, src, sizeof(*msg));
 515                 return -EINVAL;
 516         }
 517 
 518         msg = (struct delta_ipc_cb_msg *)data;
 519         if (msg->header.tag != IPC_SANITY_TAG) {
 520                 dev_err(&rpdev->dev,
 521                         "unexpected message tag received from src=%d (received %x tag while %x expected)\n",
 522                         src, msg->header.tag, IPC_SANITY_TAG);
 523                 return -EINVAL;
 524         }
 525 
 526         ctx = msg_to_ctx(msg);
 527         if (!ctx) {
 528                 dev_err(&rpdev->dev,
 529                         "unexpected message with NULL host_hdl received from src=%d\n",
 530                         src);
 531                 return -EINVAL;
 532         }
 533 
 534         /*
 535          * if not already known, save copro instance context
 536          * to ensure re-entrance on copro side
 537          */
 538         if (!ctx->copro_hdl)
 539                 ctx->copro_hdl = msg_to_copro_hdl(msg);
 540 
 541         /*
 542          * all is fine,
 543          * update status & complete command
 544          */
 545         ctx->cb_err = msg->err;
 546         complete(&ctx->done);
 547 
 548         return 0;
 549 }
 550 
 551 static int delta_ipc_probe(struct rpmsg_device *rpmsg_device)
 552 {
 553         struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpmsg_device->dev.driver);
 554         struct delta_dev *delta = to_delta(rpdrv);
 555 
 556         delta->rpmsg_device = rpmsg_device;
 557 
 558         return 0;
 559 }
 560 
 561 static void delta_ipc_remove(struct rpmsg_device *rpmsg_device)
 562 {
 563         struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpmsg_device->dev.driver);
 564         struct delta_dev *delta = to_delta(rpdrv);
 565 
 566         delta->rpmsg_device = NULL;
 567 }
 568 
 569 static struct rpmsg_device_id delta_ipc_device_id_table[] = {
 570         {.name = "rpmsg-delta"},
 571         {},
 572 };
 573 
 574 static struct rpmsg_driver delta_rpmsg_driver = {
 575         .drv = {.name = KBUILD_MODNAME},
 576         .id_table = delta_ipc_device_id_table,
 577         .probe = delta_ipc_probe,
 578         .callback = delta_ipc_cb,
 579         .remove = delta_ipc_remove,
 580 };
 581 
 582 int delta_ipc_init(struct delta_dev *delta)
 583 {
 584         delta->rpmsg_driver = delta_rpmsg_driver;
 585 
 586         return register_rpmsg_driver(&delta->rpmsg_driver);
 587 }
 588 
 589 void delta_ipc_exit(struct delta_dev *delta)
 590 {
 591         unregister_rpmsg_driver(&delta->rpmsg_driver);
 592 }

/* [<][>][^][v][top][bottom][index][help] */