hab_ghs.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
  4. * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  5. */
  6. #include "hab.h"
  7. #include "hab_ghs.h"
  8. #define GIPC_VM_SET_CNT 22
  9. /* same vmid assignment for all the vms. it should matches dt_gipc_path_name */
  10. static int mmid_order[GIPC_VM_SET_CNT] = {
  11. MM_AUD_1,
  12. MM_AUD_2,
  13. MM_AUD_3,
  14. MM_AUD_4,
  15. MM_CAM_1,
  16. MM_CAM_2,
  17. MM_DISP_1,
  18. MM_DISP_2,
  19. MM_DISP_3,
  20. MM_DISP_4,
  21. MM_DISP_5,
  22. MM_GFX,
  23. MM_VID,
  24. MM_MISC,
  25. MM_QCPE_VM1,
  26. MM_VID_2, /* newly recycled */
  27. 0,
  28. 0,
  29. MM_CLK_VM1,
  30. MM_CLK_VM2,
  31. MM_FDE_1,
  32. MM_BUFFERQ_1,
  33. };
  34. struct ghs_vmm_plugin_info_s ghs_vmm_plugin_info = {
  35. dt_gipc_path_name,
  36. mmid_order,
  37. 0,
  38. 0,
  39. };
  40. int get_dt_name_idx(int vmid_base, int mmid,
  41. struct ghs_vmm_plugin_info_s *plugin_info)
  42. {
  43. int idx = -1;
  44. int i;
  45. if (vmid_base < 0 || vmid_base > plugin_info->probe_cnt /
  46. GIPC_VM_SET_CNT) {
  47. pr_err("vmid %d overflow expected max %d\n", vmid_base,
  48. plugin_info->probe_cnt / GIPC_VM_SET_CNT);
  49. return idx;
  50. }
  51. for (i = 0; i < GIPC_VM_SET_CNT; i++) {
  52. if (mmid == plugin_info->mmid_dt_mapping[i]) {
  53. idx = vmid_base * GIPC_VM_SET_CNT + i;
  54. if (idx > plugin_info->probe_cnt) {
  55. pr_err("dt name idx %d overflow max %d\n",
  56. idx, plugin_info->probe_cnt);
  57. idx = -1;
  58. }
  59. break;
  60. }
  61. }
  62. return idx;
  63. }
  64. /* static struct physical_channel *habhyp_commdev_alloc(int id) */
  65. int habhyp_commdev_alloc(void **commdev, int is_be, char *name, int vmid_remote,
  66. struct hab_device *mmid_device)
  67. {
  68. struct ghs_vdev *dev = NULL;
  69. struct ghs_vdev_os *dev_os = NULL;
  70. struct physical_channel *pchan = NULL;
  71. struct physical_channel **ppchan = (struct physical_channel **)commdev;
  72. int ret = 0;
  73. if (ghs_vmm_plugin_info.curr > ghs_vmm_plugin_info.probe_cnt) {
  74. pr_err("too many commdev alloc %d, supported is %d\n",
  75. ghs_vmm_plugin_info.curr,
  76. ghs_vmm_plugin_info.probe_cnt);
  77. ret = -ENOENT;
  78. goto err;
  79. }
  80. /* common part for hyp_data */
  81. dev = kzalloc(sizeof(*dev), GFP_KERNEL);
  82. if (!dev) {
  83. ret = -ENOMEM;
  84. pr_err("allocate struct ghs_vdev failed %zu bytes on pchan %s\n",
  85. sizeof(*dev), name);
  86. goto err;
  87. }
  88. memset(dev, 0, sizeof(*dev));
  89. /* os specific part for hyp_data */
  90. dev_os = kzalloc(sizeof(*dev_os), GFP_KERNEL);
  91. if (!dev_os) {
  92. ret = -ENOMEM;
  93. pr_err("allocate ghs_vdev_os failed %zu bytes on pchan %s\n",
  94. sizeof(*dev_os), name);
  95. goto err;
  96. }
  97. dev->os_data = dev_os;
  98. spin_lock_init(&dev->io_lock);
  99. /*
  100. * TODO: ExtractEndpoint is in ghs_comm.c because it blocks.
  101. * Extrace and Request should be in roughly the same spot
  102. */
  103. ret = hab_gipc_ep_attach(is_be, name, vmid_remote, mmid_device, dev);
  104. if (ret)
  105. goto err;
  106. /* add pchan into the mmid_device list */
  107. pchan = hab_pchan_alloc(mmid_device, vmid_remote);
  108. if (!pchan) {
  109. pr_err("hab_pchan_alloc failed for %s, cnt %d\n",
  110. mmid_device->name, mmid_device->pchan_cnt);
  111. ret = -ENOMEM;
  112. goto err;
  113. }
  114. pchan->closed = 0;
  115. pchan->hyp_data = (void *)dev;
  116. pchan->is_be = is_be;
  117. strscpy(dev->name, name, sizeof(dev->name));
  118. strscpy(pchan->name, name, sizeof(pchan->name));
  119. *ppchan = pchan;
  120. dev->read_data = kmalloc(GIPC_RECV_BUFF_SIZE_BYTES, GFP_KERNEL);
  121. if (!dev->read_data) {
  122. ret = -ENOMEM;
  123. goto err;
  124. }
  125. ret = habhyp_commdev_create_dispatcher(pchan);
  126. if (ret)
  127. goto err;
  128. /* this value could be more than devp total */
  129. ghs_vmm_plugin_info.curr++;
  130. return 0;
  131. err:
  132. hab_pchan_put(pchan);
  133. kfree(dev);
  134. kfree(dev_os);
  135. return ret;
  136. }
  137. int habhyp_commdev_dealloc(void *commdev)
  138. {
  139. struct physical_channel *pchan = (struct physical_channel *)commdev;
  140. struct ghs_vdev *dev = pchan->hyp_data;
  141. /* os specific deallocation for this commdev */
  142. habhyp_commdev_dealloc_os(commdev);
  143. kfree(dev->read_data);
  144. kfree(dev->os_data);
  145. kfree(dev);
  146. pchan->closed = 1;
  147. pchan->hyp_data = NULL;
  148. if (get_refcnt(pchan->refcount) > 1) {
  149. pr_warn("potential leak pchan %s vchans %d refcnt %d\n",
  150. pchan->name, pchan->vcnt, get_refcnt(pchan->refcount));
  151. }
  152. hab_pchan_put(pchan);
  153. return 0;
  154. }
  155. void hab_hypervisor_unregister(void)
  156. {
  157. pr_debug("total %d\n", hab_driver.ndevices);
  158. hab_hypervisor_unregister_common();
  159. ghs_vmm_plugin_info.curr = 0;
  160. }
  161. int hab_hypervisor_register(void)
  162. {
  163. int ret = 0;
  164. /* os-specific registration work */
  165. ret = hab_hypervisor_register_os();
  166. return ret;
  167. }
  168. int hab_hypervisor_register_post(void) { return 0; }