1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
|
/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/export.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/of_address.h>
#include <linux/dma-contiguous.h>
#include <soc/qcom/scm.h>
#define SHARED_HEAP_SVC_ID 0x2
#define SHARED_HEAP_CMD_ID 0xB
#define SHARED_HEAP_TYPE_READ 0x1
#define SHARED_HEAP_TYPE_WRITE 0x2
static int msm_shared_heap_unlock(dma_addr_t base,
size_t size, unsigned int proc_type)
{
int rc;
struct shared_heap_unlock {
u32 start;
u32 size;
u32 proc;
u32 share_type;
} request;
int resp = 0;
struct scm_desc desc = {0};
desc.arginfo = SCM_ARGS(4);
desc.args[0] = request.start = base;
desc.args[1] = request.size = size;
desc.args[2] = request.proc = proc_type;
desc.args[3] = request.share_type = SHARED_HEAP_TYPE_READ |
SHARED_HEAP_TYPE_WRITE;
if (!is_scm_armv8())
rc = scm_call(SHARED_HEAP_SVC_ID, SHARED_HEAP_CMD_ID, &request,
sizeof(request), &resp, 1);
else
rc = scm_call2(SCM_SIP_FNID(SHARED_HEAP_SVC_ID,
SHARED_HEAP_CMD_ID), &desc);
if (rc)
pr_err("shared_heap: Failed to unlock the shared heap %d\n",
rc);
return rc;
}
static int msm_shared_heap_populate_base_and_size
(struct device_node *node, size_t *size,
dma_addr_t *base, struct device *priv)
{
int ret = 0;
struct device_node *pnode;
pnode = of_parse_phandle(node, "linux,contiguous-region", 0);
if (pnode != NULL) {
const u32 *addr;
u64 len;
addr = of_get_address(pnode, 0, &len, NULL);
if (!addr) {
of_node_put(pnode);
ret = -EINVAL;
goto out;
}
*size = cma_get_size(priv);
*base = cma_get_base(priv);
of_node_put(pnode);
} else {
pr_err("%s: Unable to parse phandle\n", __func__);
ret = -EINVAL;
}
out:
return ret;
}
static int get_heap_and_unlock(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
struct device *priv;
dma_addr_t base;
size_t size;
int proc_type;
int ret = 0;
priv = &pdev->dev;
ret = msm_shared_heap_populate_base_and_size(node, &size, &base, priv);
if (ret)
return ret;
ret = of_property_read_u32(node, "qcom,proc-id", &proc_type);
if (ret) {
pr_err("Unable to find the proc_type\n");
return ret;
}
ret = msm_shared_heap_unlock(base, size, proc_type);
if (ret)
pr_err("%s: Cannot unlock memory %pa of size %zx, error = %d\n",
__func__, &base, size, ret);
else
pr_info("shared_mem: Unlocked memory %pa of size %zx\n",
&base, size);
return ret;
}
static int msm_shared_memory_probe(struct platform_device *pdev)
{
int ret = 0;
if (pdev->dev.of_node)
ret = get_heap_and_unlock(pdev);
if (ret)
pr_err("%s: Unable to unlock heap due to error %d\n",
__func__, ret);
return ret;
}
static int msm_shared_memory_remove(struct platform_device *pdev)
{
return 0;
}
static struct of_device_id msm_shared_memory_table[] = {
{.compatible = "qcom,msm-shared-memory",
},
{}
};
static struct platform_driver msm_shared_memory = {
.probe = msm_shared_memory_probe,
.remove = msm_shared_memory_remove,
.driver = {
.name = "msm-shared-memory",
.of_match_table = msm_shared_memory_table,
},
};
static int __init msm_shared_memory_init(void)
{
return platform_driver_register(&msm_shared_memory);
}
static void __exit msm_shared_memory_exit(void)
{
platform_driver_unregister(&msm_shared_memory);
};
subsys_initcall(msm_shared_memory_init);
module_exit(msm_shared_memory_exit);
|