msm_sharedmem.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
  4. * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved.
  5. */
  6. #define DRIVER_NAME "msm_sharedmem"
  7. #define pr_fmt(fmt) DRIVER_NAME ": %s: " fmt, __func__
  8. #include <linux/uio_driver.h>
  9. #include <linux/module.h>
  10. #include <linux/platform_device.h>
  11. #include <linux/err.h>
  12. #include <linux/of.h>
  13. #include <linux/dma-mapping.h>
  14. #include <linux/qcom_scm.h>
  15. #include <soc/qcom/secure_buffer.h>
  16. #define CLIENT_ID_PROP "qcom,client-id"
  17. #define MPSS_RMTS_CLIENT_ID 1
  18. static int uio_get_mem_index(struct uio_info *info, struct vm_area_struct *vma)
  19. {
  20. if (vma->vm_pgoff >= MAX_UIO_MAPS)
  21. return -EINVAL;
  22. if (info->mem[vma->vm_pgoff].size == 0)
  23. return -EINVAL;
  24. return (int)vma->vm_pgoff;
  25. }
  26. static int sharedmem_mmap(struct uio_info *info, struct vm_area_struct *vma)
  27. {
  28. int result;
  29. struct uio_mem *mem;
  30. int mem_index = uio_get_mem_index(info, vma);
  31. if (mem_index < 0) {
  32. pr_err("mem_index is invalid errno %d\n", mem_index);
  33. return mem_index;
  34. }
  35. mem = info->mem + mem_index;
  36. if (vma->vm_end - vma->vm_start > mem->size) {
  37. pr_err("vm_end[%lu] - vm_start[%lu] [%lu] > mem->size[%pa]\n",
  38. vma->vm_end, vma->vm_start,
  39. (vma->vm_end - vma->vm_start), &mem->size);
  40. return -EINVAL;
  41. }
  42. pr_debug("Attempting to setup mmap.\n");
  43. vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
  44. result = remap_pfn_range(vma,
  45. vma->vm_start,
  46. mem->addr >> PAGE_SHIFT,
  47. vma->vm_end - vma->vm_start,
  48. vma->vm_page_prot);
  49. if (result != 0)
  50. pr_err("mmap Failed with errno %d\n", result);
  51. else
  52. pr_debug("mmap success\n");
  53. return result;
  54. }
  55. /* Setup the shared ram permissions.
  56. * This function currently supports the mpss and nav clients only.
  57. */
  58. static void setup_shared_ram_perms(u32 client_id, phys_addr_t addr, u32 size,
  59. bool vm_nav_path)
  60. {
  61. struct qcom_scm_vmperm *dest_vmids;
  62. u64 source_vmlist = BIT(VMID_HLOS);
  63. int ret, nr;
  64. if (client_id != MPSS_RMTS_CLIENT_ID)
  65. return;
  66. if (vm_nav_path) {
  67. nr = 3;
  68. dest_vmids = kcalloc(nr, sizeof(struct qcom_scm_vmperm), GFP_KERNEL);
  69. if (!dest_vmids) {
  70. pr_err("failed to alloc memory when vm_nav_path=true\n");
  71. return;
  72. }
  73. *dest_vmids = (struct qcom_scm_vmperm){VMID_HLOS, PERM_READ|PERM_WRITE};
  74. *(dest_vmids + 1) = (struct qcom_scm_vmperm){VMID_MSS_MSA, PERM_READ|PERM_WRITE};
  75. *(dest_vmids + 2) = (struct qcom_scm_vmperm){VMID_NAV, PERM_READ|PERM_WRITE};
  76. } else {
  77. nr = 2;
  78. dest_vmids = kcalloc(nr, sizeof(struct qcom_scm_vmperm), GFP_KERNEL);
  79. if (!dest_vmids) {
  80. pr_err("failed to alloc memory when vm_nav_path=false\n");
  81. return;
  82. }
  83. *dest_vmids = (struct qcom_scm_vmperm){VMID_HLOS, PERM_READ|PERM_WRITE};
  84. *(dest_vmids + 1) = (struct qcom_scm_vmperm){VMID_MSS_MSA, PERM_READ|PERM_WRITE};
  85. }
  86. ret = qcom_scm_assign_mem(addr, size, &source_vmlist,
  87. dest_vmids, nr);
  88. kfree(dest_vmids);
  89. if (ret != 0) {
  90. if (ret == -EINVAL)
  91. pr_warn("qcom_scm_assign_mem is not supported!\n");
  92. else
  93. pr_err("qcom_scm_assign_mem failed IPA=0x016%pa size=%u err=%d\n",
  94. &addr, size, ret);
  95. }
  96. }
  97. static int msm_sharedmem_probe(struct platform_device *pdev)
  98. {
  99. int ret = 0;
  100. struct uio_info *info = NULL;
  101. struct resource *clnt_res = NULL;
  102. u32 client_id = ((u32)~0U);
  103. u32 shared_mem_size = 0;
  104. u32 shared_mem_tot_sz = 0;
  105. void *shared_mem = NULL;
  106. phys_addr_t shared_mem_pyhsical = 0;
  107. bool is_addr_dynamic = false;
  108. bool guard_memory = false;
  109. bool vm_nav_path = false;
  110. /* Get the addresses from platform-data */
  111. if (!pdev->dev.of_node) {
  112. pr_err("Node not found\n");
  113. ret = -ENODEV;
  114. goto out;
  115. }
  116. clnt_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  117. if (!clnt_res) {
  118. pr_err("resource not found\n");
  119. return -ENODEV;
  120. }
  121. ret = of_property_read_u32(pdev->dev.of_node, CLIENT_ID_PROP,
  122. &client_id);
  123. if (ret) {
  124. client_id = ((u32)~0U);
  125. pr_warn("qcom,client-id property not found\n");
  126. }
  127. info = devm_kzalloc(&pdev->dev, sizeof(struct uio_info), GFP_KERNEL);
  128. if (!info)
  129. return -ENOMEM;
  130. shared_mem_size = resource_size(clnt_res);
  131. shared_mem_pyhsical = clnt_res->start;
  132. if (shared_mem_size == 0) {
  133. pr_err("Shared memory size is zero\n");
  134. return -EINVAL;
  135. }
  136. if (shared_mem_pyhsical == 0) {
  137. is_addr_dynamic = true;
  138. /*
  139. * If guard_memory is set, then the shared memory region
  140. * will be guarded by SZ_4K at the start and at the end.
  141. * This is needed to overcome the XPU limitation on few
  142. * MSM HW, so as to make this memory not contiguous with
  143. * other allocations that may possibly happen from other
  144. * clients in the system.
  145. */
  146. guard_memory = of_property_read_bool(pdev->dev.of_node,
  147. "qcom,guard-memory");
  148. shared_mem_tot_sz = guard_memory ? shared_mem_size + SZ_8K :
  149. shared_mem_size;
  150. shared_mem = dma_alloc_coherent(&pdev->dev, shared_mem_tot_sz,
  151. &shared_mem_pyhsical, GFP_KERNEL);
  152. if (shared_mem == NULL) {
  153. pr_err("failed to alloc memory %d\n", shared_mem_tot_sz);
  154. return -ENOMEM;
  155. }
  156. if (guard_memory)
  157. shared_mem_pyhsical += SZ_4K;
  158. }
  159. /*
  160. * If this dtsi property is set, then the shared memory region
  161. * will be given access to vm-nav-path also.
  162. */
  163. vm_nav_path = of_property_read_bool(pdev->dev.of_node,
  164. "qcom,vm-nav-path");
  165. /* Set up the permissions for the shared ram that was allocated. */
  166. setup_shared_ram_perms(client_id, shared_mem_pyhsical, shared_mem_size,
  167. vm_nav_path);
  168. /* Setup device */
  169. info->mmap = sharedmem_mmap; /* Custom mmap function. */
  170. info->name = clnt_res->name;
  171. info->version = "1.0";
  172. info->mem[0].addr = shared_mem_pyhsical;
  173. info->mem[0].size = shared_mem_size;
  174. info->mem[0].memtype = UIO_MEM_PHYS;
  175. ret = uio_register_device(&pdev->dev, info);
  176. if (ret) {
  177. pr_err("uio register failed ret=%d\n", ret);
  178. goto out;
  179. }
  180. dev_set_drvdata(&pdev->dev, info);
  181. pr_info("Device created for client '%s'\n", clnt_res->name);
  182. out:
  183. return ret;
  184. }
  185. static int msm_sharedmem_remove(struct platform_device *pdev)
  186. {
  187. struct uio_info *info = dev_get_drvdata(&pdev->dev);
  188. uio_unregister_device(info);
  189. return 0;
  190. }
  191. static const struct of_device_id msm_sharedmem_of_match[] = {
  192. {.compatible = "qcom,sharedmem-uio",},
  193. {},
  194. };
  195. MODULE_DEVICE_TABLE(of, msm_sharedmem_of_match);
  196. static struct platform_driver msm_sharedmem_driver = {
  197. .probe = msm_sharedmem_probe,
  198. .remove = msm_sharedmem_remove,
  199. .driver = {
  200. .name = DRIVER_NAME,
  201. .of_match_table = msm_sharedmem_of_match,
  202. },
  203. };
  204. static int __init msm_sharedmem_init(void)
  205. {
  206. int result;
  207. result = platform_driver_register(&msm_sharedmem_driver);
  208. if (result != 0) {
  209. pr_err("Platform driver registration failed\n");
  210. return result;
  211. }
  212. return 0;
  213. }
  214. static void __exit msm_sharedmem_exit(void)
  215. {
  216. platform_driver_unregister(&msm_sharedmem_driver);
  217. }
  218. module_init(msm_sharedmem_init);
  219. module_exit(msm_sharedmem_exit);
  220. MODULE_LICENSE("GPL");