update hil_proc not to add new user data struct
[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 <metal/io.h>
49 #include <metal/alloc.h>
50 #include <metal/device.h>
51 #include <metal/shmem.h>
52 #include <metal/utilities.h>
54 #define DEFAULT_VRING_MEM_SIZE 0x10000
56 /*--------------------------- Globals ---------------------------------- */
57 static METAL_DECLARE_LIST (procs);
59 #if defined (OPENAMP_BENCHMARK_ENABLE)
61 unsigned long long boot_time_stamp;
62 unsigned long long shutdown_time_stamp;
64 #endif
66 metal_phys_addr_t hil_generic_start_paddr = 0;
67 struct metal_io_region hil_shm_generic_io = {
68         0,
69         &hil_generic_start_paddr,
70         (size_t)(-1),
71         (sizeof(metal_phys_addr_t) << 3),
72         (metal_phys_addr_t)(-1),
73         0,
74         {NULL},
75 };
77 struct metal_io_region hil_devmem_generic_io = {
78         0,
79         &hil_generic_start_paddr,
80         (size_t)(-1),
81         (sizeof(metal_phys_addr_t) << 3),
82         (metal_phys_addr_t)(-1),
83         METAL_UNCACHED | METAL_SHARED_MEM,
84         {NULL},
85 };
87 struct hil_proc *hil_create_proc(struct hil_platform_ops *ops,
88                         unsigned long cpu_id, void *pdata)
89 {
90         struct hil_proc *proc = 0;
91         int i;
93         proc = metal_allocate_memory(sizeof(struct hil_proc));
94         if (!proc)
95                 return NULL;
96         memset(proc, 0, sizeof(struct hil_proc));
98         proc->ops = ops;
99         proc->num_chnls = 1;
100         proc->cpu_id = cpu_id;
101         proc->pdata = pdata;
103         /* Setup generic shared memory I/O region */
104         proc->sh_buff.io = &hil_shm_generic_io;
105         /* Setup generic vrings I/O region */
106         for (i = 0; i < HIL_MAX_NUM_VRINGS; i++)
107                 proc->vdev.vring_info[i].io = &hil_devmem_generic_io;
109         metal_list_add_tail(&procs, &proc->node);
111         return proc;
114 /**
115  * hil_delete_proc
116  *
117  * This function deletes the given proc instance and frees the
118  * associated resources.
119  *
120  * @param proc - pointer to hil remote_proc instance
121  *
122  */
123 void hil_delete_proc(struct hil_proc *proc)
125         struct metal_list *node;
126         struct metal_device *dev;
127         struct metal_io_region *io;
128         struct proc_vring *vring;
129         int i;
130         metal_list_for_each(&procs, node) {
131                 if (proc ==
132                         metal_container_of(node, struct hil_proc, node)) {
133                         metal_list_del(&proc->node);
134                         proc->ops->release(proc);
135                         /* Close shmem device */
136                         dev = proc->sh_buff.dev;
137                         io = proc->sh_buff.io;
138                         if (dev) {
139                                 metal_device_close(dev);
140                         } else if (io && io->ops.close) {
141                                 io->ops.close(io);
142                         }
144                         /* Close vring device */
145                         for (i = 0; i < HIL_MAX_NUM_VRINGS; i++) {
146                                 vring = &proc->vdev.vring_info[i];
147                                 dev = vring->dev;
148                                 io = vring->io;
149                                 if (dev) {
150                                         metal_device_close(dev);
151                                 } if (io && io->ops.close) {
152                                         io->ops.close(io);
153                                 }
154                         }
156                         metal_free_memory(proc);
157                         return;
158                 }
159         }
162 int hil_init_proc(struct hil_proc *proc)
164         int ret = 0;
165         if (!proc->is_initialized && proc->ops->initialize) {
166                 ret = proc->ops->initialize(proc);
167                 if (!ret)
168                         proc->is_initialized = 1;
169                 else
170                         return -1;
171         }
172         return 0;
174 /**
175  * hil_isr()
176  *
177  * This function is called when interrupt is received for the vring.
178  * This function gets the corresponding virtqueue and generates
179  * call back for it.
180  *
181  * @param vring_hw   - pointer to vring control block
182  *
183  */
184 void hil_isr(struct proc_vring *vring_hw)
186         virtqueue_notification(vring_hw->vq);
189 /**
190  * hil_get_chnl_info
191  *
192  * This function returns channels info for given proc.
193  *
194  * @param proc - pointer to proc info struct
195  * @param num_chnls - pointer to integer variable to hold
196  *                    number of available channels
197  *
198  * @return - pointer to channel info control block
199  *
200  */
201 struct proc_chnl *hil_get_chnl_info(struct hil_proc *proc, int *num_chnls)
203         *num_chnls = proc->num_chnls;
204         return (proc->chnls);
207 /**
208  * hil_get_vdev_info
209  *
210  * This function return virtio device for remote core.
211  *
212  * @param proc - pointer to remote proc
213  *
214  * @return - pointer to virtio HW device.
215  *
216  */
218 struct proc_vdev *hil_get_vdev_info(struct hil_proc *proc)
220         return (&proc->vdev);
224 /**
225  * hil_get_vring_info
226  *
227  * This function returns vring_info_table. The caller will use
228  * this table to get the vring HW info which will be subsequently
229  * used to create virtqueues.
230  *
231  * @param vdev - pointer to virtio HW device
232  * @param num_vrings - pointer to hold number of vrings
233  *
234  * @return - pointer to vring hardware info table
235  */
236 struct proc_vring *hil_get_vring_info(struct proc_vdev *vdev, int *num_vrings)
239         *num_vrings = vdev->num_vrings;
240         return (vdev->vring_info);
244 /**
245  * hil_get_shm_info
246  *
247  * This function returns shared memory info control block. The caller
248  * will use this information to create and manage memory buffers for
249  * vring descriptor table.
250  *
251  * @param proc - pointer to proc instance
252  *
253  * @return - pointer to shared memory region used for buffers
254  *
255  */
256 struct proc_shm *hil_get_shm_info(struct hil_proc *proc)
258         return (&proc->sh_buff);
261 /**
262  * hil_enable_vring_notifications()
263  *
264  * This function is called after successful creation of virtqueues.
265  * This function saves queue handle in the vring_info_table which
266  * will be used during interrupt handling .This function setups
267  * interrupt handlers.
268  *
269  * @param vring_index - index to vring HW table
270  * @param vq          - pointer to virtqueue to save in vring HW table
271  *
272  * @return            - execution status
273  */
274 int hil_enable_vring_notifications(int vring_index, struct virtqueue *vq)
276         struct hil_proc *proc_hw = (struct hil_proc *)vq->vq_dev->device;
277         struct proc_vring *vring_hw = &proc_hw->vdev.vring_info[vring_index];
278         /* Save virtqueue pointer for later reference */
279         vring_hw->vq = vq;
281         if (proc_hw->ops->enable_interrupt) {
282                 proc_hw->ops->enable_interrupt(vring_hw);
283         }
285         return 0;
288 /**
289  * hil_vring_notify()
290  *
291  * This function generates IPI to let the other side know that there is
292  * job available for it. The required information to achieve this, like interrupt
293  * vector, CPU id etc is be obtained from the proc_vring table.
294  *
295  * @param vq - pointer to virtqueue
296  *
297  */
298 void hil_vring_notify(struct virtqueue *vq)
300         struct hil_proc *proc_hw = (struct hil_proc *)vq->vq_dev->device;
301         struct proc_vring *vring_hw =
302             &proc_hw->vdev.vring_info[vq->vq_queue_index];
304         if (proc_hw->ops->notify) {
305                 proc_hw->ops->notify(proc_hw, &vring_hw->intr_info);
306         }
309 /**
310  * hil_get_status
311  *
312  * This function is used to check if the given core is up and running.
313  * This call will return after it is confirmed that remote core has
314  * started.
315  *
316  * @param proc - pointer to proc instance
317  *
318  * @return - execution status
319  */
320 int hil_get_status(struct hil_proc *proc)
322         (void)proc;
324         /* For future use only. */
325         return 0;
328 /**
329  * hil_set_status
330  *
331  * This function is used to update the status
332  * of the given core i.e it is ready for IPC.
333  *
334  * @param proc - pointer to remote proc
335  *
336  * @return - execution status
337  */
338 int hil_set_status(struct hil_proc *proc)
340         (void)proc;
342         /* For future use only. */
343         return 0;
346 /**
347  * hil_boot_cpu
348  *
349  * This function boots the remote processor.
350  *
351  * @param proc       - pointer to remote proc
352  * @param start_addr - start address of remote cpu
353  *
354  * @return - execution status
355  */
356 int hil_boot_cpu(struct hil_proc *proc, unsigned int start_addr)
359         if (proc->ops->boot_cpu) {
360                 proc->ops->boot_cpu(proc, start_addr);
361         }
362 #if defined (OPENAMP_BENCHMARK_ENABLE)
363         boot_time_stamp = env_get_timestamp();
364 #endif
366         return 0;
369 /**
370  * hil_shutdown_cpu
371  *
372  *  This function shutdowns the remote processor
373  *
374  * @param proc - pointer to remote proc
375  *
376  */
377 void hil_shutdown_cpu(struct hil_proc *proc)
379         if (proc->ops->shutdown_cpu) {
380                 proc->ops->shutdown_cpu(proc);
381         }
382 #if defined (OPENAMP_BENCHMARK_ENABLE)
383         shutdown_time_stamp = env_get_timestamp();
384 #endif
387 /**
388  * hil_get_firmware
389  *
390  * This function returns address and size of given firmware name passed as
391  * parameter.
392  *
393  * @param fw_name    - name of the firmware
394  * @param start_addr - pointer t hold start address of firmware
395  * @param size       - pointer to hold size of firmware
396  *
397  * returns -  status of function execution
398  *
399  */
400 int hil_get_firmware(char *fw_name, uintptr_t *start_addr,
401                      unsigned int *size)
403         return (config_get_firmware(fw_name, start_addr, size));
406 int hil_poll (struct hil_proc *proc, int nonblock)
408         return proc->ops->poll(proc, nonblock);
411 int hil_set_shm (struct hil_proc *proc,
412                  const char *bus_name, const char *name,
413                  metal_phys_addr_t paddr, size_t size)
415         struct metal_device *dev;
416         struct metal_io_region *io;
417         int ret;
418         if (!proc)
419                 return -1;
420         if (name && bus_name) {
421                 ret = metal_device_open(bus_name, name, &dev);
422                 if (ret)
423                         return ret;
424                 io = metal_device_io_region(dev, 0);
425                 if (!io)
426                         return -1;
427                 proc->sh_buff.io = io;
428                 proc->sh_buff.dev = dev;
429         } else if (name) {
430                 ret = metal_shmem_open(name, size, &io);
431                 if (ret)
432                         return ret;
433                 proc->sh_buff.io = io;
434         }
435         if (!paddr && io) {
436                 proc->sh_buff.start_paddr = io->physmap[0];
437                 proc->sh_buff.start_addr = io->virt;
438         } else {
439                 proc->sh_buff.start_paddr = paddr;
440         }
441         if (!size && io)
442                 proc->sh_buff.size = io->size;
443         else
444                 proc->sh_buff.size = size;
446         metal_io_mem_map(proc->sh_buff.start_paddr, proc->sh_buff.io,
447                          proc->sh_buff.size);
448         return 0;
451 int hil_set_vring (struct hil_proc *proc, int index,
452                  const char *bus_name, const char *name)
454         struct metal_device *dev;
455         struct metal_io_region *io;
456         struct proc_vring *vring;
457         int ret;
459         if (!proc)
460                 return -1;
461         if (index >= HIL_MAX_NUM_VRINGS)
462                 return -1;
463         vring = &proc->vdev.vring_info[index];
464         if (name && bus_name) {
465                 ret = metal_device_open(bus_name, name, &dev);
466                 if (ret)
467                         return ret;
468                 io = metal_device_io_region(dev, 0);
469                 if (!io)
470                         return -1;
471                 vring->io = io;
472                 vring->dev = dev;
473         } else if (name) {
474                 ret = metal_shmem_open(name, DEFAULT_VRING_MEM_SIZE, &io);
475                 if (ret)
476                         return ret;
477                 vring->io = io;
478         }
480         return 0;
483 int hil_set_ipi (struct hil_proc *proc, int index,
484                  unsigned int irq, void *data)
486         struct proc_intr *vring_intr;
488         if (!proc)
489                 return -1;
490         vring_intr = &proc->vdev.vring_info[index].intr_info;
491         vring_intr->vect_id = irq;
492         vring_intr->data = data;
493         return 0;
496 int hil_set_rpmsg_channel (struct hil_proc *proc, int index,
497                            char *name)
499         if (!proc)
500                 return -1;
501         if (index >= HIL_MAX_NUM_CHANNELS)
502                 return -1;
503         strcpy(proc->chnls[index].name, name);
504         return 0;