rmtfs_mem.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2017 Linaro Ltd.
  4. */
  5. #include <linux/kernel.h>
  6. #include <linux/cdev.h>
  7. #include <linux/err.h>
  8. #include <linux/module.h>
  9. #include <linux/platform_device.h>
  10. #include <linux/of.h>
  11. #include <linux/of_reserved_mem.h>
  12. #include <linux/dma-mapping.h>
  13. #include <linux/slab.h>
  14. #include <linux/uaccess.h>
  15. #include <linux/io.h>
  16. #include <linux/firmware/qcom/qcom_scm.h>
  17. #define QCOM_RMTFS_MEM_DEV_MAX (MINORMASK + 1)
  18. #define NUM_MAX_VMIDS 2
  19. static dev_t qcom_rmtfs_mem_major;
  20. struct qcom_rmtfs_mem {
  21. struct device dev;
  22. struct cdev cdev;
  23. void *base;
  24. phys_addr_t addr;
  25. phys_addr_t size;
  26. unsigned int client_id;
  27. u64 perms;
  28. };
  29. static ssize_t qcom_rmtfs_mem_show(struct device *dev,
  30. struct device_attribute *attr,
  31. char *buf);
  32. static DEVICE_ATTR(phys_addr, 0444, qcom_rmtfs_mem_show, NULL);
  33. static DEVICE_ATTR(size, 0444, qcom_rmtfs_mem_show, NULL);
  34. static DEVICE_ATTR(client_id, 0444, qcom_rmtfs_mem_show, NULL);
  35. static ssize_t qcom_rmtfs_mem_show(struct device *dev,
  36. struct device_attribute *attr,
  37. char *buf)
  38. {
  39. struct qcom_rmtfs_mem *rmtfs_mem = container_of(dev,
  40. struct qcom_rmtfs_mem,
  41. dev);
  42. if (attr == &dev_attr_phys_addr)
  43. return sprintf(buf, "%pa\n", &rmtfs_mem->addr);
  44. if (attr == &dev_attr_size)
  45. return sprintf(buf, "%pa\n", &rmtfs_mem->size);
  46. if (attr == &dev_attr_client_id)
  47. return sprintf(buf, "%d\n", rmtfs_mem->client_id);
  48. return -EINVAL;
  49. }
  50. static struct attribute *qcom_rmtfs_mem_attrs[] = {
  51. &dev_attr_phys_addr.attr,
  52. &dev_attr_size.attr,
  53. &dev_attr_client_id.attr,
  54. NULL
  55. };
  56. ATTRIBUTE_GROUPS(qcom_rmtfs_mem);
  57. static int qcom_rmtfs_mem_open(struct inode *inode, struct file *filp)
  58. {
  59. struct qcom_rmtfs_mem *rmtfs_mem = container_of(inode->i_cdev,
  60. struct qcom_rmtfs_mem,
  61. cdev);
  62. get_device(&rmtfs_mem->dev);
  63. filp->private_data = rmtfs_mem;
  64. return 0;
  65. }
  66. static ssize_t qcom_rmtfs_mem_read(struct file *filp,
  67. char __user *buf, size_t count, loff_t *f_pos)
  68. {
  69. struct qcom_rmtfs_mem *rmtfs_mem = filp->private_data;
  70. if (*f_pos >= rmtfs_mem->size)
  71. return 0;
  72. if (*f_pos + count >= rmtfs_mem->size)
  73. count = rmtfs_mem->size - *f_pos;
  74. if (copy_to_user(buf, rmtfs_mem->base + *f_pos, count))
  75. return -EFAULT;
  76. *f_pos += count;
  77. return count;
  78. }
  79. static ssize_t qcom_rmtfs_mem_write(struct file *filp,
  80. const char __user *buf, size_t count,
  81. loff_t *f_pos)
  82. {
  83. struct qcom_rmtfs_mem *rmtfs_mem = filp->private_data;
  84. if (*f_pos >= rmtfs_mem->size)
  85. return 0;
  86. if (*f_pos + count >= rmtfs_mem->size)
  87. count = rmtfs_mem->size - *f_pos;
  88. if (copy_from_user(rmtfs_mem->base + *f_pos, buf, count))
  89. return -EFAULT;
  90. *f_pos += count;
  91. return count;
  92. }
  93. static int qcom_rmtfs_mem_release(struct inode *inode, struct file *filp)
  94. {
  95. struct qcom_rmtfs_mem *rmtfs_mem = filp->private_data;
  96. put_device(&rmtfs_mem->dev);
  97. return 0;
  98. }
  99. static const struct class rmtfs_class = {
  100. .name = "rmtfs",
  101. };
  102. static int qcom_rmtfs_mem_mmap(struct file *filep, struct vm_area_struct *vma)
  103. {
  104. struct qcom_rmtfs_mem *rmtfs_mem = filep->private_data;
  105. if (vma->vm_end - vma->vm_start > rmtfs_mem->size) {
  106. dev_dbg(&rmtfs_mem->dev,
  107. "vm_end[%lu] - vm_start[%lu] [%lu] > mem->size[%pa]\n",
  108. vma->vm_end, vma->vm_start,
  109. (vma->vm_end - vma->vm_start), &rmtfs_mem->size);
  110. return -EINVAL;
  111. }
  112. vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
  113. return remap_pfn_range(vma,
  114. vma->vm_start,
  115. rmtfs_mem->addr >> PAGE_SHIFT,
  116. vma->vm_end - vma->vm_start,
  117. vma->vm_page_prot);
  118. }
  119. static const struct file_operations qcom_rmtfs_mem_fops = {
  120. .owner = THIS_MODULE,
  121. .open = qcom_rmtfs_mem_open,
  122. .read = qcom_rmtfs_mem_read,
  123. .write = qcom_rmtfs_mem_write,
  124. .release = qcom_rmtfs_mem_release,
  125. .llseek = default_llseek,
  126. .mmap = qcom_rmtfs_mem_mmap,
  127. };
  128. static void qcom_rmtfs_mem_release_device(struct device *dev)
  129. {
  130. struct qcom_rmtfs_mem *rmtfs_mem = container_of(dev,
  131. struct qcom_rmtfs_mem,
  132. dev);
  133. kfree(rmtfs_mem);
  134. }
  135. static int qcom_rmtfs_mem_probe(struct platform_device *pdev)
  136. {
  137. struct device_node *node = pdev->dev.of_node;
  138. struct qcom_scm_vmperm perms[NUM_MAX_VMIDS + 1];
  139. struct reserved_mem *rmem;
  140. struct qcom_rmtfs_mem *rmtfs_mem;
  141. u32 client_id;
  142. u32 vmid[NUM_MAX_VMIDS];
  143. int num_vmids;
  144. int ret, i;
  145. rmem = of_reserved_mem_lookup(node);
  146. if (!rmem) {
  147. dev_err(&pdev->dev, "failed to acquire memory region\n");
  148. return -EINVAL;
  149. }
  150. ret = of_property_read_u32(node, "qcom,client-id", &client_id);
  151. if (ret) {
  152. dev_err(&pdev->dev, "failed to parse \"qcom,client-id\"\n");
  153. return ret;
  154. }
  155. rmtfs_mem = kzalloc_obj(*rmtfs_mem);
  156. if (!rmtfs_mem)
  157. return -ENOMEM;
  158. rmtfs_mem->addr = rmem->base;
  159. rmtfs_mem->client_id = client_id;
  160. rmtfs_mem->size = rmem->size;
  161. /*
  162. * If requested, discard the first and last 4k block in order to ensure
  163. * that the rmtfs region isn't adjacent to other protected regions.
  164. */
  165. if (of_property_read_bool(node, "qcom,use-guard-pages")) {
  166. rmtfs_mem->addr += SZ_4K;
  167. rmtfs_mem->size -= 2 * SZ_4K;
  168. }
  169. device_initialize(&rmtfs_mem->dev);
  170. rmtfs_mem->dev.parent = &pdev->dev;
  171. rmtfs_mem->dev.groups = qcom_rmtfs_mem_groups;
  172. rmtfs_mem->dev.release = qcom_rmtfs_mem_release_device;
  173. rmtfs_mem->base = devm_memremap(&rmtfs_mem->dev, rmtfs_mem->addr,
  174. rmtfs_mem->size, MEMREMAP_WC);
  175. if (IS_ERR(rmtfs_mem->base)) {
  176. dev_err(&pdev->dev, "failed to remap rmtfs_mem region\n");
  177. ret = PTR_ERR(rmtfs_mem->base);
  178. goto put_device;
  179. }
  180. cdev_init(&rmtfs_mem->cdev, &qcom_rmtfs_mem_fops);
  181. rmtfs_mem->cdev.owner = THIS_MODULE;
  182. dev_set_name(&rmtfs_mem->dev, "qcom_rmtfs_mem%d", client_id);
  183. rmtfs_mem->dev.id = client_id;
  184. rmtfs_mem->dev.class = &rmtfs_class;
  185. rmtfs_mem->dev.devt = MKDEV(MAJOR(qcom_rmtfs_mem_major), client_id);
  186. ret = cdev_device_add(&rmtfs_mem->cdev, &rmtfs_mem->dev);
  187. if (ret) {
  188. dev_err(&pdev->dev, "failed to add cdev: %d\n", ret);
  189. goto put_device;
  190. }
  191. num_vmids = of_property_count_u32_elems(node, "qcom,vmid");
  192. if (num_vmids == -EINVAL) {
  193. /* qcom,vmid is optional */
  194. num_vmids = 0;
  195. } else if (num_vmids < 0) {
  196. dev_err(&pdev->dev, "failed to count qcom,vmid elements: %d\n", num_vmids);
  197. ret = num_vmids;
  198. goto remove_cdev;
  199. } else if (num_vmids > NUM_MAX_VMIDS) {
  200. dev_warn(&pdev->dev,
  201. "too many VMIDs (%d) specified! Only mapping first %d entries\n",
  202. num_vmids, NUM_MAX_VMIDS);
  203. num_vmids = NUM_MAX_VMIDS;
  204. }
  205. ret = of_property_read_u32_array(node, "qcom,vmid", vmid, num_vmids);
  206. if (ret < 0 && ret != -EINVAL) {
  207. dev_err(&pdev->dev, "failed to parse qcom,vmid\n");
  208. goto remove_cdev;
  209. } else if (!ret) {
  210. if (!qcom_scm_is_available()) {
  211. ret = -EPROBE_DEFER;
  212. goto remove_cdev;
  213. }
  214. perms[0].vmid = QCOM_SCM_VMID_HLOS;
  215. perms[0].perm = QCOM_SCM_PERM_RW;
  216. for (i = 0; i < num_vmids; i++) {
  217. perms[i + 1].vmid = vmid[i];
  218. perms[i + 1].perm = QCOM_SCM_PERM_RW;
  219. }
  220. rmtfs_mem->perms = BIT(QCOM_SCM_VMID_HLOS);
  221. ret = qcom_scm_assign_mem(rmtfs_mem->addr, rmtfs_mem->size,
  222. &rmtfs_mem->perms, perms, num_vmids + 1);
  223. if (ret < 0) {
  224. dev_err(&pdev->dev, "assign memory failed\n");
  225. goto remove_cdev;
  226. }
  227. }
  228. dev_set_drvdata(&pdev->dev, rmtfs_mem);
  229. return 0;
  230. remove_cdev:
  231. cdev_device_del(&rmtfs_mem->cdev, &rmtfs_mem->dev);
  232. put_device:
  233. put_device(&rmtfs_mem->dev);
  234. return ret;
  235. }
  236. static void qcom_rmtfs_mem_remove(struct platform_device *pdev)
  237. {
  238. struct qcom_rmtfs_mem *rmtfs_mem = dev_get_drvdata(&pdev->dev);
  239. struct qcom_scm_vmperm perm;
  240. if (rmtfs_mem->perms) {
  241. perm.vmid = QCOM_SCM_VMID_HLOS;
  242. perm.perm = QCOM_SCM_PERM_RW;
  243. qcom_scm_assign_mem(rmtfs_mem->addr, rmtfs_mem->size,
  244. &rmtfs_mem->perms, &perm, 1);
  245. }
  246. cdev_device_del(&rmtfs_mem->cdev, &rmtfs_mem->dev);
  247. put_device(&rmtfs_mem->dev);
  248. }
  249. static const struct of_device_id qcom_rmtfs_mem_of_match[] = {
  250. { .compatible = "qcom,rmtfs-mem" },
  251. {}
  252. };
  253. MODULE_DEVICE_TABLE(of, qcom_rmtfs_mem_of_match);
  254. static struct platform_driver qcom_rmtfs_mem_driver = {
  255. .probe = qcom_rmtfs_mem_probe,
  256. .remove = qcom_rmtfs_mem_remove,
  257. .driver = {
  258. .name = "qcom_rmtfs_mem",
  259. .of_match_table = qcom_rmtfs_mem_of_match,
  260. },
  261. };
  262. static int __init qcom_rmtfs_mem_init(void)
  263. {
  264. int ret;
  265. ret = class_register(&rmtfs_class);
  266. if (ret)
  267. return ret;
  268. ret = alloc_chrdev_region(&qcom_rmtfs_mem_major, 0,
  269. QCOM_RMTFS_MEM_DEV_MAX, "qcom_rmtfs_mem");
  270. if (ret < 0) {
  271. pr_err("qcom_rmtfs_mem: failed to allocate char dev region\n");
  272. goto unregister_class;
  273. }
  274. ret = platform_driver_register(&qcom_rmtfs_mem_driver);
  275. if (ret < 0) {
  276. pr_err("qcom_rmtfs_mem: failed to register rmtfs_mem driver\n");
  277. goto unregister_chrdev;
  278. }
  279. return 0;
  280. unregister_chrdev:
  281. unregister_chrdev_region(qcom_rmtfs_mem_major, QCOM_RMTFS_MEM_DEV_MAX);
  282. unregister_class:
  283. class_unregister(&rmtfs_class);
  284. return ret;
  285. }
  286. module_init(qcom_rmtfs_mem_init);
  287. static void __exit qcom_rmtfs_mem_exit(void)
  288. {
  289. platform_driver_unregister(&qcom_rmtfs_mem_driver);
  290. unregister_chrdev_region(qcom_rmtfs_mem_major, QCOM_RMTFS_MEM_DEV_MAX);
  291. class_unregister(&rmtfs_class);
  292. }
  293. module_exit(qcom_rmtfs_mem_exit);
  294. MODULE_AUTHOR("Linaro Ltd");
  295. MODULE_DESCRIPTION("Qualcomm Remote Filesystem memory driver");
  296. MODULE_LICENSE("GPL v2");