]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - processor-sdk/open-amp.git/blob - lib/remoteproc/drivers/linux_remoteproc.c
Add Linux remoteproc between two processes
[processor-sdk/open-amp.git] / lib / remoteproc / drivers / linux_remoteproc.c
1 /*
2  * Copyright (c) 2014, Mentor Graphics Corporation
3  * All rights reserved.
4  * Copyright (c) 2016 Xilinx, Inc.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright notice,
10  *    this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  *    this list of conditions and the following disclaimer in the documentation
13  *    and/or other materials provided with the distribution.
14  * 3. Neither the name of Mentor Graphics Corporation nor the names of its
15  *    contributors may be used to endorse or promote products derived from this
16  *    software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  */
31 /**************************************************************************
32  * FILE NAME
33  *
34  *       zynqmp_remoteproc_r5.c
35  *
36  * DESCRIPTION
37  *
38  *       This file is the Implementation of IPC hardware layer interface
39  *       for Xilinx Zynq UltraScale+ MPSoC system.
40  *
41  **************************************************************************/
43 #include <errno.h>
44 #include <string.h>
45 #include <stdio.h>
46 #include <poll.h>
47 #include <metal/io.h>
48 #include <metal/device.h>
49 #include <metal/utilities.h>
50 #include <metal/atomic.h>
51 #include <metal/irq.h>
52 #include <metal/cpu.h>
53 #include <metal/alloc.h>
54 #include <metal/shmem.h>
55 #include <sys/socket.h>
56 #include <sys/un.h>
57 #include "openamp/hil.h"
58 #include "openamp/virtqueue.h"
60 #define MAX_VRING_MEM_SIZE 0x20000
61 #define _rproc_wait() metal_cpu_yield()
63 #define UNIX_PREFIX "unix:"
64 #define UNIXS_PREFIX "unixs:"
66 struct vring_ipi_info {
67         /* Socket file path */
68         char *path;
69         int fd;
70         struct metal_io_region *vring_io;
71         atomic_int sync;
72 };
74 /*--------------------------- Declare Functions ------------------------ */
75 static int _ipi_handler(int vect_id, void *data);
76 static int _enable_interrupt(struct proc_vring *vring_hw);
77 static void _notify(struct hil_proc *proc, struct proc_intr *intr_info);
78 static int _boot_cpu(struct hil_proc *proc, unsigned int load_addr);
79 static void _shutdown_cpu(struct hil_proc *proc);
80 static int _poll(struct hil_proc *proc, int nonblock);
81 static int _initialize(struct hil_proc *proc);
82 static void _release(struct hil_proc *proc);
84 /*--------------------------- Globals ---------------------------------- */
85 struct hil_platform_ops linux_proc_ops = {
86         .enable_interrupt     = _enable_interrupt,
87         .notify               = _notify,
88         .boot_cpu             = _boot_cpu,
89         .shutdown_cpu         = _shutdown_cpu,
90         .poll                 = _poll,
91         .initialize    = _initialize,
92         .release    = _release,
93 };
95 static int sk_unix_client(const char *descr)
96 {
97         struct sockaddr_un addr;
98         int fd;
100         fd = socket(AF_UNIX, SOCK_STREAM, 0);
102         memset(&addr, 0, sizeof addr);
103         addr.sun_family = AF_UNIX;
104         strncpy(addr.sun_path, descr + strlen(UNIX_PREFIX),
105                 sizeof addr.sun_path);
106         if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) >= 0) {
107                 printf("connected to %s\n", descr + strlen(UNIX_PREFIX));
108                 return fd;
109         }
111         close(fd);
112         return -1;
115 static int sk_unix_server(const char *descr)
117         struct sockaddr_un addr;
118         int fd, nfd;
120         fd = socket(AF_UNIX, SOCK_STREAM, 0);
122         addr.sun_family = AF_UNIX;
123         strncpy(addr.sun_path, descr + strlen(UNIXS_PREFIX),
124                 sizeof addr.sun_path);
125         unlink(addr.sun_path);
126         if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
127                 goto fail;
128         }
130         listen(fd, 5);
131         printf("Waiting for connection on %s\n", addr.sun_path);
132         nfd = accept(fd, NULL, NULL);
133         close(fd);
134         return nfd;
135 fail:
136         close(fd);
137         return -1;
140 static int event_open(const char *descr)
142         int fd = -1;
143         int i;
145         if (descr == NULL) {
146                 return fd;
147         }
149         if (memcmp(UNIX_PREFIX, descr, strlen(UNIX_PREFIX)) == 0) {
150                 /* UNIX.  Retry to connect a few times to give the peer a
151                 * chance to setup.  */
152                 for (i = 0; i < 100 && fd == -1; i++) {
153                         fd = sk_unix_client(descr);
154                         if (fd == -1)
155                                 usleep(i * 10 * 1000);
156                 }
157         }
158         if (memcmp(UNIXS_PREFIX, descr, strlen(UNIXS_PREFIX)) == 0) {
159                 /* UNIX.  */
160                 fd = sk_unix_server(descr);
161         }
162         printf("Open IPI: %s\n", descr);
163         return fd;
166 static int _ipi_handler(int vect_id, void *data)
168         (void) vect_id;
169         (void) data;
170         char dummy_buf[32];
171         struct proc_vring *vring_hw = (struct proc_vring *)(data);
172         struct vring_ipi_info *ipi =
173                 (struct vring_ipi_info *)(vring_hw->intr_info.data);
174         read(vect_id, dummy_buf, sizeof(dummy_buf));
175         atomic_flag_clear(&ipi->sync);
176         return 0;
179 static int _enable_interrupt(struct proc_vring *vring_hw)
181         struct vring_ipi_info *ipi = vring_hw->intr_info.data;
183         ipi->fd = event_open(ipi->path);
184         if (ipi->fd < 0) {
185                 fprintf(stderr, "ERROR: Failed to open sock %s for IPI.\n",
186                         ipi->path);
187                 return -1;
188         }
190         vring_hw->intr_info.vect_id = ipi->fd;
192         /* Register ISR */
193         metal_irq_register(ipi->fd, _ipi_handler,
194                                 NULL, vring_hw);
195         return 0;
198 static void _notify(struct hil_proc *proc, struct proc_intr *intr_info)
201         (void)proc;
202         struct vring_ipi_info *ipi = (struct vring_ipi_info *)(intr_info->data);
203         if (ipi == NULL)
204                 return;
206         char dummy = 1;
207         send(ipi->fd, &dummy, 1, MSG_NOSIGNAL);
208         //printf("%s:%d\n", __func__, ipi->fd);
211 static int _boot_cpu(struct hil_proc *proc, unsigned int load_addr)
213         (void)proc;
214         (void)load_addr;
215         return -1;
218 static void _shutdown_cpu(struct hil_proc *proc)
220         (void)proc;
221         return;
224 static int _poll(struct hil_proc *proc, int nonblock)
226         (void) nonblock;
227         struct proc_vring *vring;
228         struct vring_ipi_info *ipi;
229         unsigned int flags;
231         //struct pollfd fds[32];
232         //char dummy_buf[32];
233         int num_vrings = proc->vdev.num_vrings;
234         int ret = 0;
235         int notified;
236         //int r;
237         int i;
239         assert(proc);
240         //assert(num_vrings <= (int)(sizeof(fds)/sizeof(fds[0])));
242         notified = 0;
243         while (1) {
244                 for (i = 0; i < num_vrings; i++) {
245                         vring = &proc->vdev.vring_info[i];
246                         ipi = (struct vring_ipi_info *)(vring->intr_info.data);
247                         flags = metal_irq_save_disable();
248                         if (!(atomic_flag_test_and_set(&ipi->sync))) {
249                                 metal_irq_restore_enable(flags);
250                                 virtqueue_notification(vring->vq);
251                                 notified = 1;
252                         } else {
253                                 metal_irq_restore_enable(flags);
254                         }
255                 }
256                 if (notified)
257                         return 0;
258                 if (nonblock)
259                         return -EAGAIN;
260                 _rproc_wait();
261         }
262         return ret;
265 /**
266  * @brief   _adjust_vring_io - Adjust the vring I/O region to map to the
267  *                             specified start device address.
268  * @param[in] io - vring I/O region
269  * @param[in] start_phy - start device address of the vring, this is
270  *                            not the actual physical address.
271  * @return adjusted I/O region
272  */
273 static struct metal_io_region *_create_vring_io(struct metal_io_region *in_io,
274                                                 int start_phy)
276         struct metal_io_region *io = 0;
277         metal_phys_addr_t *phys;
278         io = metal_allocate_memory(sizeof(struct metal_io_region));
279         if (!io) {
280                 fprintf(stderr, "ERROR: Failed to allocation I/O for vring.\n");
281                 return NULL;
282         }
283         phys = metal_allocate_memory(sizeof(metal_phys_addr_t));
284         if (!phys) {
285                 fprintf(stderr, "ERROR: Failed to allocation phys for vring.\n");
286                 metal_free_memory(io);
287                 return NULL;
288         }
289         *phys = (metal_phys_addr_t)start_phy;
290         metal_io_init(io, in_io->virt, phys, in_io->size, -1, 0, NULL);
291         return io;
294 static int _initialize(struct hil_proc *proc)
296         struct proc_vring *vring;
297         struct vring_ipi_info *ipi;
298         struct metal_io_region *io;
299         int i;
300         if (proc) {
301                 for (i = 0; i < 2; i++) {
302                         vring = &proc->vdev.vring_info[i];
303                         ipi = (struct vring_ipi_info *)vring->intr_info.data;
304                         if (ipi && !ipi->vring_io && vring->io) {
305                                 io = _create_vring_io(vring->io, 0);
306                                 if (!io)
307                                         return -1;
308                                 ipi->vring_io = vring->io;
309                                 vring->io = io;
310                                 atomic_store(&ipi->sync, 1);
311                         }
312                 }
313         }
314         return 0;
317 static void _release(struct hil_proc *proc)
319         struct proc_vring *vring;
320         struct vring_ipi_info *ipi;
321         int i;
322         if (proc) {
323                 for (i = 0; i < 2; i++) {
324                         vring = &proc->vdev.vring_info[i];
325                         ipi = (struct vring_ipi_info *)vring->intr_info.data;
326                         if (ipi) {
327                                 if (ipi->fd >= 0) {
328                                         metal_irq_register(ipi->fd, 0, NULL,
329                                                 vring);
330                                         close(ipi->fd);
331                                 }
332                                 if (ipi->vring_io) {
333                                         metal_free_memory(
334                                                 (void *)vring->io->physmap);
335                                         metal_free_memory(vring->io);
336                                         vring->io = NULL;
337                                         if (ipi->vring_io->ops.close)
338                                                 ipi->vring_io->ops.close(
339                                                         ipi->vring_io);
340                                         ipi->vring_io = NULL;
341                                 }
342                         }
343                 }
344         }