qcom_scm_hab.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2022-2024, Qualcomm Innovation Center, Inc. All rights reserved.
  4. */
  5. #define pr_fmt(fmt) __FILE__ ": " fmt
  6. #include <linux/module.h>
  7. #include <linux/habmm.h>
  8. #include <linux/qcom_scm.h>
  9. #include <linux/spinlock.h>
  10. #include <soc/qcom/qseecom_scm.h>
  11. #include "qcom_scm.h"
  12. /**
  13. * struct smc_params_s
  14. * @fn_id: Function id used for hab channel communication
  15. * @arginfo: Argument information used for hab channel communication
  16. * @args: The array of values used for hab cannel communication
  17. */
  18. struct smc_params_s {
  19. uint64_t fn_id;
  20. uint64_t arginfo;
  21. uint64_t args[MAX_SCM_ARGS];
  22. } __packed;
  23. static u32 nonatomic_handle;
  24. static u32 atomic_handle;
  25. static bool opened;
  26. int scm_qcpe_hab_open(void)
  27. {
  28. int ret;
  29. if (!opened) {
  30. ret = habmm_socket_open(&nonatomic_handle, MM_QCPE_VM1, 0, 0);
  31. if (ret) {
  32. pr_err("habmm_socket_open failed for nonatomic with ret = %d\n", ret);
  33. return ret;
  34. }
  35. ret = habmm_socket_open(&atomic_handle, MM_QCPE_VM1, 0, 0);
  36. if (ret) {
  37. pr_err("habmm_socket_open failed for atomic with ret = %d\n", ret);
  38. habmm_socket_close(nonatomic_handle);
  39. return ret;
  40. }
  41. opened = true;
  42. pr_info("HAB channel established\n");
  43. }
  44. return 0;
  45. }
  46. EXPORT_SYMBOL(scm_qcpe_hab_open);
  47. void scm_qcpe_hab_close(void)
  48. {
  49. if (opened) {
  50. habmm_socket_close(nonatomic_handle);
  51. habmm_socket_close(atomic_handle);
  52. opened = false;
  53. nonatomic_handle = atomic_handle = 0;
  54. }
  55. }
  56. EXPORT_SYMBOL(scm_qcpe_hab_close);
  57. /*
  58. * Send SMC over HAB, receive the response. Both operations are blocking.
  59. * This is meant to be called from non-atomic context.
  60. */
  61. static int scm_qcpe_hab_send_receive(struct smc_params_s *smc_params,
  62. u32 *size_bytes)
  63. {
  64. int ret;
  65. uint64_t fn = smc_params->fn_id;
  66. ret = habmm_socket_send(nonatomic_handle, smc_params, sizeof(*smc_params), 0);
  67. if (ret) {
  68. pr_err("HAB send failed for 0x%lx, nonatomic, ret= 0x%x\n", fn, ret);
  69. return ret;
  70. }
  71. memset(smc_params, 0x0, sizeof(*smc_params));
  72. do {
  73. *size_bytes = sizeof(*smc_params);
  74. ret = habmm_socket_recv(nonatomic_handle, smc_params, size_bytes, 0,
  75. HABMM_SOCKET_RECV_FLAGS_UNINTERRUPTIBLE);
  76. } while (-EAGAIN == ret);
  77. if (ret) {
  78. pr_err("HAB recv failed for 0x%lx, nonatomic, ret= 0x%x\n",
  79. fn, ret);
  80. return ret;
  81. }
  82. return 0;
  83. }
  84. /*
  85. * Send SMC over HAB, receive the response, in non-blocking mode.
  86. * This is meant to be called from atomic context.
  87. */
  88. static int scm_qcpe_hab_send_receive_atomic(struct smc_params_s *smc_params,
  89. u32 *size_bytes)
  90. {
  91. static DEFINE_SPINLOCK(qcom_scm_hab_atomic_lock);
  92. int ret;
  93. int fn = smc_params->fn_id;
  94. spin_lock_bh(&qcom_scm_hab_atomic_lock);
  95. do {
  96. ret = habmm_socket_send(atomic_handle, smc_params, sizeof(*smc_params),
  97. HABMM_SOCKET_SEND_FLAGS_NON_BLOCKING);
  98. } while (-EAGAIN == ret);
  99. if (ret) {
  100. pr_err("HAB send failed for 0x%lx, atomic, ret= 0x%x\n", fn, ret);
  101. spin_unlock_bh(&qcom_scm_hab_atomic_lock);
  102. return ret;
  103. }
  104. memset(smc_params, 0x0, sizeof(*smc_params));
  105. do {
  106. *size_bytes = sizeof(*smc_params);
  107. ret = habmm_socket_recv(atomic_handle, smc_params, size_bytes, 0,
  108. HABMM_SOCKET_RECV_FLAGS_NON_BLOCKING);
  109. } while ((-EAGAIN == ret) && (*size_bytes == 0));
  110. spin_unlock_bh(&qcom_scm_hab_atomic_lock);
  111. if (ret) {
  112. pr_err("HAB recv failed for syscall 0x%lx, atomic, ret= 0x%x\n",
  113. fn, ret);
  114. return ret;
  115. }
  116. return 0;
  117. }
  118. int scm_call_qcpe(const struct arm_smccc_args *smc,
  119. struct arm_smccc_res *res, const bool atomic)
  120. {
  121. u32 size_bytes;
  122. struct smc_params_s smc_params = {0,};
  123. int ret;
  124. if (!opened) {
  125. if (!atomic) {
  126. if (scm_qcpe_hab_open()) {
  127. pr_err("HAB channel re-open failed\n");
  128. return -ENODEV;
  129. }
  130. } else {
  131. pr_err("HAB channel is not opened\n");
  132. return -ENODEV;
  133. }
  134. }
  135. smc_params.fn_id = smc->args[0];
  136. smc_params.arginfo = smc->args[1];
  137. smc_params.args[0] = smc->args[2];
  138. smc_params.args[1] = smc->args[3];
  139. smc_params.args[2] = smc->args[4];
  140. smc_params.args[3] = smc->args[5];
  141. smc_params.args[4] = 0;
  142. if (!atomic) {
  143. ret = scm_qcpe_hab_send_receive(&smc_params, &size_bytes);
  144. if (ret) {
  145. pr_err("send/receive failed, non-atomic, ret= 0x%x\n",
  146. ret);
  147. goto err_ret;
  148. }
  149. } else {
  150. ret = scm_qcpe_hab_send_receive_atomic(&smc_params,
  151. &size_bytes);
  152. if (ret) {
  153. pr_err("send/receive failed, ret= 0x%x\n", ret);
  154. goto err_ret;
  155. }
  156. }
  157. if (size_bytes != sizeof(smc_params)) {
  158. pr_err("habmm_socket_recv expected size: %lu, actual=%u\n",
  159. sizeof(smc_params), size_bytes);
  160. ret = QCOM_SCM_ERROR;
  161. goto err_ret;
  162. }
  163. res->a1 = smc_params.args[1];
  164. res->a2 = smc_params.args[2];
  165. res->a3 = smc_params.args[3];
  166. res->a0 = smc_params.args[0];
  167. goto no_err;
  168. err_ret:
  169. if (!atomic) {
  170. /* In case of an error, try to recover the hab connection
  171. * for next time. This can only be done if called in
  172. * non-atomic context.
  173. */
  174. scm_qcpe_hab_close();
  175. if (scm_qcpe_hab_open())
  176. pr_err("scm_qcpe_hab_open failed\n");
  177. }
  178. no_err:
  179. return res->a0;
  180. }
  181. EXPORT_SYMBOL(scm_call_qcpe);
  182. MODULE_DESCRIPTION("SCM HAB driver");
  183. MODULE_LICENSE("GPL");