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;
114 }
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)
126 {
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 }
162 }
164 int hil_init_proc(struct hil_proc *proc)
165 {
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;
175 }
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)
187 {
188 virtqueue_notification(vring_hw->vq);
189 }
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)
204 {
205 *num_chnls = proc->num_chnls;
206 return (proc->chnls);
207 }
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)
221 {
222 return (&proc->vdev);
224 }
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)
239 {
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);
265 }
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)
280 {
281 return (&proc->sh_buff);
282 }
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)
298 {
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;
309 }
311 /**
312 * hil_vring_notify()
313 *
314 * This function generates IPI to let the other side know that there is
315 * job available for it. The required information to achieve this, like interrupt
316 * vector, CPU id etc is be obtained from the proc_vring table.
317 *
318 * @param vq - pointer to virtqueue
319 *
320 */
321 void hil_vring_notify(struct virtqueue *vq)
322 {
323 struct hil_proc *proc_hw = (struct hil_proc *)vq->vq_dev->device;
324 struct proc_vring *vring_hw =
325 &proc_hw->vdev.vring_info[vq->vq_queue_index];
327 if (proc_hw->ops->notify) {
328 proc_hw->ops->notify(proc_hw, &vring_hw->intr_info);
329 }
330 }
332 /**
333 * hil_get_status
334 *
335 * This function is used to check if the given core is up and running.
336 * This call will return after it is confirmed that remote core has
337 * started.
338 *
339 * @param proc - pointer to proc instance
340 *
341 * @return - execution status
342 */
343 int hil_get_status(struct hil_proc *proc)
344 {
345 (void)proc;
347 /* For future use only. */
348 return 0;
349 }
351 /**
352 * hil_set_status
353 *
354 * This function is used to update the status
355 * of the given core i.e it is ready for IPC.
356 *
357 * @param proc - pointer to remote proc
358 *
359 * @return - execution status
360 */
361 int hil_set_status(struct hil_proc *proc)
362 {
363 (void)proc;
365 /* For future use only. */
366 return 0;
367 }
369 /**
370 * hil_boot_cpu
371 *
372 * This function boots the remote processor.
373 *
374 * @param proc - pointer to remote proc
375 * @param start_addr - start address of remote cpu
376 *
377 * @return - execution status
378 */
379 int hil_boot_cpu(struct hil_proc *proc, unsigned int start_addr)
380 {
382 if (proc->ops->boot_cpu) {
383 proc->ops->boot_cpu(proc, start_addr);
384 }
385 #if defined (OPENAMP_BENCHMARK_ENABLE)
386 boot_time_stamp = metal_get_timestamp();
387 #endif
389 return 0;
390 }
392 /**
393 * hil_shutdown_cpu
394 *
395 * This function shutdowns the remote processor
396 *
397 * @param proc - pointer to remote proc
398 *
399 */
400 void hil_shutdown_cpu(struct hil_proc *proc)
401 {
402 if (proc->ops->shutdown_cpu) {
403 proc->ops->shutdown_cpu(proc);
404 }
405 #if defined (OPENAMP_BENCHMARK_ENABLE)
406 shutdown_time_stamp = metal_get_timestamp();
407 #endif
408 }
410 /**
411 * hil_get_firmware
412 *
413 * This function returns address and size of given firmware name passed as
414 * parameter.
415 *
416 * @param fw_name - name of the firmware
417 * @param start_addr - pointer t hold start address of firmware
418 * @param size - pointer to hold size of firmware
419 *
420 * returns - status of function execution
421 *
422 */
423 int hil_get_firmware(char *fw_name, uintptr_t *start_addr,
424 unsigned int *size)
425 {
426 return (config_get_firmware(fw_name, start_addr, size));
427 }
429 int hil_poll (struct hil_proc *proc, int nonblock)
430 {
431 return proc->ops->poll(proc, nonblock);
432 }
434 int hil_set_shm (struct hil_proc *proc,
435 const char *bus_name, const char *name,
436 metal_phys_addr_t paddr, size_t size)
437 {
438 struct metal_device *dev;
439 struct metal_io_region *io;
440 int ret;
441 if (!proc)
442 return -1;
443 if (name && bus_name) {
444 ret = metal_device_open(bus_name, name, &dev);
445 if (ret)
446 return ret;
447 io = metal_device_io_region(dev, 0);
448 if (!io)
449 return -1;
450 proc->sh_buff.io = io;
451 proc->sh_buff.dev = dev;
452 } else if (name) {
453 ret = metal_shmem_open(name, size, &io);
454 if (ret)
455 return ret;
456 proc->sh_buff.io = io;
457 }
458 if (!paddr && io) {
459 proc->sh_buff.start_paddr = io->physmap[0];
460 proc->sh_buff.start_addr = io->virt;
461 } else {
462 proc->sh_buff.start_paddr = paddr;
463 }
464 if (!size && io)
465 proc->sh_buff.size = io->size;
466 else
467 proc->sh_buff.size = size;
469 metal_io_mem_map(proc->sh_buff.start_paddr, proc->sh_buff.io,
470 proc->sh_buff.size);
471 return 0;
472 }
474 int hil_set_vring (struct hil_proc *proc, int index,
475 const char *bus_name, const char *name)
476 {
477 struct metal_device *dev;
478 struct metal_io_region *io;
479 struct proc_vring *vring;
480 int ret;
482 if (!proc)
483 return -1;
484 if (index >= HIL_MAX_NUM_VRINGS)
485 return -1;
486 vring = &proc->vdev.vring_info[index];
487 if (name && bus_name) {
488 ret = metal_device_open(bus_name, name, &dev);
489 if (ret)
490 return ret;
491 io = metal_device_io_region(dev, 0);
492 if (!io)
493 return -1;
494 vring->io = io;
495 vring->dev = dev;
496 } else if (name) {
497 ret = metal_shmem_open(name, DEFAULT_VRING_MEM_SIZE, &io);
498 if (ret)
499 return ret;
500 vring->io = io;
501 }
503 return 0;
504 }
506 int hil_set_ipi (struct hil_proc *proc, int index,
507 unsigned int irq, void *data)
508 {
509 struct proc_intr *vring_intr;
511 if (!proc)
512 return -1;
513 vring_intr = &proc->vdev.vring_info[index].intr_info;
514 vring_intr->vect_id = irq;
515 vring_intr->data = data;
516 return 0;
517 }
519 int hil_set_rpmsg_channel (struct hil_proc *proc, int index,
520 char *name)
521 {
522 if (!proc)
523 return -1;
524 if (index >= HIL_MAX_NUM_CHANNELS)
525 return -1;
526 strcpy(proc->chnls[index].name, name);
527 return 0;
528 }