PageRenderTime 51ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_shim.c

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