diff options
author | Suman Anna | 2014-08-29 15:38:44 -0500 |
---|---|---|
committer | Suman Anna | 2014-08-29 15:39:16 -0500 |
commit | a6a650e0e517fc1881525cdb15013836a9821a2d (patch) | |
tree | bb018a66be00d607526bfd186d904abc28834ab1 | |
parent | 951dbd6f870731f2431645604a768718fce182b8 (diff) | |
parent | 1d987626bd652ce5cc798fbf1383670bfb587871 (diff) | |
download | kernel-video-a6a650e0e517fc1881525cdb15013836a9821a2d.tar.gz kernel-video-a6a650e0e517fc1881525cdb15013836a9821a2d.tar.xz kernel-video-a6a650e0e517fc1881525cdb15013836a9821a2d.zip |
Merge branch 'rpmsg-linux-3.14.y' of git://git.ti.com/rpmsg/rpmsg into rpmsg-ti-linux-3.14.y
Pull in the base rpmsg tree that adds two new rpmsg client drivers:
rpmsg-rpc & rpmsg-proto.
The rpmsg-rpc driver is currently used with the MultiMedia stack, and
needs a patch in omapdrm for proper cache flushing of the pages where
the rpc pointer translations are being handled.
The rpmsg-proto driver supports the MessageQ API in the IPC product
* 'rpmsg-linux-3.14.y' of git://git.ti.com/rpmsg/rpmsg:
net/rpmsg: add support for new rpmsg sockets
rpmsg: add api for creating and deleting rpmsg channels
drm/omap: flush the mapped page in kmap/kunmap
rpmsg: rpc: introduce a new rpmsg_rpc driver
rpmsg: add api for getting the underlying virtio device
Signed-off-by: Suman Anna <s-anna@ti.com>
-rw-r--r-- | drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c | 19 | ||||
-rw-r--r-- | drivers/rpmsg/Kconfig | 15 | ||||
-rw-r--r-- | drivers/rpmsg/Makefile | 3 | ||||
-rw-r--r-- | drivers/rpmsg/rpmsg_rpc.c | 1389 | ||||
-rw-r--r-- | drivers/rpmsg/rpmsg_rpc_dmabuf.c | 655 | ||||
-rw-r--r-- | drivers/rpmsg/rpmsg_rpc_internal.h | 416 | ||||
-rw-r--r-- | drivers/rpmsg/rpmsg_rpc_sysfs.c | 255 | ||||
-rw-r--r-- | drivers/rpmsg/virtio_rpmsg_bus.c | 88 | ||||
-rw-r--r-- | include/linux/rpmsg.h | 5 | ||||
-rw-r--r-- | include/linux/rpmsg_rpc.h | 105 | ||||
-rw-r--r-- | include/linux/socket.h | 5 | ||||
-rw-r--r-- | include/uapi/linux/rpmsg_rpc.h | 208 | ||||
-rw-r--r-- | include/uapi/linux/rpmsg_socket.h | 47 | ||||
-rw-r--r-- | net/Makefile | 1 | ||||
-rw-r--r-- | net/rpmsg/Makefile | 1 | ||||
-rw-r--r-- | net/rpmsg/rpmsg_proto.c | 684 |
16 files changed, 3889 insertions, 7 deletions
diff --git a/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c b/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c index 4fcca8d4279..ded3d82e149 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c +++ b/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c | |||
@@ -122,8 +122,18 @@ static void *omap_gem_dmabuf_kmap(struct dma_buf *buffer, | |||
122 | { | 122 | { |
123 | struct drm_gem_object *obj = buffer->priv; | 123 | struct drm_gem_object *obj = buffer->priv; |
124 | struct page **pages; | 124 | struct page **pages; |
125 | dma_addr_t dma_addr; | ||
125 | omap_gem_get_pages(obj, &pages, false); | 126 | omap_gem_get_pages(obj, &pages, false); |
126 | omap_gem_cpu_sync(obj, page_num); | 127 | omap_gem_cpu_sync(obj, page_num); |
128 | |||
129 | /* | ||
130 | * invalidate/flush the cache for this page deliberately. | ||
131 | * XXX: revisit this, to find the proper place for invoking these calls. | ||
132 | */ | ||
133 | dma_addr = dma_map_page(obj->dev->dev, pages[page_num], 0, PAGE_SIZE, | ||
134 | DMA_BIDIRECTIONAL); | ||
135 | dma_unmap_page(obj->dev->dev, dma_addr, PAGE_SIZE, DMA_BIDIRECTIONAL); | ||
136 | |||
127 | return kmap(pages[page_num]); | 137 | return kmap(pages[page_num]); |
128 | } | 138 | } |
129 | 139 | ||
@@ -132,8 +142,17 @@ static void omap_gem_dmabuf_kunmap(struct dma_buf *buffer, | |||
132 | { | 142 | { |
133 | struct drm_gem_object *obj = buffer->priv; | 143 | struct drm_gem_object *obj = buffer->priv; |
134 | struct page **pages; | 144 | struct page **pages; |
145 | dma_addr_t dma_addr; | ||
135 | omap_gem_get_pages(obj, &pages, false); | 146 | omap_gem_get_pages(obj, &pages, false); |
136 | kunmap(pages[page_num]); | 147 | kunmap(pages[page_num]); |
148 | |||
149 | /* | ||
150 | * invalidate/flush the cache for this page deliberately. | ||
151 | * XXX: revisit this, to find the proper place for invoking these calls. | ||
152 | */ | ||
153 | dma_addr = dma_map_page(obj->dev->dev, pages[page_num], 0, PAGE_SIZE, | ||
154 | DMA_BIDIRECTIONAL); | ||
155 | dma_unmap_page(obj->dev->dev, dma_addr, PAGE_SIZE, DMA_BIDIRECTIONAL); | ||
137 | } | 156 | } |
138 | 157 | ||
139 | static int omap_gem_dmabuf_mmap(struct dma_buf *buffer, | 158 | static int omap_gem_dmabuf_mmap(struct dma_buf *buffer, |
diff --git a/drivers/rpmsg/Kconfig b/drivers/rpmsg/Kconfig index 69a21938758..1b18619447d 100644 --- a/drivers/rpmsg/Kconfig +++ b/drivers/rpmsg/Kconfig | |||
@@ -6,4 +6,19 @@ config RPMSG | |||
6 | select VIRTIO | 6 | select VIRTIO |
7 | select VIRTUALIZATION | 7 | select VIRTUALIZATION |
8 | 8 | ||
9 | config RPMSG_RPC | ||
10 | tristate "rpmsg Remote Procedure Call driver" | ||
11 | default n | ||
12 | depends on RPMSG | ||
13 | depends on REMOTEPROC | ||
14 | depends on OMAP_REMOTEPROC | ||
15 | select DMA_SHARED_BUFFER | ||
16 | ---help--- | ||
17 | An rpmsg driver that exposes the Remote Procedure Call API to | ||
18 | user space, in order to allow applications to distribute | ||
19 | remote calls to more power-efficient remote processors. This is | ||
20 | currently available only on OMAP4+ systems. | ||
21 | |||
22 | If unsure, say N. | ||
23 | |||
9 | endmenu | 24 | endmenu |
diff --git a/drivers/rpmsg/Makefile b/drivers/rpmsg/Makefile index 7617fcb8259..74c670366d3 100644 --- a/drivers/rpmsg/Makefile +++ b/drivers/rpmsg/Makefile | |||
@@ -1 +1,4 @@ | |||
1 | obj-$(CONFIG_RPMSG) += virtio_rpmsg_bus.o | 1 | obj-$(CONFIG_RPMSG) += virtio_rpmsg_bus.o |
2 | |||
3 | obj-$(CONFIG_RPMSG_RPC) += rpmsg-rpc.o | ||
4 | rpmsg-rpc-y := rpmsg_rpc.o rpmsg_rpc_sysfs.o rpmsg_rpc_dmabuf.o | ||
diff --git a/drivers/rpmsg/rpmsg_rpc.c b/drivers/rpmsg/rpmsg_rpc.c new file mode 100644 index 00000000000..e5aeb4d446f --- /dev/null +++ b/drivers/rpmsg/rpmsg_rpc.c | |||
@@ -0,0 +1,1389 @@ | |||
1 | /* | ||
2 | * Remote Processor Procedure Call Driver | ||
3 | * | ||
4 | * Copyright(c) 2012-2014 Texas Instruments. All rights reserved. | ||
5 | * | ||
6 | * Erik Rainey <erik.rainey@ti.com> | ||
7 | * Suman Anna <s-anna@ti.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | */ | ||
18 | |||
19 | #define pr_fmt(fmt) "%s: " fmt, __func__ | ||
20 | |||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/idr.h> | ||
25 | #include <linux/poll.h> | ||
26 | #include <linux/mutex.h> | ||
27 | #include <linux/sched.h> | ||
28 | #include <linux/fdtable.h> | ||
29 | #include <linux/remoteproc.h> | ||
30 | #include <linux/rpmsg.h> | ||
31 | #include <linux/rpmsg_rpc.h> | ||
32 | |||
33 | #include "rpmsg_rpc_internal.h" | ||
34 | |||
35 | #define RPPC_MAX_DEVICES (8) | ||
36 | #define RPPC_MAX_REG_FDS (10) | ||
37 | |||
38 | #define RPPC_SIG_NUM_PARAM(sig) ((sig).num_param - 1) | ||
39 | |||
40 | /* TODO: remove these fields */ | ||
41 | #define RPPC_JOBID_DISCRETE (0) | ||
42 | #define RPPC_POOLID_DEFAULT (0x8000) | ||
43 | |||
44 | static struct class *rppc_class; | ||
45 | static dev_t rppc_dev; | ||
46 | |||
47 | /* store all remote rpc connection services (usually one per remoteproc) */ | ||
48 | static DEFINE_IDR(rppc_devices); | ||
49 | static DEFINE_MUTEX(rppc_devices_lock); | ||
50 | |||
51 | /* | ||
52 | * Retrieve the rproc instance so that it can be used for performing | ||
53 | * address translations | ||
54 | */ | ||
55 | static struct rproc *rpdev_to_rproc(struct rpmsg_channel *rpdev) | ||
56 | { | ||
57 | struct virtio_device *vdev; | ||
58 | |||
59 | vdev = rpmsg_get_virtio_dev(rpdev); | ||
60 | if (!vdev) | ||
61 | return NULL; | ||
62 | |||
63 | return rproc_vdev_to_rproc_safe(vdev); | ||
64 | } | ||
65 | |||
66 | /* | ||
67 | * A wrapper function to translate local physical addresses to the remote core | ||
68 | * device addresses (virtual addresses that a code on remote processor can use | ||
69 | * directly. | ||
70 | */ | ||
71 | phys_addr_t rppc_local_to_remote_da(struct rppc_instance *rpc, phys_addr_t pa) | ||
72 | { | ||
73 | int ret; | ||
74 | struct rproc *rproc; | ||
75 | u64 da; | ||
76 | phys_addr_t rda; | ||
77 | struct device *dev = rpc->rppcdev->dev; | ||
78 | |||
79 | if (mutex_lock_interruptible(&rpc->rppcdev->lock)) | ||
80 | return -EINTR; | ||
81 | |||
82 | rproc = rpdev_to_rproc(rpc->rppcdev->rpdev); | ||
83 | if (!rproc) { | ||
84 | dev_err(dev, "error getting rproc for rpdev 0x%x\n", | ||
85 | (u32)rpc->rppcdev->rpdev); | ||
86 | } else { | ||
87 | ret = rproc_pa_to_da(rproc, pa, &da); | ||
88 | if (ret) { | ||
89 | dev_err(dev, "error from rproc_pa_to_da, rproc = %p, pa = 0x%x ret = %d\n", | ||
90 | rproc, pa, ret); | ||
91 | da = 0; | ||
92 | } | ||
93 | } | ||
94 | rda = (phys_addr_t) da; | ||
95 | |||
96 | mutex_unlock(&rpc->rppcdev->lock); | ||
97 | |||
98 | return rda; | ||
99 | } | ||
100 | |||
101 | static void rppc_print_msg(struct rppc_instance *rpc, char *prefix, | ||
102 | char buffer[512]) | ||
103 | { | ||
104 | struct rppc_msg_header *hdr = (struct rppc_msg_header *)buffer; | ||
105 | struct rppc_instance_handle *hdl = NULL; | ||
106 | struct rppc_query_function *info = NULL; | ||
107 | struct rppc_packet *packet = NULL; | ||
108 | struct rppc_param_data *param = NULL; | ||
109 | struct device *dev = rpc->rppcdev->dev; | ||
110 | u32 i = 0, paramsz = sizeof(*param); | ||
111 | |||
112 | dev_dbg(dev, "%s HDR: msg_type = %d msg_len = %d\n", | ||
113 | prefix, hdr->msg_type, hdr->msg_len); | ||
114 | |||
115 | switch (hdr->msg_type) { | ||
116 | case RPPC_MSGTYPE_CREATE_RESP: | ||
117 | case RPPC_MSGTYPE_DELETE_RESP: | ||
118 | hdl = RPPC_PAYLOAD(buffer, rppc_instance_handle); | ||
119 | dev_dbg(dev, "%s endpoint = %d status = %d\n", | ||
120 | prefix, hdl->endpoint_address, hdl->status); | ||
121 | break; | ||
122 | case RPPC_MSGTYPE_FUNCTION_INFO: | ||
123 | info = RPPC_PAYLOAD(buffer, rppc_query_function); | ||
124 | dev_dbg(dev, "%s (info not yet implemented)\n", prefix); | ||
125 | break; | ||
126 | case RPPC_MSGTYPE_FUNCTION_CALL: | ||
127 | packet = RPPC_PAYLOAD(buffer, rppc_packet); | ||
128 | dev_dbg(dev, "%s PACKET: desc = %04x msg_id = %04x flags = %08x func = 0x%08x result = %d size = %u\n", | ||
129 | prefix, packet->desc, packet->msg_id, | ||
130 | packet->flags, packet->fxn_id, | ||
131 | packet->result, packet->data_size); | ||
132 | param = (struct rppc_param_data *)packet->data; | ||
133 | for (i = 0; i < (packet->data_size / paramsz); i++) { | ||
134 | dev_dbg(dev, "%s param[%u] size = %zu data = %zu (0x%08x)", | ||
135 | prefix, i, param[i].size, param[i].data, | ||
136 | param[i].data); | ||
137 | } | ||
138 | break; | ||
139 | default: | ||
140 | break; | ||
141 | } | ||
142 | } | ||
143 | |||
144 | /* free any outstanding function calls */ | ||
145 | static void rppc_delete_fxns(struct rppc_instance *rpc) | ||
146 | { | ||
147 | struct rppc_function_list *pos, *n; | ||
148 | |||
149 | if (!list_empty(&rpc->fxn_list)) { | ||
150 | mutex_lock(&rpc->lock); | ||
151 | list_for_each_entry_safe(pos, n, &rpc->fxn_list, list) { | ||
152 | list_del(&pos->list); | ||
153 | kfree(pos->function); | ||
154 | kfree(pos); | ||
155 | } | ||
156 | mutex_unlock(&rpc->lock); | ||
157 | } | ||
158 | } | ||
159 | |||
160 | static | ||
161 | struct rppc_function *rppc_find_fxn(struct rppc_instance *rpc, u16 msg_id) | ||
162 | { | ||
163 | struct rppc_function *function = NULL; | ||
164 | struct rppc_function_list *pos, *n; | ||
165 | struct device *dev = rpc->rppcdev->dev; | ||
166 | |||
167 | mutex_lock(&rpc->lock); | ||
168 | list_for_each_entry_safe(pos, n, &rpc->fxn_list, list) { | ||
169 | dev_dbg(dev, "looking for msg %u, found msg %u\n", | ||
170 | msg_id, pos->msg_id); | ||
171 | if (pos->msg_id == msg_id) { | ||
172 | function = pos->function; | ||
173 | list_del(&pos->list); | ||
174 | kfree(pos); | ||
175 | break; | ||
176 | } | ||
177 | } | ||
178 | mutex_unlock(&rpc->lock); | ||
179 | |||
180 | return function; | ||
181 | } | ||
182 | |||
183 | static int rppc_add_fxn(struct rppc_instance *rpc, | ||
184 | struct rppc_function *function, u16 msg_id) | ||
185 | { | ||
186 | struct rppc_function_list *fxn = NULL; | ||
187 | struct device *dev = rpc->rppcdev->dev; | ||
188 | |||
189 | fxn = kzalloc(sizeof(*fxn), GFP_KERNEL); | ||
190 | if (!fxn) { | ||
191 | dev_err(dev, "failed to add function %p to list with msg id %d\n", | ||
192 | function, msg_id); | ||
193 | return -ENOMEM; | ||
194 | } | ||
195 | |||
196 | fxn->function = function; | ||
197 | fxn->msg_id = msg_id; | ||
198 | mutex_lock(&rpc->lock); | ||
199 | list_add(&fxn->list, &rpc->fxn_list); | ||
200 | mutex_unlock(&rpc->lock); | ||
201 | dev_dbg(dev, "added msg id %u to list", msg_id); | ||
202 | |||
203 | return 0; | ||
204 | } | ||
205 | |||
206 | static | ||
207 | void rppc_handle_create_resp(struct rppc_instance *rpc, char *data, int len) | ||
208 | { | ||
209 | struct device *dev = rpc->rppcdev->dev; | ||
210 | struct rppc_msg_header *hdr = (struct rppc_msg_header *)data; | ||
211 | struct rppc_instance_handle *hdl; | ||
212 | u32 exp_len = sizeof(*hdl) + sizeof(*hdr); | ||
213 | |||
214 | if (len != exp_len) { | ||
215 | dev_err(dev, "invalid response message length %d (expected %d bytes)", | ||
216 | len, exp_len); | ||
217 | rpc->state = RPPC_STATE_STALE; | ||
218 | return; | ||
219 | } | ||
220 | |||
221 | hdl = RPPC_PAYLOAD(data, rppc_instance_handle); | ||
222 | |||
223 | mutex_lock(&rpc->lock); | ||
224 | if (rpc->state != RPPC_STATE_STALE && hdl->status == 0) { | ||
225 | rpc->dst = hdl->endpoint_address; | ||
226 | rpc->state = RPPC_STATE_CONNECTED; | ||
227 | } else { | ||
228 | rpc->state = RPPC_STATE_STALE; | ||
229 | } | ||
230 | rpc->in_transition = 0; | ||
231 | dev_dbg(dev, "creation response: status %d addr 0x%x\n", | ||
232 | hdl->status, hdl->endpoint_address); | ||
233 | |||
234 | complete(&rpc->reply_arrived); | ||
235 | mutex_unlock(&rpc->lock); | ||
236 | } | ||
237 | |||
238 | static | ||
239 | void rppc_handle_delete_resp(struct rppc_instance *rpc, char *data, int len) | ||
240 | { | ||
241 | struct device *dev = rpc->rppcdev->dev; | ||
242 | struct rppc_msg_header *hdr = (struct rppc_msg_header *)data; | ||
243 | struct rppc_instance_handle *hdl; | ||
244 | u32 exp_len = sizeof(*hdl) + sizeof(*hdr); | ||
245 | |||
246 | if (len != exp_len) { | ||
247 | dev_err(dev, "invalid response message length %d (expected %d bytes)", | ||
248 | len, exp_len); | ||
249 | rpc->state = RPPC_STATE_STALE; | ||
250 | return; | ||
251 | } | ||
252 | if (hdr->msg_len != sizeof(*hdl)) { | ||
253 | dev_err(dev, "disconnect message was incorrect size!\n"); | ||
254 | rpc->state = RPPC_STATE_STALE; | ||
255 | return; | ||
256 | } | ||
257 | |||
258 | hdl = RPPC_PAYLOAD(data, rppc_instance_handle); | ||
259 | dev_dbg(dev, "deletion response: status %d addr 0x%x\n", | ||
260 | hdl->status, hdl->endpoint_address); | ||
261 | mutex_lock(&rpc->lock); | ||
262 | rpc->dst = 0; | ||
263 | rpc->state = RPPC_STATE_DISCONNECTED; | ||
264 | rpc->in_transition = 0; | ||
265 | complete(&rpc->reply_arrived); | ||
266 | mutex_unlock(&rpc->lock); | ||
267 | } | ||
268 | |||
269 | /* | ||
270 | * store the received message and wake up any blocking processes, | ||
271 | * waiting for new data. The allocated buffer would be freed after | ||
272 | * the user-space reads the packet. | ||
273 | */ | ||
274 | static void rppc_handle_fxn_resp(struct rppc_instance *rpc, char *data, int len) | ||
275 | { | ||
276 | struct device *dev = rpc->rppcdev->dev; | ||
277 | struct rppc_msg_header *hdr = (struct rppc_msg_header *)data; | ||
278 | struct sk_buff *skb; | ||
279 | char *skbdata; | ||
280 | |||
281 | /* TODO: need to check the response length? */ | ||
282 | skb = alloc_skb(hdr->msg_len, GFP_KERNEL); | ||
283 | if (!skb) { | ||
284 | dev_err(dev, "alloc_skb failed: %u\n", hdr->msg_len); | ||
285 | return; | ||
286 | } | ||
287 | skbdata = skb_put(skb, hdr->msg_len); | ||
288 | memcpy(skbdata, hdr->msg_data, hdr->msg_len); | ||
289 | |||
290 | mutex_lock(&rpc->lock); | ||
291 | skb_queue_tail(&rpc->queue, skb); | ||
292 | mutex_unlock(&rpc->lock); | ||
293 | |||
294 | wake_up_interruptible(&rpc->readq); | ||
295 | } | ||
296 | |||
297 | /* | ||
298 | * callback function for processing the different responses | ||
299 | * from the remote processor on a particular rpmsg channel | ||
300 | * instance. | ||
301 | */ | ||
302 | static void rppc_cb(struct rpmsg_channel *rpdev, | ||
303 | void *data, int len, void *priv, u32 src) | ||
304 | { | ||
305 | struct rppc_msg_header *hdr = data; | ||
306 | struct rppc_instance *rpc = priv; | ||
307 | struct device *dev = rpc->rppcdev->dev; | ||
308 | char *buf = (char *)data; | ||
309 | |||
310 | dev_dbg(dev, "<== incoming msg src %d len %d msg_type %d msg_len %d\n", | ||
311 | src, len, hdr->msg_type, hdr->msg_len); | ||
312 | rppc_print_msg(rpc, "RX:", buf); | ||
313 | |||
314 | if (len <= sizeof(*hdr)) { | ||
315 | dev_err(dev, "message truncated\n"); | ||
316 | rpc->state = RPPC_STATE_STALE; | ||
317 | return; | ||
318 | } | ||
319 | |||
320 | switch (hdr->msg_type) { | ||
321 | case RPPC_MSGTYPE_CREATE_RESP: | ||
322 | rppc_handle_create_resp(rpc, data, len); | ||
323 | break; | ||
324 | case RPPC_MSGTYPE_DELETE_RESP: | ||
325 | rppc_handle_delete_resp(rpc, data, len); | ||
326 | break; | ||
327 | case RPPC_MSGTYPE_FUNCTION_CALL: | ||
328 | case RPPC_MSGTYPE_FUNCTION_RET: | ||
329 | rppc_handle_fxn_resp(rpc, data, len); | ||
330 | break; | ||
331 | default: | ||
332 | dev_warn(dev, "unexpected msg type: %d\n", hdr->msg_type); | ||
333 | break; | ||
334 | } | ||
335 | } | ||
336 | |||
337 | /* | ||
338 | * send a connection request to the remote rpc connection service. Use | ||
339 | * the new local address created during .open for this instance as the | ||
340 | * source address to complete the connection. | ||
341 | */ | ||
342 | static int rppc_connect(struct rppc_instance *rpc, | ||
343 | struct rppc_create_instance *connect) | ||
344 | { | ||
345 | int ret = 0; | ||
346 | u32 len = 0; | ||
347 | char kbuf[512]; | ||
348 | struct rppc_device *rppcdev = rpc->rppcdev; | ||
349 | struct rppc_msg_header *hdr = (struct rppc_msg_header *)&kbuf[0]; | ||
350 | |||
351 | if (rpc->state == RPPC_STATE_CONNECTED) { | ||
352 | dev_dbg(rppcdev->dev, "endpoint already connected\n"); | ||
353 | return -EISCONN; | ||
354 | } | ||
355 | |||
356 | hdr->msg_type = RPPC_MSGTYPE_CREATE_REQ; | ||
357 | hdr->msg_len = sizeof(*connect); | ||
358 | memcpy(hdr->msg_data, connect, hdr->msg_len); | ||
359 | len = sizeof(struct rppc_msg_header) + hdr->msg_len; | ||
360 | |||
361 | init_completion(&rpc->reply_arrived); | ||
362 | rpc->in_transition = 1; | ||
363 | ret = rpmsg_send_offchannel(rppcdev->rpdev, rpc->ept->addr, | ||
364 | rppcdev->rpdev->dst, (char *)kbuf, len); | ||
365 | if (ret > 0) { | ||
366 | dev_err(rppcdev->dev, "rpmsg_send failed: %d\n", ret); | ||
367 | return ret; | ||
368 | } | ||
369 | |||
370 | ret = wait_for_completion_interruptible_timeout(&rpc->reply_arrived, | ||
371 | msecs_to_jiffies(5000)); | ||
372 | if (rpc->state == RPPC_STATE_CONNECTED) | ||
373 | return 0; | ||
374 | |||
375 | if (rpc->state == RPPC_STATE_STALE) | ||
376 | return -ENXIO; | ||
377 | |||
378 | if (ret > 0) { | ||
379 | dev_err(rppcdev->dev, "premature wakeup: %d\n", ret); | ||
380 | return -EIO; | ||
381 | } | ||
382 | |||
383 | return -ETIMEDOUT; | ||
384 | } | ||
385 | |||
386 | static void rppc_disconnect(struct rppc_instance *rpc) | ||
387 | { | ||
388 | int ret; | ||
389 | size_t len; | ||
390 | char kbuf[512]; | ||
391 | struct rppc_device *rppcdev = rpc->rppcdev; | ||
392 | struct rppc_msg_header *hdr = (struct rppc_msg_header *)&kbuf[0]; | ||
393 | struct rppc_instance_handle *handle = | ||
394 | RPPC_PAYLOAD(kbuf, rppc_instance_handle); | ||
395 | |||
396 | if (rpc->state != RPPC_STATE_CONNECTED) | ||
397 | return; | ||
398 | |||
399 | hdr->msg_type = RPPC_MSGTYPE_DELETE_REQ; | ||
400 | hdr->msg_len = sizeof(uint32_t); | ||
401 | handle->endpoint_address = rpc->dst; | ||
402 | handle->status = 0; | ||
403 | len = sizeof(struct rppc_msg_header) + hdr->msg_len; | ||
404 | |||
405 | dev_dbg(rppcdev->dev, "disconnecting from RPC service at %d\n", | ||
406 | rpc->dst); | ||
407 | ret = rpmsg_send_offchannel(rppcdev->rpdev, rpc->ept->addr, | ||
408 | rppcdev->rpdev->dst, kbuf, len); | ||
409 | if (ret) | ||
410 | dev_err(rppcdev->dev, "rpmsg_send failed: %d\n", ret); | ||
411 | |||
412 | /* | ||
413 | * TODO: should we wait for a message to come back? | ||
414 | * For now, no. | ||
415 | */ | ||
416 | wait_for_completion_interruptible(&rpc->reply_arrived); | ||
417 | } | ||
418 | |||
419 | static int rppc_register_buffers(struct rppc_instance *rpc, | ||
420 | unsigned long arg) | ||
421 | { | ||
422 | struct rppc_buf_fds data; | ||
423 | int *fds = NULL; | ||
424 | struct rppc_dma_buf **bufs = NULL; | ||
425 | struct rppc_dma_buf *tmp; | ||
426 | int i = 0, ret = 0; | ||
427 | |||
428 | if (copy_from_user(&data, (char __user *)arg, sizeof(data))) | ||
429 | return -EFAULT; | ||
430 | |||
431 | /* impose a maximum number of buffers for now */ | ||
432 | if (data.num > RPPC_MAX_REG_FDS) | ||
433 | return -EINVAL; | ||
434 | |||
435 | fds = kzalloc(sizeof(*fds) * data.num, GFP_KERNEL); | ||
436 | if (!fds) | ||
437 | return -ENOMEM; | ||
438 | |||
439 | if (copy_from_user(fds, (char __user *)data.fds, | ||
440 | sizeof(*fds) * data.num)) { | ||
441 | ret = -EFAULT; | ||
442 | goto free_fds; | ||
443 | } | ||
444 | |||
445 | for (i = 0; i < data.num; i++) { | ||
446 | if (!fcheck(fds[i])) { | ||
447 | ret = -EBADF; | ||
448 | goto free_fds; | ||
449 | } | ||
450 | |||
451 | tmp = rppc_find_dmabuf(rpc, fds[i]); | ||
452 | if (!IS_ERR_OR_NULL(tmp)) { | ||
453 | ret = -EEXIST; | ||
454 | goto free_fds; | ||
455 | } | ||
456 | } | ||
457 | |||
458 | bufs = kzalloc(sizeof(*bufs) * data.num, GFP_KERNEL); | ||
459 | if (!bufs) { | ||
460 | ret = -ENOMEM; | ||
461 | goto free_fds; | ||
462 | } | ||
463 | |||
464 | for (i = 0; i < data.num; i++) { | ||
465 | bufs[i] = rppc_alloc_dmabuf(rpc, fds[i], false); | ||
466 | if (IS_ERR(bufs[i])) { | ||
467 | ret = PTR_ERR(bufs[i]); | ||
468 | break; | ||
469 | } | ||
470 | } | ||
471 | if (i == data.num) | ||
472 | goto free_bufs; | ||
473 | |||
474 | for (i -= 1; i >= 0; i--) | ||
475 | rppc_free_dmabuf(bufs[i]->id, bufs[i], rpc); | ||
476 | |||
477 | free_bufs: | ||
478 | kfree(bufs); | ||
479 | free_fds: | ||
480 | kfree(fds); | ||
481 | return ret; | ||
482 | } | ||
483 | |||
484 | static int rppc_unregister_buffers(struct rppc_instance *rpc, | ||
485 | unsigned long arg) | ||
486 | { | ||
487 | struct rppc_buf_fds data; | ||
488 | int *fds = NULL; | ||
489 | struct rppc_dma_buf **bufs = NULL; | ||
490 | int i = 0, ret = 0; | ||
491 | |||
492 | if (copy_from_user(&data, (char __user *)arg, sizeof(data))) | ||
493 | return -EFAULT; | ||
494 | |||
495 | /* impose a maximum number of buffers for now */ | ||
496 | if (data.num > RPPC_MAX_REG_FDS) | ||
497 | return -EINVAL; | ||
498 | |||
499 | fds = kzalloc(sizeof(*fds) * data.num, GFP_KERNEL); | ||
500 | if (!fds) | ||
501 | return -ENOMEM; | ||
502 | |||
503 | if (copy_from_user(fds, (char __user *)data.fds, | ||
504 | sizeof(*fds) * data.num)) { | ||
505 | ret = -EFAULT; | ||
506 | goto free_fds; | ||
507 | } | ||
508 | |||
509 | bufs = kzalloc(sizeof(*bufs) * data.num, GFP_KERNEL); | ||
510 | if (!bufs) { | ||
511 | ret = -ENOMEM; | ||
512 | goto free_fds; | ||
513 | } | ||
514 | |||
515 | for (i = 0; i < data.num; i++) { | ||
516 | if (!fcheck(fds[i])) { | ||
517 | ret = -EBADF; | ||
518 | goto free_bufs; | ||
519 | } | ||
520 | |||
521 | bufs[i] = rppc_find_dmabuf(rpc, fds[i]); | ||
522 | if (IS_ERR_OR_NULL(bufs[i])) { | ||
523 | ret = -EEXIST; | ||
524 | goto free_bufs; | ||
525 | } | ||
526 | } | ||
527 | |||
528 | for (i = 0; i < data.num; i++) | ||
529 | rppc_free_dmabuf(bufs[i]->id, bufs[i], rpc); | ||
530 | |||
531 | free_bufs: | ||
532 | kfree(bufs); | ||
533 | free_fds: | ||
534 | kfree(fds); | ||
535 | return ret; | ||
536 | } | ||
537 | |||
538 | /* | ||
539 | * create a new rpc instance that a user-space client can use to invoke | ||
540 | * remote functions. A new local address would be created and tied with | ||
541 | * this instance for uniquely identifying the messages communicated by | ||
542 | * this instance with the remote side. | ||
543 | * | ||
544 | * The function is blocking if there is no underlying connection manager | ||
545 | * channel, unless the device is opened with non-blocking flags specifically. | ||
546 | */ | ||
547 | static int rppc_open(struct inode *inode, struct file *filp) | ||
548 | { | ||
549 | struct rppc_device *rppcdev; | ||
550 | struct rppc_instance *rpc; | ||
551 | |||
552 | rppcdev = container_of(inode->i_cdev, struct rppc_device, cdev); | ||
553 | |||
554 | if (!rppcdev->rpdev) | ||
555 | if ((filp->f_flags & O_NONBLOCK) || | ||
556 | wait_for_completion_interruptible(&rppcdev->comp)) | ||
557 | return -EBUSY; | ||
558 | |||
559 | rpc = kzalloc(sizeof(*rpc), GFP_KERNEL); | ||
560 | if (!rpc) | ||
561 | return -ENOMEM; | ||
562 | |||
563 | mutex_init(&rpc->lock); | ||
564 | skb_queue_head_init(&rpc->queue); | ||
565 | init_waitqueue_head(&rpc->readq); | ||
566 | INIT_LIST_HEAD(&rpc->fxn_list); | ||
567 | idr_init(&rpc->dma_idr); | ||
568 | rpc->in_transition = 0; | ||
569 | rpc->msg_id = 0; | ||
570 | rpc->state = RPPC_STATE_DISCONNECTED; | ||
571 | rpc->rppcdev = rppcdev; | ||
572 | |||
573 | rpc->ept = rpmsg_create_ept(rppcdev->rpdev, rppc_cb, rpc, | ||
574 | RPMSG_ADDR_ANY); | ||
575 | if (!rpc->ept) { | ||
576 | dev_err(rppcdev->dev, "create ept failed\n"); | ||
577 | kfree(rpc); | ||
578 | return -ENOMEM; | ||
579 | } | ||
580 | filp->private_data = rpc; | ||
581 | |||
582 | mutex_lock(&rppcdev->lock); | ||
583 | list_add(&rpc->list, &rppcdev->instances); | ||
584 | mutex_unlock(&rppcdev->lock); | ||
585 | |||
586 | dev_dbg(rppcdev->dev, "local addr assigned: 0x%x\n", rpc->ept->addr); | ||
587 | |||
588 | return 0; | ||
589 | } | ||
590 | |||
591 | /* | ||
592 | * release and free all the resources associated with a particular rpc | ||
593 | * instance. This includes the data structures maintaining the current | ||
594 | * outstanding function invocations, and all the buffers registered for | ||
595 | * use with this instance. Send a disconnect message and cleanup the | ||
596 | * local end-point only if the instance is in a normal state, with the | ||
597 | * remote connection manager functional. | ||
598 | */ | ||
599 | static int rppc_release(struct inode *inode, struct file *filp) | ||
600 | { | ||
601 | struct rppc_instance *rpc = filp->private_data; | ||
602 | struct rppc_device *rppcdev = rpc->rppcdev; | ||
603 | |||
604 | dev_dbg(rppcdev->dev, "releasing Instance %p, in state %d\n", rpc, | ||
605 | rpc->state); | ||
606 | |||
607 | if (rpc->state != RPPC_STATE_STALE) { | ||
608 | if (rpc->ept) { | ||
609 | rppc_disconnect(rpc); | ||
610 | rpmsg_destroy_ept(rpc->ept); | ||
611 | rpc->ept = NULL; | ||
612 | } | ||
613 | } | ||
614 | |||
615 | rppc_delete_fxns(rpc); | ||
616 | |||
617 | mutex_lock(&rpc->lock); | ||
618 | idr_for_each(&rpc->dma_idr, rppc_free_dmabuf, rpc); | ||
619 | idr_destroy(&rpc->dma_idr); | ||
620 | mutex_unlock(&rpc->lock); | ||
621 | |||
622 | mutex_lock(&rppcdev->lock); | ||
623 | list_del(&rpc->list); | ||
624 | mutex_unlock(&rppcdev->lock); | ||
625 | |||
626 | dev_dbg(rppcdev->dev, "instance %p has been deleted!\n", rpc); | ||
627 | if (list_empty(&rppcdev->instances)) | ||
628 | dev_dbg(rppcdev->dev, "all instances have been removed!\n"); | ||
629 | |||
630 | kfree(rpc); | ||
631 | return 0; | ||
632 | } | ||
633 | |||
634 | static long rppc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | ||
635 | { | ||
636 | struct rppc_instance *rpc = filp->private_data; | ||
637 | struct rppc_device *rppcdev = rpc->rppcdev; | ||
638 | struct rppc_create_instance connect; | ||
639 | int ret = 0; | ||
640 | |||
641 | dev_dbg(rppcdev->dev, "%s: cmd %d, arg 0x%lx\n", __func__, cmd, arg); | ||
642 | |||
643 | if (_IOC_TYPE(cmd) != RPPC_IOC_MAGIC) | ||
644 | return -ENOTTY; | ||
645 | |||
646 | if (_IOC_NR(cmd) > RPPC_IOC_MAXNR) | ||
647 | return -ENOTTY; | ||
648 | |||
649 | switch (cmd) { | ||
650 | case RPPC_IOC_CREATE: | ||
651 | ret = copy_from_user(&connect, (char __user *)arg, | ||
652 | sizeof(connect)); | ||
653 | if (ret) { | ||
654 | dev_err(rppcdev->dev, "%s: %d: copy_from_user fail: %d\n", | ||
655 | __func__, _IOC_NR(cmd), ret); | ||
656 | ret = -EFAULT; | ||
657 | } else { | ||
658 | connect.name[sizeof(connect.name) - 1] = '\0'; | ||
659 | ret = rppc_connect(rpc, &connect); | ||
660 | } | ||
661 | break; | ||
662 | case RPPC_IOC_BUFREGISTER: | ||
663 | ret = rppc_register_buffers(rpc, arg); | ||
664 | break; | ||
665 | case RPPC_IOC_BUFUNREGISTER: | ||
666 | ret = rppc_unregister_buffers(rpc, arg); | ||
667 | break; | ||
668 | default: | ||
669 | dev_err(rppcdev->dev, "unhandled ioctl cmd: %d\n", cmd); | ||
670 | break; | ||
671 | } | ||
672 | |||
673 | return ret; | ||
674 | } | ||
675 | |||
676 | static ssize_t rppc_read(struct file *filp, char __user *buf, size_t len, | ||
677 | loff_t *offp) | ||
678 | { | ||
679 | struct rppc_instance *rpc = filp->private_data; | ||
680 | struct rppc_packet *packet = NULL; | ||
681 | struct rppc_param_data *parameters = NULL; | ||
682 | struct rppc_function *function = NULL; | ||
683 | struct rppc_function_return returned; | ||
684 | struct sk_buff *skb = NULL; | ||
685 | int ret = 0; | ||
686 | int use = sizeof(returned); | ||
687 | DEFINE_WAIT(wait); | ||
688 | |||
689 | if (mutex_lock_interruptible(&rpc->lock)) | ||
690 | return -ERESTARTSYS; | ||
691 | |||
692 | /* instance is invalid */ | ||
693 | if (rpc->state == RPPC_STATE_STALE) { | ||
694 | mutex_unlock(&rpc->lock); | ||
695 | return -ENXIO; | ||
696 | } | ||
697 | |||
698 | /* not yet connected to the remote side */ | ||
699 | if (rpc->state == RPPC_STATE_DISCONNECTED) { | ||
700 | mutex_unlock(&rpc->lock); | ||
701 | return -ENOTCONN; | ||
702 | } | ||
703 | |||
704 | if (len > use) { | ||
705 | mutex_unlock(&rpc->lock); | ||
706 | return -EOVERFLOW; | ||
707 | } | ||
708 | if (len < use) { | ||
709 | mutex_unlock(&rpc->lock); | ||
710 | return -EINVAL; | ||
711 | } | ||
712 | |||
713 | while (skb_queue_empty(&rpc->queue)) { | ||
714 | mutex_unlock(&rpc->lock); | ||
715 | /* non-blocking requested ? return now */ | ||
716 | if (filp->f_flags & O_NONBLOCK) | ||
717 | return -EAGAIN; | ||
718 | |||
719 | prepare_to_wait_exclusive(&rpc->readq, &wait, | ||
720 | TASK_INTERRUPTIBLE); | ||
721 | schedule(); | ||
722 | finish_wait(&rpc->readq, &wait); | ||
723 | if (signal_pending(current)) | ||
724 | return -ERESTARTSYS; | ||
725 | |||
726 | ret = mutex_lock_interruptible(&rpc->lock); | ||
727 | if (ret < 0) | ||
728 | return -ERESTARTSYS; | ||
729 | |||
730 | /* make sure state is sane while we waited */ | ||
731 | if (rpc->state != RPPC_STATE_CONNECTED) { | ||
732 | ret = -EIO; | ||
733 | goto out; | ||
734 | } | ||
735 | } | ||
736 | |||
737 | skb = skb_dequeue(&rpc->queue); | ||
738 | if (WARN_ON(!skb)) { | ||
739 | ret = -EIO; | ||
740 | goto out; | ||
741 | } | ||
742 | mutex_unlock(&rpc->lock); | ||
743 | |||
744 | packet = (struct rppc_packet *)skb->data; | ||
745 | parameters = (struct rppc_param_data *)packet->data; | ||
746 | |||
747 | /* | ||
748 | * pull the function memory from the list and untranslate | ||
749 | * the remote device address pointers in the packet back | ||
750 | * to MPU pointers. | ||
751 | */ | ||
752 | function = rppc_find_fxn(rpc, packet->msg_id); | ||
753 | if (function && function->num_translations > 0) { | ||
754 | ret = rppc_xlate_buffers(rpc, function, RPPC_RPA_TO_UVA); | ||
755 | if (ret < 0) | ||
756 | goto failure; | ||
757 | } | ||
758 | returned.fxn_id = RPPC_FXN_MASK(packet->fxn_id); | ||
759 | returned.status = packet->result; | ||
760 | |||
761 | if (copy_to_user(buf, &returned, use)) { | ||
762 | dev_err(rpc->rppcdev->dev, "%s: copy_to_user fail\n", __func__); | ||
763 | ret = -EFAULT; | ||
764 | } else { | ||
765 | ret = use; | ||
766 | } | ||
767 | |||
768 | failure: | ||
769 | kfree(function); | ||
770 | kfree_skb(skb); | ||
771 | out: | ||
772 | return ret; | ||
773 | } | ||
774 | |||
775 | static ssize_t rppc_write(struct file *filp, const char __user *ubuf, | ||
776 | size_t len, loff_t *offp) | ||
777 | { | ||
778 | struct rppc_instance *rpc = filp->private_data; | ||
779 | struct rppc_device *rppcdev = rpc->rppcdev; | ||
780 | struct device *dev = rppcdev->dev; | ||
781 | struct rppc_msg_header *hdr = NULL; | ||
782 | struct rppc_function *function = NULL; | ||
783 | struct rppc_packet *packet = NULL; | ||
784 | struct rppc_param_data *parameters = NULL; | ||
785 | char kbuf[512]; | ||
786 | int use = 0, ret = 0, param = 0; | ||
787 | uint32_t sig_idx = 0; | ||
788 | uint32_t sig_prm = 0; | ||
789 | static u32 rppc_atomic_size[RPPC_PARAM_ATOMIC_MAX] = { | ||
790 | 0, /* RPPC_PARAM_VOID */ | ||
791 | 1, /* RPPC_PARAM_S08 */ | ||
792 | 1, /* RPPC_PARAM_U08 */ | ||
793 | 2, /* RPPC_PARAM_S16 */ | ||
794 | 2, /* RPPC_PARAM_U16 */ | ||
795 | 4, /* RPPC_PARAM_S32 */ | ||
796 | 4, /* RPPC_PARAM_U32 */ | ||
797 | 8, /* RPPC_PARAM_S64 */ | ||
798 | 8 /* RPPC_PARAM_U64 */ | ||
799 | }; | ||
800 | |||
801 | if (len < sizeof(*function)) { | ||
802 | ret = -ENOTSUPP; | ||
803 | goto failure; | ||
804 | } | ||
805 | |||
806 | if (len > (sizeof(*function) + RPPC_MAX_TRANSLATIONS * | ||
807 | sizeof(struct rppc_param_translation))) { | ||
808 | ret = -ENOTSUPP; | ||
809 | goto failure; | ||
810 | } | ||
811 | |||
812 | if (rpc->state != RPPC_STATE_CONNECTED) { | ||
813 | ret = -ENOTCONN; | ||
814 | goto failure; | ||
815 | } | ||
816 | |||
817 | function = kzalloc(len, GFP_KERNEL); | ||
818 | if (function == NULL) { | ||
819 | ret = -ENOMEM; | ||
820 | goto failure; | ||
821 | } | ||
822 | |||
823 | if (copy_from_user(function, ubuf, len)) { | ||
824 | ret = -EMSGSIZE; | ||
825 | goto failure; | ||
826 | } | ||
827 | |||
828 | /* increment the message id and wrap if needed */ | ||
829 | rpc->msg_id = (rpc->msg_id + 1) & 0xFFFF; | ||
830 | |||
831 | memset(kbuf, 0, sizeof(kbuf)); | ||
832 | sig_idx = function->fxn_id + 1; | ||
833 | hdr = (struct rppc_msg_header *)kbuf; | ||
834 | hdr->msg_type = RPPC_MSGTYPE_FUNCTION_CALL; | ||
835 | hdr->msg_len = sizeof(*packet); | ||
836 | packet = RPPC_PAYLOAD(kbuf, rppc_packet); | ||
837 | packet->desc = RPPC_DESC_EXEC_SYNC; | ||
838 | packet->msg_id = rpc->msg_id; | ||
839 | packet->flags = (RPPC_JOBID_DISCRETE << 16) | RPPC_POOLID_DEFAULT; | ||
840 | packet->fxn_id = RPPC_SET_FXN_IDX(function->fxn_id); | ||
841 | packet->result = 0; | ||
842 | packet->data_size = sizeof(*parameters) * function->num_params; | ||
843 | |||
844 | /* check the signatures against what were published */ | ||
845 | if (RPPC_SIG_NUM_PARAM(rppcdev->signatures[sig_idx]) != | ||
846 | function->num_params) { | ||
847 | dev_err(dev, "number of parameters mismatch! params = %u expected = %u\n", | ||
848 | function->num_params, | ||
849 | RPPC_SIG_NUM_PARAM(rppcdev->signatures[sig_idx])); | ||
850 | ret = -EINVAL; | ||
851 | goto failure; | ||
852 | } | ||
853 | |||
854 | /* | ||
855 | * compute the parameter pointer changes last since this will cause the | ||
856 | * cache operations | ||
857 | */ | ||
858 | parameters = (struct rppc_param_data *)packet->data; | ||
859 | for (param = 0; param < function->num_params; param++) { | ||
860 | sig_prm = param + 1; | ||
861 | /* | ||
862 | * check to make sure the parameter description matches the | ||
863 | * signature published from the other side. | ||
864 | */ | ||
865 | if (function->params[param].type == RPPC_PARAM_TYPE_PTR && | ||
866 | !RPPC_IS_PTR( | ||
867 | rppcdev->signatures[sig_idx].params[sig_prm].type)) { | ||
868 | dev_err(dev, "parameter %u Pointer Type Mismatch sig type:%x func %u\n", | ||
869 | param, rppcdev->signatures[sig_idx]. | ||
870 | params[sig_prm].type, sig_idx); | ||
871 | ret = -EINVAL; | ||
872 | goto failure; | ||
873 | } else if (param > 0 && function->params[param].type == | ||
874 | RPPC_PARAM_TYPE_ATOMIC) { | ||
875 | if (!RPPC_IS_ATOMIC( | ||
876 | rppcdev->signatures[sig_idx].params[sig_prm].type)) { | ||
877 | dev_err(dev, "parameter Atomic Type Mismatch\n"); | ||
878 | ret = -EINVAL; | ||
879 | goto failure; | ||
880 | } else { | ||
881 | uint32_t t = rppcdev->signatures[sig_idx]. | ||
882 | params[sig_prm].type; | ||
883 | if (rppc_atomic_size[t] != | ||
884 | function->params[param].size) { | ||
885 | dev_err(dev, "size mismatch! u:%u sig:%u\n", | ||
886 | function->params[param].size, | ||
887 | rppc_atomic_size[t]); | ||
888 | ret = -EINVAL; | ||
889 | goto failure; | ||
890 | } | ||
891 | } | ||
892 | } | ||
893 | |||
894 | parameters[param].size = function->params[param].size; | ||
895 | |||
896 | /* check the type and lookup if it's a pointer */ | ||
897 | if (function->params[param].type == RPPC_PARAM_TYPE_PTR) { | ||
898 | /* | ||
899 | * internally the buffer translations takes care of the | ||
900 | * offsets. | ||
901 | */ | ||
902 | int fd = function->params[param].fd; | ||
903 | parameters[param].data = (size_t) rppc_buffer_lookup( | ||
904 | rpc, | ||
905 | (virt_addr_t) | ||
906 | function-> | ||
907 | params[param].data, | ||
908 | (virt_addr_t) | ||
909 | function-> | ||
910 | params[param].base, | ||
911 | fd); | ||
912 | } else if (function->params[param].type == | ||
913 | RPPC_PARAM_TYPE_ATOMIC) { | ||
914 | parameters[param].data = function->params[param].data; | ||
915 | } else { | ||
916 | ret = -ENOTSUPP; | ||
917 | goto failure; | ||
918 | } | ||
919 | } | ||
920 | |||
921 | /* compute the size of the rpmsg packet */ | ||
922 | use = sizeof(*hdr) + hdr->msg_len + packet->data_size; | ||
923 | |||
924 | /* failed to provide the translation data */ | ||
925 | if (function->num_translations > 0 && | ||
926 | len < (sizeof(*function) + (function->num_translations * | ||
927 | sizeof(struct rppc_param_translation)))) { | ||
928 | ret = -ENXIO; | ||
929 | goto failure; | ||
930 | } | ||
931 | |||
932 | /* | ||
933 | * if there are pointers to translate for the user, do so now. | ||
934 | * alter our copy of function and the user's parameters so that | ||
935 | * the proper pointers can be sent to remote cores | ||
936 | */ | ||
937 | if (function->num_translations > 0) { | ||
938 | ret = rppc_xlate_buffers(rpc, function, RPPC_UVA_TO_RPA); | ||
939 | if (ret < 0) { | ||
940 | dev_err(dev, "failed to translate all pointers for remote core!\n"); | ||
941 | goto failure; | ||
942 | } | ||
943 | } | ||
944 | |||
945 | ret = rppc_add_fxn(rpc, function, rpc->msg_id); | ||
946 | if (ret < 0) { | ||
947 | rppc_xlate_buffers(rpc, function, RPPC_RPA_TO_UVA); | ||
948 | goto failure; | ||
949 | } | ||
950 | |||
951 | rppc_print_msg(rpc, "TX:", kbuf); | ||
952 | |||
953 | ret = rpmsg_send_offchannel(rppcdev->rpdev, rpc->ept->addr, rpc->dst, | ||
954 | kbuf, use); | ||
955 | if (ret) { | ||
956 | dev_err(dev, "rpmsg_send failed: %d\n", ret); | ||
957 | rppc_find_fxn(rpc, rpc->msg_id); | ||
958 | rppc_xlate_buffers(rpc, function, RPPC_RPA_TO_UVA); | ||
959 | goto failure; | ||
960 | } | ||
961 | dev_dbg(dev, "==> sent msg to remote endpoint %u\n", rpc->dst); | ||
962 | |||
963 | failure: | ||
964 | if (ret >= 0) | ||
965 | ret = len; | ||
966 | else | ||
967 | kfree(function); | ||
968 | |||
969 | return ret; | ||
970 | } | ||
971 | |||
972 | static unsigned int rppc_poll(struct file *filp, struct poll_table_struct *wait) | ||
973 | { | ||
974 | struct rppc_instance *rpc = filp->private_data; | ||
975 | unsigned int mask = 0; | ||
976 | |||
977 | if (mutex_lock_interruptible(&rpc->lock)) | ||
978 | return -ERESTARTSYS; | ||
979 | |||
980 | poll_wait(filp, &rpc->readq, wait); | ||
981 | if (rpc->state == RPPC_STATE_STALE) { | ||
982 | mask = POLLERR; | ||
983 | goto out; | ||
984 | } | ||
985 | |||
986 | /* if the queue is not empty set the poll bit correctly */ | ||
987 | if (!skb_queue_empty(&rpc->queue)) | ||
988 | mask |= (POLLIN | POLLRDNORM); | ||
989 | |||
990 | /* TODO: writes are deemed to be successful always, fix this later */ | ||
991 | if (true) | ||
992 | mask |= POLLOUT | POLLWRNORM; | ||
993 | |||
994 | out: | ||
995 | mutex_unlock(&rpc->lock); | ||
996 | return mask; | ||
997 | } | ||
998 | |||
999 | static const struct file_operations rppc_fops = { | ||
1000 | .owner = THIS_MODULE, | ||
1001 | .open = rppc_open, | ||
1002 | .release = rppc_release, | ||
1003 | .unlocked_ioctl = rppc_ioctl, | ||
1004 | .read = rppc_read, | ||
1005 | .write = rppc_write, | ||
1006 | .poll = rppc_poll, | ||
1007 | }; | ||
1008 | |||
1009 | /* | ||
1010 | * send a function query message, the sysfs entry will be created | ||
1011 | * during the processing of the response message | ||
1012 | */ | ||
1013 | static int rppc_query_function(struct rpmsg_channel *rpdev) | ||
1014 | { | ||
1015 | int ret = 0; | ||
1016 | u32 len = 0; | ||
1017 | char kbuf[512]; | ||
1018 | struct rppc_device *rppcdev = dev_get_drvdata(&rpdev->dev); | ||
1019 | struct rppc_msg_header *hdr = (struct rppc_msg_header *)&kbuf[0]; | ||
1020 | struct rppc_query_function *fxn_info = | ||
1021 | (struct rppc_query_function *)hdr->msg_data; | ||
1022 | |||
1023 | if (rppcdev->cur_func >= rppcdev->num_funcs) | ||
1024 | return -EINVAL; | ||
1025 | |||
1026 | hdr->msg_type = RPPC_MSGTYPE_FUNCTION_QUERY; | ||
1027 | hdr->msg_len = sizeof(*fxn_info); | ||
1028 | len = sizeof(*hdr) + hdr->msg_len; | ||
1029 | fxn_info->info_type = RPPC_INFOTYPE_FUNC_SIGNATURE; | ||
1030 | fxn_info->fxn_id = rppcdev->cur_func++; | ||
1031 | |||
1032 | dev_dbg(&rpdev->dev, "sending function query type %u for function %u\n", | ||
1033 | fxn_info->info_type, fxn_info->fxn_id); | ||
1034 | ret = rpmsg_send(rpdev, (char *)kbuf, len); | ||
1035 | if (ret) { | ||
1036 | dev_err(&rpdev->dev, "rpmsg_send failed: %d\n", ret); | ||
1037 | return ret; | ||
1038 | } | ||
1039 | |||
1040 | return 0; | ||
1041 | } | ||
1042 | |||
1043 | static void | ||
1044 | rppc_handle_devinfo_resp(struct rpmsg_channel *rpdev, char *data, int len) | ||
1045 | { | ||
1046 | struct rppc_device *rppcdev = dev_get_drvdata(&rpdev->dev); | ||
1047 | struct rppc_device_info *info; | ||
1048 | u32 exp_len = sizeof(*info) + sizeof(struct rppc_msg_header); | ||
1049 | |||
1050 | if (len != exp_len) { | ||
1051 | dev_err(&rpdev->dev, "invalid message length %d (expected %d bytes)", | ||
1052 | len, exp_len); | ||
1053 | return; | ||
1054 | } | ||
1055 | |||
1056 | info = RPPC_PAYLOAD(data, rppc_device_info); | ||
1057 | if (info->num_funcs > RPPC_MAX_NUM_FUNCS) { | ||
1058 | rppcdev->num_funcs = 0; | ||
1059 | dev_err(&rpdev->dev, "number of functions (%d) exceeds the limit supported(%d)\n", | ||
1060 | info->num_funcs, RPPC_MAX_NUM_FUNCS); | ||
1061 | return; | ||
1062 | } | ||
1063 | |||
1064 | rppcdev->num_funcs = info->num_funcs; | ||
1065 | rppcdev->signatures = kzalloc(rppcdev->num_funcs * | ||
1066 | sizeof(struct rppc_func_signature), GFP_KERNEL); | ||
1067 | if (!rppcdev->signatures) { | ||
1068 | dev_err(&rpdev->dev, "failed to alloc signatures\n"); | ||
1069 | return; | ||
1070 | } | ||
1071 | |||
1072 | dev_info(&rpdev->dev, "publised functions = %u\n", info->num_funcs); | ||
1073 | |||
1074 | /* send the function query for first function */ | ||
1075 | if (rppc_query_function(rpdev) == -EINVAL) | ||
1076 | dev_err(&rpdev->dev, "failed to get a reasonable number of functions!\n"); | ||
1077 | } | ||
1078 | |||
1079 | static void | ||
1080 | rppc_handle_fxninfo_resp(struct rpmsg_channel *rpdev, char *data, int len) | ||
1081 | { | ||
1082 | struct rppc_device *rppcdev = dev_get_drvdata(&rpdev->dev); | ||
1083 | struct rppc_query_function *fxn_info; | ||
1084 | struct rppc_func_signature *signature; | ||
1085 | u32 exp_len = sizeof(*fxn_info) + sizeof(struct rppc_msg_header); | ||
1086 | int i; | ||
1087 | |||
1088 | if (len != exp_len) { | ||
1089 | dev_err(&rpdev->dev, "invalid message length %d (expected %d bytes)", | ||
1090 | len, exp_len); | ||
1091 | return; | ||
1092 | } | ||
1093 | |||
1094 | fxn_info = RPPC_PAYLOAD(data, rppc_query_function); | ||
1095 | dev_dbg(&rpdev->dev, "response for function query of type %u\n", | ||
1096 | fxn_info->info_type); | ||
1097 | |||
1098 | switch (fxn_info->info_type) { | ||
1099 | case RPPC_INFOTYPE_FUNC_SIGNATURE: | ||
1100 | if (fxn_info->fxn_id >= rppcdev->num_funcs) { | ||
1101 | dev_err(&rpdev->dev, "function(%d) is out of range!\n", | ||
1102 | fxn_info->fxn_id); | ||
1103 | break; | ||
1104 | } | ||
1105 | |||
1106 | memcpy(&rppcdev->signatures[fxn_info->fxn_id], | ||
1107 | &fxn_info->info.signature, sizeof(*signature)); | ||
1108 | |||
1109 | /* TODO: delete these debug prints later */ | ||
1110 | dev_dbg(&rpdev->dev, "received info for func(%d); name = %s #params = %u\n", | ||
1111 | fxn_info->fxn_id, fxn_info->info.signature.name, | ||
1112 | fxn_info->info.signature.num_param); | ||
1113 | signature = &rppcdev->signatures[fxn_info->fxn_id]; | ||
1114 | for (i = 0; i < signature->num_param; i++) { | ||
1115 | dev_dbg(&rpdev->dev, "param[%u] type = %x dir = %u\n", | ||
1116 | i, signature->params[i].type, | ||
1117 | signature->params[i].direction); | ||
1118 | } | ||
1119 | |||
1120 | /* query again until we've hit our limit */ | ||
1121 | if (rppc_query_function(rpdev) == -EINVAL) { | ||
1122 | dev_dbg(&rpdev->dev, "reached end of function list!\n"); | ||
1123 | rppc_create_sysfs(rppcdev); | ||
1124 | } | ||
1125 | break; | ||
1126 | default: | ||
1127 | dev_err(&rpdev->dev, "unrecognized fxn query response %u\n", | ||
1128 | fxn_info->info_type); | ||
1129 | break; | ||
1130 | } | ||
1131 | } | ||
1132 | |||
1133 | static void rppc_driver_cb(struct rpmsg_channel *rpdev, void *data, int len, | ||
1134 | void *priv, u32 src) | ||
1135 | { | ||
1136 | struct rppc_msg_header *hdr = data; | ||
1137 | char *buf = (char *)data; | ||
1138 | |||
1139 | dev_dbg(&rpdev->dev, "<== incoming drv msg src %d len %d msg_type %d msg_len %d\n", | ||
1140 | src, len, hdr->msg_type, hdr->msg_len); | ||
1141 | |||
1142 | if (len <= sizeof(*hdr)) { | ||
1143 | dev_err(&rpdev->dev, "message truncated\n"); | ||
1144 | return; | ||
1145 | } | ||
1146 | |||
1147 | switch (hdr->msg_type) { | ||
1148 | case RPPC_MSGTYPE_DEVINFO_RESP: | ||
1149 | rppc_handle_devinfo_resp(rpdev, buf, len); | ||
1150 | break; | ||
1151 | case RPPC_MSGTYPE_FUNCTION_INFO: | ||
1152 | rppc_handle_fxninfo_resp(rpdev, buf, len); | ||
1153 | break; | ||
1154 | default: | ||
1155 | dev_err(&rpdev->dev, "unrecognized message type %u\n", | ||
1156 | hdr->msg_type); | ||
1157 | break; | ||
1158 | } | ||
1159 | } | ||
1160 | |||
1161 | static int find_rpccdev_by_name(int id, void *p, void *data) | ||
1162 | { | ||
1163 | struct rppc_device *rppcdev = p; | ||
1164 | |||
1165 | return strcmp(dev_name(rppcdev->dev), data) ? 0 : (int)p; | ||
1166 | } | ||
1167 | |||
1168 | /* | ||
1169 | * send a device info query message, the device will be created | ||
1170 | * during the processing of the response message | ||
1171 | */ | ||
1172 | static int rppc_device_create(struct rpmsg_channel *rpdev) | ||
1173 | { | ||
1174 | int ret; | ||
1175 | u32 len; | ||
1176 | char kbuf[512]; | ||
1177 | struct rppc_msg_header *hdr = (struct rppc_msg_header *)&kbuf[0]; | ||
1178 | |||
1179 | hdr->msg_type = RPPC_MSGTYPE_DEVINFO_REQ; | ||
1180 | hdr->msg_len = 0; | ||
1181 | len = sizeof(*hdr); | ||
1182 | ret = rpmsg_send(rpdev, (char *)kbuf, len); | ||
1183 | if (ret) { | ||
1184 | dev_err(&rpdev->dev, "rpmsg_send failed: %d\n", ret); | ||
1185 | return ret; | ||
1186 | } | ||
1187 | |||
1188 | return 0; | ||
1189 | } | ||
1190 | |||
1191 | static int rppc_probe(struct rpmsg_channel *rpdev) | ||
1192 | { | ||
1193 | int ret, major, minor; | ||
1194 | struct rppc_device *rppcdev = NULL; | ||
1195 | dev_t dev; | ||
1196 | char namedesc[RPMSG_NAME_SIZE]; | ||
1197 | |||
1198 | dev_info(&rpdev->dev, "probing service %s with src %u dst %u\n", | ||
1199 | rpdev->desc, rpdev->src, rpdev->dst); | ||
1200 | |||
1201 | mutex_lock(&rppc_devices_lock); | ||
1202 | snprintf(namedesc, sizeof(namedesc), "%s", rpdev->desc); | ||
1203 | rppcdev = (struct rppc_device *)idr_for_each(&rppc_devices, | ||
1204 | find_rpccdev_by_name, namedesc); | ||
1205 | if (rppcdev) { | ||
1206 | rppcdev->rpdev = rpdev; | ||
1207 | dev_set_drvdata(&rpdev->dev, rppcdev); | ||
1208 | goto serv_up; | ||
1209 | } | ||
1210 | |||
1211 | rppcdev = kzalloc(sizeof(*rppcdev), GFP_KERNEL); | ||
1212 | if (!rppcdev) { | ||
1213 | ret = -ENOMEM; | ||
1214 | goto exit; | ||
1215 | } | ||
1216 | |||
1217 | minor = idr_alloc(&rppc_devices, rppcdev, 0, 0, GFP_KERNEL); | ||
1218 | if (minor < 0) { | ||
1219 | ret = minor; | ||
1220 | dev_err(&rpdev->dev, "failed to get a minor number: %d\n", ret); | ||
1221 | goto free_rppcdev; | ||
1222 | } | ||
1223 | |||
1224 | INIT_LIST_HEAD(&rppcdev->instances); | ||
1225 | mutex_init(&rppcdev->lock); | ||
1226 | init_completion(&rppcdev->comp); | ||
1227 | |||
1228 | rppcdev->minor = minor; | ||
1229 | rppcdev->rpdev = rpdev; | ||
1230 | dev_set_drvdata(&rpdev->dev, rppcdev); | ||
1231 | |||
1232 | major = MAJOR(rppc_dev); | ||
1233 | cdev_init(&rppcdev->cdev, &rppc_fops); | ||
1234 | rppcdev->cdev.owner = THIS_MODULE; | ||
1235 | dev = MKDEV(major, minor); | ||
1236 | ret = cdev_add(&rppcdev->cdev, dev, 1); | ||
1237 | if (ret) { | ||
1238 | dev_err(&rpdev->dev, "cdev_add failed: %d\n", ret); | ||
1239 | goto free_id; | ||
1240 | } | ||
1241 | |||
1242 | rppcdev->dev = device_create(rppc_class, &rpdev->dev, dev, NULL, | ||
1243 | namedesc); | ||
1244 | if (IS_ERR(rppcdev->dev)) { | ||
1245 | int ret = PTR_ERR(rppcdev->dev); | ||
1246 | dev_err(&rpdev->dev, "device_create failed: %d\n", ret); | ||
1247 | goto free_cdev; | ||
1248 | } | ||
1249 | dev_set_drvdata(rppcdev->dev, rppcdev); | ||
1250 | |||
1251 | serv_up: | ||
1252 | ret = rppc_device_create(rpdev); | ||
1253 | if (ret) { | ||
1254 | dev_err(&rpdev->dev, "failed to query channel info: %d\n", ret); | ||
1255 | dev = MKDEV(MAJOR(rppc_dev), rppcdev->minor); | ||
1256 | goto free_dev; | ||
1257 | } | ||
1258 | |||
1259 | complete_all(&rppcdev->comp); | ||
1260 | |||
1261 | dev_dbg(&rpdev->dev, "new RPPC connection srv channel: %u -> %u!\n", | ||
1262 | rpdev->src, rpdev->dst); | ||
1263 | |||
1264 | mutex_unlock(&rppc_devices_lock); | ||
1265 | return 0; | ||
1266 | |||
1267 | free_dev: | ||
1268 | device_destroy(rppc_class, dev); | ||
1269 | free_cdev: | ||
1270 | cdev_del(&rppcdev->cdev); | ||
1271 | free_id: | ||
1272 | idr_remove(&rppc_devices, rppcdev->minor); | ||
1273 | free_rppcdev: | ||
1274 | kfree(rppcdev); | ||
1275 | exit: | ||
1276 | mutex_unlock(&rppc_devices_lock); | ||
1277 | return ret; | ||
1278 | } | ||
1279 | |||
1280 | static void rppc_remove(struct rpmsg_channel *rpdev) | ||
1281 | { | ||
1282 | struct rppc_device *rppcdev = dev_get_drvdata(&rpdev->dev); | ||
1283 | struct rppc_instance *rpc = NULL; | ||
1284 | int major = MAJOR(rppc_dev); | ||
1285 | |||
1286 | dev_dbg(rppcdev->dev, "removing rpmsg-rpc device %u.%u\n", | ||
1287 | major, rppcdev->minor); | ||
1288 | |||
1289 | mutex_lock(&rppc_devices_lock); | ||
1290 | |||
1291 | rppc_remove_sysfs(rppcdev); | ||
1292 | rppcdev->cur_func = 0; | ||
1293 | kfree(rppcdev->signatures); | ||
1294 | |||
1295 | /* if there are no instances in the list, just teardown */ | ||
1296 | if (list_empty(&rppcdev->instances)) { | ||
1297 | dev_dbg(&rpdev->dev, "no instances, removing device!\n"); | ||
1298 | device_destroy(rppc_class, MKDEV(major, rppcdev->minor)); | ||
1299 | cdev_del(&rppcdev->cdev); | ||
1300 | idr_remove(&rppc_devices, rppcdev->minor); | ||
1301 | kfree(rppcdev); | ||
1302 | mutex_unlock(&rppc_devices_lock); | ||
1303 | return; | ||
1304 | } | ||
1305 | |||
1306 | /* | ||
1307 | * if there are rpc instances that means that this is a recovery | ||
1308 | * operation. Don't clean the rppcdev, and retain it for reuse. | ||
1309 | * mark each instance as invalid, and complete any on-going transactions | ||
1310 | */ | ||
1311 | init_completion(&rppcdev->comp); | ||
1312 | mutex_lock(&rppcdev->lock); | ||
1313 | list_for_each_entry(rpc, &rppcdev->instances, list) { | ||
1314 | dev_dbg(rppcdev->dev, "instance %p in state %d\n", | ||
1315 | rpc, rpc->state); | ||
1316 | if ((rpc->state == RPPC_STATE_CONNECTED) && rpc->in_transition) | ||
1317 | complete_all(&rpc->reply_arrived); | ||
1318 | rpc->state = RPPC_STATE_STALE; | ||
1319 | wake_up_interruptible(&rpc->readq); | ||
1320 | } | ||
1321 | rppcdev->rpdev = NULL; | ||
1322 | mutex_unlock(&rppcdev->lock); | ||
1323 | mutex_unlock(&rppc_devices_lock); | ||
1324 | dev_dbg(&rpdev->dev, "removed rpmsg rpmsgrpc driver.\n"); | ||
1325 | } | ||
1326 | |||
1327 | static struct rpmsg_device_id rppc_id_table[] = { | ||
1328 | {.name = "rpmsg-rpc"}, | ||
1329 | {}, | ||
1330 | }; | ||
1331 | |||
1332 | static struct rpmsg_driver rppc_driver = { | ||
1333 | .drv.name = KBUILD_MODNAME, | ||
1334 | .drv.owner = THIS_MODULE, | ||
1335 | .id_table = rppc_id_table, | ||
1336 | .probe = rppc_probe, | ||
1337 | .remove = rppc_remove, | ||
1338 | .callback = rppc_driver_cb, | ||
1339 | }; | ||
1340 | |||
1341 | static int __init rppc_init(void) | ||
1342 | { | ||
1343 | int ret; | ||
1344 | |||
1345 | ret = alloc_chrdev_region(&rppc_dev, 0, RPPC_MAX_DEVICES, | ||
1346 | KBUILD_MODNAME); | ||
1347 | if (ret) { | ||
1348 | pr_err("alloc_chrdev_region failed: %d\n", ret); | ||
1349 | goto out; | ||
1350 | } | ||
1351 | |||
1352 | rppc_class = class_create(THIS_MODULE, KBUILD_MODNAME); | ||
1353 | if (IS_ERR(rppc_class)) { | ||
1354 | ret = PTR_ERR(rppc_class); | ||
1355 | pr_err("class_create failed: %d\n", ret); | ||
1356 | goto unreg_region; | ||
1357 | } | ||
1358 | |||
1359 | ret = register_rpmsg_driver(&rppc_driver); | ||
1360 | if (ret) { | ||
1361 | pr_err("register_rpmsg_driver failed: %d\n", ret); | ||
1362 | goto destroy_class; | ||
1363 | } | ||
1364 | return 0; | ||
1365 | |||
1366 | destroy_class: | ||
1367 | class_destroy(rppc_class); | ||
1368 | unreg_region: | ||
1369 | unregister_chrdev_region(rppc_dev, RPPC_MAX_DEVICES); | ||
1370 | out: | ||
1371 | return ret; | ||
1372 | } | ||
1373 | |||
1374 | static void __exit rppc_exit(void) | ||
1375 | { | ||
1376 | unregister_rpmsg_driver(&rppc_driver); | ||
1377 | class_destroy(rppc_class); | ||
1378 | unregister_chrdev_region(rppc_dev, RPPC_MAX_DEVICES); | ||
1379 | } | ||
1380 | |||
1381 | module_init(rppc_init); | ||
1382 | module_exit(rppc_exit); | ||
1383 | MODULE_DEVICE_TABLE(rpmsg, rppc_id_table); | ||
1384 | |||
1385 | MODULE_AUTHOR("Suman Anna <s-anna@ti.com>"); | ||
1386 | MODULE_AUTHOR("Erik Rainey <erik.rainey@ti.com>"); | ||
1387 | MODULE_DESCRIPTION("Remote Processor Procedure Call Driver"); | ||
1388 | MODULE_ALIAS("rpmsg:rpmsg-rpc"); | ||
1389 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/rpmsg/rpmsg_rpc_dmabuf.c b/drivers/rpmsg/rpmsg_rpc_dmabuf.c new file mode 100644 index 00000000000..2da48c4fee4 --- /dev/null +++ b/drivers/rpmsg/rpmsg_rpc_dmabuf.c | |||
@@ -0,0 +1,655 @@ | |||
1 | /* | ||
2 | * Remote Processor Procedure Call Driver | ||
3 | * | ||
4 | * Copyright(c) 2012-2014 Texas Instruments. All rights reserved. | ||
5 | * | ||
6 | * Erik Rainey <erik.rainey@ti.com> | ||
7 | * Suman Anna <s-anna@ti.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | */ | ||
18 | |||
19 | #include <linux/dma-buf.h> | ||
20 | #include <linux/rpmsg_rpc.h> | ||
21 | |||
22 | #include "rpmsg_rpc_internal.h" | ||
23 | |||
24 | #if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) || \ | ||
25 | defined(CONFIG_SOC_DRA7XX) | ||
26 | /* | ||
27 | * TODO: Remove tiler_stride_from_region & rppc_recalc_off from here, and | ||
28 | * rely on OMAPDRM/TILER code for OMAP dependencies | ||
29 | */ | ||
30 | |||
31 | /** | ||
32 | * tiler_stride_from_region() - calculate stride value for OMAP TILER | ||
33 | * @localphys: The local physical address. | ||
34 | * | ||
35 | * Returns the stride value as seen by remote processors based on the local | ||
36 | * address given to the function. This stride value is calculated based on the | ||
37 | * actual bus address, and is assumed that the TILER regions are mapped in a | ||
38 | * in a linear fashion. | ||
39 | * | ||
40 | * The physical address range decoding of local addresses is as follows: | ||
41 | * | ||
42 | * 0x60000000 - 0x67FFFFFF : 8-bit region (Stride is 16K bytes) | ||
43 | * 0x68000000 - 0x6FFFFFFF : 16-bit region (Stride is 32K bytes) | ||
44 | * 0x70000000 - 0x77FFFFFF : 32-bit region (Stride is 32K bytes) | ||
45 | * 0x78000000 - 0x7FFFFFFF : Page mode region (Stride is 0 bytes) | ||
46 | * | ||
47 | * Return: stride value | ||
48 | */ | ||
49 | static long tiler_stride_from_region(phys_addr_t localphys) | ||
50 | { | ||
51 | switch (localphys & 0xf8000000) { | ||
52 | case 0x60000000: | ||
53 | return 0x4000; | ||
54 | case 0x68000000: | ||
55 | case 0x70000000: | ||
56 | return 0x8000; | ||
57 | default: | ||
58 | return 0; | ||
59 | } | ||
60 | } | ||
61 | |||
62 | /** | ||
63 | * rppc_recalc_off() - Recalculate the unsigned offset in a buffer due to | ||
64 | * it's location in the TILER. | ||
65 | * @lpa: local physical address | ||
66 | * @uoff: unsigned offset | ||
67 | * | ||
68 | * Return: adjusted offset accounting for TILER region | ||
69 | */ | ||
70 | static long rppc_recalc_off(phys_addr_t lpa, long uoff) | ||
71 | { | ||
72 | long stride = tiler_stride_from_region(lpa); | ||
73 | |||
74 | return (stride != 0) ? (stride * (uoff / PAGE_SIZE)) + | ||
75 | (uoff & (PAGE_SIZE - 1)) : uoff; | ||
76 | } | ||
77 | #else | ||
78 | static inline long rppc_recalc_off(phys_addr_t lpa, long uoff) | ||
79 | { | ||
80 | return uoff; | ||
81 | } | ||
82 | #endif | ||
83 | |||
84 | /** | ||
85 | * rppc_alloc_dmabuf - import a buffer and store in a rppc buffer descriptor | ||
86 | * @rpc - rppc instance handle | ||
87 | * @fd - dma_buf file descriptor | ||
88 | * @autoreg: flag indicating the mode of creation | ||
89 | * | ||
90 | * This function primarily imports a buffer into the driver and holds | ||
91 | * a reference to the buffer on behalf of the remote processor. The | ||
92 | * buffer to be imported is represented by a dma-buf file descriptor, | ||
93 | * and as such is agnostic of the buffer allocator and/or exporter. | ||
94 | * The buffer is imported using the dma-buf api, and a driver specific | ||
95 | * buffer descriptor is used to store the imported buffer properties. | ||
96 | * The imported buffers are all stored in a rppc instance specific | ||
97 | * idr, to be used for looking up and cleaning up the driver buffer | ||
98 | * descriptors. | ||
99 | * | ||
100 | * The @autoreg field is used to dictate the manner in which the buffer | ||
101 | * is imported. The user-side can pre-register the buffers with the driver | ||
102 | * (which will import the buffers) if the application is going to use | ||
103 | * these repeatedly in consecutive function invocations. The buffers | ||
104 | * are auto-imported if the user-side has not registered them previously | ||
105 | * and are un-imported once the remote function call returns. | ||
106 | * | ||
107 | * This function is to be called only after checking that buffer has | ||
108 | * not been imported already (see rppc_find_dmabuf). | ||
109 | * | ||
110 | * Return: allocated rppc_dma_buf or error | ||
111 | */ | ||
112 | struct rppc_dma_buf *rppc_alloc_dmabuf(struct rppc_instance *rpc, int fd, | ||
113 | bool autoreg) | ||
114 | { | ||
115 | struct rppc_device *rppcdev = rpc->rppcdev; | ||
116 | struct rppc_dma_buf *dma; | ||
117 | void *ret; | ||
118 | int id; | ||
119 | |||
120 | dma = kzalloc(sizeof(*dma), GFP_KERNEL); | ||
121 | if (!dma) | ||
122 | return ERR_PTR(-ENOMEM); | ||
123 | |||
124 | dma->fd = fd; | ||
125 | dma->autoreg = !!autoreg; | ||
126 | dma->buf = dma_buf_get(dma->fd); | ||
127 | if (IS_ERR(dma->buf)) { | ||
128 | ret = dma->buf; | ||
129 | goto free_dma; | ||
130 | } | ||
131 | |||
132 | dma->attach = dma_buf_attach(dma->buf, rppcdev->dev); | ||
133 | if (IS_ERR(dma->attach)) { | ||
134 | ret = dma->attach; | ||
135 | goto put_buf; | ||
136 | } | ||
137 | |||
138 | dma->sgt = dma_buf_map_attachment(dma->attach, DMA_BIDIRECTIONAL); | ||
139 | if (IS_ERR(dma->sgt)) { | ||
140 | ret = dma->sgt; | ||
141 | goto detach_buf; | ||
142 | } | ||
143 | |||
144 | dma->pa = sg_dma_address(dma->sgt->sgl); | ||
145 | mutex_lock(&rpc->lock); | ||
146 | id = idr_alloc(&rpc->dma_idr, dma, 0, 0, GFP_KERNEL); | ||
147 | dma->id = id; | ||
148 | mutex_unlock(&rpc->lock); | ||
149 | if (id < 0) { | ||
150 | ret = ERR_PTR(id); | ||
151 | goto unmap_buf; | ||
152 | } | ||
153 | |||
154 | return dma; | ||
155 | |||
156 | unmap_buf: | ||
157 | dma_buf_unmap_attachment(dma->attach, dma->sgt, DMA_BIDIRECTIONAL); | ||
158 | detach_buf: | ||
159 | dma_buf_detach(dma->buf, dma->attach); | ||
160 | put_buf: | ||
161 | dma_buf_put(dma->buf); | ||
162 | free_dma: | ||
163 | kfree(dma); | ||
164 | |||
165 | return ret; | ||
166 | } | ||
167 | |||
168 | /** | ||
169 | * rppc_free_dmabuf - release the imported buffer | ||
170 | * @id: idr index of the imported buffer descriptor | ||
171 | * @p: imported buffer descriptor allocated during rppc_alloc_dmabuf | ||
172 | * @data: rpc instance handle | ||
173 | * | ||
174 | * This function is used to release a buffer that has been previously | ||
175 | * imported through a rppc_alloc_dmabuf call. The function can be used | ||
176 | * either individually for releasing a specific buffer or in a loop iterator | ||
177 | * for releasing all the buffers associated with a remote function call, or | ||
178 | * during cleanup of the rpc instance. | ||
179 | * | ||
180 | * Return: 0 on success, and -ENOENT if invalid pointers passed in | ||
181 | */ | ||
182 | int rppc_free_dmabuf(int id, void *p, void *data) | ||
183 | { | ||
184 | struct rppc_dma_buf *dma = p; | ||
185 | struct rppc_instance *rpc = data; | ||
186 | |||
187 | if (!dma || !rpc) | ||
188 | return -ENOENT; | ||
189 | |||
190 | dma_buf_unmap_attachment(dma->attach, dma->sgt, DMA_BIDIRECTIONAL); | ||
191 | dma_buf_detach(dma->buf, dma->attach); | ||
192 | dma_buf_put(dma->buf); | ||
193 | WARN_ON(id != dma->id); | ||
194 | idr_remove(&rpc->dma_idr, id); | ||
195 | kfree(dma); | ||
196 | |||
197 | return 0; | ||
198 | } | ||
199 | |||
200 | /** | ||
201 | * rppc_free_auto_dmabuf - release an auto-registered imported buffer | ||
202 | * @id: idr index of the imported buffer descriptor | ||
203 | * @p: imported buffer descriptor allocated during the rppc_alloc_dmabuf | ||
204 | * @data: rpc instance handle | ||
205 | * | ||
206 | * This function is used to release a buffer that has been previously | ||
207 | * imported automatically in the remote function invocation path (for | ||
208 | * rppc_alloc_dmabuf invocations with autoreg set as true). The function | ||
209 | * is used as a loop iterator for releasing all such buffers associated | ||
210 | * with a remote function call, and is called after processing the | ||
211 | * translations while handling the return message of an executed function | ||
212 | * call. | ||
213 | * | ||
214 | * Return: 0 on success or if the buffer is not auto-imported, and -ENOENT | ||
215 | * if invalid pointers passed in | ||
216 | */ | ||
217 | static int rppc_free_auto_dmabuf(int id, void *p, void *data) | ||
218 | { | ||
219 | struct rppc_dma_buf *dma = p; | ||
220 | struct rppc_instance *rpc = data; | ||
221 | |||
222 | if (WARN_ON(!dma || !rpc)) | ||
223 | return -ENOENT; | ||
224 | |||
225 | if (!dma->autoreg) | ||
226 | return 0; | ||
227 | |||
228 | rppc_free_dmabuf(id, p, data); | ||
229 | return 0; | ||
230 | } | ||
231 | |||
232 | /** | ||
233 | * find_dma_by_fd - find the allocated buffer descriptor | ||
234 | * @id: idr loop index | ||
235 | * @p: imported buffer descriptor associated with each idr index @id | ||
236 | * @data: dma-buf file descriptor of the buffer | ||
237 | * | ||
238 | * This is a idr iterator helper function, used for checking if a buffer | ||
239 | * has been imported before and present within the rpc instance's idr. | ||
240 | * | ||
241 | * Return: rpc buffer descriptor if file descriptor matches, and 0 otherwise | ||
242 | */ | ||
243 | static int find_dma_by_fd(int id, void *p, void *data) | ||
244 | { | ||
245 | struct rppc_dma_buf *dma = p; | ||
246 | int fd = (int)data; | ||
247 | |||
248 | if (dma->fd == fd) | ||
249 | return (int)p; | ||
250 | |||
251 | return 0; | ||
252 | } | ||
253 | |||
254 | /** | ||
255 | * rppc_find_dmabuf - find and return the rppc buffer descriptor of an imported | ||
256 | * buffer | ||
257 | * @rpc: rpc instance | ||
258 | * @fd: dma-buf file descriptor of the buffer | ||
259 | * | ||
260 | * This function is used to find and return the rppc buffer descriptor of an | ||
261 | * imported buffer. The function is used to check if ia buffer has already | ||
262 | * been imported (during manual registration to return an error), and to return | ||
263 | * the rppc buffer descriptor to be used for freeing (during manual | ||
264 | * deregistration). It is also used during auto-registration to see if the | ||
265 | * buffer needs to be imported through a rppc_alloc_dmabuf if not found. | ||
266 | * | ||
267 | * Return: rppc buffer descriptor of the buffer if it has already been imported, | ||
268 | * or NULL otherwise. | ||
269 | */ | ||
270 | struct rppc_dma_buf *rppc_find_dmabuf(struct rppc_instance *rpc, int fd) | ||
271 | { | ||
272 | struct rppc_dma_buf *node = NULL; | ||
273 | void *data = (void *)fd; | ||
274 | |||
275 | dev_dbg(rpc->rppcdev->dev, "looking for fd %u\n", fd); | ||
276 | |||
277 | mutex_lock(&rpc->lock); | ||
278 | node = (struct rppc_dma_buf *) | ||
279 | idr_for_each(&rpc->dma_idr, find_dma_by_fd, data); | ||
280 | mutex_unlock(&rpc->lock); | ||
281 | |||
282 | dev_dbg(rpc->rppcdev->dev, "returning node %p for fd %u\n", | ||
283 | node, fd); | ||
284 | |||
285 | return node; | ||
286 | } | ||
287 | |||
288 | /** | ||
289 | * rppc_map_page - import and map a kernel page in a dma_buf | ||
290 | * @rpc - rppc instance handle | ||
291 | * @fd: file descriptor of the dma_buf to import | ||
292 | * @offset: offset of the translate location within the buffer | ||
293 | * @base_ptr: pointer for returning mapped kernel address | ||
294 | * @dmabuf: pointer for returning the imported dma_buf | ||
295 | * | ||
296 | * A helper function to import the dma_buf buffer and map into kernel | ||
297 | * the page containing the offset within the buffer. The function is | ||
298 | * called by rppc_xlate_buffers and returns the pointers to the kernel | ||
299 | * mapped address and the imported dma_buf handle in arguments. The | ||
300 | * mapping is used for performing in-place translation of the user | ||
301 | * provided pointer at location @offset within the buffer. | ||
302 | * | ||
303 | * The mapping is achieved through the appropriate dma_buf ops, and | ||
304 | * the page will be unmapped after performing the translation. See | ||
305 | * also rppc_unmap_page. | ||
306 | * | ||
307 | * Return: 0 on success, or an appropriate failure code otherwise | ||
308 | */ | ||
309 | static int rppc_map_page(struct rppc_instance *rpc, int fd, u32 offset, | ||
310 | uint8_t **base_ptr, struct dma_buf **dmabuf) | ||
311 | { | ||
312 | int ret = 0; | ||
313 | uint8_t *ptr = NULL; | ||
314 | struct dma_buf *dbuf = NULL; | ||
315 | uint32_t pg_offset; | ||
316 | unsigned long pg_num; | ||
317 | size_t begin, end = PAGE_SIZE; | ||
318 | struct device *dev = rpc->rppcdev->dev; | ||
319 | |||
320 | if (!base_ptr || !dmabuf) | ||
321 | return -EINVAL; | ||
322 | |||
323 | pg_offset = (offset & (PAGE_SIZE - 1)); | ||
324 | begin = offset & PAGE_MASK; | ||
325 | pg_num = offset >> PAGE_SHIFT; | ||
326 | |||
327 | dbuf = dma_buf_get(fd); | ||
328 | if (IS_ERR(dbuf)) { | ||
329 | ret = PTR_ERR(dbuf); | ||
330 | dev_err(dev, "invalid dma_buf file descriptor passed! fd = %d ret = %d\n", | ||
331 | fd, ret); | ||
332 | goto out; | ||
333 | } | ||
334 | |||
335 | ret = dma_buf_begin_cpu_access(dbuf, begin, end, DMA_BIDIRECTIONAL); | ||
336 | if (ret < 0) { | ||
337 | dev_err(dev, "failed to acquire cpu access to the dma buf fd = %d offset = 0x%x, ret = %d\n", | ||
338 | fd, offset, ret); | ||
339 | goto put_dmabuf; | ||
340 | } | ||
341 | |||
342 | ptr = dma_buf_kmap(dbuf, pg_num); | ||
343 | if (!ptr) { | ||
344 | ret = -ENOBUFS; | ||
345 | dev_err(dev, "failed to map the page containing the translation into kernel fd = %d offset = 0x%x\n", | ||
346 | fd, offset); | ||
347 | goto end_cpuaccess; | ||
348 | } | ||
349 | |||
350 | *base_ptr = ptr; | ||
351 | *dmabuf = dbuf; | ||
352 | dev_dbg(dev, "kmap'd base_ptr = %p buf = %p into kernel from %zu for %zu bytes, pg_offset = 0x%x\n", | ||
353 | ptr, dbuf, begin, end, pg_offset); | ||
354 | return 0; | ||
355 | |||
356 | end_cpuaccess: | ||
357 | dma_buf_end_cpu_access(dbuf, begin, end, DMA_BIDIRECTIONAL); | ||
358 | put_dmabuf: | ||
359 | dma_buf_put(dbuf); | ||
360 | out: | ||
361 | return ret; | ||
362 | } | ||
363 | |||
364 | /** | ||
365 | * rppc_unmap_page - unmap and release a previously mapped page | ||
366 | * @rpc - rppc instance handle | ||
367 | * @offset: offset of the translate location within the buffer | ||
368 | * @base_ptr: kernel mapped address for the page to be unmapped | ||
369 | * @dmabuf: imported dma_buf to be released | ||
370 | * | ||
371 | * This function is called by rppc_xlate_buffers to unmap the | ||
372 | * page and release the imported buffer. It essentially undoes | ||
373 | * the functionality of rppc_map_page. | ||
374 | */ | ||
375 | static void rppc_unmap_page(struct rppc_instance *rpc, u32 offset, | ||
376 | uint8_t *base_ptr, struct dma_buf *dmabuf) | ||
377 | { | ||
378 | uint32_t pg_offset; | ||
379 | unsigned long pg_num; | ||
380 | size_t begin, end = PAGE_SIZE; | ||
381 | struct device *dev = rpc->rppcdev->dev; | ||
382 | |||
383 | if (!base_ptr || !dmabuf) | ||
384 | return; | ||
385 | |||
386 | pg_offset = (offset & (PAGE_SIZE - 1)); | ||
387 | begin = offset & PAGE_MASK; | ||
388 | pg_num = offset >> PAGE_SHIFT; | ||
389 | |||
390 | dev_dbg(dev, "Unkmaping base_ptr = %p of buf = %p from %zu to %zu bytes\n", | ||
391 | base_ptr, dmabuf, begin, end); | ||
392 | dma_buf_kunmap(dmabuf, pg_num, base_ptr); | ||
393 | dma_buf_end_cpu_access(dmabuf, begin, end, DMA_BIDIRECTIONAL); | ||
394 | dma_buf_put(dmabuf); | ||
395 | } | ||
396 | |||
397 | /** | ||
398 | * rppc_buffer_lookup - convert a buffer pointer to a remote processor pointer | ||
399 | * @rpc: rpc instance | ||
400 | * @uva: buffer pointer that needs to be translated | ||
401 | * @buva: base pointer of the allocated buffer | ||
402 | * @fd: dma-buf file descriptor of the allocated buffer | ||
403 | * | ||
404 | * This function is used for converting a pointer value in the function | ||
405 | * arguments to its appropriate remote processor device address value. | ||
406 | * The @uva and @buva are used for identifying the offset of the function | ||
407 | * argument pointer in an original allocation. This supports the cases where | ||
408 | * an offset pointer (eg: alignment, packed buffers etc) needs to be passed | ||
409 | * as the argument rather than the actual allocated pointer. | ||
410 | * | ||
411 | * The remote processor device address is done by retrieving the base physical | ||
412 | * address of the buffer by importing the buffer and converting it to the | ||
413 | * remote processor device address using a remoteproc api, with adjustments | ||
414 | * to the offset. | ||
415 | * | ||
416 | * The offset is specifically adjusted for OMAP TILER to account for the stride | ||
417 | * and mapping onto the remote processor. | ||
418 | * | ||
419 | * Return: remote processor device address, 0 on failure (implies invalid | ||
420 | * arguments) | ||
421 | */ | ||
422 | phys_addr_t rppc_buffer_lookup(struct rppc_instance *rpc, virt_addr_t uva, | ||
423 | virt_addr_t buva, int fd) | ||
424 | { | ||
425 | phys_addr_t lpa = 0, rda = 0; | ||
426 | long uoff = uva - buva; | ||
427 | struct device *dev = rpc->rppcdev->dev; | ||
428 | struct rppc_dma_buf *buf; | ||
429 | |||
430 | dev_dbg(dev, "buva = %p uva = %p offset = %ld [0x%016lx] fd = %d\n", | ||
431 | (void *)buva, (void *)uva, uoff, (ulong) uoff, fd); | ||
432 | |||
433 | if (uoff < 0) { | ||
434 | dev_err(dev, "invalid pointer values for uva = %p from buva = %p\n", | ||
435 | (void *)uva, (void *)buva); | ||
436 | return rda; | ||
437 | } | ||
438 | |||
439 | buf = rppc_find_dmabuf(rpc, fd); | ||
440 | if (IS_ERR_OR_NULL(buf)) { | ||
441 | buf = rppc_alloc_dmabuf(rpc, fd, true); | ||
442 | if (IS_ERR(buf)) | ||
443 | goto out; | ||
444 | } | ||
445 | |||
446 | lpa = buf->pa; | ||
447 | WARN_ON(lpa != sg_dma_address(buf->sgt->sgl)); | ||
448 | uoff = rppc_recalc_off(lpa, uoff); | ||
449 | lpa += uoff; | ||
450 | rda = rppc_local_to_remote_da(rpc, lpa); | ||
451 | |||
452 | out: | ||
453 | dev_dbg(dev, "host uva %p == host pa %p => remote da %p (fd %d)\n", | ||
454 | (void *)uva, (void *)lpa, (void *)rda, fd); | ||
455 | return rda; | ||
456 | } | ||
457 | |||
458 | /** | ||
459 | * rppc_xlate_buffers - translate argument pointers in the marshalled packet | ||
460 | * @rpc: rppc instance | ||
461 | * @func: rppc function packet being acted upon | ||
462 | * @direction: direction of translation | ||
463 | * | ||
464 | * This function translates all the pointers within the function call packet | ||
465 | * structure, based on the translation descriptor structures. The translation | ||
466 | * replaces the pointers to the appropriate pointers based on the direction. | ||
467 | * The function is invoked in preparing the packet to be sent to the remote | ||
468 | * processor-side and replaces the pointers to the remote processor device | ||
469 | * address pointers; and in processing the packet back after executing the | ||
470 | * function and replacing back the remote processor device addresses with | ||
471 | * the original pointers. | ||
472 | * | ||
473 | * Return: 0 on success, or an appropriate failure code otherwise | ||
474 | */ | ||
475 | int rppc_xlate_buffers(struct rppc_instance *rpc, struct rppc_function *func, | ||
476 | int direction) | ||
477 | { | ||
478 | uint8_t *base_ptr = NULL; | ||
479 | struct dma_buf *dbuf = NULL; | ||
480 | struct device *dev = rpc->rppcdev->dev; | ||
481 | uint32_t ptr_idx, pri_offset, sec_offset, offset, pg_offset, size; | ||
482 | int i, limit, inc = 1; | ||
483 | virt_addr_t kva, uva, buva; | ||
484 | phys_addr_t rda; | ||
485 | int ret = 0; | ||
486 | int xlate_fd; | ||
487 | |||
488 | limit = func->num_translations; | ||
489 | if (WARN_ON(!limit)) | ||
490 | return 0; | ||
491 | |||
492 | dev_dbg(dev, "operating on %d pointers\n", func->num_translations); | ||
493 | |||
494 | /* sanity check the translation elements */ | ||
495 | for (i = 0; i < limit; i++) { | ||
496 | ptr_idx = func->translations[i].index; | ||
497 | pri_offset = func->params[ptr_idx].data - | ||
498 | func->params[ptr_idx].base; | ||
499 | sec_offset = func->translations[i].offset; | ||
500 | size = func->params[ptr_idx].size; | ||
501 | |||
502 | if (ptr_idx >= RPPC_MAX_PARAMETERS) { | ||
503 | dev_err(dev, "xlate[%d] - invalid parameter pointer index %u\n", | ||
504 | i, ptr_idx); | ||
505 | return -EINVAL; | ||
506 | } | ||
507 | if (func->params[ptr_idx].type != RPPC_PARAM_TYPE_PTR) { | ||
508 | dev_err(dev, "xlate[%d] - parameter index %u is not a pointer (type %u)\n", | ||
509 | i, ptr_idx, func->params[ptr_idx].type); | ||
510 | return -EINVAL; | ||
511 | } | ||
512 | if (func->params[ptr_idx].data == 0) { | ||
513 | dev_err(dev, "xlate[%d] - supplied user pointer is NULL!\n", | ||
514 | i); | ||
515 | return -EINVAL; | ||
516 | } | ||
517 | if (sec_offset > (size - sizeof(virt_addr_t))) { | ||
518 | dev_err(dev, "xlate[%d] offset is larger than data area! (sec_offset = %u size = %u)\n", | ||
519 | i, sec_offset, size); | ||
520 | return -ENOSPC; | ||
521 | } | ||
522 | } | ||
523 | |||
524 | /* | ||
525 | * we may have a failure during translation, in which case use the same | ||
526 | * loop to unwind the whole operation | ||
527 | */ | ||
528 | for (i = 0; i != limit; i += inc) { | ||
529 | dev_dbg(dev, "starting translation %d of %d by %d\n", | ||
530 | i, limit, inc); | ||
531 | |||
532 | ptr_idx = func->translations[i].index; | ||
533 | pri_offset = func->params[ptr_idx].data - | ||
534 | func->params[ptr_idx].base; | ||
535 | sec_offset = func->translations[i].offset; | ||
536 | offset = pri_offset + sec_offset; | ||
537 | pg_offset = (offset & (PAGE_SIZE - 1)); | ||
538 | |||
539 | /* | ||
540 | * map into kernel the page containing the offset, where the | ||
541 | * pointer needs to be translated. | ||
542 | */ | ||
543 | ret = rppc_map_page(rpc, func->params[ptr_idx].fd, offset, | ||
544 | &base_ptr, &dbuf); | ||
545 | if (ret) { | ||
546 | dev_err(dev, "rppc_map_page failed, translation = %d param_index = %d fd = %d ret = %d\n", | ||
547 | i, ptr_idx, func->params[ptr_idx].fd, ret); | ||
548 | goto unwind; | ||
549 | } | ||
550 | |||
551 | /* | ||
552 | * perform the actual translation as per the direction. | ||
553 | */ | ||
554 | if (direction == RPPC_UVA_TO_RPA) { | ||
555 | kva = (virt_addr_t) &(base_ptr[pg_offset]); | ||
556 | if (kva & 0x3) { | ||
557 | dev_err(dev, "kernel virtual address %p is not aligned for translation = %d\n", | ||
558 | (void *)kva, i); | ||
559 | ret = -EADDRNOTAVAIL; | ||
560 | goto unmap; | ||
561 | } | ||
562 | |||
563 | uva = *(virt_addr_t *)kva; | ||
564 | if (!uva) { | ||
565 | dev_err(dev, "user pointer in the translated offset location is NULL for translation = %d\n", | ||
566 | i); | ||
567 | print_hex_dump(KERN_DEBUG, "KMAP: ", | ||
568 | DUMP_PREFIX_NONE, 16, 1, | ||
569 | base_ptr, PAGE_SIZE, true); | ||
570 | ret = -EADDRNOTAVAIL; | ||
571 | goto unmap; | ||
572 | } | ||
573 | |||
574 | buva = (virt_addr_t) func->translations[i].base; | ||
575 | xlate_fd = func->translations[i].fd; | ||
576 | |||
577 | dev_dbg(dev, "replacing UVA %p at KVA %p prt_idx = %u pg_offset = 0x%x fd = %d\n", | ||
578 | (void *)uva, (void *)kva, ptr_idx, | ||
579 | pg_offset, xlate_fd); | ||
580 | |||
581 | /* compute the corresponding remote device address */ | ||
582 | rda = rppc_buffer_lookup(rpc, uva, buva, xlate_fd); | ||
583 | if (!rda) { | ||
584 | ret = -ENODATA; | ||
585 | goto unmap; | ||
586 | } | ||
587 | |||
588 | /* | ||
589 | * replace the pointer, save the old value for replacing | ||
590 | * it back on the function return path | ||
591 | */ | ||
592 | func->translations[i].fd = (int32_t) uva; | ||
593 | *(phys_addr_t *)kva = rda; | ||
594 | dev_dbg(dev, "replaced UVA %p with RDA %p at KVA %p\n", | ||
595 | (void *)uva, (void *)rda, (void *)kva); | ||
596 | } else if (direction == RPPC_RPA_TO_UVA) { | ||
597 | kva = (virt_addr_t) &(base_ptr[pg_offset]); | ||
598 | if (kva & 0x3) { | ||
599 | ret = -EADDRNOTAVAIL; | ||
600 | goto unmap; | ||
601 | } | ||
602 | |||
603 | rda = *(phys_addr_t *)kva; | ||
604 | uva = (virt_addr_t) func->translations[i].fd; | ||
605 | WARN_ON(!uva); | ||
606 | *(virt_addr_t *)kva = uva; | ||
607 | |||
608 | dev_dbg(dev, "replaced RDA %p with UVA %p at KVA %p\n", | ||
609 | (void *)rda, (void *)uva, (void *)kva); | ||
610 | } | ||
611 | |||
612 | unmap: | ||
613 | /* | ||
614 | * unmap the page containing the translation from kernel, the | ||
615 | * next translation acting on the same fd might be in a | ||
616 | * different page altogether from the current one | ||
617 | */ | ||
618 | rppc_unmap_page(rpc, offset, base_ptr, dbuf); | ||
619 | dbuf = NULL; | ||
620 | base_ptr = NULL; | ||
621 | |||
622 | if (!ret) | ||
623 | continue; | ||
624 | |||
625 | unwind: | ||
626 | /* | ||
627 | * unwind all the previous translations if the failure occurs | ||
628 | * while sending a message to the remote-side. There's nothing | ||
629 | * to do but to continue if the failure occurs during the | ||
630 | * processing of a function response. | ||
631 | */ | ||
632 | if (direction == RPPC_UVA_TO_RPA) { | ||
633 | dev_err(dev, "unwinding UVA to RDA translations! translation = %d\n", | ||
634 | i); | ||
635 | direction = RPPC_RPA_TO_UVA; | ||
636 | inc = -1; | ||
637 | limit = -1; | ||
638 | } else if (direction == RPPC_RPA_TO_UVA) { | ||
639 | dev_err(dev, "error during UVA to RDA translations!! current translation = %d\n", | ||
640 | i); | ||
641 | } | ||
642 | } | ||
643 | |||
644 | /* | ||
645 | * all the in-place pointer replacements are done, release all the | ||
646 | * imported buffers during the remote function return path | ||
647 | */ | ||
648 | if (direction == RPPC_RPA_TO_UVA) { | ||
649 | mutex_lock(&rpc->lock); | ||
650 | idr_for_each(&rpc->dma_idr, rppc_free_auto_dmabuf, rpc); | ||
651 | mutex_unlock(&rpc->lock); | ||
652 | } | ||
653 | |||
654 | return ret; | ||
655 | } | ||
diff --git a/drivers/rpmsg/rpmsg_rpc_internal.h b/drivers/rpmsg/rpmsg_rpc_internal.h new file mode 100644 index 00000000000..ea787101375 --- /dev/null +++ b/drivers/rpmsg/rpmsg_rpc_internal.h | |||
@@ -0,0 +1,416 @@ | |||
1 | /* | ||
2 | * Remote Processor Procedure Call Driver | ||
3 | * | ||
4 | * Copyright(c) 2012-2014 Texas Instruments. All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * | ||
10 | * * Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer. | ||
12 | * * Redistributions in binary form must reproduce the above copyright | ||
13 | * notice, this list of conditions and the following disclaimer in | ||
14 | * the documentation and/or other materials provided with the | ||
15 | * distribution. | ||
16 | * * Neither the name Texas Instruments nor the names of its | ||
17 | * contributors may be used to endorse or promote products derived | ||
18 | * from this software without specific prior written permission. | ||
19 | * | ||
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
31 | */ | ||
32 | |||
33 | #ifndef _RPMSG_RPC_INTERNAL_H_ | ||
34 | #define _RPMSG_RPC_INTERNAL_H_ | ||
35 | |||
36 | #include <linux/cdev.h> | ||
37 | #include <linux/idr.h> | ||
38 | #include <linux/wait.h> | ||
39 | #include <linux/fs.h> | ||
40 | #include <linux/skbuff.h> | ||
41 | |||
42 | #ifdef CONFIG_PHYS_ADDR_T_64BIT | ||
43 | typedef u64 virt_addr_t; | ||
44 | #else | ||
45 | typedef u32 virt_addr_t; | ||
46 | #endif | ||
47 | |||
48 | /** | ||
49 | * struct rppc_device - The per-device (server) data | ||
50 | * @cdev: character device | ||
51 | * @dev: device | ||
52 | * @rpdev: rpmsg channel device associated with the remote server | ||
53 | * @instances: list of currently opened/connected instances | ||
54 | * @lock: mutex for protection of device variables | ||
55 | * @comp: completion signal used for unblocking users during a | ||
56 | * remote processor recovery | ||
57 | * @sig_attr: array of device attributes to use with the publishing of | ||
58 | * function information in sysfs for all the functions | ||
59 | * associated with this remote server device. | ||
60 | * @signatures: function signatures for the functions published by this | ||
61 | * remote server device | ||
62 | * @minor: minor number for the character device | ||
63 | * @num_funcs: number of functions published by this remote server device | ||
64 | * @cur_func: counter used while querying information for each function | ||
65 | * associated with this remote server device | ||
66 | * | ||
67 | * A rppc_device indicates the base remote server device that supports the | ||
68 | * execution of a bunch of remote functions. Each such remote server device | ||
69 | * has an associated character device that is used by the userland apps to | ||
70 | * connect to it, and request the execution of any of these remote functions. | ||
71 | */ | ||
72 | struct rppc_device { | ||
73 | struct cdev cdev; | ||
74 | struct device *dev; | ||
75 | struct rpmsg_channel *rpdev; | ||
76 | struct list_head instances; | ||
77 | struct mutex lock; | ||
78 | struct completion comp; | ||
79 | struct device_attribute *sig_attr; | ||
80 | struct rppc_func_signature *signatures; | ||
81 | unsigned int minor; | ||
82 | u32 num_funcs; | ||
83 | u32 cur_func; | ||
84 | }; | ||
85 | |||
86 | /** | ||
87 | * struct rppc_instance - The per-instance data structure (per user) | ||
88 | * @list: list node | ||
89 | * @rppcdev: the rppc device (remote server instance) handle | ||
90 | * @queue: queue of buffers waiting to be read by the user | ||
91 | * @lock: mutex for protecting instance variables | ||
92 | * @readq: wait queue of blocked user threads waiting to read data | ||
93 | * @reply_arrived: signal for unblocking the user thread | ||
94 | * @ept: rpmsg endpoint associated with the rppc device | ||
95 | * @in_transition: flag for storing a pending connection request | ||
96 | * @dst: destination end-point of the remote server instance | ||
97 | * @state: state of the opened instance, see enum rppc_state | ||
98 | * @dma_idr: idr structure storing the imported buffers | ||
99 | * @msg_id: last/current active message id tagged on a message sent | ||
100 | * to the remote processor | ||
101 | * @fxn_list: list of functions published by the remote server instance | ||
102 | * | ||
103 | * This structure is created whenever the user opens the driver. The | ||
104 | * various elements of the structure are used to store its state and | ||
105 | * information about the remote server it is connected to. | ||
106 | */ | ||
107 | struct rppc_instance { | ||
108 | struct list_head list; | ||
109 | struct rppc_device *rppcdev; | ||
110 | struct sk_buff_head queue; | ||
111 | struct mutex lock; | ||
112 | wait_queue_head_t readq; | ||
113 | struct completion reply_arrived; | ||
114 | struct rpmsg_endpoint *ept; | ||
115 | int in_transition; | ||
116 | u32 dst; | ||
117 | int state; | ||
118 | struct idr dma_idr; | ||
119 | u16 msg_id; | ||
120 | struct list_head fxn_list; | ||
121 | }; | ||
122 | |||
123 | /** | ||
124 | * struct rppc_function_list - outstanding function descriptor | ||
125 | * @list: list node | ||
126 | * @function: current remote function descriptor | ||
127 | * @msg_id: message id for the function invocation | ||
128 | * | ||
129 | * This structure is used for storing the information about outstanding | ||
130 | * functions that the remote side is executing. This provides the host | ||
131 | * side a means to track every outstanding function, and a means to process | ||
132 | * the responses received from the remote processor. | ||
133 | */ | ||
134 | struct rppc_function_list { | ||
135 | struct list_head list; | ||
136 | struct rppc_function *function; | ||
137 | u16 msg_id; | ||
138 | }; | ||
139 | |||
140 | /** | ||
141 | * struct rppc_dma_buf - a rppc dma_buf descriptor for buffers imported by rppc | ||
142 | * @fd: file descriptor of a buffer used to import the dma_buf | ||
143 | * @id: idr index value for this descriptor | ||
144 | * @buf: imported dma_buf handle for the buffer | ||
145 | * @attach: attachment structure returned by exporter upon attaching to | ||
146 | * the buffer by the rppc driver | ||
147 | * @sgt: the scatter-gather structure associated with @buf | ||
148 | * @pa: the physical address associated with the imported buffer | ||
149 | * @autoreg: mode of how the descriptor is created | ||
150 | * | ||
151 | * This structure is used for storing the information relevant to the imported | ||
152 | * buffer. The rpmsg rpc driver acts as a proxy on behalf of the remote core | ||
153 | * and attaches itself to the driver while the remote processor/accelerators are | ||
154 | * operating on the buffer. | ||
155 | */ | ||
156 | struct rppc_dma_buf { | ||
157 | int fd; | ||
158 | int id; | ||
159 | struct dma_buf *buf; | ||
160 | struct dma_buf_attachment *attach; | ||
161 | struct sg_table *sgt; | ||
162 | phys_addr_t pa; | ||
163 | int autoreg; | ||
164 | }; | ||
165 | |||
166 | /** | ||
167 | * enum rppc_msg_type - message types exchanged between host and remote server | ||
168 | * @RPPC_MSGTYPE_DEVINFO_REQ: request remote server for channel information | ||
169 | * @RPPC_MSGTYPE_DEVINFO_RESP: response message from remote server for a | ||
170 | * request of type RPPC_MSGTYPE_DEVINFO_REQ | ||
171 | * @RPPC_MSGTYPE_FUNCTION_QUERY: request remote server for information about a | ||
172 | * specific function | ||
173 | * @RPPC_MSGTYPE_FUNCTION_INFO: response message from remote server for a prior | ||
174 | * request of type RPPC_MSGTYPE_FUNCTION_QUERY | ||
175 | * @RPPC_MSGTYPE_CREATE_REQ: request the remote server manager to create a new | ||
176 | * remote server instance. No secondary data is | ||
177 | * needed | ||
178 | * @RPPC_MSGTYPE_CREATE_RESP: response message from remote server manager for a | ||
179 | * request of type RPPC_MSGTYPE_CREATE_REQ. The | ||
180 | * message contains the new endpoint address in the | ||
181 | * rppc_instance_handle | ||
182 | * @RPPC_MSGTYPE_DELETE_REQ: request the remote server manager to delete a | ||
183 | * remote server instance | ||
184 | * @RPPC_MSGTYPE_DELETE_RESP: response message from remote server manager to a | ||
185 | * request of type RPPC_MSGTYPE_DELETE_REQ. The | ||
186 | * message contains the old endpoint address in the | ||
187 | * rppc_instance_handle | ||
188 | * @RPPC_MSGTYPE_FUNCTION_CALL: request remote server to execute a specific | ||
189 | * function | ||
190 | * @RPPC_MSGTYPE_FUNCTION_RET: response message carrying the return status of a | ||
191 | * specific function execution | ||
192 | * @RPPC_MSGTYPE_ERROR: an error response message sent by either the remote | ||
193 | * server manager or remote server instance while | ||
194 | * processing any request messages | ||
195 | * @RPPC_MSGTYPE_MAX: limit value to define the maximum message type value | ||
196 | * | ||
197 | * Every message exchanged between the host-side and the remote-side is | ||
198 | * identified through a message type defined in this enum. The message type | ||
199 | * is specified through the msg_type field of the struct rppc_msg_header, | ||
200 | * which is the common header for rppc messages. | ||
201 | */ | ||
202 | enum rppc_msg_type { | ||
203 | RPPC_MSGTYPE_DEVINFO_REQ = 0, | ||
204 | RPPC_MSGTYPE_DEVINFO_RESP = 1, | ||
205 | RPPC_MSGTYPE_FUNCTION_QUERY = 2, | ||
206 | RPPC_MSGTYPE_FUNCTION_INFO = 3, | ||
207 | RPPC_MSGTYPE_CREATE_REQ = 6, | ||
208 | RPPC_MSGTYPE_CREATE_RESP = 8, | ||
209 | RPPC_MSGTYPE_DELETE_REQ = 4, | ||
210 | RPPC_MSGTYPE_DELETE_RESP = 7, | ||
211 | RPPC_MSGTYPE_FUNCTION_CALL = 5, | ||
212 | RPPC_MSGTYPE_FUNCTION_RET = 9, | ||
213 | RPPC_MSGTYPE_ERROR = 10, | ||
214 | RPPC_MSGTYPE_MAX | ||
215 | }; | ||
216 | |||
217 | /** | ||
218 | * enum rppc_infotype - function information query type | ||
219 | * @RPPC_INFOTYPE_FUNC_SIGNATURE: function signature | ||
220 | * @RPPC_INFOTYPE_NUM_CALLS: the number of times a function has been invoked | ||
221 | * @RPPC_INFOTYPE_MAX: limit value to define the maximum info type | ||
222 | * | ||
223 | * This enum is used for identifying the type of information queried | ||
224 | * from the remote processor. Only RPPC_INFOTYPE_FUNC_SIGNATURE is | ||
225 | * currently used. | ||
226 | */ | ||
227 | enum rppc_infotype { | ||
228 | RPPC_INFOTYPE_FUNC_SIGNATURE = 1, | ||
229 | RPPC_INFOTYPE_NUM_CALLS, | ||
230 | RPPC_INFOTYPE_MAX | ||
231 | }; | ||
232 | |||
233 | /** | ||
234 | * struct rppc_instance_handle - rppc instance information | ||
235 | * @endpoint_address: end-point address of the remote server instance | ||
236 | * @status: status of the request | ||
237 | * | ||
238 | * This structure indicates the format of the message payload exchanged | ||
239 | * between the host and the remote sides for messages pertaining to | ||
240 | * creation and deletion of the remote server instances. This payload | ||
241 | * is associated with messages of type RPPC_MSGTYPE_CREATE_RESP and | ||
242 | * RPPC_MSGTYPE_DELETE_RESP. | ||
243 | */ | ||
244 | struct rppc_instance_handle { | ||
245 | uint32_t endpoint_address; | ||
246 | uint32_t status; | ||
247 | } __packed; | ||
248 | |||
249 | /** | ||
250 | * struct rppc_param_signature - parameter descriptor | ||
251 | * @direction: input or output classifier, see enum rppc_param_direction | ||
252 | * @type: parameter data type, see enum rppc_param_type | ||
253 | * @count: used to do some basic sanity checking on array bounds | ||
254 | */ | ||
255 | struct rppc_param_signature { | ||
256 | uint32_t direction; | ||
257 | uint32_t type; | ||
258 | uint32_t count; | ||
259 | }; | ||
260 | |||
261 | /** | ||
262 | * struct rppc_func_signature - remote function signature descriptor | ||
263 | * @name: name of the function | ||
264 | * @num_param: number of parameters to the function | ||
265 | * @params: parameter descriptors for each of the parameters | ||
266 | * | ||
267 | * This structure contains the indicates the format of the message payload | ||
268 | * exchanged between the host and the remote sides for messages pertaining | ||
269 | * to creation and deletion of the remote server instances. This payload | ||
270 | * is associated with messages of type RPPC_MSGTYPE_CREATE_RESP and | ||
271 | * RPPC_MSGTYPE_FUNCTION_INFO. | ||
272 | */ | ||
273 | struct rppc_func_signature { | ||
274 | char name[RPPC_MAX_CHANNEL_NAMELEN]; | ||
275 | uint32_t num_param; | ||
276 | struct rppc_param_signature params[RPPC_MAX_NUM_PARAMS + 1]; | ||
277 | }; | ||
278 | |||
279 | /** | ||
280 | * struct rppc_query_function - function info packet structure | ||
281 | * @info_type: type of the function information requested, see | ||
282 | * enum rppc_infotype | ||
283 | * @fxn_id: function identifier on this specific remote server instance | ||
284 | * @num_calls: number of types function is invoked, filled in during a response | ||
285 | * (only valid for rppc_infotype RPPC_INFOTYPE_NUM_CALLS) | ||
286 | * @signature: the signature of the function including its return type, | ||
287 | * parameters and thier description | ||
288 | * (only valid for rppc_infotype RPPC_INFOTYPE_FUNC_SIGNATURE) | ||
289 | * | ||
290 | * This structure indicates the format of the message payload exchanged | ||
291 | * between the host and the remote sides for messages pertaining to | ||
292 | * information about each function supported by the remote server instance. | ||
293 | * This payload is associated with messages of type RPPC_MSGTYPE_FUNCTION_QUERY | ||
294 | * and RPPC_MSGTYPE_FUNCTION_INFO. | ||
295 | */ | ||
296 | struct rppc_query_function { | ||
297 | uint32_t info_type; | ||
298 | uint32_t fxn_id; | ||
299 | union { | ||
300 | uint32_t num_calls; | ||
301 | struct rppc_func_signature signature; | ||
302 | } info; | ||
303 | }; | ||
304 | |||
305 | /** | ||
306 | * enum rppc_translate_direction - pointer translation direction | ||
307 | * @RPPC_UVA_TO_RPA: user virtual address to remote device address translation | ||
308 | * @RPPC_RPA_TO_UVA: remote device address to user virtual address translation | ||
309 | * | ||
310 | * An enum used for identifying the rppc function message direction, whether | ||
311 | * it is going to the remote side, or is a response from the remote side. This | ||
312 | * is used in translating the pointers from the host-side to the remote-side | ||
313 | * and vice versa depending on the packet direction. | ||
314 | */ | ||
315 | enum rppc_translate_direction { | ||
316 | RPPC_UVA_TO_RPA, | ||
317 | RPPC_RPA_TO_UVA, | ||
318 | }; | ||
319 | |||
320 | /** | ||
321 | * enum rppc_state - rppc instance state | ||
322 | * @RPPC_STATE_DISCONNECTED: uninitialized state | ||
323 | * @RPPC_STATE_CONNECTED: initialized state | ||
324 | * @RPPC_STATE_STALE: invalid or stale state | ||
325 | * @RPPC_STATE_MAX: limit value for the different state values | ||
326 | * | ||
327 | * This enum value is used to define the status values of a | ||
328 | * rppc_instance object. | ||
329 | */ | ||
330 | enum rppc_state { | ||
331 | RPPC_STATE_DISCONNECTED, | ||
332 | RPPC_STATE_CONNECTED, | ||
333 | RPPC_STATE_STALE, | ||
334 | RPPC_STATE_MAX | ||
335 | }; | ||
336 | |||
337 | /** | ||
338 | * struct rppc_device_info - rppc remote server device info | ||
339 | * @num_funcs: number of functions supported by a remote server instance | ||
340 | * | ||
341 | * This structure indicates the format of the message payload responded by | ||
342 | * the remote side upon a request for message type RPPC_MSGTYPE_DEVINFO_REQ. | ||
343 | * This payload is associated with messages of type RPPC_MSGTYPE_DEVINFO_RESP. | ||
344 | */ | ||
345 | struct rppc_device_info { | ||
346 | uint32_t num_funcs; | ||
347 | }; | ||
348 | |||
349 | /** | ||
350 | * struct rppc_error - rppc error information | ||
351 | * @endpoint_address: end-point address of the remote server instance | ||
352 | * @status: status of the request | ||
353 | * | ||
354 | * This structure indicates the format of the message payload exchanged | ||
355 | * between the host and the remote sides for error messages. This payload | ||
356 | * is associated with messages of type RPPC_MSGTYPE_ERROR | ||
357 | * XXX: check if this is needed still, not used anywhere at present | ||
358 | */ | ||
359 | struct rppc_error { | ||
360 | uint32_t endpoint_address; | ||
361 | uint32_t status; | ||
362 | } __packed; | ||
363 | |||
364 | /** | ||
365 | * struct rppc_param_data - marshalled parameter data structure | ||
366 | * @size: size of the parameter data type | ||
367 | * @data: actual parameter data | ||
368 | * | ||
369 | * Each function parameter is marshalled in this form between the host | ||
370 | * and remote sides. The @data field would contain the actual value of | ||
371 | * of the parameter if it is a scalar argument type, or the remote-side | ||
372 | * device address (virtual address) of the pointer if the argument is | ||
373 | * of pointer type. | ||
374 | */ | ||
375 | struct rppc_param_data { | ||
376 | size_t size; | ||
377 | size_t data; | ||
378 | } __packed; | ||
379 | |||
380 | /** | ||
381 | * struct rppc_msg_header - generic rpmsg rpc message header | ||
382 | * @msg_type: message type, see enum rppc_msg_type | ||
383 | * @msg_len: length of the message payload in bytes | ||
384 | * @msg_data: the actual message payload (depends on message type) | ||
385 | * | ||
386 | * All RPPC messages will start with this common header (which will begin | ||
387 | * right after the standard rpmsg header ends). | ||
388 | */ | ||
389 | struct rppc_msg_header { | ||
390 | uint32_t msg_type; | ||
391 | uint32_t msg_len; | ||
392 | uint8_t msg_data[0]; | ||
393 | } __packed; | ||
394 | |||
395 | #define RPPC_PAYLOAD(ptr, type) \ | ||
396 | ((struct type *)&(ptr)[sizeof(struct rppc_msg_header)]) | ||
397 | |||
398 | |||
399 | /* from rpmsg_rpc.c */ | ||
400 | phys_addr_t rppc_local_to_remote_da(struct rppc_instance *rpc, phys_addr_t pa); | ||
401 | |||
402 | /* from rpmsg_rpc_dmabuf.c */ | ||
403 | struct rppc_dma_buf *rppc_alloc_dmabuf(struct rppc_instance *rpc, | ||
404 | int fd, bool autoreg); | ||
405 | struct rppc_dma_buf *rppc_find_dmabuf(struct rppc_instance *rpc, int fd); | ||
406 | int rppc_free_dmabuf(int id, void *p, void *data); | ||
407 | phys_addr_t rppc_buffer_lookup(struct rppc_instance *rpc, virt_addr_t uva, | ||
408 | virt_addr_t buva, int fd); | ||
409 | int rppc_xlate_buffers(struct rppc_instance *rpc, struct rppc_function *func, | ||
410 | int direction); | ||
411 | |||
412 | /* from rpmsg_rpc_sysfs.c */ | ||
413 | int rppc_create_sysfs(struct rppc_device *rppcdev); | ||
414 | int rppc_remove_sysfs(struct rppc_device *rppcdev); | ||
415 | |||
416 | #endif | ||
diff --git a/drivers/rpmsg/rpmsg_rpc_sysfs.c b/drivers/rpmsg/rpmsg_rpc_sysfs.c new file mode 100644 index 00000000000..da0e3275e47 --- /dev/null +++ b/drivers/rpmsg/rpmsg_rpc_sysfs.c | |||
@@ -0,0 +1,255 @@ | |||
1 | /* | ||
2 | * Remote Processor Procedure Call Driver | ||
3 | * | ||
4 | * Copyright(c) 2012-2014 Texas Instruments. All rights reserved. | ||
5 | * | ||
6 | * Erik Rainey <erik.rainey@ti.com> | ||
7 | * Suman Anna <s-anna@ti.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | */ | ||
18 | |||
19 | #include <linux/device.h> | ||
20 | #include <linux/slab.h> | ||
21 | #include <linux/rpmsg_rpc.h> | ||
22 | |||
23 | #include "rpmsg_rpc_internal.h" | ||
24 | |||
25 | static ssize_t show_numfuncs(struct device *dev, struct device_attribute *attr, | ||
26 | char *buf) | ||
27 | { | ||
28 | struct rppc_device *rppcdev = dev_get_drvdata(dev); | ||
29 | return snprintf(buf, PAGE_SIZE, "%u\n", rppcdev->num_funcs - 1); | ||
30 | } | ||
31 | |||
32 | static ssize_t set_type_c(char *buf, uint32_t len, | ||
33 | struct rppc_param_signature *psig) | ||
34 | { | ||
35 | char *isptr = (psig->type & RPPC_PARAM_PTR ? " *" : ""); | ||
36 | |||
37 | switch (psig->type & RPPC_PARAM_MASK) { | ||
38 | case RPPC_PARAM_S08: | ||
39 | return snprintf(buf, len, "int8_t%s", isptr); | ||
40 | case RPPC_PARAM_U08: | ||
41 | return snprintf(buf, len, "uint8_t%s", isptr); | ||
42 | case RPPC_PARAM_S16: | ||
43 | return snprintf(buf, len, "int16_t%s", isptr); | ||
44 | case RPPC_PARAM_U16: | ||
45 | return snprintf(buf, len, "uint16_t%s", isptr); | ||
46 | case RPPC_PARAM_S32: | ||
47 | return snprintf(buf, len, "int32_t%s", isptr); | ||
48 | case RPPC_PARAM_U32: | ||
49 | return snprintf(buf, len, "uint32_t%s", isptr); | ||
50 | case RPPC_PARAM_S64: | ||
51 | return snprintf(buf, len, "int64_t%s", isptr); | ||
52 | case RPPC_PARAM_U64: | ||
53 | return snprintf(buf, len, "uint64_t%s", isptr); | ||
54 | default: | ||
55 | return snprintf(buf, len, "<unknown>%s", isptr); | ||
56 | } | ||
57 | } | ||
58 | |||
59 | static ssize_t set_type_doxy(char *buf, uint32_t len, | ||
60 | struct rppc_param_signature *psig) | ||
61 | { | ||
62 | char *isptr = (psig->type & RPPC_PARAM_PTR ? " *" : ""); | ||
63 | char dir[10]; | ||
64 | |||
65 | switch (psig->direction) { | ||
66 | case RPPC_PARAMDIR_IN: | ||
67 | snprintf(dir, sizeof(dir), "[in]"); | ||
68 | break; | ||
69 | case RPPC_PARAMDIR_OUT: | ||
70 | snprintf(dir, sizeof(dir), "[out]"); | ||
71 | break; | ||
72 | case RPPC_PARAMDIR_BI: | ||
73 | snprintf(dir, sizeof(dir), "[in,out]"); | ||
74 | break; | ||
75 | default: | ||
76 | snprintf(dir, sizeof(dir), "[unknown]"); | ||
77 | break; | ||
78 | } | ||
79 | |||
80 | switch (psig->type & RPPC_PARAM_MASK) { | ||
81 | case RPPC_PARAM_S08: | ||
82 | return snprintf(buf, len, "%s int8_t%s", dir, isptr); | ||
83 | case RPPC_PARAM_U08: | ||
84 | return snprintf(buf, len, "%s uint8_t%s", dir, isptr); | ||
85 | case RPPC_PARAM_S16: | ||
86 | return snprintf(buf, len, "%s int16_t%s", dir, isptr); | ||
87 | case RPPC_PARAM_U16: | ||
88 | return snprintf(buf, len, "%s uint16_t%s", dir, isptr); | ||
89 | case RPPC_PARAM_S32: | ||
90 | return snprintf(buf, len, "%s int32_t%s", dir, isptr); | ||
91 | case RPPC_PARAM_U32: | ||
92 | return snprintf(buf, len, "%s uint32_t%s", dir, isptr); | ||
93 | case RPPC_PARAM_S64: | ||
94 | return snprintf(buf, len, "%s int64_t%s", dir, isptr); | ||
95 | case RPPC_PARAM_U64: | ||
96 | return snprintf(buf, len, "%s uint64_t%s", dir, isptr); | ||
97 | default: | ||
98 | return snprintf(buf, len, "%s <unknown>%s", dir, isptr); | ||
99 | } | ||
100 | } | ||
101 | |||
102 | static ssize_t show_c_function(struct device *dev, | ||
103 | struct device_attribute *attr, char *buf) | ||
104 | { | ||
105 | struct rppc_device *rppcdev = dev_get_drvdata(dev); | ||
106 | char return_value[11]; /* longest string is strlen("uintXX_t *") = 10 */ | ||
107 | char parameters[110]; /* longest string * 10 + 9(,) */ | ||
108 | char comment[300]; | ||
109 | int p; | ||
110 | ssize_t pidx = 0; | ||
111 | ssize_t cidx = 0; | ||
112 | __u32 index = 0; | ||
113 | |||
114 | if (sscanf(attr->attr.name, "c_function%u\n", &index) != 1) | ||
115 | return -EIO; | ||
116 | |||
117 | memset(return_value, 0, sizeof(return_value)); | ||
118 | memset(parameters, 0, sizeof(parameters)); | ||
119 | |||
120 | strcpy(return_value, "void"); | ||
121 | strcpy(parameters, "void"); | ||
122 | cidx += snprintf(&comment[cidx], sizeof(comment) - cidx, "/**\n"); | ||
123 | cidx += snprintf(&comment[cidx], sizeof(comment) - cidx, | ||
124 | " * \\fn %s\n", rppcdev->signatures[index].name); | ||
125 | for (p = 0; p < rppcdev->signatures[index].num_param; p++) { | ||
126 | if (p == 0) { | ||
127 | set_type_c(return_value, sizeof(return_value), | ||
128 | &rppcdev->signatures[index].params[0]); | ||
129 | cidx += snprintf(&comment[cidx], sizeof(comment) - cidx, | ||
130 | " * \\return %s\n", return_value); | ||
131 | } else { | ||
132 | pidx += set_type_c(¶meters[pidx], | ||
133 | sizeof(parameters) - pidx, | ||
134 | &rppcdev->signatures[index].params[p]); | ||
135 | if (p != rppcdev->signatures[index].num_param - 1) | ||
136 | parameters[pidx++] = ','; | ||
137 | cidx += snprintf(&comment[cidx], sizeof(comment) - cidx, | ||
138 | " * \\param "); | ||
139 | cidx += set_type_doxy(&comment[cidx], | ||
140 | sizeof(comment) - cidx, | ||
141 | &rppcdev->signatures[index].params[p]); | ||
142 | cidx += snprintf(&comment[cidx], sizeof(comment) - cidx, | ||
143 | "\n"); | ||
144 | } | ||
145 | } | ||
146 | if (p <= 1) | ||
147 | pidx += strlen("void"); | ||
148 | if (pidx < sizeof(parameters)) | ||
149 | parameters[pidx] = '\0'; | ||
150 | cidx += snprintf(&comment[cidx], sizeof(comment) - cidx, " */"); | ||
151 | return snprintf(buf, PAGE_SIZE, "%s\nextern \"C\" %s %s(%s);\n", | ||
152 | comment, return_value, rppcdev->signatures[index].name, | ||
153 | parameters); | ||
154 | } | ||
155 | |||
156 | static struct device_attribute rppc_attrs[] = { | ||
157 | __ATTR(num_funcs, S_IRUGO, show_numfuncs, NULL), | ||
158 | }; | ||
159 | |||
160 | /** | ||
161 | * rppc_create_sysfs - Creates the sysfs entry structures for the instance | ||
162 | * @rppcdev: the rppc device (remote server instance) handle | ||
163 | * | ||
164 | * Helper function to create all the sysfs entries associated with a rppc | ||
165 | * device. Each device is associated with a number of remote procedure | ||
166 | * functions. The number of such functions and the signatures of those | ||
167 | * functions are created in sysfs. Function is invoked after querying | ||
168 | * the remote side about the supported functions on this device. | ||
169 | * | ||
170 | * The entries are split into a set of static entries, which are common | ||
171 | * between all rppc devices, and a set of dynamic entries specific to | ||
172 | * each rppc device. | ||
173 | * | ||
174 | * Return: 0 on success, or an appropriate error code otherwise | ||
175 | */ | ||
176 | int rppc_create_sysfs(struct rppc_device *rppcdev) | ||
177 | { | ||
178 | int i; | ||
179 | int ret; | ||
180 | |||
181 | rppcdev->sig_attr = kzalloc(sizeof(*rppcdev->sig_attr) * | ||
182 | rppcdev->num_funcs, GFP_KERNEL); | ||
183 | if (!rppcdev->sig_attr) | ||
184 | return -ENOMEM; | ||
185 | |||
186 | for (i = 0; i < ARRAY_SIZE(rppc_attrs); i++) { | ||
187 | ret = device_create_file(rppcdev->dev, &rppc_attrs[i]); | ||
188 | if (ret) { | ||
189 | dev_err(rppcdev->dev, "failed to create sysfs entry\n"); | ||
190 | goto clean_static_entries; | ||
191 | } | ||
192 | } | ||
193 | |||
194 | for (i = 1; i < rppcdev->num_funcs; i++) { | ||
195 | sysfs_attr_init(&rppcdev->sig_attr[i].attr); | ||
196 | rppcdev->sig_attr[i].attr.name = | ||
197 | kzalloc(RPPC_MAX_FUNC_NAMELEN, GFP_KERNEL); | ||
198 | if (!rppcdev->sig_attr[i].attr.name) { | ||
199 | ret = -ENOMEM; | ||
200 | goto clean_dynamic_entries; | ||
201 | } | ||
202 | snprintf((char *)rppcdev->sig_attr[i].attr.name, | ||
203 | RPPC_MAX_FUNC_NAMELEN, "c_function%u", i); | ||
204 | rppcdev->sig_attr[i].attr.mode = S_IRUGO; | ||
205 | rppcdev->sig_attr[i].show = show_c_function; | ||
206 | rppcdev->sig_attr[i].store = NULL; | ||
207 | |||
208 | ret = device_create_file(rppcdev->dev, &rppcdev->sig_attr[i]); | ||
209 | if (ret) { | ||
210 | dev_err(rppcdev->dev, "failed to create sysfs function entry (%d)\n", | ||
211 | ret); | ||
212 | goto clean_dynamic_entries; | ||
213 | } | ||
214 | } | ||
215 | return 0; | ||
216 | |||
217 | clean_dynamic_entries: | ||
218 | while (i-- > 1) { | ||
219 | device_remove_file(rppcdev->dev, &rppcdev->sig_attr[i]); | ||
220 | kfree(rppcdev->sig_attr[i].attr.name); | ||
221 | } | ||
222 | i = ARRAY_SIZE(rppc_attrs); | ||
223 | clean_static_entries: | ||
224 | while (i-- > 0) | ||
225 | device_remove_file(rppcdev->dev, &rppc_attrs[i]); | ||
226 | kfree(rppcdev->sig_attr); | ||
227 | return ret; | ||
228 | } | ||
229 | |||
230 | /** | ||
231 | * rppc_remove_sysfs: Removes the sysfs entry structures for the instance | ||
232 | * @rppcdev: the rppc device (remote server instance) handle | ||
233 | * | ||
234 | * Helper function to remove all the sysfs entries associated with the | ||
235 | * rppc device. | ||
236 | * | ||
237 | * Return: 0 on success, or an appropriate error code otherwise | ||
238 | */ | ||
239 | int rppc_remove_sysfs(struct rppc_device *rppcdev) | ||
240 | { | ||
241 | int i; | ||
242 | |||
243 | if (rppcdev->sig_attr) { | ||
244 | for (i = 1; i < rppcdev->num_funcs; i++) { | ||
245 | device_remove_file(rppcdev->dev, &rppcdev->sig_attr[i]); | ||
246 | kfree(rppcdev->sig_attr[i].attr.name); | ||
247 | } | ||
248 | } | ||
249 | kfree(rppcdev->sig_attr); | ||
250 | |||
251 | for (i = 0; i < ARRAY_SIZE(rppc_attrs); i++) | ||
252 | device_remove_file(rppcdev->dev, &rppc_attrs[i]); | ||
253 | |||
254 | return 0; | ||
255 | } | ||
diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c index 3dcf8b4269a..4ce5f43a54a 100644 --- a/drivers/rpmsg/virtio_rpmsg_bus.c +++ b/drivers/rpmsg/virtio_rpmsg_bus.c | |||
@@ -502,7 +502,7 @@ static int rpmsg_channel_match(struct device *dev, void *data) | |||
502 | * this function will be used to create both static and dynamic | 502 | * this function will be used to create both static and dynamic |
503 | * channels. | 503 | * channels. |
504 | */ | 504 | */ |
505 | static struct rpmsg_channel *rpmsg_create_channel(struct virtproc_info *vrp, | 505 | static struct rpmsg_channel *__rpmsg_create_channel(struct virtproc_info *vrp, |
506 | struct rpmsg_channel_info *chinfo) | 506 | struct rpmsg_channel_info *chinfo) |
507 | { | 507 | { |
508 | struct rpmsg_channel *rpdev; | 508 | struct rpmsg_channel *rpdev; |
@@ -556,11 +556,42 @@ static struct rpmsg_channel *rpmsg_create_channel(struct virtproc_info *vrp, | |||
556 | return rpdev; | 556 | return rpdev; |
557 | } | 557 | } |
558 | 558 | ||
559 | /** | ||
560 | * rpmsg_create_channel - create a rpmsg channel using its name, desc, id and | ||
561 | * address | ||
562 | * @vrp: the virtual processor on which this channel is being created | ||
563 | * @name: name of the rpmsg channel | ||
564 | * @desc: description of the rpmsg channel | ||
565 | * @src: source end-point address for the channel | ||
566 | * @dst: destination end-point address for the channel | ||
567 | * | ||
568 | * This function provides a means to create new rpmsg channels on a particular | ||
569 | * virtual processor. The caller supplies the address info, name and descriptor | ||
570 | * for the channel. This is useful when creating channels from the host side. | ||
571 | * | ||
572 | * Return: a pointer to a newly created rpmsg channel device on success, | ||
573 | * or NULL on failure | ||
574 | */ | ||
575 | struct rpmsg_channel *rpmsg_create_channel(struct virtproc_info *vrp, | ||
576 | const char *name, const char *desc, | ||
577 | int src, int dst) | ||
578 | { | ||
579 | struct rpmsg_channel_info chinfo; | ||
580 | |||
581 | strncpy(chinfo.name, name, sizeof(chinfo.name)); | ||
582 | strncpy(chinfo.desc, desc, sizeof(chinfo.desc)); | ||
583 | chinfo.src = src; | ||
584 | chinfo.dst = dst; | ||
585 | |||
586 | return __rpmsg_create_channel(vrp, &chinfo); | ||
587 | } | ||
588 | EXPORT_SYMBOL(rpmsg_create_channel); | ||
589 | |||
559 | /* | 590 | /* |
560 | * find an existing channel using its name + address properties, | 591 | * find an existing channel using its name + address properties, |
561 | * and destroy it | 592 | * and destroy it |
562 | */ | 593 | */ |
563 | static int rpmsg_destroy_channel(struct virtproc_info *vrp, | 594 | static int __rpmsg_destroy_channel(struct virtproc_info *vrp, |
564 | struct rpmsg_channel_info *chinfo) | 595 | struct rpmsg_channel_info *chinfo) |
565 | { | 596 | { |
566 | struct virtio_device *vdev = vrp->vdev; | 597 | struct virtio_device *vdev = vrp->vdev; |
@@ -577,6 +608,34 @@ static int rpmsg_destroy_channel(struct virtproc_info *vrp, | |||
577 | return 0; | 608 | return 0; |
578 | } | 609 | } |
579 | 610 | ||
611 | /** | ||
612 | * rpmsg_destroy_channel - destroy a rpmsg channel | ||
613 | * @rpdev: rpmsg channel to be destroyed | ||
614 | * | ||
615 | * This function is the primary means to destroy a rpmsg channel that was | ||
616 | * created from the host-side. This API is strictly intended to be used only | ||
617 | * for channels created using the rpmsg_create_channel API. | ||
618 | * | ||
619 | * Return: 0 on success, or a failure code otherwise | ||
620 | */ | ||
621 | int rpmsg_destroy_channel(struct rpmsg_channel *rpdev) | ||
622 | { | ||
623 | struct device *dev; | ||
624 | struct virtio_device *vdev = rpmsg_get_virtio_dev(rpdev); | ||
625 | |||
626 | if (!rpdev || !vdev) | ||
627 | return -EINVAL; | ||
628 | |||
629 | dev = &rpdev->dev; | ||
630 | if (dev->bus != &rpmsg_bus || dev->parent != &vdev->dev) | ||
631 | return -EINVAL; | ||
632 | |||
633 | device_unregister(dev); | ||
634 | |||
635 | return 0; | ||
636 | } | ||
637 | EXPORT_SYMBOL(rpmsg_destroy_channel); | ||
638 | |||
580 | /* super simple buffer "allocator" that is just enough for now */ | 639 | /* super simple buffer "allocator" that is just enough for now */ |
581 | static void *get_a_tx_buf(struct virtproc_info *vrp) | 640 | static void *get_a_tx_buf(struct virtproc_info *vrp) |
582 | { | 641 | { |
@@ -789,6 +848,22 @@ out: | |||
789 | } | 848 | } |
790 | EXPORT_SYMBOL(rpmsg_send_offchannel_raw); | 849 | EXPORT_SYMBOL(rpmsg_send_offchannel_raw); |
791 | 850 | ||
851 | /** | ||
852 | * rpmsg_get_virtio_dev - Get underlying virtio device | ||
853 | * @rpdev: the rpmsg channel | ||
854 | * | ||
855 | * Returns the underlying remoteproc virtio device, if one exists. Returns NULL | ||
856 | * otherwise. | ||
857 | */ | ||
858 | struct virtio_device *rpmsg_get_virtio_dev(struct rpmsg_channel *rpdev) | ||
859 | { | ||
860 | if (!rpdev || !rpdev->vrp) | ||
861 | return NULL; | ||
862 | |||
863 | return rpdev->vrp->vdev; | ||
864 | } | ||
865 | EXPORT_SYMBOL(rpmsg_get_virtio_dev); | ||
866 | |||
792 | static int rpmsg_recv_single(struct virtproc_info *vrp, struct device *dev, | 867 | static int rpmsg_recv_single(struct virtproc_info *vrp, struct device *dev, |
793 | struct rpmsg_hdr *msg, unsigned int len) | 868 | struct rpmsg_hdr *msg, unsigned int len) |
794 | { | 869 | { |
@@ -948,13 +1023,14 @@ static void rpmsg_ns_cb(struct rpmsg_channel *rpdev, void *data, int len, | |||
948 | chinfo.dst = msg->addr; | 1023 | chinfo.dst = msg->addr; |
949 | 1024 | ||
950 | if (msg->flags & RPMSG_NS_DESTROY) { | 1025 | if (msg->flags & RPMSG_NS_DESTROY) { |
951 | ret = rpmsg_destroy_channel(vrp, &chinfo); | 1026 | ret = __rpmsg_destroy_channel(vrp, &chinfo); |
952 | if (ret) | 1027 | if (ret) |
953 | dev_err(dev, "rpmsg_destroy_channel failed: %d\n", ret); | 1028 | dev_err(dev, "__rpmsg_destroy_channel failed: %d\n", |
1029 | ret); | ||
954 | } else { | 1030 | } else { |
955 | newch = rpmsg_create_channel(vrp, &chinfo); | 1031 | newch = __rpmsg_create_channel(vrp, &chinfo); |
956 | if (!newch) | 1032 | if (!newch) |
957 | dev_err(dev, "rpmsg_create_channel failed\n"); | 1033 | dev_err(dev, "__rpmsg_create_channel failed\n"); |
958 | } | 1034 | } |
959 | } | 1035 | } |
960 | 1036 | ||
diff --git a/include/linux/rpmsg.h b/include/linux/rpmsg.h index ec1b7fbd993..fe00b06536f 100644 --- a/include/linux/rpmsg.h +++ b/include/linux/rpmsg.h | |||
@@ -180,6 +180,11 @@ struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_channel *, | |||
180 | rpmsg_rx_cb_t cb, void *priv, u32 addr); | 180 | rpmsg_rx_cb_t cb, void *priv, u32 addr); |
181 | int | 181 | int |
182 | rpmsg_send_offchannel_raw(struct rpmsg_channel *, u32, u32, void *, int, bool); | 182 | rpmsg_send_offchannel_raw(struct rpmsg_channel *, u32, u32, void *, int, bool); |
183 | struct virtio_device *rpmsg_get_virtio_dev(struct rpmsg_channel *rpdev); | ||
184 | struct rpmsg_channel *rpmsg_create_channel(struct virtproc_info *vrp, | ||
185 | const char *name, const char *desc, | ||
186 | int src, int dst); | ||
187 | int rpmsg_destroy_channel(struct rpmsg_channel *rpdev); | ||
183 | 188 | ||
184 | /** | 189 | /** |
185 | * rpmsg_send() - send a message across to the remote processor | 190 | * rpmsg_send() - send a message across to the remote processor |
diff --git a/include/linux/rpmsg_rpc.h b/include/linux/rpmsg_rpc.h new file mode 100644 index 00000000000..5141c34d829 --- /dev/null +++ b/include/linux/rpmsg_rpc.h | |||
@@ -0,0 +1,105 @@ | |||
1 | /* | ||
2 | * Remote Processor Procedure Call Driver | ||
3 | * | ||
4 | * Copyright(c) 2012-2014 Texas Instruments. All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * | ||
10 | * * Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer. | ||
12 | * * Redistributions in binary form must reproduce the above copyright | ||
13 | * notice, this list of conditions and the following disclaimer in | ||
14 | * the documentation and/or other materials provided with the | ||
15 | * distribution. | ||
16 | * * Neither the name Texas Instruments nor the names of its | ||
17 | * contributors may be used to endorse or promote products derived | ||
18 | * from this software without specific prior written permission. | ||
19 | * | ||
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
31 | */ | ||
32 | |||
33 | #ifndef _LINUX_RPMSG_RPC_H_ | ||
34 | #define _LINUX_RPMSG_RPC_H_ | ||
35 | |||
36 | #include <uapi/linux/rpmsg_rpc.h> | ||
37 | |||
38 | #define RPPC_MAX_NUM_FUNCS (1024) | ||
39 | #define RPPC_MAX_CHANNEL_NAMELEN (64) | ||
40 | #define RPPC_MAX_FUNC_NAMELEN (64) | ||
41 | #define RPPC_MAX_NUM_PARAMS (10) | ||
42 | |||
43 | /** | ||
44 | * enum rppc_param_direction - direction of the function parameter | ||
45 | * @RPPC_PARAMDIR_IN: input argument | ||
46 | * @RPPC_PARAMDIR_OUT: output argument | ||
47 | * @RPPC_PARAMDIR_BI: an in and out argument | ||
48 | * @RPPC_PARAMDIR_MAX: limit value for the direction type | ||
49 | * | ||
50 | * The parameter direction is described as relative to the function. | ||
51 | */ | ||
52 | enum rppc_param_direction { | ||
53 | RPPC_PARAMDIR_IN = 0, | ||
54 | RPPC_PARAMDIR_OUT, | ||
55 | RPPC_PARAMDIR_BI, | ||
56 | RPPC_PARAMDIR_MAX | ||
57 | }; | ||
58 | |||
59 | /** | ||
60 | * enum rppc_param_datatype - parameter data type and descriptor flags | ||
61 | * @RPPC_PARAM_VOID: parameter is of type 'void' | ||
62 | * @RPPC_PARAM_S08: parameter is of type 's8' | ||
63 | * @RPPC_PARAM_U08: parameter is of type 'u8' | ||
64 | * @RPPC_PARAM_S16: parameter is of type 's16' | ||
65 | * @RPPC_PARAM_U16: parameter is of type 'u16' | ||
66 | * @RPPC_PARAM_S32: parameter is of type 's32' | ||
67 | * @RPPC_PARAM_U32: parameter is of type 'u32' | ||
68 | * @RPPC_PARAM_S64: parameter is of type 's64' | ||
69 | * @RPPC_PARAM_U64: parameter is of type 'u64' | ||
70 | * @RPPC_PARAM_ATOMIC_MAX: limit value for scalar data types | ||
71 | * @RPPC_PARAM_MASK: mask field for retrieving the scalar data type | ||
72 | * @RPPC_PARAM_PTR: flag to indicate the data type is a pointer | ||
73 | * @RPPC_PARAM_MAX: max limit value used as a marker | ||
74 | * | ||
75 | * This enum is used to describe the data type for the parameters. | ||
76 | * A pointer of a data type is reflected by using an additional bit | ||
77 | * mask field. | ||
78 | */ | ||
79 | enum rppc_param_datatype { | ||
80 | RPPC_PARAM_VOID = 0, | ||
81 | RPPC_PARAM_S08, | ||
82 | RPPC_PARAM_U08, | ||
83 | RPPC_PARAM_S16, | ||
84 | RPPC_PARAM_U16, | ||
85 | RPPC_PARAM_S32, | ||
86 | RPPC_PARAM_U32, | ||
87 | RPPC_PARAM_S64, | ||
88 | RPPC_PARAM_U64, | ||
89 | RPPC_PARAM_ATOMIC_MAX, | ||
90 | |||
91 | RPPC_PARAM_MASK = 0x7F, | ||
92 | RPPC_PARAM_PTR = 0x80, | ||
93 | |||
94 | RPPC_PARAM_MAX | ||
95 | }; | ||
96 | |||
97 | /* | ||
98 | * helper macros to deal with parameter types | ||
99 | */ | ||
100 | #define RPPC_PTR_TYPE(type) ((type) | RPPC_PARAM_PTR) | ||
101 | #define RPPC_IS_PTR(type) ((type) & RPPC_PARAM_PTR) | ||
102 | #define RPPC_IS_ATOMIC(type) (((type) > RPPC_PARAM_VOID) && \ | ||
103 | ((type) < RPPC_PARAM_ATOMIC_MAX)) | ||
104 | |||
105 | #endif /* _LINUX_RPMSG_RPC_H_ */ | ||
diff --git a/include/linux/socket.h b/include/linux/socket.h index 8e98297f138..32f4e537f87 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h | |||
@@ -180,7 +180,8 @@ struct ucred { | |||
180 | #define AF_ALG 38 /* Algorithm sockets */ | 180 | #define AF_ALG 38 /* Algorithm sockets */ |
181 | #define AF_NFC 39 /* NFC sockets */ | 181 | #define AF_NFC 39 /* NFC sockets */ |
182 | #define AF_VSOCK 40 /* vSockets */ | 182 | #define AF_VSOCK 40 /* vSockets */ |
183 | #define AF_MAX 41 /* For now.. */ | 183 | #define AF_RPMSG 41 /* Remote-processor messaging */ |
184 | #define AF_MAX 42 /* For now.. */ | ||
184 | 185 | ||
185 | /* Protocol families, same as address families. */ | 186 | /* Protocol families, same as address families. */ |
186 | #define PF_UNSPEC AF_UNSPEC | 187 | #define PF_UNSPEC AF_UNSPEC |
@@ -225,6 +226,7 @@ struct ucred { | |||
225 | #define PF_ALG AF_ALG | 226 | #define PF_ALG AF_ALG |
226 | #define PF_NFC AF_NFC | 227 | #define PF_NFC AF_NFC |
227 | #define PF_VSOCK AF_VSOCK | 228 | #define PF_VSOCK AF_VSOCK |
229 | #define PF_RPMSG AF_RPMSG | ||
228 | #define PF_MAX AF_MAX | 230 | #define PF_MAX AF_MAX |
229 | 231 | ||
230 | /* Maximum queue length specifiable by listen. */ | 232 | /* Maximum queue length specifiable by listen. */ |
@@ -301,6 +303,7 @@ struct ucred { | |||
301 | #define SOL_CAIF 278 | 303 | #define SOL_CAIF 278 |
302 | #define SOL_ALG 279 | 304 | #define SOL_ALG 279 |
303 | #define SOL_NFC 280 | 305 | #define SOL_NFC 280 |
306 | #define SOL_RPMSG 281 | ||
304 | 307 | ||
305 | /* IPX options */ | 308 | /* IPX options */ |
306 | #define IPX_TYPE 1 | 309 | #define IPX_TYPE 1 |
diff --git a/include/uapi/linux/rpmsg_rpc.h b/include/uapi/linux/rpmsg_rpc.h new file mode 100644 index 00000000000..2c8724f36cd --- /dev/null +++ b/include/uapi/linux/rpmsg_rpc.h | |||
@@ -0,0 +1,208 @@ | |||
1 | /* | ||
2 | * Remote Processor Procedure Call Driver | ||
3 | * | ||
4 | * Copyright(c) 2012-2014 Texas Instruments. All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * | ||
10 | * * Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer. | ||
12 | * * Redistributions in binary form must reproduce the above copyright | ||
13 | * notice, this list of conditions and the following disclaimer in | ||
14 | * the documentation and/or other materials provided with the | ||
15 | * distribution. | ||
16 | * * Neither the name Texas Instruments nor the names of its | ||
17 | * contributors may be used to endorse or promote products derived | ||
18 | * from this software without specific prior written permission. | ||
19 | * | ||
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
31 | */ | ||
32 | |||
33 | #ifndef _UAPI_LINUX_RPMSG_RPC_H_ | ||
34 | #define _UAPI_LINUX_RPMSG_RPC_H_ | ||
35 | |||
36 | #include <linux/ioctl.h> | ||
37 | |||
38 | /** | ||
39 | * struct rppc_buf_fds - rppc buffer registration/deregistration | ||
40 | * @num: number of file descriptors | ||
41 | * @fds: pointer to the array holding the file descriptors | ||
42 | */ | ||
43 | struct rppc_buf_fds { | ||
44 | uint32_t num; | ||
45 | int32_t *fds; | ||
46 | }; | ||
47 | |||
48 | /* | ||
49 | * ioctl definitions | ||
50 | */ | ||
51 | #define RPPC_IOC_MAGIC 'r' | ||
52 | #define RPPC_IOC_CREATE _IOW(RPPC_IOC_MAGIC, 1, char *) | ||
53 | #define RPPC_IOC_BUFREGISTER _IOW(RPPC_IOC_MAGIC, 2, struct rppc_buf_fds) | ||
54 | #define RPPC_IOC_BUFUNREGISTER _IOW(RPPC_IOC_MAGIC, 3, struct rppc_buf_fds) | ||
55 | #define RPPC_IOC_MAXNR (4) | ||
56 | |||
57 | #define RPPC_MAX_PARAMETERS (10) | ||
58 | #define RPPC_MAX_TRANSLATIONS (1024) | ||
59 | #define RPPC_MAX_INST_NAMELEN (48) | ||
60 | |||
61 | /** | ||
62 | * enum rppc_param_type - RPC function parameter type | ||
63 | * @RPPC_PARAM_TYPE_UNKNOWN: unrecognized parameter | ||
64 | * @RPPC_PARAM_TYPE_ATOMIC: an atomic data type, 1 byte to architecture limit | ||
65 | * sized bytes | ||
66 | * @RPPC_PARAM_TYPE_PTR: a pointer to shared memory. The fd field in the | ||
67 | * structures rppc_param and rppc_param_translation must | ||
68 | * contain the file descriptor of the associated dma_buf | ||
69 | * @RPPC_PARAM_TYPE_STRUCT: (unsupported) a structure type. Will be architecture | ||
70 | * width aligned in memory | ||
71 | * | ||
72 | * These enum values are used to identify the parameter type for every | ||
73 | * parameter argument of the remote function. | ||
74 | */ | ||
75 | enum rppc_param_type { | ||
76 | RPPC_PARAM_TYPE_UNKNOWN = 0, | ||
77 | RPPC_PARAM_TYPE_ATOMIC, | ||
78 | RPPC_PARAM_TYPE_PTR, | ||
79 | RPPC_PARAM_TYPE_STRUCT, | ||
80 | }; | ||
81 | |||
82 | /** | ||
83 | * struct rppc_param_translation - pointer translation helper structure | ||
84 | * @index: index of the parameter where the translation needs to be done in. | ||
85 | * used for computing the primary offset and mapping into kernel | ||
86 | * the page from the buffer referred to in the correspoding parameter | ||
87 | * @offset: offset from the primary base pointer to the pointer to translate. | ||
88 | * This is the secondary offset, and used either for mentioning the | ||
89 | * offset from an structure array element base, or within a single | ||
90 | * structure which itself is at an offset in an allocated buffer | ||
91 | * @base: the base user virtual address of the pointer to translate (used to | ||
92 | * calculate translated pointer offset) | ||
93 | * @fd: dma_buf file descriptor of the allocated buffer pointer within which | ||
94 | * the translated pointer is present | ||
95 | */ | ||
96 | struct rppc_param_translation { | ||
97 | uint32_t index; | ||
98 | ptrdiff_t offset; | ||
99 | size_t base; | ||
100 | int32_t fd; | ||
101 | }; | ||
102 | |||
103 | /** | ||
104 | * struct rppc_param - descriptor structure for each parameter | ||
105 | * @type: type of the parameter, as dictated by enum rppc_param_type | ||
106 | * @size: size of the data (for atomic types) or size of the containing | ||
107 | * structure in which translations are performed | ||
108 | * @data: either the parameter value itself (for atomic type) or | ||
109 | * the actual user space pointer address to the data (for pointer type) | ||
110 | * @base: the base user space pointer address of the original allocated buffer, | ||
111 | * providing a reference if data has the pointer that is at an offset | ||
112 | * from the original pointer | ||
113 | * @fd: file descriptor of the exported allocation (will be used to | ||
114 | * import the associated dma_buf within the driver). | ||
115 | */ | ||
116 | struct rppc_param { | ||
117 | uint32_t type; | ||
118 | size_t size; | ||
119 | size_t data; | ||
120 | size_t base; | ||
121 | int32_t fd; | ||
122 | }; | ||
123 | |||
124 | /** | ||
125 | * struct rppc_function - descriptor structure for the remote function | ||
126 | * @fxn_id: index of the function to invoke on the opened rppc device | ||
127 | * @num_params: number of parameters filled in the params field | ||
128 | * @params: array of parameter descriptor structures | ||
129 | * @num_translations: number of in-place translations to be performed within | ||
130 | * the arguments. | ||
131 | * @translations: an open array of the translation descriptor structures, whose | ||
132 | * length is given in @num_translations. Used for translating | ||
133 | * the pointers within the function data. | ||
134 | * | ||
135 | * This is the primary descriptor structure passed down from the userspace, | ||
136 | * describing the function, its parameter arguments and the needed translations. | ||
137 | */ | ||
138 | struct rppc_function { | ||
139 | uint32_t fxn_id; | ||
140 | uint32_t num_params; | ||
141 | struct rppc_param params[RPPC_MAX_PARAMETERS]; | ||
142 | uint32_t num_translations; | ||
143 | struct rppc_param_translation translations[0]; | ||
144 | }; | ||
145 | |||
146 | /** | ||
147 | * struct rppc_function_return - function return status descriptor structure | ||
148 | * @fxn_id: index of the function invoked on the opened rppc device | ||
149 | * @status: return value of the executed function | ||
150 | */ | ||
151 | struct rppc_function_return { | ||
152 | uint32_t fxn_id; | ||
153 | uint32_t status; | ||
154 | }; | ||
155 | |||
156 | /** | ||
157 | * struct rppc_create_instance - rppc channel connector helper | ||
158 | * @name: Name of the rppc server device to establish a connection with | ||
159 | */ | ||
160 | struct rppc_create_instance { | ||
161 | char name[RPPC_MAX_INST_NAMELEN]; | ||
162 | }; | ||
163 | |||
164 | /* | ||
165 | * helper macros for manipulating the function index in the marshalled packet | ||
166 | */ | ||
167 | #define RPPC_DESC_EXEC_SYNC (0x0100) | ||
168 | #define RPPC_DESC_TYPE_MASK (0x0F00) | ||
169 | |||
170 | /* | ||
171 | * helper macros for manipulating the function index in the marshalled packet. | ||
172 | * The remote functions are offset by one relative to the client | ||
173 | * XXX: Remove the relative offset | ||
174 | */ | ||
175 | #define RPPC_SET_FXN_IDX(idx) (((idx) + 1) | 0x80000000) | ||
176 | #define RPPC_FXN_MASK(idx) (((idx) - 1) & 0x7FFFFFFF) | ||
177 | |||
178 | /** | ||
179 | * struct rppc_packet - the actual marshalled packet | ||
180 | * @desc: type of function execution, currently only synchronous function | ||
181 | * invocations are supported | ||
182 | * @msg_id: an incremental message index identifier | ||
183 | * @flags: a combination of job id and pool id of the worker threads | ||
184 | * of the server | ||
185 | * @fxn_id: id of the function to execute | ||
186 | * @result: result of the remotely executed function | ||
187 | * @data_size: size of the payload packet | ||
188 | * @data: variable payload, containing the marshalled function data. | ||
189 | * | ||
190 | * This is actually a condensed structure of the Remote Command Messaging | ||
191 | * (RCM) structure. The initial fields of the structure are used by the | ||
192 | * remote-side server to schedule the execution of the function. The actual | ||
193 | * variable payload data starts from the .data field. This marshalled packet | ||
194 | * is the payload for a rpmsg message. | ||
195 | * | ||
196 | * XXX: remove or mask unneeded fields, some fields can be stripped down | ||
197 | */ | ||
198 | struct rppc_packet { | ||
199 | uint16_t desc; | ||
200 | uint16_t msg_id; | ||
201 | uint32_t flags; | ||
202 | uint32_t fxn_id; | ||
203 | int32_t result; | ||
204 | uint32_t data_size; | ||
205 | uint8_t data[0]; | ||
206 | } __packed; | ||
207 | |||
208 | #endif /* _UAPI_LINUX_RPMSG_RPC_H_ */ | ||
diff --git a/include/uapi/linux/rpmsg_socket.h b/include/uapi/linux/rpmsg_socket.h new file mode 100644 index 00000000000..3b26bffacf3 --- /dev/null +++ b/include/uapi/linux/rpmsg_socket.h | |||
@@ -0,0 +1,47 @@ | |||
1 | /* | ||
2 | * Remote processor messaging sockets | ||
3 | * | ||
4 | * Copyright (C) 2011-2014 Texas Instruments, Inc | ||
5 | * | ||
6 | * Ohad Ben-Cohen <ohad@wizery.com> | ||
7 | * Suman Anna <s-anna@ti.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | */ | ||
18 | |||
19 | #ifndef _UAPI_RPMSG_SOCKET_H | ||
20 | #define _UAPI_RPMSG_SOCKET_H | ||
21 | |||
22 | #include <linux/types.h> | ||
23 | #include <linux/socket.h> | ||
24 | |||
25 | /* user space needs this */ | ||
26 | #ifndef AF_RPMSG | ||
27 | #define AF_RPMSG 41 | ||
28 | #define PF_RPMSG AF_RPMSG | ||
29 | #endif | ||
30 | |||
31 | /* Connection and socket states */ | ||
32 | enum { | ||
33 | RPMSG_CONNECTED = 1, /* wait_for_packet() wants this... */ | ||
34 | RPMSG_OPEN, | ||
35 | RPMSG_LISTENING, | ||
36 | RPMSG_CLOSED, | ||
37 | }; | ||
38 | |||
39 | struct sockaddr_rpmsg { | ||
40 | __kernel_sa_family_t family; | ||
41 | __u32 vproc_id; | ||
42 | __u32 addr; | ||
43 | }; | ||
44 | |||
45 | #define RPMSG_LOCALHOST ((__u32) ~0UL) | ||
46 | |||
47 | #endif /* _UAPI_RPMSG_SOCKET_H */ | ||
diff --git a/net/Makefile b/net/Makefile index cbbbe6d657c..902436fb3e9 100644 --- a/net/Makefile +++ b/net/Makefile | |||
@@ -72,3 +72,4 @@ obj-$(CONFIG_OPENVSWITCH) += openvswitch/ | |||
72 | obj-$(CONFIG_VSOCKETS) += vmw_vsock/ | 72 | obj-$(CONFIG_VSOCKETS) += vmw_vsock/ |
73 | obj-$(CONFIG_NET_MPLS_GSO) += mpls/ | 73 | obj-$(CONFIG_NET_MPLS_GSO) += mpls/ |
74 | obj-$(CONFIG_HSR) += hsr/ | 74 | obj-$(CONFIG_HSR) += hsr/ |
75 | obj-$(CONFIG_RPMSG) += rpmsg/ | ||
diff --git a/net/rpmsg/Makefile b/net/rpmsg/Makefile new file mode 100644 index 00000000000..4db19dfdb38 --- /dev/null +++ b/net/rpmsg/Makefile | |||
@@ -0,0 +1 @@ | |||
obj-$(CONFIG_RPMSG) += rpmsg_proto.o | |||
diff --git a/net/rpmsg/rpmsg_proto.c b/net/rpmsg/rpmsg_proto.c new file mode 100644 index 00000000000..4534b6cc954 --- /dev/null +++ b/net/rpmsg/rpmsg_proto.c | |||
@@ -0,0 +1,684 @@ | |||
1 | /* | ||
2 | * AF_RPMSG: Remote processor messaging sockets | ||
3 | * | ||
4 | * Copyright (C) 2011-2014 Texas Instruments, Inc. | ||
5 | * | ||
6 | * Ohad Ben-Cohen <ohad@wizery.com> | ||
7 | * Robert Tivy <rtivy@ti.com> | ||
8 | * G Anthony <a0783926@ti.com> | ||
9 | * Suman Anna <s-anna@ti.com> | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License | ||
13 | * version 2 as published by the Free Software Foundation. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | */ | ||
20 | |||
21 | #define pr_fmt(fmt) "%s: " fmt, __func__ | ||
22 | |||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/device.h> | ||
26 | #include <linux/types.h> | ||
27 | #include <linux/list.h> | ||
28 | #include <linux/errno.h> | ||
29 | #include <linux/skbuff.h> | ||
30 | #include <linux/rwlock.h> | ||
31 | #include <linux/err.h> | ||
32 | #include <linux/mutex.h> | ||
33 | #include <linux/rpmsg.h> | ||
34 | #include <linux/radix-tree.h> | ||
35 | #include <linux/remoteproc.h> | ||
36 | #include <net/sock.h> | ||
37 | #include <uapi/linux/rpmsg_socket.h> | ||
38 | |||
39 | #define RPMSG_CB(skb) (*(struct sockaddr_rpmsg *)&((skb)->cb)) | ||
40 | |||
41 | /* Used to distinguish between bound and connected socket channels in the | ||
42 | * radix tree index space. | ||
43 | * Must match value as in drivers/rpmsg/virtio_rpmsg_bus.c: | ||
44 | */ | ||
45 | #define RPMSG_RESERVED_ADDRESSES (1024) | ||
46 | |||
47 | struct rpmsg_socket { | ||
48 | struct sock sk; | ||
49 | struct rpmsg_channel *rpdev; | ||
50 | bool unregister_rpdev; | ||
51 | }; | ||
52 | |||
53 | /* A two-level radix-tree-based scheme is used to maintain the rpmsg channels | ||
54 | * we're exposing to userland. The first radix tree maps vproc index id | ||
55 | * to its channels, and the second radix tree associates each channel | ||
56 | * with its destination addresses (so sockaddr_rpmsg lookups are quick). | ||
57 | * | ||
58 | * Currently only channels with a valid dst address are supported (aka 'client' | ||
59 | * channels as opposed to 'server' channels which usually only have a valid | ||
60 | * src address). | ||
61 | */ | ||
62 | static RADIX_TREE(rpmsg_channels, GFP_KERNEL); | ||
63 | |||
64 | /* Synchronization of access to the tree is achieved using a mutex, | ||
65 | * because we're using non-atomic radix tree allocations. | ||
66 | */ | ||
67 | static DEFINE_MUTEX(rpmsg_channels_lock); | ||
68 | |||
69 | /* A radix tree is used to retrieve the virtproc_info structure | ||
70 | * from the associated system-wide unique processor id. | ||
71 | */ | ||
72 | static RADIX_TREE(rpmsg_vprocs, GFP_KERNEL); | ||
73 | static DEFINE_MUTEX(rpmsg_vprocs_lock); | ||
74 | |||
75 | static struct proto rpmsg_proto = { | ||
76 | .name = "RPMSG", | ||
77 | .owner = THIS_MODULE, | ||
78 | .obj_size = sizeof(struct rpmsg_socket), | ||
79 | }; | ||
80 | |||
81 | /* Retrieve the rproc instance so that it can be used for retrieving | ||
82 | * the processor id associated with the rpmsg channel. | ||
83 | */ | ||
84 | static struct rproc *rpdev_to_rproc(struct rpmsg_channel *rpdev) | ||
85 | { | ||
86 | struct virtio_device *vdev; | ||
87 | |||
88 | vdev = rpmsg_get_virtio_dev(rpdev); | ||
89 | if (!vdev) | ||
90 | return NULL; | ||
91 | |||
92 | return rproc_vdev_to_rproc_safe(vdev); | ||
93 | } | ||
94 | |||
95 | /* Retrieve the rproc id. The rproc id _relies_ on aliases being defined | ||
96 | * in the DT blob for each of the remoteproc devices, and is essentially | ||
97 | * the alias id. These are assumed to match to be fixed for a particular | ||
98 | * SoC, and this provides a means to have a fixed interface to identify | ||
99 | * a remote processor. | ||
100 | */ | ||
101 | static int rpmsg_sock_get_proc_id(struct rpmsg_channel *rpdev) | ||
102 | { | ||
103 | struct rproc *rproc = rpdev_to_rproc(rpdev); | ||
104 | int id; | ||
105 | |||
106 | if (!rproc) { | ||
107 | WARN_ON(1); | ||
108 | return -EINVAL; | ||
109 | } | ||
110 | |||
111 | id = rproc_get_alias_id(rproc); | ||
112 | WARN_ON(id < 0); | ||
113 | |||
114 | return id; | ||
115 | } | ||
116 | |||
117 | static int rpmsg_sock_connect(struct socket *sock, struct sockaddr *addr, | ||
118 | int alen, int flags) | ||
119 | { | ||
120 | struct sock *sk = sock->sk; | ||
121 | struct rpmsg_socket *rpsk; | ||
122 | struct sockaddr_rpmsg *sa; | ||
123 | int err = 0; | ||
124 | struct radix_tree_root *vrp_channels; | ||
125 | struct rpmsg_channel *rpdev; | ||
126 | |||
127 | if (sk->sk_state != RPMSG_OPEN) | ||
128 | return -EBADFD; | ||
129 | |||
130 | if (sk->sk_type != SOCK_SEQPACKET) | ||
131 | return -EINVAL; | ||
132 | |||
133 | if (!addr || addr->sa_family != AF_RPMSG) | ||
134 | return -EINVAL; | ||
135 | |||
136 | if (alen < sizeof(*sa)) | ||
137 | return -EINVAL; | ||
138 | |||
139 | sa = (struct sockaddr_rpmsg *)addr; | ||
140 | |||
141 | lock_sock(sk); | ||
142 | |||
143 | rpsk = container_of(sk, struct rpmsg_socket, sk); | ||
144 | |||
145 | mutex_lock(&rpmsg_channels_lock); | ||
146 | |||
147 | /* find the set of channels exposed by this remote processor */ | ||
148 | vrp_channels = radix_tree_lookup(&rpmsg_channels, sa->vproc_id); | ||
149 | if (!vrp_channels) { | ||
150 | err = -EINVAL; | ||
151 | goto out; | ||
152 | } | ||
153 | |||
154 | /* find the specific channel we need to connect with, by dst addr: */ | ||
155 | rpdev = radix_tree_lookup(vrp_channels, sa->addr); | ||
156 | if (!rpdev) { | ||
157 | err = -EINVAL; | ||
158 | goto out; | ||
159 | } | ||
160 | |||
161 | rpsk->rpdev = rpdev; | ||
162 | |||
163 | /* bind this socket with its rpmsg endpoint */ | ||
164 | rpdev->ept->priv = sk; | ||
165 | |||
166 | /* XXX take care of disconnection state too */ | ||
167 | sk->sk_state = RPMSG_CONNECTED; | ||
168 | |||
169 | out: | ||
170 | mutex_unlock(&rpmsg_channels_lock); | ||
171 | release_sock(sk); | ||
172 | return err; | ||
173 | } | ||
174 | |||
175 | static int rpmsg_sock_sendmsg(struct kiocb *iocb, struct socket *sock, | ||
176 | struct msghdr *msg, size_t len) | ||
177 | { | ||
178 | struct sock *sk = sock->sk; | ||
179 | struct rpmsg_socket *rpsk; | ||
180 | char payload[512];/* todo: sane payload length methodology */ | ||
181 | int err; | ||
182 | |||
183 | /* XXX check for sock_error as well ? */ | ||
184 | /* XXX handle noblock ? */ | ||
185 | if (msg->msg_flags & MSG_OOB) | ||
186 | return -EOPNOTSUPP; | ||
187 | |||
188 | /* no payload ? */ | ||
189 | if (msg->msg_iov->iov_base == NULL) | ||
190 | return -EINVAL; | ||
191 | |||
192 | lock_sock(sk); | ||
193 | |||
194 | /* we don't support loopback at this point */ | ||
195 | if (sk->sk_state != RPMSG_CONNECTED) { | ||
196 | release_sock(sk); | ||
197 | return -ENOTCONN; | ||
198 | } | ||
199 | |||
200 | rpsk = container_of(sk, struct rpmsg_socket, sk); | ||
201 | |||
202 | /* XXX for now, ignore the peer address. later use it | ||
203 | * with rpmsg_sendto, but only if user is root | ||
204 | */ | ||
205 | err = memcpy_fromiovec(payload, msg->msg_iov, len); | ||
206 | if (err) | ||
207 | goto out; | ||
208 | |||
209 | /* XXX add length validation */ | ||
210 | err = rpmsg_send(rpsk->rpdev, payload, len); | ||
211 | if (err) | ||
212 | pr_err("rpmsg_send failed: %d\n", err); | ||
213 | |||
214 | out: | ||
215 | release_sock(sk); | ||
216 | return err; | ||
217 | } | ||
218 | |||
219 | static int rpmsg_sock_recvmsg(struct kiocb *iocb, struct socket *sock, | ||
220 | struct msghdr *msg, size_t len, int flags) | ||
221 | { | ||
222 | struct sock *sk = sock->sk; | ||
223 | struct sockaddr_rpmsg *sa; | ||
224 | struct sk_buff *skb; | ||
225 | int noblock = flags & MSG_DONTWAIT; | ||
226 | int ret; | ||
227 | |||
228 | if (flags & MSG_OOB) { | ||
229 | pr_err("MSG_OOB: %d\n", EOPNOTSUPP); | ||
230 | return -EOPNOTSUPP; | ||
231 | } | ||
232 | |||
233 | msg->msg_namelen = 0; | ||
234 | |||
235 | skb = skb_recv_datagram(sk, flags, noblock, &ret); | ||
236 | if (!skb) { | ||
237 | /* check for shutdown ? */ | ||
238 | pr_err("skb_recv_datagram: %d\n", ret); | ||
239 | return ret; | ||
240 | } | ||
241 | |||
242 | if (msg->msg_name) { | ||
243 | msg->msg_namelen = sizeof(*sa); | ||
244 | sa = (struct sockaddr_rpmsg *)msg->msg_name; | ||
245 | sa->vproc_id = RPMSG_CB(skb).vproc_id; | ||
246 | sa->addr = RPMSG_CB(skb).addr; | ||
247 | sa->family = AF_RPMSG; | ||
248 | } | ||
249 | |||
250 | if (len > skb->len) { | ||
251 | len = skb->len; | ||
252 | } else if (len < skb->len) { | ||
253 | pr_warn("user buffer is too small\n"); | ||
254 | /* XXX truncate or error ? */ | ||
255 | msg->msg_flags |= MSG_TRUNC; | ||
256 | } | ||
257 | |||
258 | ret = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, len); | ||
259 | if (ret) { | ||
260 | pr_err("error copying skb data: %d\n", ret); | ||
261 | goto out_free; | ||
262 | } | ||
263 | |||
264 | ret = len; | ||
265 | |||
266 | out_free: | ||
267 | skb_free_datagram(sk, skb); | ||
268 | return ret; | ||
269 | } | ||
270 | |||
271 | static unsigned int rpmsg_sock_poll(struct file *file, struct socket *sock, | ||
272 | poll_table *wait) | ||
273 | { | ||
274 | struct sock *sk = sock->sk; | ||
275 | unsigned int mask = 0; | ||
276 | |||
277 | poll_wait(file, sk_sleep(sk), wait); | ||
278 | |||
279 | /* exceptional events? */ | ||
280 | if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue)) | ||
281 | mask |= POLLERR; | ||
282 | if (sk->sk_shutdown & RCV_SHUTDOWN) | ||
283 | mask |= POLLRDHUP; | ||
284 | if (sk->sk_shutdown == SHUTDOWN_MASK) | ||
285 | mask |= POLLHUP; | ||
286 | |||
287 | /* readable? */ | ||
288 | if (!skb_queue_empty(&sk->sk_receive_queue) || | ||
289 | (sk->sk_shutdown & RCV_SHUTDOWN)) | ||
290 | mask |= POLLIN | POLLRDNORM; | ||
291 | |||
292 | if (sk->sk_state == RPMSG_CLOSED) | ||
293 | mask |= POLLHUP; | ||
294 | |||
295 | /* XXX is writable ? | ||
296 | * this depends on the destination processor. | ||
297 | * if loopback: we're writable unless no memory | ||
298 | * if to remote: we need enabled rpmsg buffer or user supplied bufs | ||
299 | * for now, let's always be writable. | ||
300 | */ | ||
301 | mask |= POLLOUT | POLLWRNORM | POLLWRBAND; | ||
302 | |||
303 | return mask; | ||
304 | } | ||
305 | |||
306 | /* return bound socket address information, either local or remote | ||
307 | * note: len is just an output parameter, doesn't carry any input value | ||
308 | */ | ||
309 | static int rpmsg_sock_getname(struct socket *sock, struct sockaddr *addr, | ||
310 | int *len, int peer) | ||
311 | { | ||
312 | struct sock *sk = sock->sk; | ||
313 | struct rpmsg_socket *rpsk; | ||
314 | struct rpmsg_channel *rpdev; | ||
315 | struct sockaddr_rpmsg *sa; | ||
316 | |||
317 | rpsk = container_of(sk, struct rpmsg_socket, sk); | ||
318 | rpdev = rpsk->rpdev; | ||
319 | |||
320 | if (!rpdev) | ||
321 | return -ENOTCONN; | ||
322 | |||
323 | addr->sa_family = AF_RPMSG; | ||
324 | |||
325 | sa = (struct sockaddr_rpmsg *)addr; | ||
326 | |||
327 | *len = sizeof(*sa); | ||
328 | |||
329 | if (peer) { | ||
330 | sa->vproc_id = rpmsg_sock_get_proc_id(rpdev); | ||
331 | sa->addr = rpdev->dst; | ||
332 | } else { | ||
333 | sa->vproc_id = RPMSG_LOCALHOST; | ||
334 | sa->addr = rpsk->rpdev->src; | ||
335 | } | ||
336 | |||
337 | return 0; | ||
338 | } | ||
339 | |||
340 | static int rpmsg_sock_release(struct socket *sock) | ||
341 | { | ||
342 | struct sock *sk = sock->sk; | ||
343 | struct rpmsg_socket *rpsk = container_of(sk, struct rpmsg_socket, sk); | ||
344 | int ret; | ||
345 | |||
346 | if (!sk) | ||
347 | return 0; | ||
348 | |||
349 | if (rpsk->unregister_rpdev) { | ||
350 | ret = rpmsg_destroy_channel(rpsk->rpdev); | ||
351 | if (ret) | ||
352 | pr_err("rpmsg_destroy_channel failed for sk %p\n", sk); | ||
353 | } | ||
354 | |||
355 | sock_put(sock->sk); | ||
356 | |||
357 | return 0; | ||
358 | } | ||
359 | |||
360 | /* Notes: | ||
361 | * - calling connect after bind isn't currently supported (is it even needed?). | ||
362 | * - userspace arguments to bind aren't intuitive: one needs to provide | ||
363 | * the vproc id of the remote processor that the channel needs to be shared | ||
364 | * with, and the -local- source address the channel is to be bound with | ||
365 | */ | ||
366 | static int | ||
367 | rpmsg_sock_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) | ||
368 | { | ||
369 | struct sock *sk = sock->sk; | ||
370 | struct rpmsg_socket *rpsk = container_of(sk, struct rpmsg_socket, sk); | ||
371 | struct rpmsg_channel *rpdev; | ||
372 | struct sockaddr_rpmsg *sa = (struct sockaddr_rpmsg *)uaddr; | ||
373 | struct virtproc_info *vrp; | ||
374 | |||
375 | if (sock->state == SS_CONNECTED) | ||
376 | return -EINVAL; | ||
377 | |||
378 | if (addr_len != sizeof(*sa)) | ||
379 | return -EINVAL; | ||
380 | |||
381 | if (sa->family != AF_RPMSG) | ||
382 | return -EINVAL; | ||
383 | |||
384 | if (rpsk->rpdev) | ||
385 | return -EBUSY; | ||
386 | |||
387 | if (sk->sk_state != RPMSG_OPEN) | ||
388 | return -EINVAL; | ||
389 | |||
390 | vrp = radix_tree_lookup(&rpmsg_vprocs, sa->vproc_id); | ||
391 | if (!vrp) | ||
392 | return -EINVAL; | ||
393 | |||
394 | rpdev = rpmsg_create_channel(vrp, "rpmsg-proto", "", sa->addr, | ||
395 | RPMSG_ADDR_ANY); | ||
396 | if (!rpdev) | ||
397 | return -EINVAL; | ||
398 | |||
399 | rpsk->rpdev = rpdev; | ||
400 | rpsk->unregister_rpdev = true; | ||
401 | |||
402 | /* bind this socket with its rpmsg endpoint */ | ||
403 | rpdev->ept->priv = sk; | ||
404 | |||
405 | sk->sk_state = RPMSG_LISTENING; | ||
406 | |||
407 | return 0; | ||
408 | } | ||
409 | |||
410 | static const struct proto_ops rpmsg_sock_ops = { | ||
411 | .family = PF_RPMSG, | ||
412 | .owner = THIS_MODULE, | ||
413 | |||
414 | .release = rpmsg_sock_release, | ||
415 | .connect = rpmsg_sock_connect, | ||
416 | .getname = rpmsg_sock_getname, | ||
417 | .sendmsg = rpmsg_sock_sendmsg, | ||
418 | .recvmsg = rpmsg_sock_recvmsg, | ||
419 | .poll = rpmsg_sock_poll, | ||
420 | .bind = rpmsg_sock_bind, | ||
421 | |||
422 | .listen = sock_no_listen, | ||
423 | .accept = sock_no_accept, | ||
424 | .ioctl = sock_no_ioctl, | ||
425 | .mmap = sock_no_mmap, | ||
426 | .socketpair = sock_no_socketpair, | ||
427 | .shutdown = sock_no_shutdown, | ||
428 | .setsockopt = sock_no_setsockopt, | ||
429 | .getsockopt = sock_no_getsockopt | ||
430 | }; | ||
431 | |||
432 | static void rpmsg_sock_destruct(struct sock *sk) | ||
433 | { | ||
434 | } | ||
435 | |||
436 | static int rpmsg_sock_create(struct net *net, struct socket *sock, int proto, | ||
437 | int kern) | ||
438 | { | ||
439 | struct sock *sk; | ||
440 | |||
441 | if (sock->type != SOCK_SEQPACKET) | ||
442 | return -ESOCKTNOSUPPORT; | ||
443 | if (proto != 0) | ||
444 | return -EPROTONOSUPPORT; | ||
445 | |||
446 | sk = sk_alloc(net, PF_RPMSG, GFP_KERNEL, &rpmsg_proto); | ||
447 | if (!sk) | ||
448 | return -ENOMEM; | ||
449 | |||
450 | sock->state = SS_UNCONNECTED; | ||
451 | sock->ops = &rpmsg_sock_ops; | ||
452 | sock_init_data(sock, sk); | ||
453 | |||
454 | sk->sk_destruct = rpmsg_sock_destruct; | ||
455 | sk->sk_protocol = proto; | ||
456 | |||
457 | sk->sk_state = RPMSG_OPEN; | ||
458 | |||
459 | return 0; | ||
460 | } | ||
461 | |||
462 | static const struct net_proto_family rpmsg_proto_family = { | ||
463 | .family = PF_RPMSG, | ||
464 | .create = rpmsg_sock_create, | ||
465 | .owner = THIS_MODULE, | ||
466 | }; | ||
467 | |||
468 | static void __rpmsg_proto_cb(struct device *dev, int from_vproc_id, void *data, | ||
469 | int len, struct sock *sk, u32 src) | ||
470 | { | ||
471 | struct rpmsg_socket *rpsk = container_of(sk, struct rpmsg_socket, sk); | ||
472 | struct sk_buff *skb; | ||
473 | int ret; | ||
474 | |||
475 | #ifdef RPMSG_PROTO_DEBUG /* left in place only for debugging sake */ | ||
476 | print_hex_dump(KERN_DEBUG, __func__, DUMP_PREFIX_NONE, 16, 1, | ||
477 | data, len, true); | ||
478 | #endif | ||
479 | |||
480 | lock_sock(sk); | ||
481 | |||
482 | switch (sk->sk_state) { | ||
483 | case RPMSG_CONNECTED: | ||
484 | if (rpsk->rpdev->dst != src) | ||
485 | dev_warn(dev, "unexpected source address: %d\n", src); | ||
486 | break; | ||
487 | case RPMSG_LISTENING: | ||
488 | /* When an inbound message is received while we're listening, | ||
489 | * we implicitly become connected | ||
490 | */ | ||
491 | sk->sk_state = RPMSG_CONNECTED; | ||
492 | rpsk->rpdev->dst = src; | ||
493 | break; | ||
494 | default: | ||
495 | dev_warn(dev, "unexpected inbound message (from %d)\n", src); | ||
496 | break; | ||
497 | } | ||
498 | |||
499 | skb = sock_alloc_send_skb(sk, len, 1, &ret); | ||
500 | if (!skb) { | ||
501 | dev_err(dev, "sock_alloc_send_skb failed: %d\n", ret); | ||
502 | ret = -ENOMEM; | ||
503 | goto out; | ||
504 | } | ||
505 | |||
506 | RPMSG_CB(skb).vproc_id = from_vproc_id; | ||
507 | RPMSG_CB(skb).addr = src; | ||
508 | RPMSG_CB(skb).family = AF_RPMSG; | ||
509 | |||
510 | memcpy(skb_put(skb, len), data, len); | ||
511 | |||
512 | ret = sock_queue_rcv_skb(sk, skb); | ||
513 | if (ret) { | ||
514 | dev_err(dev, "sock_queue_rcv_skb failed: %d\n", ret); | ||
515 | kfree_skb(skb); | ||
516 | } | ||
517 | |||
518 | out: | ||
519 | release_sock(sk); | ||
520 | } | ||
521 | |||
522 | static void rpmsg_proto_cb(struct rpmsg_channel *rpdev, void *data, int len, | ||
523 | void *priv, u32 src) | ||
524 | { | ||
525 | int id = rpmsg_sock_get_proc_id(rpdev); | ||
526 | |||
527 | __rpmsg_proto_cb(&rpdev->dev, id, data, len, priv, src); | ||
528 | } | ||
529 | |||
530 | /* every channel we're probed with is exposed to userland via the Socket API */ | ||
531 | static int rpmsg_proto_probe(struct rpmsg_channel *rpdev) | ||
532 | { | ||
533 | struct device *dev = &rpdev->dev; | ||
534 | int ret, dst = rpdev->dst, id; | ||
535 | struct radix_tree_root *vrp_channels; | ||
536 | struct virtproc_info *vrp; | ||
537 | |||
538 | id = rpmsg_sock_get_proc_id(rpdev); | ||
539 | |||
540 | vrp = radix_tree_lookup(&rpmsg_vprocs, id); | ||
541 | if (vrp && vrp != rpdev->vrp) | ||
542 | dev_err(dev, "id %d already associated to different vrp\n", | ||
543 | id); | ||
544 | |||
545 | if (dst == RPMSG_ADDR_ANY) | ||
546 | return 0; | ||
547 | |||
548 | /* associate id/vrp for later lookup in rpmsg_sock_bind() */ | ||
549 | if (!vrp) { | ||
550 | mutex_lock(&rpmsg_vprocs_lock); | ||
551 | ret = radix_tree_insert(&rpmsg_vprocs, (unsigned long)id, | ||
552 | rpdev->vrp); | ||
553 | mutex_unlock(&rpmsg_vprocs_lock); | ||
554 | if (ret) { | ||
555 | dev_err(dev, "radix_tree_insert(%d) failed: %d\n", | ||
556 | id, ret); | ||
557 | return ret; | ||
558 | } | ||
559 | } | ||
560 | |||
561 | mutex_lock(&rpmsg_channels_lock); | ||
562 | |||
563 | /* are we exposing channels for this remote processor yet ? */ | ||
564 | vrp_channels = radix_tree_lookup(&rpmsg_channels, id); | ||
565 | /* not yet ? let's prepare the 2nd radix tree level then */ | ||
566 | if (!vrp_channels) { | ||
567 | vrp_channels = kzalloc(sizeof(*vrp_channels), GFP_KERNEL); | ||
568 | INIT_RADIX_TREE(vrp_channels, GFP_KERNEL); | ||
569 | /* now let's associate the new channel with its vrp */ | ||
570 | ret = radix_tree_insert(&rpmsg_channels, id, vrp_channels); | ||
571 | if (ret) { | ||
572 | dev_err(dev, "radix_tree_insert failed: %d\n", ret); | ||
573 | kfree(vrp_channels); | ||
574 | goto out; | ||
575 | } | ||
576 | } | ||
577 | |||
578 | /* let's associate the new channel with its dst */ | ||
579 | ret = radix_tree_insert(vrp_channels, dst, rpdev); | ||
580 | if (ret) | ||
581 | dev_err(dev, "failed to add rpmsg addr %d: %d\n", dst, ret); | ||
582 | |||
583 | out: | ||
584 | mutex_unlock(&rpmsg_channels_lock); | ||
585 | |||
586 | return ret; | ||
587 | } | ||
588 | |||
589 | static void rpmsg_proto_remove(struct rpmsg_channel *rpdev) | ||
590 | { | ||
591 | struct device *dev = &rpdev->dev; | ||
592 | int id, dst = rpdev->dst, src = rpdev->src; | ||
593 | struct radix_tree_root *vrp_channels; | ||
594 | |||
595 | if (dst == RPMSG_ADDR_ANY) | ||
596 | return; | ||
597 | |||
598 | id = rpmsg_sock_get_proc_id(rpdev); | ||
599 | |||
600 | mutex_lock(&rpmsg_channels_lock); | ||
601 | |||
602 | vrp_channels = radix_tree_lookup(&rpmsg_channels, id); | ||
603 | if (!vrp_channels) { | ||
604 | dev_err(dev, "can't find channels for this vrp: %d\n", id); | ||
605 | goto out; | ||
606 | } | ||
607 | |||
608 | /* Only remove non-reserved channels from the tree, as only these | ||
609 | * were "probed". Note: bind is not causing a probe, and bound | ||
610 | * sockets have src addresses < RPMSG_RESERVED_ADDRESSES. | ||
611 | */ | ||
612 | if (src >= RPMSG_RESERVED_ADDRESSES) { | ||
613 | mutex_lock(&rpmsg_vprocs_lock); | ||
614 | if (!radix_tree_delete(&rpmsg_vprocs, id)) | ||
615 | dev_err(dev, "failed to delete id %d\n", id); | ||
616 | mutex_unlock(&rpmsg_vprocs_lock); | ||
617 | |||
618 | if (!radix_tree_delete(vrp_channels, dst)) | ||
619 | dev_err(dev, "failed to delete rpmsg %d\n", dst); | ||
620 | } | ||
621 | |||
622 | out: | ||
623 | mutex_unlock(&rpmsg_channels_lock); | ||
624 | } | ||
625 | |||
626 | static struct rpmsg_device_id rpmsg_proto_id_table[] = { | ||
627 | { .name = "rpmsg-proto" }, | ||
628 | { }, | ||
629 | }; | ||
630 | MODULE_DEVICE_TABLE(rpmsg, rpmsg_proto_id_table); | ||
631 | |||
632 | static struct rpmsg_driver rpmsg_proto_driver = { | ||
633 | .drv.name = KBUILD_MODNAME, | ||
634 | .drv.owner = THIS_MODULE, | ||
635 | .id_table = rpmsg_proto_id_table, | ||
636 | .probe = rpmsg_proto_probe, | ||
637 | .callback = rpmsg_proto_cb, | ||
638 | .remove = rpmsg_proto_remove, | ||
639 | }; | ||
640 | |||
641 | static int __init rpmsg_proto_init(void) | ||
642 | { | ||
643 | int ret; | ||
644 | |||
645 | ret = proto_register(&rpmsg_proto, 0); | ||
646 | if (ret) { | ||
647 | pr_err("proto_register failed: %d\n", ret); | ||
648 | return ret; | ||
649 | } | ||
650 | |||
651 | ret = sock_register(&rpmsg_proto_family); | ||
652 | if (ret) { | ||
653 | pr_err("sock_register failed: %d\n", ret); | ||
654 | goto proto_unreg; | ||
655 | } | ||
656 | |||
657 | ret = register_rpmsg_driver(&rpmsg_proto_driver); | ||
658 | if (ret) { | ||
659 | pr_err("register_rpmsg_driver failed: %d\n", ret); | ||
660 | goto sock_unreg; | ||
661 | } | ||
662 | |||
663 | return 0; | ||
664 | |||
665 | sock_unreg: | ||
666 | sock_unregister(PF_RPMSG); | ||
667 | proto_unreg: | ||
668 | proto_unregister(&rpmsg_proto); | ||
669 | return ret; | ||
670 | } | ||
671 | |||
672 | static void __exit rpmsg_proto_exit(void) | ||
673 | { | ||
674 | unregister_rpmsg_driver(&rpmsg_proto_driver); | ||
675 | sock_unregister(PF_RPMSG); | ||
676 | proto_unregister(&rpmsg_proto); | ||
677 | } | ||
678 | |||
679 | module_init(rpmsg_proto_init); | ||
680 | module_exit(rpmsg_proto_exit); | ||
681 | |||
682 | MODULE_DESCRIPTION("Remote processor messaging protocol"); | ||
683 | MODULE_LICENSE("GPL v2"); | ||
684 | MODULE_ALIAS_NETPROTO(AF_RPMSG); | ||