hil: add hil_vdev_notify
[processor-sdk/open-amp.git] / lib / common / hil.c
1 /*
2  * Copyright (c) 2014, Mentor Graphics Corporation
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  *    this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright notice,
11  *    this list of conditions and the following disclaimer in the documentation
12  *    and/or other materials provided with the distribution.
13  * 3. Neither the name of Mentor Graphics Corporation nor the names of its
14  *    contributors may be used to endorse or promote products derived from this
15  *    software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
30 /**************************************************************************
31  * FILE NAME
32  *
33  *       hil.c
34  *
35  * COMPONENT
36  *
37  *         OpenAMP  Stack.
38  *
39  * DESCRIPTION
40  *
41  *       This file is implementation of generic part of HIL.
42  *
43  *
44  *
45  **************************************************************************/
47 #include "openamp/hil.h"
48 #include "openamp/remoteproc.h"
49 #include <metal/io.h>
50 #include <metal/alloc.h>
51 #include <metal/device.h>
52 #include <metal/shmem.h>
53 #include <metal/utilities.h>
54 #include <metal/time.h>
56 #define DEFAULT_VRING_MEM_SIZE 0x10000
58 /*--------------------------- Globals ---------------------------------- */
59 static METAL_DECLARE_LIST (procs);
61 #if defined (OPENAMP_BENCHMARK_ENABLE)
63 unsigned long long boot_time_stamp;
64 unsigned long long shutdown_time_stamp;
66 #endif
68 metal_phys_addr_t hil_generic_start_paddr = 0;
69 struct metal_io_region hil_shm_generic_io = {
70         0,
71         &hil_generic_start_paddr,
72         (size_t)(-1),
73         (sizeof(metal_phys_addr_t) << 3),
74         (metal_phys_addr_t)(-1),
75         0,
76         {NULL},
77 };
79 struct metal_io_region hil_devmem_generic_io = {
80         0,
81         &hil_generic_start_paddr,
82         (size_t)(-1),
83         (sizeof(metal_phys_addr_t) << 3),
84         (metal_phys_addr_t)(-1),
85         METAL_UNCACHED | METAL_SHARED_MEM,
86         {NULL},
87 };
89 struct hil_proc *hil_create_proc(struct hil_platform_ops *ops,
90                         unsigned long cpu_id, void *pdata)
91 {
92         struct hil_proc *proc = 0;
93         int i;
95         proc = metal_allocate_memory(sizeof(struct hil_proc));
96         if (!proc)
97                 return NULL;
98         memset(proc, 0, sizeof(struct hil_proc));
100         proc->ops = ops;
101         proc->num_chnls = 1;
102         proc->cpu_id = cpu_id;
103         proc->pdata = pdata;
105         /* Setup generic shared memory I/O region */
106         proc->sh_buff.io = &hil_shm_generic_io;
107         /* Setup generic vrings I/O region */
108         for (i = 0; i < HIL_MAX_NUM_VRINGS; i++)
109                 proc->vdev.vring_info[i].io = &hil_devmem_generic_io;
111         metal_list_add_tail(&procs, &proc->node);
113         return proc;
116 /**
117  * hil_delete_proc
118  *
119  * This function deletes the given proc instance and frees the
120  * associated resources.
121  *
122  * @param proc - pointer to hil remote_proc instance
123  *
124  */
125 void hil_delete_proc(struct hil_proc *proc)
127         struct metal_list *node;
128         struct metal_device *dev;
129         struct metal_io_region *io;
130         struct proc_vring *vring;
131         int i;
132         metal_list_for_each(&procs, node) {
133                 if (proc ==
134                         metal_container_of(node, struct hil_proc, node)) {
135                         metal_list_del(&proc->node);
136                         proc->ops->release(proc);
137                         /* Close shmem device */
138                         dev = proc->sh_buff.dev;
139                         io = proc->sh_buff.io;
140                         if (dev) {
141                                 metal_device_close(dev);
142                         } else if (io && io->ops.close) {
143                                 io->ops.close(io);
144                         }
146                         /* Close vring device */
147                         for (i = 0; i < HIL_MAX_NUM_VRINGS; i++) {
148                                 vring = &proc->vdev.vring_info[i];
149                                 dev = vring->dev;
150                                 io = vring->io;
151                                 if (dev) {
152                                         metal_device_close(dev);
153                                 } if (io && io->ops.close) {
154                                         io->ops.close(io);
155                                 }
156                         }
158                         metal_free_memory(proc);
159                         return;
160                 }
161         }
164 int hil_init_proc(struct hil_proc *proc)
166         int ret = 0;
167         if (!proc->is_initialized && proc->ops->initialize) {
168                 ret = proc->ops->initialize(proc);
169                 if (!ret)
170                         proc->is_initialized = 1;
171                 else
172                         return -1;
173         }
174         return 0;
176 /**
177  * hil_isr()
178  *
179  * This function is called when interrupt is received for the vring.
180  * This function gets the corresponding virtqueue and generates
181  * call back for it.
182  *
183  * @param vring_hw   - pointer to vring control block
184  *
185  */
186 void hil_isr(struct proc_vring *vring_hw)
188         virtqueue_notification(vring_hw->vq);
191 /**
192  * hil_get_chnl_info
193  *
194  * This function returns channels info for given proc.
195  *
196  * @param proc - pointer to proc info struct
197  * @param num_chnls - pointer to integer variable to hold
198  *                    number of available channels
199  *
200  * @return - pointer to channel info control block
201  *
202  */
203 struct proc_chnl *hil_get_chnl_info(struct hil_proc *proc, int *num_chnls)
205         *num_chnls = proc->num_chnls;
206         return (proc->chnls);
209 /**
210  * hil_get_vdev_info
211  *
212  * This function return virtio device for remote core.
213  *
214  * @param proc - pointer to remote proc
215  *
216  * @return - pointer to virtio HW device.
217  *
218  */
220 struct proc_vdev *hil_get_vdev_info(struct hil_proc *proc)
222         return (&proc->vdev);
226 /**
227  * hil_get_vring_info
228  *
229  * This function returns vring_info_table. The caller will use
230  * this table to get the vring HW info which will be subsequently
231  * used to create virtqueues.
232  *
233  * @param vdev - pointer to virtio HW device
234  * @param num_vrings - pointer to hold number of vrings
235  *
236  * @return - pointer to vring hardware info table
237  */
238 struct proc_vring *hil_get_vring_info(struct proc_vdev *vdev, int *num_vrings)
240         struct fw_rsc_vdev *vdev_rsc;
241         struct fw_rsc_vdev_vring *vring_rsc;
242         struct proc_vring *vring;
243         int i;
245         vdev_rsc = vdev->vdev_info;
246         if (vdev_rsc) {
247                 vring = &vdev->vring_info[0];
248                 for (i = 0; i < vdev_rsc->num_of_vrings; i++) {
249                         /* Initialize vring with vring resource */
250                         vring_rsc = &vdev_rsc->vring[i];
251                         vring[i].num_descs = vring_rsc->num;
252                         vring[i].align = vring_rsc->align;
253                         /* Enable acccess to vring memory region */
254                         vring[i].vaddr =
255                                 metal_io_mem_map(
256                                         (metal_phys_addr_t)vring_rsc->da,
257                                         vring[i].io,
258                                         vring_size(vring_rsc->num,
259                                         vring_rsc->align));
260                 }
261         }
262         *num_vrings = vdev->num_vrings;
263         return (vdev->vring_info);
267 /**
268  * hil_get_shm_info
269  *
270  * This function returns shared memory info control block. The caller
271  * will use this information to create and manage memory buffers for
272  * vring descriptor table.
273  *
274  * @param proc - pointer to proc instance
275  *
276  * @return - pointer to shared memory region used for buffers
277  *
278  */
279 struct proc_shm *hil_get_shm_info(struct hil_proc *proc)
281         return (&proc->sh_buff);
284 /**
285  * hil_enable_vring_notifications()
286  *
287  * This function is called after successful creation of virtqueues.
288  * This function saves queue handle in the vring_info_table which
289  * will be used during interrupt handling .This function setups
290  * interrupt handlers.
291  *
292  * @param vring_index - index to vring HW table
293  * @param vq          - pointer to virtqueue to save in vring HW table
294  *
295  * @return            - execution status
296  */
297 int hil_enable_vring_notifications(int vring_index, struct virtqueue *vq)
299         struct hil_proc *proc_hw = (struct hil_proc *)vq->vq_dev->device;
300         struct proc_vring *vring_hw = &proc_hw->vdev.vring_info[vring_index];
301         /* Save virtqueue pointer for later reference */
302         vring_hw->vq = vq;
304         if (proc_hw->ops->enable_interrupt) {
305                 proc_hw->ops->enable_interrupt(vring_hw);
306         }
308         return 0;
311 /**
312  * hil_vdev_notify()
313  *
314  * This function generates IPI to let the other side know that there is
315  * update in the vritio dev configs
316  *
317  * @param vdev - pointer to the viritio device
318  *
319  */
320 void hil_vdev_notify(struct virtio_device *vdev)
322         struct hil_proc *proc = vdev->device;
323         struct proc_vdev *pvdev = &proc->vdev;
325         if (proc->ops->notify) {
326                 proc->ops->notify(proc, &pvdev->intr_info);
327         }
330 /**
331  * hil_vring_notify()
332  *
333  * This function generates IPI to let the other side know that there is
334  * job available for it. The required information to achieve this, like interrupt
335  * vector, CPU id etc is be obtained from the proc_vring table.
336  *
337  * @param vq - pointer to virtqueue
338  *
339  */
340 void hil_vring_notify(struct virtqueue *vq)
342         struct hil_proc *proc_hw = (struct hil_proc *)vq->vq_dev->device;
343         struct proc_vring *vring_hw =
344             &proc_hw->vdev.vring_info[vq->vq_queue_index];
346         if (proc_hw->ops->notify) {
347                 proc_hw->ops->notify(proc_hw, &vring_hw->intr_info);
348         }
351 /**
352  * hil_get_status
353  *
354  * This function is used to check if the given core is up and running.
355  * This call will return after it is confirmed that remote core has
356  * started.
357  *
358  * @param proc - pointer to proc instance
359  *
360  * @return - execution status
361  */
362 int hil_get_status(struct hil_proc *proc)
364         (void)proc;
366         /* For future use only. */
367         return 0;
370 /**
371  * hil_set_status
372  *
373  * This function is used to update the status
374  * of the given core i.e it is ready for IPC.
375  *
376  * @param proc - pointer to remote proc
377  *
378  * @return - execution status
379  */
380 int hil_set_status(struct hil_proc *proc)
382         (void)proc;
384         /* For future use only. */
385         return 0;
388 /**
389  * hil_boot_cpu
390  *
391  * This function boots the remote processor.
392  *
393  * @param proc       - pointer to remote proc
394  * @param start_addr - start address of remote cpu
395  *
396  * @return - execution status
397  */
398 int hil_boot_cpu(struct hil_proc *proc, unsigned int start_addr)
401         if (proc->ops->boot_cpu) {
402                 proc->ops->boot_cpu(proc, start_addr);
403         }
404 #if defined (OPENAMP_BENCHMARK_ENABLE)
405         boot_time_stamp = metal_get_timestamp();
406 #endif
408         return 0;
411 /**
412  * hil_shutdown_cpu
413  *
414  *  This function shutdowns the remote processor
415  *
416  * @param proc - pointer to remote proc
417  *
418  */
419 void hil_shutdown_cpu(struct hil_proc *proc)
421         if (proc->ops->shutdown_cpu) {
422                 proc->ops->shutdown_cpu(proc);
423         }
424 #if defined (OPENAMP_BENCHMARK_ENABLE)
425         shutdown_time_stamp = metal_get_timestamp();
426 #endif
429 /**
430  * hil_get_firmware
431  *
432  * This function returns address and size of given firmware name passed as
433  * parameter.
434  *
435  * @param fw_name    - name of the firmware
436  * @param start_addr - pointer t hold start address of firmware
437  * @param size       - pointer to hold size of firmware
438  *
439  * returns -  status of function execution
440  *
441  */
442 int hil_get_firmware(char *fw_name, uintptr_t *start_addr,
443                      unsigned int *size)
445         return (config_get_firmware(fw_name, start_addr, size));
448 int hil_poll (struct hil_proc *proc, int nonblock)
450         return proc->ops->poll(proc, nonblock);
453 int hil_set_shm (struct hil_proc *proc,
454                  const char *bus_name, const char *name,
455                  metal_phys_addr_t paddr, size_t size)
457         struct metal_device *dev;
458         struct metal_io_region *io;
459         int ret;
460         if (!proc)
461                 return -1;
462         if (name && bus_name) {
463                 ret = metal_device_open(bus_name, name, &dev);
464                 if (ret)
465                         return ret;
466                 io = metal_device_io_region(dev, 0);
467                 if (!io)
468                         return -1;
469                 proc->sh_buff.io = io;
470                 proc->sh_buff.dev = dev;
471         } else if (name) {
472                 ret = metal_shmem_open(name, size, &io);
473                 if (ret)
474                         return ret;
475                 proc->sh_buff.io = io;
476         }
477         if (!paddr && io) {
478                 proc->sh_buff.start_paddr = io->physmap[0];
479                 proc->sh_buff.start_addr = io->virt;
480         } else {
481                 proc->sh_buff.start_paddr = paddr;
482         }
483         if (!size && io)
484                 proc->sh_buff.size = io->size;
485         else
486                 proc->sh_buff.size = size;
488         metal_io_mem_map(proc->sh_buff.start_paddr, proc->sh_buff.io,
489                          proc->sh_buff.size);
490         return 0;
493 int hil_set_vring (struct hil_proc *proc, int index,
494                  const char *bus_name, const char *name)
496         struct metal_device *dev;
497         struct metal_io_region *io;
498         struct proc_vring *vring;
499         int ret;
501         if (!proc)
502                 return -1;
503         if (index >= HIL_MAX_NUM_VRINGS)
504                 return -1;
505         vring = &proc->vdev.vring_info[index];
506         if (name && bus_name) {
507                 ret = metal_device_open(bus_name, name, &dev);
508                 if (ret)
509                         return ret;
510                 io = metal_device_io_region(dev, 0);
511                 if (!io)
512                         return -1;
513                 vring->io = io;
514                 vring->dev = dev;
515         } else if (name) {
516                 ret = metal_shmem_open(name, DEFAULT_VRING_MEM_SIZE, &io);
517                 if (ret)
518                         return ret;
519                 vring->io = io;
520         }
522         return 0;
525 int hil_set_ipi (struct hil_proc *proc, int index,
526                  unsigned int irq, void *data)
528         struct proc_intr *vring_intr;
530         if (!proc)
531                 return -1;
532         vring_intr = &proc->vdev.vring_info[index].intr_info;
533         vring_intr->vect_id = irq;
534         vring_intr->data = data;
535         return 0;
538 int hil_set_rpmsg_channel (struct hil_proc *proc, int index,
539                            char *name)
541         if (!proc)
542                 return -1;
543         if (index >= HIL_MAX_NUM_CHANNELS)
544                 return -1;
545         strcpy(proc->chnls[index].name, name);
546         return 0;