blob: 8be3e36f72783c37a520477430b0d50d9cfd38d2 [file] [log] [blame]
Sahitya Tummala59e88272017-10-05 14:39:40 +05301/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
Nikhilesh Reddybc69c702015-06-01 16:08:32 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#define DRIVER_NAME "msm_sharedmem"
14#define pr_fmt(fmt) DRIVER_NAME ": %s: " fmt, __func__
15
16#include <linux/uio_driver.h>
17#include <linux/module.h>
18#include <linux/platform_device.h>
19#include <linux/err.h>
20#include <linux/of.h>
21#include <linux/dma-mapping.h>
Nikhilesh Reddy36f30122015-06-04 11:31:42 -070022
23#include <soc/qcom/secure_buffer.h>
24
Nikhilesh Reddybc69c702015-06-01 16:08:32 -070025#include "sharedmem_qmi.h"
26
27#define CLIENT_ID_PROP "qcom,client-id"
28
Nikhilesh Reddy36f30122015-06-04 11:31:42 -070029#define MPSS_RMTS_CLIENT_ID 1
30
Nikhilesh Reddybc69c702015-06-01 16:08:32 -070031static int uio_get_mem_index(struct uio_info *info, struct vm_area_struct *vma)
32{
33 if (vma->vm_pgoff >= MAX_UIO_MAPS)
34 return -EINVAL;
35
36 if (info->mem[vma->vm_pgoff].size == 0)
37 return -EINVAL;
38
39 return (int)vma->vm_pgoff;
40}
41
42static int sharedmem_mmap(struct uio_info *info, struct vm_area_struct *vma)
43{
44 int result;
45 struct uio_mem *mem;
46 int mem_index = uio_get_mem_index(info, vma);
47
48 if (mem_index < 0) {
49 pr_err("mem_index is invalid errno %d\n", mem_index);
50 return mem_index;
51 }
52
53 mem = info->mem + mem_index;
54
55 if (vma->vm_end - vma->vm_start > mem->size) {
Nikhilesh Reddy3d452512016-03-16 14:31:23 -070056 pr_err("vm_end[%lu] - vm_start[%lu] [%lu] > mem->size[%pa]\n",
Nikhilesh Reddybc69c702015-06-01 16:08:32 -070057 vma->vm_end, vma->vm_start,
Nikhilesh Reddy3d452512016-03-16 14:31:23 -070058 (vma->vm_end - vma->vm_start), &mem->size);
Nikhilesh Reddybc69c702015-06-01 16:08:32 -070059 return -EINVAL;
60 }
61 pr_debug("Attempting to setup mmap.\n");
62
63 vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
64
65 result = remap_pfn_range(vma,
66 vma->vm_start,
67 mem->addr >> PAGE_SHIFT,
68 vma->vm_end - vma->vm_start,
69 vma->vm_page_prot);
70 if (result != 0)
71 pr_err("mmap Failed with errno %d\n", result);
72 else
73 pr_debug("mmap success\n");
74
75 return result;
76}
77
Nikhilesh Reddy36f30122015-06-04 11:31:42 -070078/* Setup the shared ram permissions.
79 * This function currently supports the mpss client only.
80 */
81static void setup_shared_ram_perms(u32 client_id, phys_addr_t addr, u32 size)
82{
83 int ret;
84 u32 source_vmlist[1] = {VMID_HLOS};
85 int dest_vmids[2] = {VMID_HLOS, VMID_MSS_MSA};
86 int dest_perms[2] = {PERM_READ|PERM_WRITE,
87 PERM_READ|PERM_WRITE};
88
89 if (client_id != MPSS_RMTS_CLIENT_ID)
90 return;
91
92 ret = hyp_assign_phys(addr, size, source_vmlist, 1, dest_vmids,
93 dest_perms, 2);
94 if (ret != 0) {
95 if (ret == -EINVAL)
96 pr_warn("hyp_assign_phys is not supported!");
97 else
Prasad Sodagudid9cd67b2015-10-07 23:04:40 +053098 pr_err("hyp_assign_phys failed IPA=0x016%pa size=%u err=%d\n",
99 &addr, size, ret);
Nikhilesh Reddy36f30122015-06-04 11:31:42 -0700100 }
101}
102
Nikhilesh Reddybc69c702015-06-01 16:08:32 -0700103static int msm_sharedmem_probe(struct platform_device *pdev)
104{
105 int ret = 0;
106 struct uio_info *info = NULL;
107 struct resource *clnt_res = NULL;
108 u32 client_id = ((u32)~0U);
109 u32 shared_mem_size = 0;
Sahitya Tummala59e88272017-10-05 14:39:40 +0530110 u32 shared_mem_tot_sz = 0;
Nikhilesh Reddybc69c702015-06-01 16:08:32 -0700111 void *shared_mem = NULL;
112 phys_addr_t shared_mem_pyhsical = 0;
113 bool is_addr_dynamic = false;
114 struct sharemem_qmi_entry qmi_entry;
Sahitya Tummala59e88272017-10-05 14:39:40 +0530115 bool guard_memory = false;
Nikhilesh Reddybc69c702015-06-01 16:08:32 -0700116
117 /* Get the addresses from platform-data */
118 if (!pdev->dev.of_node) {
119 pr_err("Node not found\n");
120 ret = -ENODEV;
121 goto out;
122 }
123 clnt_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
124 if (!clnt_res) {
125 pr_err("resource not found\n");
126 return -ENODEV;
127 }
128
129 ret = of_property_read_u32(pdev->dev.of_node, CLIENT_ID_PROP,
130 &client_id);
131 if (ret) {
132 client_id = ((u32)~0U);
133 pr_warn("qcom,client-id property not found\n");
134 }
135
136 info = devm_kzalloc(&pdev->dev, sizeof(struct uio_info), GFP_KERNEL);
137 if (!info)
138 return -ENOMEM;
139
140 shared_mem_size = resource_size(clnt_res);
141 shared_mem_pyhsical = clnt_res->start;
142
143 if (shared_mem_size == 0) {
144 pr_err("Shared memory size is zero\n");
145 return -EINVAL;
146 }
147
148 if (shared_mem_pyhsical == 0) {
149 is_addr_dynamic = true;
Sahitya Tummala59e88272017-10-05 14:39:40 +0530150
151 /*
152 * If guard_memory is set, then the shared memory region
153 * will be guarded by SZ_4K at the start and at the end.
154 * This is needed to overcome the XPU limitation on few
155 * MSM HW, so as to make this memory not contiguous with
156 * other allocations that may possibly happen from other
157 * clients in the system.
158 */
159 guard_memory = of_property_read_bool(pdev->dev.of_node,
160 "qcom,guard-memory");
161
162 shared_mem_tot_sz = guard_memory ? shared_mem_size + SZ_8K :
163 shared_mem_size;
164
165 shared_mem = dma_alloc_coherent(&pdev->dev, shared_mem_tot_sz,
Nikhilesh Reddybc69c702015-06-01 16:08:32 -0700166 &shared_mem_pyhsical, GFP_KERNEL);
167 if (shared_mem == NULL) {
168 pr_err("Shared mem alloc client=%s, size=%u\n",
169 clnt_res->name, shared_mem_size);
170 return -ENOMEM;
171 }
Sahitya Tummala59e88272017-10-05 14:39:40 +0530172 if (guard_memory)
173 shared_mem_pyhsical += SZ_4K;
Nikhilesh Reddybc69c702015-06-01 16:08:32 -0700174 }
175
Nikhilesh Reddy36f30122015-06-04 11:31:42 -0700176 /* Set up the permissions for the shared ram that was allocated. */
177 setup_shared_ram_perms(client_id, shared_mem_pyhsical, shared_mem_size);
178
Nikhilesh Reddybc69c702015-06-01 16:08:32 -0700179 /* Setup device */
180 info->mmap = sharedmem_mmap; /* Custom mmap function. */
181 info->name = clnt_res->name;
182 info->version = "1.0";
183 info->mem[0].addr = shared_mem_pyhsical;
184 info->mem[0].size = shared_mem_size;
185 info->mem[0].memtype = UIO_MEM_PHYS;
186
187 ret = uio_register_device(&pdev->dev, info);
188 if (ret) {
189 pr_err("uio register failed ret=%d\n", ret);
190 goto out;
191 }
192 dev_set_drvdata(&pdev->dev, info);
193
194 qmi_entry.client_id = client_id;
195 qmi_entry.client_name = info->name;
196 qmi_entry.address = info->mem[0].addr;
197 qmi_entry.size = info->mem[0].size;
198 qmi_entry.is_addr_dynamic = is_addr_dynamic;
199
200 sharedmem_qmi_add_entry(&qmi_entry);
201 pr_info("Device created for client '%s'\n", clnt_res->name);
202out:
203 return ret;
204}
205
206static int msm_sharedmem_remove(struct platform_device *pdev)
207{
208 struct uio_info *info = dev_get_drvdata(&pdev->dev);
209
210 uio_unregister_device(info);
211
212 return 0;
213}
214
215static const struct of_device_id msm_sharedmem_of_match[] = {
216 {.compatible = "qcom,sharedmem-uio",},
217 {},
218};
219MODULE_DEVICE_TABLE(of, msm_sharedmem_of_match);
220
221static struct platform_driver msm_sharedmem_driver = {
222 .probe = msm_sharedmem_probe,
223 .remove = msm_sharedmem_remove,
224 .driver = {
225 .name = DRIVER_NAME,
226 .owner = THIS_MODULE,
227 .of_match_table = msm_sharedmem_of_match,
228 },
229};
230
231
232static int __init msm_sharedmem_init(void)
233{
234 int result;
235
236 result = sharedmem_qmi_init();
237 if (result < 0) {
238 pr_err("sharedmem_qmi_init failed result = %d\n", result);
239 return result;
240 }
241
242 result = platform_driver_register(&msm_sharedmem_driver);
243 if (result != 0) {
244 pr_err("Platform driver registration failed\n");
245 return result;
246 }
247 return 0;
248}
249
250static void __exit msm_sharedmem_exit(void)
251{
252 platform_driver_unregister(&msm_sharedmem_driver);
253 sharedmem_qmi_exit();
254}
255
256module_init(msm_sharedmem_init);
257module_exit(msm_sharedmem_exit);
258
259MODULE_LICENSE("GPL v2");