The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/contrib/vchiq/interface/vchiq_arm/vchiq_kern_lib.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /**
    2  * Copyright (c) 2010-2012 Broadcom. All rights reserved.
    3  *
    4  * Redistribution and use in source and binary forms, with or without
    5  * modification, are permitted provided that the following conditions
    6  * are met:
    7  * 1. Redistributions of source code must retain the above copyright
    8  *    notice, this list of conditions, and the following disclaimer,
    9  *    without modification.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  * 3. The names of the above-listed copyright holders may not be used
   14  *    to endorse or promote products derived from this software without
   15  *    specific prior written permission.
   16  *
   17  * ALTERNATIVELY, this software may be distributed under the terms of the
   18  * GNU General Public License ("GPL") version 2, as published by the Free
   19  * Software Foundation.
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
   22  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
   23  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   24  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
   25  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
   26  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   27  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
   28  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
   29  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
   30  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   31  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   32  */
   33 
   34 /* ---- Include Files ---------------------------------------------------- */
   35 
   36 #include "vchiq_core.h"
   37 #include "vchiq_arm.h"
   38 #include "vchiq_killable.h"
   39 
   40 /* ---- Public Variables ------------------------------------------------- */
   41 
   42 /* ---- Private Constants and Types -------------------------------------- */
   43 
   44 struct bulk_waiter_node {
   45         struct bulk_waiter bulk_waiter;
   46         int pid;
   47         struct list_head list;
   48 };
   49 
   50 struct vchiq_instance_struct {
   51         VCHIQ_STATE_T *state;
   52 
   53         int connected;
   54 
   55         struct list_head bulk_waiter_list;
   56         struct mutex bulk_waiter_list_mutex;
   57 };
   58 
   59 static VCHIQ_STATUS_T
   60 vchiq_blocking_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle, void *data,
   61         unsigned int size, VCHIQ_BULK_DIR_T dir);
   62 
   63 /****************************************************************************
   64 *
   65 *   vchiq_initialise
   66 *
   67 ***************************************************************************/
   68 #define VCHIQ_INIT_RETRIES 10
   69 VCHIQ_STATUS_T vchiq_initialise(VCHIQ_INSTANCE_T *instanceOut)
   70 {
   71         VCHIQ_STATUS_T status = VCHIQ_ERROR;
   72         VCHIQ_STATE_T *state;
   73         VCHIQ_INSTANCE_T instance = NULL;
   74         int i;
   75 
   76         vchiq_log_trace(vchiq_core_log_level, "%s called", __func__);
   77 
   78         /* VideoCore may not be ready due to boot up timing.
   79            It may never be ready if kernel and firmware are mismatched, so don't block forever. */
   80         for (i=0; i<VCHIQ_INIT_RETRIES; i++) {
   81                 state = vchiq_get_state();
   82                 if (state)
   83                         break;
   84                 udelay(500);
   85         }
   86         if (i==VCHIQ_INIT_RETRIES) {
   87                 vchiq_log_error(vchiq_core_log_level,
   88                         "%s: videocore not initialized\n", __func__);
   89                 goto failed;
   90         } else if (i>0) {
   91                 vchiq_log_warning(vchiq_core_log_level,
   92                         "%s: videocore initialized after %d retries\n", __func__, i);
   93         }
   94 
   95         instance = kzalloc(sizeof(*instance), GFP_KERNEL);
   96         if (!instance) {
   97                 vchiq_log_error(vchiq_core_log_level,
   98                         "%s: error allocating vchiq instance\n", __func__);
   99                 goto failed;
  100         }
  101 
  102         instance->connected = 0;
  103         instance->state = state;
  104         lmutex_init(&instance->bulk_waiter_list_mutex);
  105         INIT_LIST_HEAD(&instance->bulk_waiter_list);
  106 
  107         *instanceOut = instance;
  108 
  109         status = VCHIQ_SUCCESS;
  110 
  111 failed:
  112         vchiq_log_trace(vchiq_core_log_level,
  113                 "%s(%p): returning %d", __func__, instance, status);
  114 
  115         return status;
  116 }
  117 EXPORT_SYMBOL(vchiq_initialise);
  118 
  119 /****************************************************************************
  120 *
  121 *   vchiq_shutdown
  122 *
  123 ***************************************************************************/
  124 
  125 VCHIQ_STATUS_T vchiq_shutdown(VCHIQ_INSTANCE_T instance)
  126 {
  127         VCHIQ_STATUS_T status;
  128         VCHIQ_STATE_T *state = instance->state;
  129 
  130         vchiq_log_trace(vchiq_core_log_level,
  131                 "%s(%p) called", __func__, instance);
  132 
  133         if (lmutex_lock_interruptible(&state->mutex) != 0)
  134                 return VCHIQ_RETRY;
  135 
  136         /* Remove all services */
  137         status = vchiq_shutdown_internal(state, instance);
  138 
  139         lmutex_unlock(&state->mutex);
  140 
  141         vchiq_log_trace(vchiq_core_log_level,
  142                 "%s(%p): returning %d", __func__, instance, status);
  143 
  144         if (status == VCHIQ_SUCCESS) {
  145                 struct list_head *pos, *next;
  146                 list_for_each_safe(pos, next,
  147                                 &instance->bulk_waiter_list) {
  148                         struct bulk_waiter_node *waiter;
  149                         waiter = list_entry(pos,
  150                                         struct bulk_waiter_node,
  151                                         list);
  152                         list_del(pos);
  153                         vchiq_log_info(vchiq_arm_log_level,
  154                                         "bulk_waiter - cleaned up %x "
  155                                         "for pid %d",
  156                                         (unsigned int)waiter, waiter->pid);
  157                         _sema_destroy(&waiter->bulk_waiter.event);
  158 
  159                         kfree(waiter);
  160                 }
  161 
  162                 lmutex_destroy(&instance->bulk_waiter_list_mutex);
  163 
  164                 kfree(instance);
  165         }
  166 
  167         return status;
  168 }
  169 EXPORT_SYMBOL(vchiq_shutdown);
  170 
  171 /****************************************************************************
  172 *
  173 *   vchiq_is_connected
  174 *
  175 ***************************************************************************/
  176 
  177 static int vchiq_is_connected(VCHIQ_INSTANCE_T instance)
  178 {
  179         return instance->connected;
  180 }
  181 
  182 /****************************************************************************
  183 *
  184 *   vchiq_connect
  185 *
  186 ***************************************************************************/
  187 
  188 VCHIQ_STATUS_T vchiq_connect(VCHIQ_INSTANCE_T instance)
  189 {
  190         VCHIQ_STATUS_T status;
  191         VCHIQ_STATE_T *state = instance->state;
  192 
  193         vchiq_log_trace(vchiq_core_log_level,
  194                 "%s(%p) called", __func__, instance);
  195 
  196         if (lmutex_lock_interruptible(&state->mutex) != 0) {
  197                 vchiq_log_trace(vchiq_core_log_level,
  198                         "%s: call to lmutex_lock failed", __func__);
  199                 status = VCHIQ_RETRY;
  200                 goto failed;
  201         }
  202         status = vchiq_connect_internal(state, instance);
  203 
  204         if (status == VCHIQ_SUCCESS)
  205                 instance->connected = 1;
  206 
  207         lmutex_unlock(&state->mutex);
  208 
  209 failed:
  210         vchiq_log_trace(vchiq_core_log_level,
  211                 "%s(%p): returning %d", __func__, instance, status);
  212 
  213         return status;
  214 }
  215 EXPORT_SYMBOL(vchiq_connect);
  216 
  217 /****************************************************************************
  218 *
  219 *   vchiq_add_service
  220 *
  221 ***************************************************************************/
  222 
  223 VCHIQ_STATUS_T vchiq_add_service(
  224         VCHIQ_INSTANCE_T              instance,
  225         const VCHIQ_SERVICE_PARAMS_T *params,
  226         VCHIQ_SERVICE_HANDLE_T       *phandle)
  227 {
  228         VCHIQ_STATUS_T status;
  229         VCHIQ_STATE_T *state = instance->state;
  230         VCHIQ_SERVICE_T *service = NULL;
  231         int srvstate;
  232 
  233         vchiq_log_trace(vchiq_core_log_level,
  234                 "%s(%p) called", __func__, instance);
  235 
  236         *phandle = VCHIQ_SERVICE_HANDLE_INVALID;
  237 
  238         srvstate = vchiq_is_connected(instance)
  239                 ? VCHIQ_SRVSTATE_LISTENING
  240                 : VCHIQ_SRVSTATE_HIDDEN;
  241 
  242         service = vchiq_add_service_internal(
  243                 state,
  244                 params,
  245                 srvstate,
  246                 instance,
  247                 NULL);
  248 
  249         if (service) {
  250                 *phandle = service->handle;
  251                 status = VCHIQ_SUCCESS;
  252         } else
  253                 status = VCHIQ_ERROR;
  254 
  255         vchiq_log_trace(vchiq_core_log_level,
  256                 "%s(%p): returning %d", __func__, instance, status);
  257 
  258         return status;
  259 }
  260 EXPORT_SYMBOL(vchiq_add_service);
  261 
  262 /****************************************************************************
  263 *
  264 *   vchiq_open_service
  265 *
  266 ***************************************************************************/
  267 
  268 VCHIQ_STATUS_T vchiq_open_service(
  269         VCHIQ_INSTANCE_T              instance,
  270         const VCHIQ_SERVICE_PARAMS_T *params,
  271         VCHIQ_SERVICE_HANDLE_T       *phandle)
  272 {
  273         VCHIQ_STATUS_T   status = VCHIQ_ERROR;
  274         VCHIQ_STATE_T   *state = instance->state;
  275         VCHIQ_SERVICE_T *service = NULL;
  276 
  277         vchiq_log_trace(vchiq_core_log_level,
  278                 "%s(%p) called", __func__, instance);
  279 
  280         *phandle = VCHIQ_SERVICE_HANDLE_INVALID;
  281 
  282         if (!vchiq_is_connected(instance))
  283                 goto failed;
  284 
  285         service = vchiq_add_service_internal(state,
  286                 params,
  287                 VCHIQ_SRVSTATE_OPENING,
  288                 instance,
  289                 NULL);
  290 
  291         if (service) {
  292                 *phandle = service->handle;
  293                 status = vchiq_open_service_internal(service,
  294                     (uintptr_t)current);
  295                 if (status != VCHIQ_SUCCESS) {
  296                         vchiq_remove_service(service->handle);
  297                         *phandle = VCHIQ_SERVICE_HANDLE_INVALID;
  298                 }
  299         }
  300 
  301 failed:
  302         vchiq_log_trace(vchiq_core_log_level,
  303                 "%s(%p): returning %d", __func__, instance, status);
  304 
  305         return status;
  306 }
  307 EXPORT_SYMBOL(vchiq_open_service);
  308 
  309 VCHIQ_STATUS_T
  310 vchiq_queue_bulk_transmit(VCHIQ_SERVICE_HANDLE_T handle,
  311         void *data, unsigned int size, void *userdata)
  312 {
  313         return vchiq_bulk_transfer(handle,
  314                 VCHI_MEM_HANDLE_INVALID, data, size, userdata,
  315                 VCHIQ_BULK_MODE_CALLBACK, VCHIQ_BULK_TRANSMIT);
  316 }
  317 EXPORT_SYMBOL(vchiq_queue_bulk_transmit);
  318 
  319 VCHIQ_STATUS_T
  320 vchiq_queue_bulk_receive(VCHIQ_SERVICE_HANDLE_T handle, void *data,
  321         unsigned int size, void *userdata)
  322 {
  323         return vchiq_bulk_transfer(handle,
  324                 VCHI_MEM_HANDLE_INVALID, data, size, userdata,
  325                 VCHIQ_BULK_MODE_CALLBACK, VCHIQ_BULK_RECEIVE);
  326 }
  327 EXPORT_SYMBOL(vchiq_queue_bulk_receive);
  328 
  329 VCHIQ_STATUS_T
  330 vchiq_bulk_transmit(VCHIQ_SERVICE_HANDLE_T handle, void *data,
  331         unsigned int size, void *userdata, VCHIQ_BULK_MODE_T mode)
  332 {
  333         VCHIQ_STATUS_T status;
  334 
  335         switch (mode) {
  336         case VCHIQ_BULK_MODE_NOCALLBACK:
  337         case VCHIQ_BULK_MODE_CALLBACK:
  338                 status = vchiq_bulk_transfer(handle,
  339                         VCHI_MEM_HANDLE_INVALID, data, size, userdata,
  340                         mode, VCHIQ_BULK_TRANSMIT);
  341                 break;
  342         case VCHIQ_BULK_MODE_BLOCKING:
  343                 status = vchiq_blocking_bulk_transfer(handle,
  344                         data, size, VCHIQ_BULK_TRANSMIT);
  345                 break;
  346         default:
  347                 return VCHIQ_ERROR;
  348         }
  349 
  350         return status;
  351 }
  352 EXPORT_SYMBOL(vchiq_bulk_transmit);
  353 
  354 VCHIQ_STATUS_T
  355 vchiq_bulk_receive(VCHIQ_SERVICE_HANDLE_T handle, void *data,
  356         unsigned int size, void *userdata, VCHIQ_BULK_MODE_T mode)
  357 {
  358         VCHIQ_STATUS_T status;
  359 
  360         switch (mode) {
  361         case VCHIQ_BULK_MODE_NOCALLBACK:
  362         case VCHIQ_BULK_MODE_CALLBACK:
  363                 status = vchiq_bulk_transfer(handle,
  364                         VCHI_MEM_HANDLE_INVALID, data, size, userdata,
  365                         mode, VCHIQ_BULK_RECEIVE);
  366                 break;
  367         case VCHIQ_BULK_MODE_BLOCKING:
  368                 status = vchiq_blocking_bulk_transfer(handle,
  369                         data, size, VCHIQ_BULK_RECEIVE);
  370                 break;
  371         default:
  372                 return VCHIQ_ERROR;
  373         }
  374 
  375         return status;
  376 }
  377 EXPORT_SYMBOL(vchiq_bulk_receive);
  378 
  379 static VCHIQ_STATUS_T
  380 vchiq_blocking_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle, void *data,
  381         unsigned int size, VCHIQ_BULK_DIR_T dir)
  382 {
  383         VCHIQ_INSTANCE_T instance;
  384         VCHIQ_SERVICE_T *service;
  385         VCHIQ_STATUS_T status;
  386         struct bulk_waiter_node *waiter = NULL;
  387         struct list_head *pos;
  388 
  389         service = find_service_by_handle(handle);
  390         if (!service)
  391                 return VCHIQ_ERROR;
  392 
  393         instance = service->instance;
  394 
  395         unlock_service(service);
  396 
  397         lmutex_lock(&instance->bulk_waiter_list_mutex);
  398         list_for_each(pos, &instance->bulk_waiter_list) {
  399                 if (list_entry(pos, struct bulk_waiter_node,
  400                                 list)->pid == current->p_pid) {
  401                         waiter = list_entry(pos,
  402                                 struct bulk_waiter_node,
  403                                 list);
  404                         list_del(pos);
  405                         break;
  406                 }
  407         }
  408         lmutex_unlock(&instance->bulk_waiter_list_mutex);
  409 
  410         if (waiter) {
  411                 VCHIQ_BULK_T *bulk = waiter->bulk_waiter.bulk;
  412                 if (bulk) {
  413                         /* This thread has an outstanding bulk transfer. */
  414                         if ((bulk->data != data) ||
  415                                 (bulk->size != size)) {
  416                                 /* This is not a retry of the previous one.
  417                                 ** Cancel the signal when the transfer
  418                                 ** completes. */
  419                                 spin_lock(&bulk_waiter_spinlock);
  420                                 bulk->userdata = NULL;
  421                                 spin_unlock(&bulk_waiter_spinlock);
  422                         }
  423                 }
  424         }
  425 
  426         if (!waiter) {
  427                 waiter = kzalloc(sizeof(struct bulk_waiter_node), GFP_KERNEL);
  428                 if (!waiter) {
  429                         vchiq_log_error(vchiq_core_log_level,
  430                                 "%s - out of memory", __func__);
  431                         return VCHIQ_ERROR;
  432                 }
  433         }
  434 
  435         status = vchiq_bulk_transfer(handle, VCHI_MEM_HANDLE_INVALID,
  436                 data, size, &waiter->bulk_waiter, VCHIQ_BULK_MODE_BLOCKING,
  437                 dir);
  438         if ((status != VCHIQ_RETRY) || fatal_signal_pending(current) ||
  439                 !waiter->bulk_waiter.bulk) {
  440                 VCHIQ_BULK_T *bulk = waiter->bulk_waiter.bulk;
  441                 if (bulk) {
  442                         /* Cancel the signal when the transfer
  443                          ** completes. */
  444                         spin_lock(&bulk_waiter_spinlock);
  445                         bulk->userdata = NULL;
  446                         spin_unlock(&bulk_waiter_spinlock);
  447                 }
  448                 _sema_destroy(&waiter->bulk_waiter.event);
  449 
  450                 kfree(waiter);
  451         } else {
  452                 waiter->pid = current->p_pid;
  453                 lmutex_lock(&instance->bulk_waiter_list_mutex);
  454                 list_add(&waiter->list, &instance->bulk_waiter_list);
  455                 lmutex_unlock(&instance->bulk_waiter_list_mutex);
  456                 vchiq_log_info(vchiq_arm_log_level,
  457                                 "saved bulk_waiter %x for pid %d",
  458                                 (unsigned int)waiter, current->p_pid);
  459         }
  460 
  461         return status;
  462 }

Cache object: 8eb8bd0074866ba6399a684d81488faf


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.