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"
49 /*--------------------------- Globals ---------------------------------- */
50 struct hil_proc_list procs;
52 #if defined (OPENAMP_BENCHMARK_ENABLE)
54 unsigned long long boot_time_stamp;
55 unsigned long long shutdown_time_stamp;
57 #endif
59 extern int platform_get_processor_info(struct hil_proc *proc, int cpu_id);
60 extern int platform_get_processor_for_fw(char *fw_name);
62 /**
63 * hil_create_proc
64 *
65 * This function creates a HIL proc instance for given CPU id and populates
66 * it with platform info.
67 *
68 * @param cpu_id - cpu id
69 *
70 * @return - pointer to proc instance
71 *
72 */
73 struct hil_proc *hil_create_proc(int cpu_id)
74 {
75 struct hil_proc *proc = NULL;
76 struct llist *node = NULL;
77 struct llist *proc_hd = procs.proc_list;
78 int status;
80 /* If proc already exists then return it */
81 while (proc_hd != NULL) {
82 proc = (struct hil_proc *)proc_hd->data;
83 if (proc->cpu_id == (unsigned int)cpu_id) {
84 return proc;
85 }
86 proc_hd = proc_hd->next;
87 }
89 /* Allocate memory for proc instance */
90 proc = env_allocate_memory(sizeof(struct hil_proc));
91 if (!proc) {
92 return NULL;
93 }
95 /* Get HW specfic info */
96 status = platform_get_processor_info(proc, cpu_id);
97 if (status) {
98 env_free_memory(proc);
99 return NULL;
100 }
102 /* Enable mapping for the shared memory region */
103 env_map_memory((unsigned int)proc->sh_buff.start_addr,
104 (unsigned int)proc->sh_buff.start_addr,
105 proc->sh_buff.size, (SHARED_MEM | UNCACHED));
107 /* Put the new proc in the procs list */
108 node = env_allocate_memory(sizeof(struct llist));
110 if (!node) {
111 env_free_memory(proc);
112 return NULL;
113 }
115 node->data = proc;
116 add_to_list(&procs.proc_list, node);
118 return proc;
119 }
121 /**
122 * hil_get_cpuforfw
123 *
124 * This function provides the CPU ID for the given firmware.
125 *
126 * @param fw_name - name of firmware
127 *
128 * @return - cpu id
129 *
130 */
131 int hil_get_cpuforfw(char *fw_name)
132 {
133 return (platform_get_processor_for_fw(fw_name));
134 }
136 /**
137 * hil_delete_proc
138 *
139 * This function deletes the given proc instance and frees the
140 * associated resources.
141 *
142 * @param proc - pointer to hil remote_proc instance
143 *
144 */
145 void hil_delete_proc(struct hil_proc *proc)
146 {
147 struct llist *proc_hd = NULL;
149 if (!proc)
150 return;
152 proc_hd = procs.proc_list;
154 while (proc_hd != NULL) {
155 if (proc_hd->data == proc) {
156 remove_from_list(&procs.proc_list, proc_hd);
157 env_free_memory(proc_hd);
158 env_free_memory(proc);
159 break;
160 }
161 proc_hd = proc_hd->next;
162 }
164 }
166 /**
167 * hil_isr()
168 *
169 * This function is called when interrupt is received for the vring.
170 * This function gets the corresponding virtqueue and generates
171 * call back for it.
172 *
173 * @param vring_hw - pointer to vring control block
174 *
175 */
176 void hil_isr(struct proc_vring *vring_hw)
177 {
178 virtqueue_notification(vring_hw->vq);
179 }
181 /**
182 * hil_get_proc
183 *
184 * This function finds the proc instance based on the given ID
185 * from the proc list and returns it to user.
186 *
187 * @param cpu_id - cpu id
188 *
189 * @return - pointer to hil proc instance
190 *
191 */
192 struct hil_proc *hil_get_proc(int cpu_id)
193 {
194 struct llist *proc_hd = procs.proc_list;
196 if (!proc_hd)
197 return NULL;
199 while (proc_hd != NULL) {
200 struct hil_proc *proc = (struct hil_proc *)proc_hd->data;
201 if (proc->cpu_id == (unsigned int)cpu_id) {
202 return proc;
203 }
204 proc_hd = proc_hd->next;
205 }
207 return NULL;
208 }
210 /**
211 * hil_get_chnl_info
212 *
213 * This function returns channels info for given proc.
214 *
215 * @param proc - pointer to proc info struct
216 * @param num_chnls - pointer to integer variable to hold
217 * number of available channels
218 *
219 * @return - pointer to channel info control block
220 *
221 */
222 struct proc_chnl *hil_get_chnl_info(struct hil_proc *proc, int *num_chnls)
223 {
224 *num_chnls = proc->num_chnls;
225 return (proc->chnls);
226 }
228 /**
229 * hil_get_vdev_info
230 *
231 * This function return virtio device for remote core.
232 *
233 * @param proc - pointer to remote proc
234 *
235 * @return - pointer to virtio HW device.
236 *
237 */
239 struct proc_vdev *hil_get_vdev_info(struct hil_proc *proc)
240 {
241 return (&proc->vdev);
243 }
245 /**
246 * hil_get_vring_info
247 *
248 * This function returns vring_info_table. The caller will use
249 * this table to get the vring HW info which will be subsequently
250 * used to create virtqueues.
251 *
252 * @param vdev - pointer to virtio HW device
253 * @param num_vrings - pointer to hold number of vrings
254 *
255 * @return - pointer to vring hardware info table
256 */
257 struct proc_vring *hil_get_vring_info(struct proc_vdev *vdev, int *num_vrings)
258 {
260 *num_vrings = vdev->num_vrings;
261 return (vdev->vring_info);
263 }
265 /**
266 * hil_get_shm_info
267 *
268 * This function returns shared memory info control block. The caller
269 * will use this information to create and manage memory buffers for
270 * vring descriptor table.
271 *
272 * @param proc - pointer to proc instance
273 *
274 * @return - pointer to shared memory region used for buffers
275 *
276 */
277 struct proc_shm *hil_get_shm_info(struct hil_proc *proc)
278 {
279 return (&proc->sh_buff);
280 }
282 /**
283 * hil_enable_vring_notifications()
284 *
285 * This function is called after successful creation of virtqueues.
286 * This function saves queue handle in the vring_info_table which
287 * will be used during interrupt handling .This function setups
288 * interrupt handlers.
289 *
290 * @param vring_index - index to vring HW table
291 * @param vq - pointer to virtqueue to save in vring HW table
292 *
293 * @return - execution status
294 */
295 int hil_enable_vring_notifications(int vring_index, struct virtqueue *vq)
296 {
297 struct hil_proc *proc_hw = (struct hil_proc *)vq->vq_dev->device;
298 struct proc_vring *vring_hw = &proc_hw->vdev.vring_info[vring_index];
299 /* Save virtqueue pointer for later reference */
300 vring_hw->vq = vq;
302 if (proc_hw->ops->enable_interrupt) {
303 proc_hw->ops->enable_interrupt(vring_hw);
304 }
306 return 0;
307 }
309 /**
310 * hil_vring_notify()
311 *
312 * This function generates IPI to let the other side know that there is
313 * job available for it. The required information to achieve this, like interrupt
314 * vector, CPU id etc is be obtained from the proc_vring table.
315 *
316 * @param vq - pointer to virtqueue
317 *
318 */
319 void hil_vring_notify(struct virtqueue *vq)
320 {
321 struct hil_proc *proc_hw = (struct hil_proc *)vq->vq_dev->device;
322 struct proc_vring *vring_hw =
323 &proc_hw->vdev.vring_info[vq->vq_queue_index];
325 if (proc_hw->ops->notify) {
326 proc_hw->ops->notify(proc_hw->cpu_id, &vring_hw->intr_info);
327 }
328 }
330 /**
331 * hil_get_status
332 *
333 * This function is used to check if the given core is up and running.
334 * This call will return after it is confirmed that remote core has
335 * started.
336 *
337 * @param proc - pointer to proc instance
338 *
339 * @return - execution status
340 */
341 int hil_get_status(struct hil_proc *proc)
342 {
343 (void)proc;
345 /* For future use only. */
346 return 0;
347 }
349 /**
350 * hil_set_status
351 *
352 * This function is used to update the status
353 * of the given core i.e it is ready for IPC.
354 *
355 * @param proc - pointer to remote proc
356 *
357 * @return - execution status
358 */
359 int hil_set_status(struct hil_proc *proc)
360 {
361 (void)proc;
363 /* For future use only. */
364 return 0;
365 }
367 /**
368 * hil_boot_cpu
369 *
370 * This function boots the remote processor.
371 *
372 * @param proc - pointer to remote proc
373 * @param start_addr - start address of remote cpu
374 *
375 * @return - execution status
376 */
377 int hil_boot_cpu(struct hil_proc *proc, unsigned int start_addr)
378 {
380 if (proc->ops->boot_cpu) {
381 proc->ops->boot_cpu(proc->cpu_id, start_addr);
382 }
383 #if defined (OPENAMP_BENCHMARK_ENABLE)
384 boot_time_stamp = env_get_timestamp();
385 #endif
387 return 0;
388 }
390 /**
391 * hil_shutdown_cpu
392 *
393 * This function shutdowns the remote processor
394 *
395 * @param proc - pointer to remote proc
396 *
397 */
398 void hil_shutdown_cpu(struct hil_proc *proc)
399 {
400 if (proc->ops->shutdown_cpu) {
401 proc->ops->shutdown_cpu(proc->cpu_id);
402 }
403 #if defined (OPENAMP_BENCHMARK_ENABLE)
404 shutdown_time_stamp = env_get_timestamp();
405 #endif
406 }
408 /**
409 * hil_get_firmware
410 *
411 * This function returns address and size of given firmware name passed as
412 * parameter.
413 *
414 * @param fw_name - name of the firmware
415 * @param start_addr - pointer t hold start address of firmware
416 * @param size - pointer to hold size of firmware
417 *
418 * returns - status of function execution
419 *
420 */
421 int hil_get_firmware(char *fw_name, unsigned int *start_addr,
422 unsigned int *size)
423 {
424 return (config_get_firmware(fw_name, start_addr, size));
425 }