Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

staging: vc04_services: merge vchiq_kern_lib.c into vchiq_arm.c

There are two incompatible definitions of 'vchiq_instance_struct', so
passing them through vchiq_initialise(), vchiq_connect() or another
such interface is broken, as shown by building the driver with link-time
optimizations:

drivers/staging/vc04_services/interface/vchiq_arm/vchiq_if.h:129:0: error: type of 'vchiq_initialise' does not match original declaration [-Werror=lto-type-mismatch]
extern VCHIQ_STATUS_T vchiq_initialise(VCHIQ_INSTANCE_T *pinstance);

drivers/staging/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c:68:0: note: 'vchiq_initialise' was previously declared here
VCHIQ_STATUS_T vchiq_initialise(VCHIQ_INSTANCE_T *instance_out)

drivers/staging/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c:68:0: note: code may be misoptimized unless -fno-strict-aliasing is used
drivers/staging/vc04_services/interface/vchiq_arm/vchiq_if.h:131:0: error: type of 'vchiq_connect' does not match original declaration [-Werror=lto-type-mismatch]
extern VCHIQ_STATUS_T vchiq_connect(VCHIQ_INSTANCE_T instance);

drivers/staging/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c:168:0: note: 'vchiq_connect' was previously declared here
VCHIQ_STATUS_T vchiq_connect(VCHIQ_INSTANCE_T instance)

It's possible that only one of the two sides actually access the members,
but it's clear that they need to agree on the layout. The easiest way
to achieve this appears to be to merge the two files into one. I tried
moving the structure definition into a shared header first, but ended
up running into too many interdependencies that way.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Acked-by: Stefan Wahren <stefan.wahren@i2se.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Arnd Bergmann and committed by
Greg Kroah-Hartman
5c5e6ef6 e5fe0af5

+369 -432
-1
drivers/staging/vc04_services/Makefile
··· 4 4 vchiq-objs := \ 5 5 interface/vchiq_arm/vchiq_core.o \ 6 6 interface/vchiq_arm/vchiq_arm.o \ 7 - interface/vchiq_arm/vchiq_kern_lib.o \ 8 7 interface/vchiq_arm/vchiq_2835_arm.o \ 9 8 interface/vchiq_arm/vchiq_debugfs.o \ 10 9 interface/vchiq_arm/vchiq_shim.o \
+369
drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
··· 193 193 vchiq_static_assert(ARRAY_SIZE(ioctl_names) == 194 194 (VCHIQ_IOC_MAX + 1)); 195 195 196 + static VCHIQ_STATUS_T 197 + vchiq_blocking_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle, void *data, 198 + unsigned int size, VCHIQ_BULK_DIR_T dir); 199 + 200 + #define VCHIQ_INIT_RETRIES 10 201 + VCHIQ_STATUS_T vchiq_initialise(VCHIQ_INSTANCE_T *instance_out) 202 + { 203 + VCHIQ_STATUS_T status = VCHIQ_ERROR; 204 + VCHIQ_STATE_T *state; 205 + VCHIQ_INSTANCE_T instance = NULL; 206 + int i; 207 + 208 + vchiq_log_trace(vchiq_core_log_level, "%s called", __func__); 209 + 210 + /* VideoCore may not be ready due to boot up timing. 211 + * It may never be ready if kernel and firmware are mismatched,so don't 212 + * block forever. 213 + */ 214 + for (i = 0; i < VCHIQ_INIT_RETRIES; i++) { 215 + state = vchiq_get_state(); 216 + if (state) 217 + break; 218 + udelay(500); 219 + } 220 + if (i == VCHIQ_INIT_RETRIES) { 221 + vchiq_log_error(vchiq_core_log_level, 222 + "%s: videocore not initialized\n", __func__); 223 + goto failed; 224 + } else if (i > 0) { 225 + vchiq_log_warning(vchiq_core_log_level, 226 + "%s: videocore initialized after %d retries\n", 227 + __func__, i); 228 + } 229 + 230 + instance = kzalloc(sizeof(*instance), GFP_KERNEL); 231 + if (!instance) { 232 + vchiq_log_error(vchiq_core_log_level, 233 + "%s: error allocating vchiq instance\n", __func__); 234 + goto failed; 235 + } 236 + 237 + instance->connected = 0; 238 + instance->state = state; 239 + mutex_init(&instance->bulk_waiter_list_mutex); 240 + INIT_LIST_HEAD(&instance->bulk_waiter_list); 241 + 242 + *instance_out = instance; 243 + 244 + status = VCHIQ_SUCCESS; 245 + 246 + failed: 247 + vchiq_log_trace(vchiq_core_log_level, 248 + "%s(%p): returning %d", __func__, instance, status); 249 + 250 + return status; 251 + } 252 + EXPORT_SYMBOL(vchiq_initialise); 253 + 254 + VCHIQ_STATUS_T vchiq_shutdown(VCHIQ_INSTANCE_T instance) 255 + { 256 + VCHIQ_STATUS_T status; 257 + VCHIQ_STATE_T *state = instance->state; 258 + 259 + vchiq_log_trace(vchiq_core_log_level, 260 + "%s(%p) called", __func__, instance); 261 + 262 + if (mutex_lock_killable(&state->mutex) != 0) 263 + return VCHIQ_RETRY; 264 + 265 + /* Remove all services */ 266 + status = vchiq_shutdown_internal(state, instance); 267 + 268 + mutex_unlock(&state->mutex); 269 + 270 + vchiq_log_trace(vchiq_core_log_level, 271 + "%s(%p): returning %d", __func__, instance, status); 272 + 273 + if (status == VCHIQ_SUCCESS) { 274 + struct list_head *pos, *next; 275 + 276 + list_for_each_safe(pos, next, 277 + &instance->bulk_waiter_list) { 278 + struct bulk_waiter_node *waiter; 279 + 280 + waiter = list_entry(pos, 281 + struct bulk_waiter_node, 282 + list); 283 + list_del(pos); 284 + vchiq_log_info(vchiq_arm_log_level, 285 + "bulk_waiter - cleaned up %pK for pid %d", 286 + waiter, waiter->pid); 287 + kfree(waiter); 288 + } 289 + kfree(instance); 290 + } 291 + 292 + return status; 293 + } 294 + EXPORT_SYMBOL(vchiq_shutdown); 295 + 296 + static int vchiq_is_connected(VCHIQ_INSTANCE_T instance) 297 + { 298 + return instance->connected; 299 + } 300 + 301 + VCHIQ_STATUS_T vchiq_connect(VCHIQ_INSTANCE_T instance) 302 + { 303 + VCHIQ_STATUS_T status; 304 + VCHIQ_STATE_T *state = instance->state; 305 + 306 + vchiq_log_trace(vchiq_core_log_level, 307 + "%s(%p) called", __func__, instance); 308 + 309 + if (mutex_lock_killable(&state->mutex) != 0) { 310 + vchiq_log_trace(vchiq_core_log_level, 311 + "%s: call to mutex_lock failed", __func__); 312 + status = VCHIQ_RETRY; 313 + goto failed; 314 + } 315 + status = vchiq_connect_internal(state, instance); 316 + 317 + if (status == VCHIQ_SUCCESS) 318 + instance->connected = 1; 319 + 320 + mutex_unlock(&state->mutex); 321 + 322 + failed: 323 + vchiq_log_trace(vchiq_core_log_level, 324 + "%s(%p): returning %d", __func__, instance, status); 325 + 326 + return status; 327 + } 328 + EXPORT_SYMBOL(vchiq_connect); 329 + 330 + VCHIQ_STATUS_T vchiq_add_service( 331 + VCHIQ_INSTANCE_T instance, 332 + const VCHIQ_SERVICE_PARAMS_T *params, 333 + VCHIQ_SERVICE_HANDLE_T *phandle) 334 + { 335 + VCHIQ_STATUS_T status; 336 + VCHIQ_STATE_T *state = instance->state; 337 + VCHIQ_SERVICE_T *service = NULL; 338 + int srvstate; 339 + 340 + vchiq_log_trace(vchiq_core_log_level, 341 + "%s(%p) called", __func__, instance); 342 + 343 + *phandle = VCHIQ_SERVICE_HANDLE_INVALID; 344 + 345 + srvstate = vchiq_is_connected(instance) 346 + ? VCHIQ_SRVSTATE_LISTENING 347 + : VCHIQ_SRVSTATE_HIDDEN; 348 + 349 + service = vchiq_add_service_internal( 350 + state, 351 + params, 352 + srvstate, 353 + instance, 354 + NULL); 355 + 356 + if (service) { 357 + *phandle = service->handle; 358 + status = VCHIQ_SUCCESS; 359 + } else 360 + status = VCHIQ_ERROR; 361 + 362 + vchiq_log_trace(vchiq_core_log_level, 363 + "%s(%p): returning %d", __func__, instance, status); 364 + 365 + return status; 366 + } 367 + EXPORT_SYMBOL(vchiq_add_service); 368 + 369 + VCHIQ_STATUS_T vchiq_open_service( 370 + VCHIQ_INSTANCE_T instance, 371 + const VCHIQ_SERVICE_PARAMS_T *params, 372 + VCHIQ_SERVICE_HANDLE_T *phandle) 373 + { 374 + VCHIQ_STATUS_T status = VCHIQ_ERROR; 375 + VCHIQ_STATE_T *state = instance->state; 376 + VCHIQ_SERVICE_T *service = NULL; 377 + 378 + vchiq_log_trace(vchiq_core_log_level, 379 + "%s(%p) called", __func__, instance); 380 + 381 + *phandle = VCHIQ_SERVICE_HANDLE_INVALID; 382 + 383 + if (!vchiq_is_connected(instance)) 384 + goto failed; 385 + 386 + service = vchiq_add_service_internal(state, 387 + params, 388 + VCHIQ_SRVSTATE_OPENING, 389 + instance, 390 + NULL); 391 + 392 + if (service) { 393 + *phandle = service->handle; 394 + status = vchiq_open_service_internal(service, current->pid); 395 + if (status != VCHIQ_SUCCESS) { 396 + vchiq_remove_service(service->handle); 397 + *phandle = VCHIQ_SERVICE_HANDLE_INVALID; 398 + } 399 + } 400 + 401 + failed: 402 + vchiq_log_trace(vchiq_core_log_level, 403 + "%s(%p): returning %d", __func__, instance, status); 404 + 405 + return status; 406 + } 407 + EXPORT_SYMBOL(vchiq_open_service); 408 + 409 + VCHIQ_STATUS_T 410 + vchiq_queue_bulk_transmit(VCHIQ_SERVICE_HANDLE_T handle, 411 + const void *data, unsigned int size, void *userdata) 412 + { 413 + return vchiq_bulk_transfer(handle, 414 + VCHI_MEM_HANDLE_INVALID, (void *)data, size, userdata, 415 + VCHIQ_BULK_MODE_CALLBACK, VCHIQ_BULK_TRANSMIT); 416 + } 417 + EXPORT_SYMBOL(vchiq_queue_bulk_transmit); 418 + 419 + VCHIQ_STATUS_T 420 + vchiq_queue_bulk_receive(VCHIQ_SERVICE_HANDLE_T handle, void *data, 421 + unsigned int size, void *userdata) 422 + { 423 + return vchiq_bulk_transfer(handle, 424 + VCHI_MEM_HANDLE_INVALID, data, size, userdata, 425 + VCHIQ_BULK_MODE_CALLBACK, VCHIQ_BULK_RECEIVE); 426 + } 427 + EXPORT_SYMBOL(vchiq_queue_bulk_receive); 428 + 429 + VCHIQ_STATUS_T 430 + vchiq_bulk_transmit(VCHIQ_SERVICE_HANDLE_T handle, const void *data, 431 + unsigned int size, void *userdata, VCHIQ_BULK_MODE_T mode) 432 + { 433 + VCHIQ_STATUS_T status; 434 + 435 + switch (mode) { 436 + case VCHIQ_BULK_MODE_NOCALLBACK: 437 + case VCHIQ_BULK_MODE_CALLBACK: 438 + status = vchiq_bulk_transfer(handle, 439 + VCHI_MEM_HANDLE_INVALID, (void *)data, size, userdata, 440 + mode, VCHIQ_BULK_TRANSMIT); 441 + break; 442 + case VCHIQ_BULK_MODE_BLOCKING: 443 + status = vchiq_blocking_bulk_transfer(handle, 444 + (void *)data, size, VCHIQ_BULK_TRANSMIT); 445 + break; 446 + default: 447 + return VCHIQ_ERROR; 448 + } 449 + 450 + return status; 451 + } 452 + EXPORT_SYMBOL(vchiq_bulk_transmit); 453 + 454 + VCHIQ_STATUS_T 455 + vchiq_bulk_receive(VCHIQ_SERVICE_HANDLE_T handle, void *data, 456 + unsigned int size, void *userdata, VCHIQ_BULK_MODE_T mode) 457 + { 458 + VCHIQ_STATUS_T status; 459 + 460 + switch (mode) { 461 + case VCHIQ_BULK_MODE_NOCALLBACK: 462 + case VCHIQ_BULK_MODE_CALLBACK: 463 + status = vchiq_bulk_transfer(handle, 464 + VCHI_MEM_HANDLE_INVALID, data, size, userdata, 465 + mode, VCHIQ_BULK_RECEIVE); 466 + break; 467 + case VCHIQ_BULK_MODE_BLOCKING: 468 + status = vchiq_blocking_bulk_transfer(handle, 469 + (void *)data, size, VCHIQ_BULK_RECEIVE); 470 + break; 471 + default: 472 + return VCHIQ_ERROR; 473 + } 474 + 475 + return status; 476 + } 477 + EXPORT_SYMBOL(vchiq_bulk_receive); 478 + 479 + static VCHIQ_STATUS_T 480 + vchiq_blocking_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle, void *data, 481 + unsigned int size, VCHIQ_BULK_DIR_T dir) 482 + { 483 + VCHIQ_INSTANCE_T instance; 484 + VCHIQ_SERVICE_T *service; 485 + VCHIQ_STATUS_T status; 486 + struct bulk_waiter_node *waiter = NULL; 487 + struct list_head *pos; 488 + 489 + service = find_service_by_handle(handle); 490 + if (!service) 491 + return VCHIQ_ERROR; 492 + 493 + instance = service->instance; 494 + 495 + unlock_service(service); 496 + 497 + mutex_lock(&instance->bulk_waiter_list_mutex); 498 + list_for_each(pos, &instance->bulk_waiter_list) { 499 + if (list_entry(pos, struct bulk_waiter_node, 500 + list)->pid == current->pid) { 501 + waiter = list_entry(pos, 502 + struct bulk_waiter_node, 503 + list); 504 + list_del(pos); 505 + break; 506 + } 507 + } 508 + mutex_unlock(&instance->bulk_waiter_list_mutex); 509 + 510 + if (waiter) { 511 + VCHIQ_BULK_T *bulk = waiter->bulk_waiter.bulk; 512 + 513 + if (bulk) { 514 + /* This thread has an outstanding bulk transfer. */ 515 + if ((bulk->data != data) || 516 + (bulk->size != size)) { 517 + /* This is not a retry of the previous one. 518 + * Cancel the signal when the transfer 519 + * completes. 520 + */ 521 + spin_lock(&bulk_waiter_spinlock); 522 + bulk->userdata = NULL; 523 + spin_unlock(&bulk_waiter_spinlock); 524 + } 525 + } 526 + } 527 + 528 + if (!waiter) { 529 + waiter = kzalloc(sizeof(struct bulk_waiter_node), GFP_KERNEL); 530 + if (!waiter) { 531 + vchiq_log_error(vchiq_core_log_level, 532 + "%s - out of memory", __func__); 533 + return VCHIQ_ERROR; 534 + } 535 + } 536 + 537 + status = vchiq_bulk_transfer(handle, VCHI_MEM_HANDLE_INVALID, 538 + data, size, &waiter->bulk_waiter, VCHIQ_BULK_MODE_BLOCKING, 539 + dir); 540 + if ((status != VCHIQ_RETRY) || fatal_signal_pending(current) || 541 + !waiter->bulk_waiter.bulk) { 542 + VCHIQ_BULK_T *bulk = waiter->bulk_waiter.bulk; 543 + 544 + if (bulk) { 545 + /* Cancel the signal when the transfer 546 + * completes. 547 + */ 548 + spin_lock(&bulk_waiter_spinlock); 549 + bulk->userdata = NULL; 550 + spin_unlock(&bulk_waiter_spinlock); 551 + } 552 + kfree(waiter); 553 + } else { 554 + waiter->pid = current->pid; 555 + mutex_lock(&instance->bulk_waiter_list_mutex); 556 + list_add(&waiter->list, &instance->bulk_waiter_list); 557 + mutex_unlock(&instance->bulk_waiter_list_mutex); 558 + vchiq_log_info(vchiq_arm_log_level, 559 + "saved bulk_waiter %pK for pid %d", 560 + waiter, current->pid); 561 + } 562 + 563 + return status; 564 + } 196 565 /**************************************************************************** 197 566 * 198 567 * add_completion
-431
drivers/staging/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c
··· 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 <linux/kernel.h> 37 - #include <linux/module.h> 38 - #include <linux/mutex.h> 39 - 40 - #include "vchiq_core.h" 41 - #include "vchiq_arm.h" 42 - #include "vchiq_killable.h" 43 - 44 - /* ---- Public Variables ------------------------------------------------- */ 45 - 46 - /* ---- Private Constants and Types -------------------------------------- */ 47 - 48 - struct bulk_waiter_node { 49 - struct bulk_waiter bulk_waiter; 50 - int pid; 51 - struct list_head list; 52 - }; 53 - 54 - struct vchiq_instance_struct { 55 - VCHIQ_STATE_T *state; 56 - 57 - int connected; 58 - 59 - struct list_head bulk_waiter_list; 60 - struct mutex bulk_waiter_list_mutex; 61 - }; 62 - 63 - static VCHIQ_STATUS_T 64 - vchiq_blocking_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle, void *data, 65 - unsigned int size, VCHIQ_BULK_DIR_T dir); 66 - 67 - #define VCHIQ_INIT_RETRIES 10 68 - VCHIQ_STATUS_T vchiq_initialise(VCHIQ_INSTANCE_T *instance_out) 69 - { 70 - VCHIQ_STATUS_T status = VCHIQ_ERROR; 71 - VCHIQ_STATE_T *state; 72 - VCHIQ_INSTANCE_T instance = NULL; 73 - int i; 74 - 75 - vchiq_log_trace(vchiq_core_log_level, "%s called", __func__); 76 - 77 - /* VideoCore may not be ready due to boot up timing. 78 - * It may never be ready if kernel and firmware are mismatched,so don't 79 - * block forever. 80 - */ 81 - for (i = 0; i < VCHIQ_INIT_RETRIES; i++) { 82 - state = vchiq_get_state(); 83 - if (state) 84 - break; 85 - udelay(500); 86 - } 87 - if (i == VCHIQ_INIT_RETRIES) { 88 - vchiq_log_error(vchiq_core_log_level, 89 - "%s: videocore not initialized\n", __func__); 90 - goto failed; 91 - } else if (i > 0) { 92 - vchiq_log_warning(vchiq_core_log_level, 93 - "%s: videocore initialized after %d retries\n", 94 - __func__, i); 95 - } 96 - 97 - instance = kzalloc(sizeof(*instance), GFP_KERNEL); 98 - if (!instance) { 99 - vchiq_log_error(vchiq_core_log_level, 100 - "%s: error allocating vchiq instance\n", __func__); 101 - goto failed; 102 - } 103 - 104 - instance->connected = 0; 105 - instance->state = state; 106 - mutex_init(&instance->bulk_waiter_list_mutex); 107 - INIT_LIST_HEAD(&instance->bulk_waiter_list); 108 - 109 - *instance_out = instance; 110 - 111 - status = VCHIQ_SUCCESS; 112 - 113 - failed: 114 - vchiq_log_trace(vchiq_core_log_level, 115 - "%s(%p): returning %d", __func__, instance, status); 116 - 117 - return status; 118 - } 119 - EXPORT_SYMBOL(vchiq_initialise); 120 - 121 - VCHIQ_STATUS_T vchiq_shutdown(VCHIQ_INSTANCE_T instance) 122 - { 123 - VCHIQ_STATUS_T status; 124 - VCHIQ_STATE_T *state = instance->state; 125 - 126 - vchiq_log_trace(vchiq_core_log_level, 127 - "%s(%p) called", __func__, instance); 128 - 129 - if (mutex_lock_killable(&state->mutex) != 0) 130 - return VCHIQ_RETRY; 131 - 132 - /* Remove all services */ 133 - status = vchiq_shutdown_internal(state, instance); 134 - 135 - mutex_unlock(&state->mutex); 136 - 137 - vchiq_log_trace(vchiq_core_log_level, 138 - "%s(%p): returning %d", __func__, instance, status); 139 - 140 - if (status == VCHIQ_SUCCESS) { 141 - struct list_head *pos, *next; 142 - 143 - list_for_each_safe(pos, next, 144 - &instance->bulk_waiter_list) { 145 - struct bulk_waiter_node *waiter; 146 - 147 - waiter = list_entry(pos, 148 - struct bulk_waiter_node, 149 - list); 150 - list_del(pos); 151 - vchiq_log_info(vchiq_arm_log_level, 152 - "bulk_waiter - cleaned up %pK for pid %d", 153 - waiter, waiter->pid); 154 - kfree(waiter); 155 - } 156 - kfree(instance); 157 - } 158 - 159 - return status; 160 - } 161 - EXPORT_SYMBOL(vchiq_shutdown); 162 - 163 - static int vchiq_is_connected(VCHIQ_INSTANCE_T instance) 164 - { 165 - return instance->connected; 166 - } 167 - 168 - VCHIQ_STATUS_T vchiq_connect(VCHIQ_INSTANCE_T instance) 169 - { 170 - VCHIQ_STATUS_T status; 171 - VCHIQ_STATE_T *state = instance->state; 172 - 173 - vchiq_log_trace(vchiq_core_log_level, 174 - "%s(%p) called", __func__, instance); 175 - 176 - if (mutex_lock_killable(&state->mutex) != 0) { 177 - vchiq_log_trace(vchiq_core_log_level, 178 - "%s: call to mutex_lock failed", __func__); 179 - status = VCHIQ_RETRY; 180 - goto failed; 181 - } 182 - status = vchiq_connect_internal(state, instance); 183 - 184 - if (status == VCHIQ_SUCCESS) 185 - instance->connected = 1; 186 - 187 - mutex_unlock(&state->mutex); 188 - 189 - failed: 190 - vchiq_log_trace(vchiq_core_log_level, 191 - "%s(%p): returning %d", __func__, instance, status); 192 - 193 - return status; 194 - } 195 - EXPORT_SYMBOL(vchiq_connect); 196 - 197 - VCHIQ_STATUS_T vchiq_add_service( 198 - VCHIQ_INSTANCE_T instance, 199 - const VCHIQ_SERVICE_PARAMS_T *params, 200 - VCHIQ_SERVICE_HANDLE_T *phandle) 201 - { 202 - VCHIQ_STATUS_T status; 203 - VCHIQ_STATE_T *state = instance->state; 204 - VCHIQ_SERVICE_T *service = NULL; 205 - int srvstate; 206 - 207 - vchiq_log_trace(vchiq_core_log_level, 208 - "%s(%p) called", __func__, instance); 209 - 210 - *phandle = VCHIQ_SERVICE_HANDLE_INVALID; 211 - 212 - srvstate = vchiq_is_connected(instance) 213 - ? VCHIQ_SRVSTATE_LISTENING 214 - : VCHIQ_SRVSTATE_HIDDEN; 215 - 216 - service = vchiq_add_service_internal( 217 - state, 218 - params, 219 - srvstate, 220 - instance, 221 - NULL); 222 - 223 - if (service) { 224 - *phandle = service->handle; 225 - status = VCHIQ_SUCCESS; 226 - } else 227 - status = VCHIQ_ERROR; 228 - 229 - vchiq_log_trace(vchiq_core_log_level, 230 - "%s(%p): returning %d", __func__, instance, status); 231 - 232 - return status; 233 - } 234 - EXPORT_SYMBOL(vchiq_add_service); 235 - 236 - VCHIQ_STATUS_T vchiq_open_service( 237 - VCHIQ_INSTANCE_T instance, 238 - const VCHIQ_SERVICE_PARAMS_T *params, 239 - VCHIQ_SERVICE_HANDLE_T *phandle) 240 - { 241 - VCHIQ_STATUS_T status = VCHIQ_ERROR; 242 - VCHIQ_STATE_T *state = instance->state; 243 - VCHIQ_SERVICE_T *service = NULL; 244 - 245 - vchiq_log_trace(vchiq_core_log_level, 246 - "%s(%p) called", __func__, instance); 247 - 248 - *phandle = VCHIQ_SERVICE_HANDLE_INVALID; 249 - 250 - if (!vchiq_is_connected(instance)) 251 - goto failed; 252 - 253 - service = vchiq_add_service_internal(state, 254 - params, 255 - VCHIQ_SRVSTATE_OPENING, 256 - instance, 257 - NULL); 258 - 259 - if (service) { 260 - *phandle = service->handle; 261 - status = vchiq_open_service_internal(service, current->pid); 262 - if (status != VCHIQ_SUCCESS) { 263 - vchiq_remove_service(service->handle); 264 - *phandle = VCHIQ_SERVICE_HANDLE_INVALID; 265 - } 266 - } 267 - 268 - failed: 269 - vchiq_log_trace(vchiq_core_log_level, 270 - "%s(%p): returning %d", __func__, instance, status); 271 - 272 - return status; 273 - } 274 - EXPORT_SYMBOL(vchiq_open_service); 275 - 276 - VCHIQ_STATUS_T 277 - vchiq_queue_bulk_transmit(VCHIQ_SERVICE_HANDLE_T handle, 278 - const void *data, unsigned int size, void *userdata) 279 - { 280 - return vchiq_bulk_transfer(handle, 281 - VCHI_MEM_HANDLE_INVALID, (void *)data, size, userdata, 282 - VCHIQ_BULK_MODE_CALLBACK, VCHIQ_BULK_TRANSMIT); 283 - } 284 - EXPORT_SYMBOL(vchiq_queue_bulk_transmit); 285 - 286 - VCHIQ_STATUS_T 287 - vchiq_queue_bulk_receive(VCHIQ_SERVICE_HANDLE_T handle, void *data, 288 - unsigned int size, void *userdata) 289 - { 290 - return vchiq_bulk_transfer(handle, 291 - VCHI_MEM_HANDLE_INVALID, data, size, userdata, 292 - VCHIQ_BULK_MODE_CALLBACK, VCHIQ_BULK_RECEIVE); 293 - } 294 - EXPORT_SYMBOL(vchiq_queue_bulk_receive); 295 - 296 - VCHIQ_STATUS_T 297 - vchiq_bulk_transmit(VCHIQ_SERVICE_HANDLE_T handle, const void *data, 298 - unsigned int size, void *userdata, VCHIQ_BULK_MODE_T mode) 299 - { 300 - VCHIQ_STATUS_T status; 301 - 302 - switch (mode) { 303 - case VCHIQ_BULK_MODE_NOCALLBACK: 304 - case VCHIQ_BULK_MODE_CALLBACK: 305 - status = vchiq_bulk_transfer(handle, 306 - VCHI_MEM_HANDLE_INVALID, (void *)data, size, userdata, 307 - mode, VCHIQ_BULK_TRANSMIT); 308 - break; 309 - case VCHIQ_BULK_MODE_BLOCKING: 310 - status = vchiq_blocking_bulk_transfer(handle, 311 - (void *)data, size, VCHIQ_BULK_TRANSMIT); 312 - break; 313 - default: 314 - return VCHIQ_ERROR; 315 - } 316 - 317 - return status; 318 - } 319 - EXPORT_SYMBOL(vchiq_bulk_transmit); 320 - 321 - VCHIQ_STATUS_T 322 - vchiq_bulk_receive(VCHIQ_SERVICE_HANDLE_T handle, void *data, 323 - unsigned int size, void *userdata, VCHIQ_BULK_MODE_T mode) 324 - { 325 - VCHIQ_STATUS_T status; 326 - 327 - switch (mode) { 328 - case VCHIQ_BULK_MODE_NOCALLBACK: 329 - case VCHIQ_BULK_MODE_CALLBACK: 330 - status = vchiq_bulk_transfer(handle, 331 - VCHI_MEM_HANDLE_INVALID, data, size, userdata, 332 - mode, VCHIQ_BULK_RECEIVE); 333 - break; 334 - case VCHIQ_BULK_MODE_BLOCKING: 335 - status = vchiq_blocking_bulk_transfer(handle, 336 - (void *)data, size, VCHIQ_BULK_RECEIVE); 337 - break; 338 - default: 339 - return VCHIQ_ERROR; 340 - } 341 - 342 - return status; 343 - } 344 - EXPORT_SYMBOL(vchiq_bulk_receive); 345 - 346 - static VCHIQ_STATUS_T 347 - vchiq_blocking_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle, void *data, 348 - unsigned int size, VCHIQ_BULK_DIR_T dir) 349 - { 350 - VCHIQ_INSTANCE_T instance; 351 - VCHIQ_SERVICE_T *service; 352 - VCHIQ_STATUS_T status; 353 - struct bulk_waiter_node *waiter = NULL; 354 - struct list_head *pos; 355 - 356 - service = find_service_by_handle(handle); 357 - if (!service) 358 - return VCHIQ_ERROR; 359 - 360 - instance = service->instance; 361 - 362 - unlock_service(service); 363 - 364 - mutex_lock(&instance->bulk_waiter_list_mutex); 365 - list_for_each(pos, &instance->bulk_waiter_list) { 366 - if (list_entry(pos, struct bulk_waiter_node, 367 - list)->pid == current->pid) { 368 - waiter = list_entry(pos, 369 - struct bulk_waiter_node, 370 - list); 371 - list_del(pos); 372 - break; 373 - } 374 - } 375 - mutex_unlock(&instance->bulk_waiter_list_mutex); 376 - 377 - if (waiter) { 378 - VCHIQ_BULK_T *bulk = waiter->bulk_waiter.bulk; 379 - 380 - if (bulk) { 381 - /* This thread has an outstanding bulk transfer. */ 382 - if ((bulk->data != data) || 383 - (bulk->size != size)) { 384 - /* This is not a retry of the previous one. 385 - * Cancel the signal when the transfer 386 - * completes. 387 - */ 388 - spin_lock(&bulk_waiter_spinlock); 389 - bulk->userdata = NULL; 390 - spin_unlock(&bulk_waiter_spinlock); 391 - } 392 - } 393 - } 394 - 395 - if (!waiter) { 396 - waiter = kzalloc(sizeof(struct bulk_waiter_node), GFP_KERNEL); 397 - if (!waiter) { 398 - vchiq_log_error(vchiq_core_log_level, 399 - "%s - out of memory", __func__); 400 - return VCHIQ_ERROR; 401 - } 402 - } 403 - 404 - status = vchiq_bulk_transfer(handle, VCHI_MEM_HANDLE_INVALID, 405 - data, size, &waiter->bulk_waiter, VCHIQ_BULK_MODE_BLOCKING, 406 - dir); 407 - if ((status != VCHIQ_RETRY) || fatal_signal_pending(current) || 408 - !waiter->bulk_waiter.bulk) { 409 - VCHIQ_BULK_T *bulk = waiter->bulk_waiter.bulk; 410 - 411 - if (bulk) { 412 - /* Cancel the signal when the transfer 413 - * completes. 414 - */ 415 - spin_lock(&bulk_waiter_spinlock); 416 - bulk->userdata = NULL; 417 - spin_unlock(&bulk_waiter_spinlock); 418 - } 419 - kfree(waiter); 420 - } else { 421 - waiter->pid = current->pid; 422 - mutex_lock(&instance->bulk_waiter_list_mutex); 423 - list_add(&waiter->list, &instance->bulk_waiter_list); 424 - mutex_unlock(&instance->bulk_waiter_list_mutex); 425 - vchiq_log_info(vchiq_arm_log_level, 426 - "saved bulk_waiter %pK for pid %d", 427 - waiter, current->pid); 428 - } 429 - 430 - return status; 431 - }