LCOV - code coverage report
Current view: top level - drivers/staging/vc04_services/interface/vchiq_arm - vchiq_shim.c (source / functions) Hit Total Coverage
Test: gcov_data_raspi2_real_modules_combined.info Lines: 92 165 55.8 %
Date: 2020-09-30 20:25:40 Functions: 16 25 64.0 %
Branches: 23 79 29.1 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
       2                 :            : /* Copyright (c) 2010-2012 Broadcom. All rights reserved. */
       3                 :            : #include <linux/module.h>
       4                 :            : #include <linux/types.h>
       5                 :            : 
       6                 :            : #include "interface/vchi/vchi.h"
       7                 :            : #include "vchiq.h"
       8                 :            : #include "vchiq_core.h"
       9                 :            : 
      10                 :            : #include "vchiq_util.h"
      11                 :            : 
      12                 :            : #define vchiq_status_to_vchi(status) ((int32_t)status)
      13                 :            : 
      14                 :            : struct shim_service {
      15                 :            :         VCHIQ_SERVICE_HANDLE_T handle;
      16                 :            : 
      17                 :            :         struct vchiu_queue queue;
      18                 :            : 
      19                 :            :         VCHI_CALLBACK_T callback;
      20                 :            :         void *callback_param;
      21                 :            : };
      22                 :            : 
      23                 :            : /***********************************************************
      24                 :            :  * Name: vchi_msg_peek
      25                 :            :  *
      26                 :            :  * Arguments:  const VCHI_SERVICE_HANDLE_T handle,
      27                 :            :  *             void **data,
      28                 :            :  *             uint32_t *msg_size,
      29                 :            : 
      30                 :            :  *             VCHI_FLAGS_T flags
      31                 :            :  *
      32                 :            :  * Description: Routine to return a pointer to the current message (to allow in
      33                 :            :  *              place processing). The message can be removed using
      34                 :            :  *              vchi_msg_remove when you're finished
      35                 :            :  *
      36                 :            :  * Returns: int32_t - success == 0
      37                 :            :  *
      38                 :            :  ***********************************************************/
      39                 :        621 : int32_t vchi_msg_peek(VCHI_SERVICE_HANDLE_T handle,
      40                 :            :         void **data,
      41                 :            :         uint32_t *msg_size,
      42                 :            :         VCHI_FLAGS_T flags)
      43                 :            : {
      44                 :            :         struct shim_service *service = (struct shim_service *)handle;
      45                 :            :         struct vchiq_header *header;
      46                 :            : 
      47         [ -  + ]:        621 :         WARN_ON((flags != VCHI_FLAGS_NONE) &&
      48                 :            :                 (flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE));
      49                 :            : 
      50         [ +  - ]:        621 :         if (flags == VCHI_FLAGS_NONE)
      51         [ +  + ]:        621 :                 if (vchiu_queue_is_empty(&service->queue))
      52                 :            :                         return -1;
      53                 :            : 
      54                 :        207 :         header = vchiu_queue_peek(&service->queue);
      55                 :            : 
      56                 :        207 :         *data = header->data;
      57                 :        207 :         *msg_size = header->size;
      58                 :            : 
      59                 :        207 :         return 0;
      60                 :            : }
      61                 :            : EXPORT_SYMBOL(vchi_msg_peek);
      62                 :            : 
      63                 :            : /***********************************************************
      64                 :            :  * Name: vchi_msg_remove
      65                 :            :  *
      66                 :            :  * Arguments:  const VCHI_SERVICE_HANDLE_T handle,
      67                 :            :  *
      68                 :            :  * Description: Routine to remove a message (after it has been read with
      69                 :            :  *              vchi_msg_peek)
      70                 :            :  *
      71                 :            :  * Returns: int32_t - success == 0
      72                 :            :  *
      73                 :            :  ***********************************************************/
      74                 :        207 : int32_t vchi_msg_remove(VCHI_SERVICE_HANDLE_T handle)
      75                 :            : {
      76                 :            :         struct shim_service *service = (struct shim_service *)handle;
      77                 :            :         struct vchiq_header *header;
      78                 :            : 
      79                 :        207 :         header = vchiu_queue_pop(&service->queue);
      80                 :            : 
      81                 :        207 :         vchiq_release_message(service->handle, header);
      82                 :            : 
      83                 :        207 :         return 0;
      84                 :            : }
      85                 :            : EXPORT_SYMBOL(vchi_msg_remove);
      86                 :            : 
      87                 :            : /***********************************************************
      88                 :            :  * Name: vchi_msg_queue
      89                 :            :  *
      90                 :            :  * Arguments:  VCHI_SERVICE_HANDLE_T handle,
      91                 :            :  *             ssize_t (*copy_callback)(void *context, void *dest,
      92                 :            :  *                                      size_t offset, size_t maxsize),
      93                 :            :  *             void *context,
      94                 :            :  *             uint32_t data_size
      95                 :            :  *
      96                 :            :  * Description: Thin wrapper to queue a message onto a connection
      97                 :            :  *
      98                 :            :  * Returns: int32_t - success == 0
      99                 :            :  *
     100                 :            :  ***********************************************************/
     101                 :            : static
     102                 :       8073 : int32_t vchi_msg_queue(VCHI_SERVICE_HANDLE_T handle,
     103                 :            :         ssize_t (*copy_callback)(void *context, void *dest,
     104                 :            :                                  size_t offset, size_t maxsize),
     105                 :            :         void *context,
     106                 :            :         uint32_t data_size)
     107                 :            : {
     108                 :            :         struct shim_service *service = (struct shim_service *)handle;
     109                 :            :         VCHIQ_STATUS_T status;
     110                 :            : 
     111                 :            :         while (1) {
     112                 :       8073 :                 status = vchiq_queue_message(service->handle,
     113                 :            :                                              copy_callback,
     114                 :            :                                              context,
     115                 :            :                                              data_size);
     116                 :            : 
     117                 :            :                 /*
     118                 :            :                  * vchiq_queue_message() may return VCHIQ_RETRY, so we need to
     119                 :            :                  * implement a retry mechanism since this function is supposed
     120                 :            :                  * to block until queued
     121                 :            :                  */
     122         [ -  + ]:       8073 :                 if (status != VCHIQ_RETRY)
     123                 :            :                         break;
     124                 :            : 
     125                 :          0 :                 msleep(1);
     126                 :          0 :         }
     127                 :            : 
     128                 :       8073 :         return vchiq_status_to_vchi(status);
     129                 :            : }
     130                 :            : 
     131                 :            : static ssize_t
     132                 :       8073 : vchi_queue_kernel_message_callback(void *context,
     133                 :            :                                    void *dest,
     134                 :            :                                    size_t offset,
     135                 :            :                                    size_t maxsize)
     136                 :            : {
     137                 :       8073 :         memcpy(dest, context + offset, maxsize);
     138                 :       8073 :         return maxsize;
     139                 :            : }
     140                 :            : 
     141                 :            : int
     142                 :       8073 : vchi_queue_kernel_message(VCHI_SERVICE_HANDLE_T handle,
     143                 :            :                           void *data,
     144                 :            :                           unsigned int size)
     145                 :            : {
     146                 :       8073 :         return vchi_msg_queue(handle,
     147                 :            :                               vchi_queue_kernel_message_callback,
     148                 :            :                               data,
     149                 :            :                               size);
     150                 :            : }
     151                 :            : EXPORT_SYMBOL(vchi_queue_kernel_message);
     152                 :            : 
     153                 :            : struct vchi_queue_user_message_context {
     154                 :            :         void __user *data;
     155                 :            : };
     156                 :            : 
     157                 :            : static ssize_t
     158                 :          0 : vchi_queue_user_message_callback(void *context,
     159                 :            :                                  void *dest,
     160                 :            :                                  size_t offset,
     161                 :            :                                  size_t maxsize)
     162                 :            : {
     163                 :            :         struct vchi_queue_user_message_context *copycontext = context;
     164                 :            : 
     165         [ #  # ]:          0 :         if (copy_from_user(dest, copycontext->data + offset, maxsize))
     166                 :            :                 return -EFAULT;
     167                 :            : 
     168                 :          0 :         return maxsize;
     169                 :            : }
     170                 :            : 
     171                 :            : int
     172                 :          0 : vchi_queue_user_message(VCHI_SERVICE_HANDLE_T handle,
     173                 :            :                         void __user *data,
     174                 :            :                         unsigned int size)
     175                 :            : {
     176                 :          0 :         struct vchi_queue_user_message_context copycontext = {
     177                 :            :                 .data = data
     178                 :            :         };
     179                 :            : 
     180                 :          0 :         return vchi_msg_queue(handle,
     181                 :            :                               vchi_queue_user_message_callback,
     182                 :            :                               &copycontext,
     183                 :            :                               size);
     184                 :            : }
     185                 :            : EXPORT_SYMBOL(vchi_queue_user_message);
     186                 :            : 
     187                 :            : /***********************************************************
     188                 :            :  * Name: vchi_bulk_queue_receive
     189                 :            :  *
     190                 :            :  * Arguments:  VCHI_BULK_HANDLE_T handle,
     191                 :            :  *             void *data_dst,
     192                 :            :  *             const uint32_t data_size,
     193                 :            :  *             VCHI_FLAGS_T flags
     194                 :            :  *             void *bulk_handle
     195                 :            :  *
     196                 :            :  * Description: Routine to setup a rcv buffer
     197                 :            :  *
     198                 :            :  * Returns: int32_t - success == 0
     199                 :            :  *
     200                 :            :  ***********************************************************/
     201                 :          0 : int32_t vchi_bulk_queue_receive(VCHI_SERVICE_HANDLE_T handle,
     202                 :            :         void *data_dst,
     203                 :            :         uint32_t data_size,
     204                 :            :         VCHI_FLAGS_T flags,
     205                 :            :         void *bulk_handle)
     206                 :            : {
     207                 :            :         struct shim_service *service = (struct shim_service *)handle;
     208                 :            :         VCHIQ_BULK_MODE_T mode;
     209                 :            :         VCHIQ_STATUS_T status;
     210                 :            : 
     211   [ #  #  #  # ]:          0 :         switch ((int)flags) {
     212                 :            :         case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE
     213                 :            :                 | VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
     214         [ #  # ]:          0 :                 WARN_ON(!service->callback);
     215                 :            :                 mode = VCHIQ_BULK_MODE_CALLBACK;
     216                 :            :                 break;
     217                 :            :         case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE:
     218                 :            :                 mode = VCHIQ_BULK_MODE_BLOCKING;
     219                 :            :                 break;
     220                 :            :         case VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
     221                 :            :         case VCHI_FLAGS_NONE:
     222                 :            :                 mode = VCHIQ_BULK_MODE_NOCALLBACK;
     223                 :          0 :                 break;
     224                 :            :         default:
     225                 :          0 :                 WARN(1, "unsupported message\n");
     226                 :          0 :                 return vchiq_status_to_vchi(VCHIQ_ERROR);
     227                 :            :         }
     228                 :            : 
     229                 :            :         while (1) {
     230                 :          0 :                 status = vchiq_bulk_receive(service->handle, data_dst,
     231                 :            :                         data_size, bulk_handle, mode);
     232                 :            :                 /*
     233                 :            :                  * vchiq_bulk_receive() may return VCHIQ_RETRY, so we need to
     234                 :            :                  * implement a retry mechanism since this function is supposed
     235                 :            :                  * to block until queued
     236                 :            :                  */
     237         [ #  # ]:          0 :                 if (status != VCHIQ_RETRY)
     238                 :            :                         break;
     239                 :            : 
     240                 :          0 :                 msleep(1);
     241                 :          0 :         }
     242                 :            : 
     243                 :          0 :         return vchiq_status_to_vchi(status);
     244                 :            : }
     245                 :            : EXPORT_SYMBOL(vchi_bulk_queue_receive);
     246                 :            : 
     247                 :            : /***********************************************************
     248                 :            :  * Name: vchi_bulk_queue_transmit
     249                 :            :  *
     250                 :            :  * Arguments:  VCHI_BULK_HANDLE_T handle,
     251                 :            :  *             const void *data_src,
     252                 :            :  *             uint32_t data_size,
     253                 :            :  *             VCHI_FLAGS_T flags,
     254                 :            :  *             void *bulk_handle
     255                 :            :  *
     256                 :            :  * Description: Routine to transmit some data
     257                 :            :  *
     258                 :            :  * Returns: int32_t - success == 0
     259                 :            :  *
     260                 :            :  ***********************************************************/
     261                 :          0 : int32_t vchi_bulk_queue_transmit(VCHI_SERVICE_HANDLE_T handle,
     262                 :            :         const void *data_src,
     263                 :            :         uint32_t data_size,
     264                 :            :         VCHI_FLAGS_T flags,
     265                 :            :         void *bulk_handle)
     266                 :            : {
     267                 :            :         struct shim_service *service = (struct shim_service *)handle;
     268                 :            :         VCHIQ_BULK_MODE_T mode;
     269                 :            :         VCHIQ_STATUS_T status;
     270                 :            : 
     271   [ #  #  #  # ]:          0 :         switch ((int)flags) {
     272                 :            :         case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE
     273                 :            :                 | VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
     274         [ #  # ]:          0 :                 WARN_ON(!service->callback);
     275                 :            :                 mode = VCHIQ_BULK_MODE_CALLBACK;
     276                 :            :                 break;
     277                 :            :         case VCHI_FLAGS_BLOCK_UNTIL_DATA_READ:
     278                 :            :         case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE:
     279                 :            :                 mode = VCHIQ_BULK_MODE_BLOCKING;
     280                 :            :                 break;
     281                 :            :         case VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
     282                 :            :         case VCHI_FLAGS_NONE:
     283                 :            :                 mode = VCHIQ_BULK_MODE_NOCALLBACK;
     284                 :          0 :                 break;
     285                 :            :         default:
     286                 :          0 :                 WARN(1, "unsupported message\n");
     287                 :          0 :                 return vchiq_status_to_vchi(VCHIQ_ERROR);
     288                 :            :         }
     289                 :            : 
     290                 :            :         while (1) {
     291                 :          0 :                 status = vchiq_bulk_transmit(service->handle, data_src,
     292                 :            :                         data_size, bulk_handle, mode);
     293                 :            : 
     294                 :            :                 /*
     295                 :            :                  * vchiq_bulk_transmit() may return VCHIQ_RETRY, so we need to
     296                 :            :                  * implement a retry mechanism since this function is supposed
     297                 :            :                  * to block until queued
     298                 :            :                  */
     299         [ #  # ]:          0 :                 if (status != VCHIQ_RETRY)
     300                 :            :                         break;
     301                 :            : 
     302                 :          0 :                 msleep(1);
     303                 :          0 :         }
     304                 :            : 
     305                 :          0 :         return vchiq_status_to_vchi(status);
     306                 :            : }
     307                 :            : EXPORT_SYMBOL(vchi_bulk_queue_transmit);
     308                 :            : 
     309                 :            : /***********************************************************
     310                 :            :  * Name: vchi_msg_dequeue
     311                 :            :  *
     312                 :            :  * Arguments:  VCHI_SERVICE_HANDLE_T handle,
     313                 :            :  *             void *data,
     314                 :            :  *             uint32_t max_data_size_to_read,
     315                 :            :  *             uint32_t *actual_msg_size
     316                 :            :  *             VCHI_FLAGS_T flags
     317                 :            :  *
     318                 :            :  * Description: Routine to dequeue a message into the supplied buffer
     319                 :            :  *
     320                 :            :  * Returns: int32_t - success == 0
     321                 :            :  *
     322                 :            :  ***********************************************************/
     323                 :          0 : int32_t vchi_msg_dequeue(VCHI_SERVICE_HANDLE_T handle,
     324                 :            :         void *data,
     325                 :            :         uint32_t max_data_size_to_read,
     326                 :            :         uint32_t *actual_msg_size,
     327                 :            :         VCHI_FLAGS_T flags)
     328                 :            : {
     329                 :            :         struct shim_service *service = (struct shim_service *)handle;
     330                 :            :         struct vchiq_header *header;
     331                 :            : 
     332         [ #  # ]:          0 :         WARN_ON((flags != VCHI_FLAGS_NONE) &&
     333                 :            :                 (flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE));
     334                 :            : 
     335         [ #  # ]:          0 :         if (flags == VCHI_FLAGS_NONE)
     336         [ #  # ]:          0 :                 if (vchiu_queue_is_empty(&service->queue))
     337                 :            :                         return -1;
     338                 :            : 
     339                 :          0 :         header = vchiu_queue_pop(&service->queue);
     340                 :            : 
     341                 :          0 :         memcpy(data, header->data, header->size < max_data_size_to_read ?
     342                 :          0 :                 header->size : max_data_size_to_read);
     343                 :            : 
     344                 :          0 :         *actual_msg_size = header->size;
     345                 :            : 
     346                 :          0 :         vchiq_release_message(service->handle, header);
     347                 :            : 
     348                 :          0 :         return 0;
     349                 :            : }
     350                 :            : EXPORT_SYMBOL(vchi_msg_dequeue);
     351                 :            : 
     352                 :            : /***********************************************************
     353                 :            :  * Name: vchi_held_msg_release
     354                 :            :  *
     355                 :            :  * Arguments:  struct vchi_held_msg *message
     356                 :            :  *
     357                 :            :  * Description: Routine to release a held message (after it has been read with
     358                 :            :  *              vchi_msg_hold)
     359                 :            :  *
     360                 :            :  * Returns: int32_t - success == 0
     361                 :            :  *
     362                 :            :  ***********************************************************/
     363                 :       7866 : int32_t vchi_held_msg_release(struct vchi_held_msg *message)
     364                 :            : {
     365                 :            :         /*
     366                 :            :          * Convert the service field pointer back to an
     367                 :            :          * VCHIQ_SERVICE_HANDLE_T which is an int.
     368                 :            :          * This pointer is opaque to everything except
     369                 :            :          * vchi_msg_hold which simply upcasted the int
     370                 :            :          * to a pointer.
     371                 :            :          */
     372                 :            : 
     373                 :      15732 :         vchiq_release_message((VCHIQ_SERVICE_HANDLE_T)(long)message->service,
     374                 :       7866 :                               (struct vchiq_header *)message->message);
     375                 :            : 
     376                 :       7866 :         return 0;
     377                 :            : }
     378                 :            : EXPORT_SYMBOL(vchi_held_msg_release);
     379                 :            : 
     380                 :            : /***********************************************************
     381                 :            :  * Name: vchi_msg_hold
     382                 :            :  *
     383                 :            :  * Arguments:  VCHI_SERVICE_HANDLE_T handle,
     384                 :            :  *             void **data,
     385                 :            :  *             uint32_t *msg_size,
     386                 :            :  *             VCHI_FLAGS_T flags,
     387                 :            :  *             struct vchi_held_msg *message_handle
     388                 :            :  *
     389                 :            :  * Description: Routine to return a pointer to the current message (to allow
     390                 :            :  *              in place processing). The message is dequeued - don't forget
     391                 :            :  *              to release the message using vchi_held_msg_release when you're
     392                 :            :  *              finished.
     393                 :            :  *
     394                 :            :  * Returns: int32_t - success == 0
     395                 :            :  *
     396                 :            :  ***********************************************************/
     397                 :       7866 : int32_t vchi_msg_hold(VCHI_SERVICE_HANDLE_T handle,
     398                 :            :         void **data,
     399                 :            :         uint32_t *msg_size,
     400                 :            :         VCHI_FLAGS_T flags,
     401                 :            :         struct vchi_held_msg *message_handle)
     402                 :            : {
     403                 :            :         struct shim_service *service = (struct shim_service *)handle;
     404                 :            :         struct vchiq_header *header;
     405                 :            : 
     406         [ -  + ]:       7866 :         WARN_ON((flags != VCHI_FLAGS_NONE) &&
     407                 :            :                 (flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE));
     408                 :            : 
     409         [ +  - ]:       7866 :         if (flags == VCHI_FLAGS_NONE)
     410         [ +  - ]:       7866 :                 if (vchiu_queue_is_empty(&service->queue))
     411                 :            :                         return -1;
     412                 :            : 
     413                 :       7866 :         header = vchiu_queue_pop(&service->queue);
     414                 :            : 
     415                 :       7866 :         *data = header->data;
     416                 :       7866 :         *msg_size = header->size;
     417                 :            : 
     418                 :            :         /*
     419                 :            :          * upcast the VCHIQ_SERVICE_HANDLE_T which is an int
     420                 :            :          * to a pointer and stuff it in the held message.
     421                 :            :          * This pointer is opaque to everything except
     422                 :            :          * vchi_held_msg_release which simply downcasts it back
     423                 :            :          * to an int.
     424                 :            :          */
     425                 :            : 
     426                 :       7866 :         message_handle->service =
     427                 :       7866 :                 (struct opaque_vchi_service_t *)(long)service->handle;
     428                 :       7866 :         message_handle->message = header;
     429                 :            : 
     430                 :       7866 :         return 0;
     431                 :            : }
     432                 :            : EXPORT_SYMBOL(vchi_msg_hold);
     433                 :            : 
     434                 :            : /***********************************************************
     435                 :            :  * Name: vchi_initialise
     436                 :            :  *
     437                 :            :  * Arguments: VCHI_INSTANCE_T *instance_handle
     438                 :            :  *
     439                 :            :  * Description: Initialises the hardware but does not transmit anything
     440                 :            :  *              When run as a Host App this will be called twice hence the need
     441                 :            :  *              to malloc the state information
     442                 :            :  *
     443                 :            :  * Returns: 0 if successful, failure otherwise
     444                 :            :  *
     445                 :            :  ***********************************************************/
     446                 :            : 
     447                 :       1656 : int32_t vchi_initialise(VCHI_INSTANCE_T *instance_handle)
     448                 :            : {
     449                 :            :         VCHIQ_INSTANCE_T instance;
     450                 :            :         VCHIQ_STATUS_T status;
     451                 :            : 
     452                 :       1656 :         status = vchiq_initialise(&instance);
     453                 :            : 
     454                 :       1656 :         *instance_handle = (VCHI_INSTANCE_T)instance;
     455                 :            : 
     456                 :       1656 :         return vchiq_status_to_vchi(status);
     457                 :            : }
     458                 :            : EXPORT_SYMBOL(vchi_initialise);
     459                 :            : 
     460                 :            : /***********************************************************
     461                 :            :  * Name: vchi_connect
     462                 :            :  *
     463                 :            :  * Arguments: VCHI_INSTANCE_T instance_handle
     464                 :            :  *
     465                 :            :  * Description: Starts the command service on each connection,
     466                 :            :  *              causing INIT messages to be pinged back and forth
     467                 :            :  *
     468                 :            :  * Returns: 0 if successful, failure otherwise
     469                 :            :  *
     470                 :            :  ***********************************************************/
     471                 :       1656 : int32_t vchi_connect(VCHI_INSTANCE_T instance_handle)
     472                 :            : {
     473                 :            :         VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
     474                 :            : 
     475                 :       1656 :         return vchiq_connect(instance);
     476                 :            : }
     477                 :            : EXPORT_SYMBOL(vchi_connect);
     478                 :            : 
     479                 :            : /***********************************************************
     480                 :            :  * Name: vchi_disconnect
     481                 :            :  *
     482                 :            :  * Arguments: VCHI_INSTANCE_T instance_handle
     483                 :            :  *
     484                 :            :  * Description: Stops the command service on each connection,
     485                 :            :  *              causing DE-INIT messages to be pinged back and forth
     486                 :            :  *
     487                 :            :  * Returns: 0 if successful, failure otherwise
     488                 :            :  *
     489                 :            :  ***********************************************************/
     490                 :          0 : int32_t vchi_disconnect(VCHI_INSTANCE_T instance_handle)
     491                 :            : {
     492                 :            :         VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
     493                 :            : 
     494                 :          0 :         return vchiq_status_to_vchi(vchiq_shutdown(instance));
     495                 :            : }
     496                 :            : EXPORT_SYMBOL(vchi_disconnect);
     497                 :            : 
     498                 :            : /***********************************************************
     499                 :            :  * Name: vchi_service_open
     500                 :            :  * Name: vchi_service_create
     501                 :            :  *
     502                 :            :  * Arguments: VCHI_INSTANCE_T *instance_handle
     503                 :            :  *            struct service_creation *setup,
     504                 :            :  *            VCHI_SERVICE_HANDLE_T *handle
     505                 :            :  *
     506                 :            :  * Description: Routine to open a service
     507                 :            :  *
     508                 :            :  * Returns: int32_t - success == 0
     509                 :            :  *
     510                 :            :  ***********************************************************/
     511                 :            : 
     512                 :       8280 : static VCHIQ_STATUS_T shim_callback(VCHIQ_REASON_T reason,
     513                 :            :                                     struct vchiq_header *header,
     514                 :            :                                     VCHIQ_SERVICE_HANDLE_T handle,
     515                 :            :                                     void *bulk_user)
     516                 :            : {
     517                 :       8280 :         struct shim_service *service =
     518                 :            :                 (struct shim_service *)VCHIQ_GET_SERVICE_USERDATA(handle);
     519                 :            : 
     520         [ +  - ]:       8280 :         if (!service->callback)
     521                 :            :                 goto release;
     522                 :            : 
     523   [ +  -  -  +  :       8280 :         switch (reason) {
             -  -  -  - ]
     524                 :            :         case VCHIQ_MESSAGE_AVAILABLE:
     525                 :       8073 :                 vchiu_queue_push(&service->queue, header);
     526                 :            : 
     527                 :       8073 :                 service->callback(service->callback_param,
     528                 :            :                                   VCHI_CALLBACK_MSG_AVAILABLE, NULL);
     529                 :            : 
     530                 :       8073 :                 goto done;
     531                 :            : 
     532                 :            :         case VCHIQ_BULK_TRANSMIT_DONE:
     533                 :          0 :                 service->callback(service->callback_param,
     534                 :            :                                   VCHI_CALLBACK_BULK_SENT, bulk_user);
     535                 :          0 :                 break;
     536                 :            : 
     537                 :            :         case VCHIQ_BULK_RECEIVE_DONE:
     538                 :          0 :                 service->callback(service->callback_param,
     539                 :            :                                   VCHI_CALLBACK_BULK_RECEIVED, bulk_user);
     540                 :          0 :                 break;
     541                 :            : 
     542                 :            :         case VCHIQ_SERVICE_CLOSED:
     543                 :        207 :                 service->callback(service->callback_param,
     544                 :            :                                   VCHI_CALLBACK_SERVICE_CLOSED, NULL);
     545                 :        207 :                 break;
     546                 :            : 
     547                 :            :         case VCHIQ_SERVICE_OPENED:
     548                 :            :                 /* No equivalent VCHI reason */
     549                 :            :                 break;
     550                 :            : 
     551                 :            :         case VCHIQ_BULK_TRANSMIT_ABORTED:
     552                 :          0 :                 service->callback(service->callback_param,
     553                 :            :                                   VCHI_CALLBACK_BULK_TRANSMIT_ABORTED,
     554                 :            :                                   bulk_user);
     555                 :          0 :                 break;
     556                 :            : 
     557                 :            :         case VCHIQ_BULK_RECEIVE_ABORTED:
     558                 :          0 :                 service->callback(service->callback_param,
     559                 :            :                                   VCHI_CALLBACK_BULK_RECEIVE_ABORTED,
     560                 :            :                                   bulk_user);
     561                 :          0 :                 break;
     562                 :            : 
     563                 :            :         default:
     564                 :          0 :                 WARN(1, "not supported\n");
     565                 :          0 :                 break;
     566                 :            :         }
     567                 :            : 
     568                 :            : release:
     569                 :        207 :         vchiq_release_message(service->handle, header);
     570                 :            : done:
     571                 :       8280 :         return VCHIQ_SUCCESS;
     572                 :            : }
     573                 :            : 
     574                 :       1449 : static struct shim_service *service_alloc(VCHIQ_INSTANCE_T instance,
     575                 :            :         struct service_creation *setup)
     576                 :            : {
     577                 :       1449 :         struct shim_service *service = kzalloc(sizeof(struct shim_service), GFP_KERNEL);
     578                 :            : 
     579                 :            :         (void)instance;
     580                 :            : 
     581         [ +  - ]:       1449 :         if (service) {
     582         [ +  - ]:       1449 :                 if (vchiu_queue_init(&service->queue, 64)) {
     583                 :       1448 :                         service->callback = setup->callback;
     584                 :       1448 :                         service->callback_param = setup->callback_param;
     585                 :            :                 } else {
     586                 :          0 :                         kfree(service);
     587                 :            :                         service = NULL;
     588                 :            :                 }
     589                 :            :         }
     590                 :            : 
     591                 :       1448 :         return service;
     592                 :            : }
     593                 :            : 
     594                 :        207 : static void service_free(struct shim_service *service)
     595                 :            : {
     596         [ +  - ]:        207 :         if (service) {
     597                 :        207 :                 vchiu_queue_delete(&service->queue);
     598                 :        207 :                 kfree(service);
     599                 :            :         }
     600                 :        207 : }
     601                 :            : 
     602                 :       1449 : int32_t vchi_service_open(VCHI_INSTANCE_T instance_handle,
     603                 :            :         struct service_creation *setup,
     604                 :            :         VCHI_SERVICE_HANDLE_T *handle)
     605                 :            : {
     606                 :            :         VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
     607                 :       1449 :         struct shim_service *service = service_alloc(instance, setup);
     608                 :            : 
     609                 :       1449 :         *handle = (VCHI_SERVICE_HANDLE_T)service;
     610                 :            : 
     611         [ +  - ]:       1449 :         if (service) {
     612                 :            :                 struct vchiq_service_params params;
     613                 :            :                 VCHIQ_STATUS_T status;
     614                 :            : 
     615                 :       1449 :                 memset(&params, 0, sizeof(params));
     616                 :       1449 :                 params.fourcc = setup->service_id;
     617                 :       1449 :                 params.callback = shim_callback;
     618                 :       1449 :                 params.userdata = service;
     619                 :       1449 :                 params.version = setup->version.version;
     620                 :       1449 :                 params.version_min = setup->version.version_min;
     621                 :            : 
     622                 :       1449 :                 status = vchiq_open_service(instance, &params,
     623                 :            :                         &service->handle);
     624         [ -  + ]:       1449 :                 if (status != VCHIQ_SUCCESS) {
     625                 :          0 :                         service_free(service);
     626                 :            :                         service = NULL;
     627                 :          0 :                         *handle = NULL;
     628                 :            :                 }
     629                 :            :         }
     630                 :            : 
     631         [ -  + ]:       1449 :         return (service != NULL) ? 0 : -1;
     632                 :            : }
     633                 :            : EXPORT_SYMBOL(vchi_service_open);
     634                 :            : 
     635                 :        207 : int32_t vchi_service_close(const VCHI_SERVICE_HANDLE_T handle)
     636                 :            : {
     637                 :            :         int32_t ret = -1;
     638                 :            :         struct shim_service *service = (struct shim_service *)handle;
     639                 :            : 
     640         [ +  - ]:        207 :         if (service) {
     641                 :        207 :                 VCHIQ_STATUS_T status = vchiq_close_service(service->handle);
     642         [ +  - ]:        207 :                 if (status == VCHIQ_SUCCESS)
     643                 :        207 :                         service_free(service);
     644                 :            : 
     645                 :            :                 ret = vchiq_status_to_vchi(status);
     646                 :            :         }
     647                 :        207 :         return ret;
     648                 :            : }
     649                 :            : EXPORT_SYMBOL(vchi_service_close);
     650                 :            : 
     651                 :          0 : int32_t vchi_service_destroy(const VCHI_SERVICE_HANDLE_T handle)
     652                 :            : {
     653                 :            :         int32_t ret = -1;
     654                 :            :         struct shim_service *service = (struct shim_service *)handle;
     655                 :            : 
     656         [ #  # ]:          0 :         if (service) {
     657                 :          0 :                 VCHIQ_STATUS_T status = vchiq_remove_service(service->handle);
     658                 :            : 
     659         [ #  # ]:          0 :                 if (status == VCHIQ_SUCCESS) {
     660                 :          0 :                         service_free(service);
     661                 :            :                         service = NULL;
     662                 :            :                 }
     663                 :            : 
     664                 :            :                 ret = vchiq_status_to_vchi(status);
     665                 :            :         }
     666                 :          0 :         return ret;
     667                 :            : }
     668                 :            : EXPORT_SYMBOL(vchi_service_destroy);
     669                 :            : 
     670                 :          0 : int32_t vchi_service_set_option(const VCHI_SERVICE_HANDLE_T handle,
     671                 :            :                                 VCHI_SERVICE_OPTION_T option,
     672                 :            :                                 int value)
     673                 :            : {
     674                 :            :         int32_t ret = -1;
     675                 :            :         struct shim_service *service = (struct shim_service *)handle;
     676                 :            :         VCHIQ_SERVICE_OPTION_T vchiq_option;
     677                 :            : 
     678      [ #  #  # ]:          0 :         switch (option) {
     679                 :            :         case VCHI_SERVICE_OPTION_TRACE:
     680                 :            :                 vchiq_option = VCHIQ_SERVICE_OPTION_TRACE;
     681                 :            :                 break;
     682                 :            :         case VCHI_SERVICE_OPTION_SYNCHRONOUS:
     683                 :            :                 vchiq_option = VCHIQ_SERVICE_OPTION_SYNCHRONOUS;
     684                 :          0 :                 break;
     685                 :            :         default:
     686                 :            :                 service = NULL;
     687                 :          0 :                 break;
     688                 :            :         }
     689         [ #  # ]:          0 :         if (service) {
     690                 :          0 :                 VCHIQ_STATUS_T status =
     691                 :          0 :                         vchiq_set_service_option(service->handle,
     692                 :            :                                                 vchiq_option,
     693                 :            :                                                 value);
     694                 :            : 
     695                 :            :                 ret = vchiq_status_to_vchi(status);
     696                 :            :         }
     697                 :          0 :         return ret;
     698                 :            : }
     699                 :            : EXPORT_SYMBOL(vchi_service_set_option);
     700                 :            : 
     701                 :          0 : int32_t vchi_get_peer_version(const VCHI_SERVICE_HANDLE_T handle, short *peer_version)
     702                 :            : {
     703                 :            :         int32_t ret = -1;
     704                 :            :         struct shim_service *service = (struct shim_service *)handle;
     705                 :            : 
     706         [ #  # ]:          0 :         if (service) {
     707                 :            :                 VCHIQ_STATUS_T status;
     708                 :            : 
     709                 :          0 :                 status = vchiq_get_peer_version(service->handle, peer_version);
     710                 :            :                 ret = vchiq_status_to_vchi(status);
     711                 :            :         }
     712                 :          0 :         return ret;
     713                 :            : }
     714                 :            : EXPORT_SYMBOL(vchi_get_peer_version);
     715                 :            : 
     716                 :            : /***********************************************************
     717                 :            :  * Name: vchi_service_use
     718                 :            :  *
     719                 :            :  * Arguments: const VCHI_SERVICE_HANDLE_T handle
     720                 :            :  *
     721                 :            :  * Description: Routine to increment refcount on a service
     722                 :            :  *
     723                 :            :  * Returns: void
     724                 :            :  *
     725                 :            :  ***********************************************************/
     726                 :       8487 : int32_t vchi_service_use(const VCHI_SERVICE_HANDLE_T handle)
     727                 :            : {
     728                 :            :         int32_t ret = -1;
     729                 :            : 
     730                 :            :         struct shim_service *service = (struct shim_service *)handle;
     731         [ +  + ]:       8487 :         if (service)
     732                 :       8486 :                 ret = vchiq_status_to_vchi(vchiq_use_service(service->handle));
     733                 :       8488 :         return ret;
     734                 :            : }
     735                 :            : EXPORT_SYMBOL(vchi_service_use);
     736                 :            : 
     737                 :            : /***********************************************************
     738                 :            :  * Name: vchi_service_release
     739                 :            :  *
     740                 :            :  * Arguments: const VCHI_SERVICE_HANDLE_T handle
     741                 :            :  *
     742                 :            :  * Description: Routine to decrement refcount on a service
     743                 :            :  *
     744                 :            :  * Returns: void
     745                 :            :  *
     746                 :            :  ***********************************************************/
     747                 :       9729 : int32_t vchi_service_release(const VCHI_SERVICE_HANDLE_T handle)
     748                 :            : {
     749                 :            :         int32_t ret = -1;
     750                 :            : 
     751                 :            :         struct shim_service *service = (struct shim_service *)handle;
     752         [ +  + ]:       9729 :         if (service)
     753                 :       9728 :                 ret = vchiq_status_to_vchi(
     754                 :            :                         vchiq_release_service(service->handle));
     755                 :       9730 :         return ret;
     756                 :            : }
     757                 :            : EXPORT_SYMBOL(vchi_service_release);

Generated by: LCOV version 1.14