]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - processor-sdk/open-amp.git/blob - lib/common/hil.c
rpmsg: rx_callback: do not handle name service.
[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_mutex_init(&proc->lock);
112         metal_list_add_tail(&procs, &proc->node);
114         return proc;
117 /**
118  * hil_delete_proc
119  *
120  * This function deletes the given proc instance and frees the
121  * associated resources.
122  *
123  * @param proc - pointer to hil remote_proc instance
124  *
125  */
126 void hil_delete_proc(struct hil_proc *proc)
128         struct metal_list *node;
129         struct metal_device *dev;
130         struct metal_io_region *io;
131         struct proc_vring *vring;
132         int i;
133         metal_list_for_each(&procs, node) {
134                 if (proc ==
135                         metal_container_of(node, struct hil_proc, node)) {
136                         metal_list_del(&proc->node);
137                         metal_mutex_acquire(&proc->lock);
138                         proc->ops->release(proc);
139                         /* Close shmem device */
140                         dev = proc->sh_buff.dev;
141                         io = proc->sh_buff.io;
142                         if (dev) {
143                                 metal_device_close(dev);
144                         } else if (io && io->ops.close) {
145                                 io->ops.close(io);
146                         }
148                         /* Close vring device */
149                         for (i = 0; i < HIL_MAX_NUM_VRINGS; i++) {
150                                 vring = &proc->vdev.vring_info[i];
151                                 dev = vring->dev;
152                                 io = vring->io;
153                                 if (dev) {
154                                         metal_device_close(dev);
155                                 } if (io && io->ops.close) {
156                                         io->ops.close(io);
157                                 }
158                         }
160                         metal_mutex_release(&proc->lock);
161                         metal_mutex_deinit(&proc->lock);
162                         metal_free_memory(proc);
163                         return;
164                 }
165         }
168 int hil_init_proc(struct hil_proc *proc)
170         int ret = 0;
171         if (!proc->is_initialized && proc->ops->initialize) {
172                 ret = proc->ops->initialize(proc);
173                 if (!ret)
174                         proc->is_initialized = 1;
175                 else
176                         return -1;
177         }
178         return 0;
181 /**
182  * hil_get_chnl_info
183  *
184  * This function returns channels info for given proc.
185  *
186  * @param proc - pointer to proc info struct
187  * @param num_chnls - pointer to integer variable to hold
188  *                    number of available channels
189  *
190  * @return - pointer to channel info control block
191  *
192  */
193 struct proc_chnl *hil_get_chnl_info(struct hil_proc *proc, int *num_chnls)
195         *num_chnls = proc->num_chnls;
196         return (proc->chnls);
199 void hil_notified(struct hil_proc *proc, uint32_t notifyid)
201         struct proc_vdev *pvdev = &proc->vdev;
202         struct fw_rsc_vdev *vdev_rsc = pvdev->vdev_info;
203         int i;
204         if (vdev_rsc->status & VIRTIO_CONFIG_STATUS_NEEDS_RESET) {
205                 if (pvdev->rst_cb)
206                         pvdev->rst_cb(proc, 0);
207         } else {
208                 for(i = 0; i < (int)pvdev->num_vrings; i++) {
209                         struct fw_rsc_vdev_vring *vring_rsc;
210                         vring_rsc = &vdev_rsc->vring[i];
211                         if (notifyid == (uint32_t)(-1) ||
212                                 notifyid == vring_rsc->notifyid)
213                                 virtqueue_notification(
214                                         pvdev->vring_info[i].vq);
215                 }
216         }
219 /**
220  * hil_get_vdev_info
221  *
222  * This function return virtio device for remote core.
223  *
224  * @param proc - pointer to remote proc
225  *
226  * @return - pointer to virtio HW device.
227  *
228  */
230 struct proc_vdev *hil_get_vdev_info(struct hil_proc *proc)
232         return (&proc->vdev);
236 /**
237  * hil_get_vring_info
238  *
239  * This function returns vring_info_table. The caller will use
240  * this table to get the vring HW info which will be subsequently
241  * used to create virtqueues.
242  *
243  * @param vdev - pointer to virtio HW device
244  * @param num_vrings - pointer to hold number of vrings
245  *
246  * @return - pointer to vring hardware info table
247  */
248 struct proc_vring *hil_get_vring_info(struct proc_vdev *vdev, int *num_vrings)
250         struct fw_rsc_vdev *vdev_rsc;
251         struct fw_rsc_vdev_vring *vring_rsc;
252         struct proc_vring *vring;
253         int i;
255         vdev_rsc = vdev->vdev_info;
256         if (vdev_rsc) {
257                 vring = &vdev->vring_info[0];
258                 for (i = 0; i < vdev_rsc->num_of_vrings; i++) {
259                         /* Initialize vring with vring resource */
260                         vring_rsc = &vdev_rsc->vring[i];
261                         vring[i].num_descs = vring_rsc->num;
262                         vring[i].align = vring_rsc->align;
263                         /* Enable acccess to vring memory region */
264                         vring[i].vaddr =
265                                 metal_io_mem_map(
266                                         (metal_phys_addr_t)vring_rsc->da,
267                                         vring[i].io,
268                                         vring_size(vring_rsc->num,
269                                         vring_rsc->align));
270                 }
271         }
272         *num_vrings = vdev->num_vrings;
273         return (vdev->vring_info);
277 /**
278  * hil_get_shm_info
279  *
280  * This function returns shared memory info control block. The caller
281  * will use this information to create and manage memory buffers for
282  * vring descriptor table.
283  *
284  * @param proc - pointer to proc instance
285  *
286  * @return - pointer to shared memory region used for buffers
287  *
288  */
289 struct proc_shm *hil_get_shm_info(struct hil_proc *proc)
291         return (&proc->sh_buff);
294 void hil_free_vqs(struct virtio_device *vdev)
296         struct hil_proc *proc = vdev->device;
297         struct proc_vdev *pvdev = &proc->vdev;
298         int num_vrings = (int)pvdev->num_vrings;
299         int i;
301         metal_mutex_acquire(&proc->lock);
302         for(i = 0; i < num_vrings; i++) {
303                 struct proc_vring *pvring = &pvdev->vring_info[i];
304                 struct virtqueue *vq = pvring->vq;
305                 if (vq) {
306                         virtqueue_free(vq);
307                         pvring->vq = 0;
308                 }
309         }
310         metal_mutex_release(&proc->lock);
313 /**
314  * hil_enable_vring_notifications()
315  *
316  * This function is called after successful creation of virtqueues.
317  * This function saves queue handle in the vring_info_table which
318  * will be used during interrupt handling .This function setups
319  * interrupt handlers.
320  *
321  * @param vring_index - index to vring HW table
322  * @param vq          - pointer to virtqueue to save in vring HW table
323  *
324  * @return            - execution status
325  */
326 int hil_enable_vring_notifications(int vring_index, struct virtqueue *vq)
328         struct hil_proc *proc_hw = (struct hil_proc *)vq->vq_dev->device;
329         struct proc_vring *vring_hw = &proc_hw->vdev.vring_info[vring_index];
330         /* Save virtqueue pointer for later reference */
331         vring_hw->vq = vq;
333         if (proc_hw->ops->enable_interrupt) {
334                 proc_hw->ops->enable_interrupt(&vring_hw->intr_info);
335         }
337         return 0;
340 /**
341  * hil_vdev_notify()
342  *
343  * This function generates IPI to let the other side know that there is
344  * update in the vritio dev configs
345  *
346  * @param vdev - pointer to the viritio device
347  *
348  */
349 void hil_vdev_notify(struct virtio_device *vdev)
351         struct hil_proc *proc = vdev->device;
352         struct proc_vdev *pvdev = &proc->vdev;
354         if (proc->ops->notify) {
355                 proc->ops->notify(proc, &pvdev->intr_info);
356         }
359 /**
360  * hil_vring_notify()
361  *
362  * This function generates IPI to let the other side know that there is
363  * job available for it. The required information to achieve this, like interrupt
364  * vector, CPU id etc is be obtained from the proc_vring table.
365  *
366  * @param vq - pointer to virtqueue
367  *
368  */
369 void hil_vring_notify(struct virtqueue *vq)
371         struct hil_proc *proc_hw = (struct hil_proc *)vq->vq_dev->device;
372         struct proc_vring *vring_hw =
373             &proc_hw->vdev.vring_info[vq->vq_queue_index];
375         if (proc_hw->ops->notify) {
376                 proc_hw->ops->notify(proc_hw, &vring_hw->intr_info);
377         }
380 /**
381  * hil_get_status
382  *
383  * This function is used to check if the given core is up and running.
384  * This call will return after it is confirmed that remote core has
385  * started.
386  *
387  * @param proc - pointer to proc instance
388  *
389  * @return - execution status
390  */
391 int hil_get_status(struct hil_proc *proc)
393         (void)proc;
395         /* For future use only. */
396         return 0;
399 /**
400  * hil_set_status
401  *
402  * This function is used to update the status
403  * of the given core i.e it is ready for IPC.
404  *
405  * @param proc - pointer to remote proc
406  *
407  * @return - execution status
408  */
409 int hil_set_status(struct hil_proc *proc)
411         (void)proc;
413         /* For future use only. */
414         return 0;
417 /**
418  * hil_boot_cpu
419  *
420  * This function boots the remote processor.
421  *
422  * @param proc       - pointer to remote proc
423  * @param start_addr - start address of remote cpu
424  *
425  * @return - execution status
426  */
427 int hil_boot_cpu(struct hil_proc *proc, unsigned int start_addr)
430         if (proc->ops->boot_cpu) {
431                 proc->ops->boot_cpu(proc, start_addr);
432         }
433 #if defined (OPENAMP_BENCHMARK_ENABLE)
434         boot_time_stamp = metal_get_timestamp();
435 #endif
437         return 0;
440 /**
441  * hil_shutdown_cpu
442  *
443  *  This function shutdowns the remote processor
444  *
445  * @param proc - pointer to remote proc
446  *
447  */
448 void hil_shutdown_cpu(struct hil_proc *proc)
450         if (proc->ops->shutdown_cpu) {
451                 proc->ops->shutdown_cpu(proc);
452         }
453 #if defined (OPENAMP_BENCHMARK_ENABLE)
454         shutdown_time_stamp = metal_get_timestamp();
455 #endif
458 /**
459  * hil_get_firmware
460  *
461  * This function returns address and size of given firmware name passed as
462  * parameter.
463  *
464  * @param fw_name    - name of the firmware
465  * @param start_addr - pointer t hold start address of firmware
466  * @param size       - pointer to hold size of firmware
467  *
468  * returns -  status of function execution
469  *
470  */
471 int hil_get_firmware(char *fw_name, uintptr_t *start_addr,
472                      unsigned int *size)
474         return (config_get_firmware(fw_name, start_addr, size));
477 int hil_poll (struct hil_proc *proc, int nonblock)
479         return proc->ops->poll(proc, nonblock);
482 int hil_set_shm (struct hil_proc *proc,
483                  const char *bus_name, const char *name,
484                  metal_phys_addr_t paddr, size_t size)
486         struct metal_device *dev;
487         struct metal_io_region *io;
488         int ret;
489         if (!proc)
490                 return -1;
491         if (name && bus_name) {
492                 ret = metal_device_open(bus_name, name, &dev);
493                 if (ret)
494                         return ret;
495                 io = metal_device_io_region(dev, 0);
496                 if (!io)
497                         return -1;
498                 proc->sh_buff.io = io;
499                 proc->sh_buff.dev = dev;
500         } else if (name) {
501                 ret = metal_shmem_open(name, size, &io);
502                 if (ret)
503                         return ret;
504                 proc->sh_buff.io = io;
505         }
506         if (!paddr && io) {
507                 proc->sh_buff.start_paddr = io->physmap[0];
508                 proc->sh_buff.start_addr = io->virt;
509         } else {
510                 proc->sh_buff.start_paddr = paddr;
511         }
512         if (!size && io)
513                 proc->sh_buff.size = io->size;
514         else
515                 proc->sh_buff.size = size;
517         metal_io_mem_map(proc->sh_buff.start_paddr, proc->sh_buff.io,
518                          proc->sh_buff.size);
519         return 0;
522 int hil_set_vring (struct hil_proc *proc, int index,
523                  const char *bus_name, const char *name)
525         struct metal_device *dev;
526         struct metal_io_region *io;
527         struct proc_vring *vring;
528         int ret;
530         if (!proc)
531                 return -1;
532         if (index >= HIL_MAX_NUM_VRINGS)
533                 return -1;
534         vring = &proc->vdev.vring_info[index];
535         if (name && bus_name) {
536                 ret = metal_device_open(bus_name, name, &dev);
537                 if (ret)
538                         return ret;
539                 io = metal_device_io_region(dev, 0);
540                 if (!io)
541                         return -1;
542                 vring->io = io;
543                 vring->dev = dev;
544         } else if (name) {
545                 ret = metal_shmem_open(name, DEFAULT_VRING_MEM_SIZE, &io);
546                 if (ret)
547                         return ret;
548                 vring->io = io;
549         }
551         return 0;
554 int hil_set_vdev_ipi (struct hil_proc *proc, int index,
555                  unsigned int irq, void *data)
557         struct proc_intr *vring_intr;
559         /* As we support only one vdev for now */
560         (void)index;
562         if (!proc)
563                 return -1;
564         vring_intr = &proc->vdev.intr_info;
565         vring_intr->vect_id = irq;
566         vring_intr->data = data;
567         return 0;
570 int hil_set_vring_ipi (struct hil_proc *proc, int index,
571                  unsigned int irq, void *data)
573         struct proc_intr *vring_intr;
575         if (!proc)
576                 return -1;
577         vring_intr = &proc->vdev.vring_info[index].intr_info;
578         vring_intr->vect_id = irq;
579         vring_intr->data = data;
580         return 0;
583 int hil_set_rpmsg_channel (struct hil_proc *proc, int index,
584                            char *name)
586         if (!proc)
587                 return -1;
588         if (index >= HIL_MAX_NUM_CHANNELS)
589                 return -1;
590         strcpy(proc->chnls[index].name, name);
591         return 0;