1 /*******************************************************************************
2 * Copyright (C) 2018 Cadence Design Systems, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to use this Software with Cadence processor cores only and
7 * not with any other processors and platforms, subject to
8 * the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included
11 * in all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
14 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
15 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
16 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
17 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
18 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
19 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21 ******************************************************************************/
22
23 /*******************************************************************************
24 * xf-core.c
25 *
26 * DSP processing framework core
27 *
28 ******************************************************************************/
29
30 #define MODULE_TAG CORE
31
32 /*******************************************************************************
33 * Includes
34 ******************************************************************************/
35
36 #include "xf.h"
37
38 /*******************************************************************************
39 * Tracing tags
40 ******************************************************************************/
41
42 /* ...general initialization sequence */
43 TRACE_TAG(INIT, 1);
44
45 /* ...message dispatching */
46 TRACE_TAG(DISP, 1);
47
48 /* ...client registration procedures */
49 TRACE_TAG(REG, 1);
50
51 /* ...ports routing/unrouting */
52 TRACE_TAG(ROUTE, 1);
53
54 #ifdef XAF_PROFILE_DSP
55 /* ... MCPS/profile info */
56 #include "xa_profiler.h"
57 #endif
58 /*******************************************************************************
59 * Internal helpers
60 ******************************************************************************/
61
62 /* ...translate client-id into component handle */
xf_client_lookup(xf_core_data_t * cd,u32 client)63 static inline xf_component_t * xf_client_lookup(xf_core_data_t *cd, u32 client)
64 {
65 xf_cmap_link_t *link = &cd->cmap[client];
66
67 /* ...if link pointer is less than XF_CFG_MAX_CLIENTS, it is a free descriptor */
68 return (link->next > XF_CFG_MAX_CLIENTS ? link->c : NULL);
69 }
70
71 /* ...allocate client-id */
xf_client_alloc(xf_core_data_t * cd)72 static inline u32 xf_client_alloc(xf_core_data_t *cd)
73 {
74 u32 client = cd->free;
75
76 /* ...advance list head to next free id */
77 (client < XF_CFG_MAX_CLIENTS ? cd->free = cd->cmap[client].next : 0);
78
79 return client;
80 }
81
82 /* ...recycle client-id */
xf_client_free(xf_core_data_t * cd,u32 client)83 static inline void xf_client_free(xf_core_data_t *cd, u32 client)
84 {
85 /* ...put client into the head of the free id list */
86 cd->cmap[client].next = cd->free, cd->free = client;
87 }
88
89 /*******************************************************************************
90 * Process commands to a proxy
91 ******************************************************************************/
92
93 /* ...register new client */
xf_proxy_register(u32 core,xf_message_t * m)94 static int xf_proxy_register(u32 core, xf_message_t *m)
95 {
96 xf_core_data_t *cd = XF_CORE_DATA(core);
97 u32 src = XF_MSG_SRC(m->id);
98 u32 client;
99 xf_component_t *component;
100
101 /* ...allocate new client-id */
102 XF_CHK_ERR((client = xf_client_alloc(cd)) != XF_CFG_MAX_CLIENTS, -EBUSY);
103
104 /* ...create component via class factory */
105 if ((component = xf_component_factory(core, m->buffer, m->length)) == NULL)
106 {
107 TRACE(ERROR, _x("Component creation failed"));
108
109 /* ...recycle client-id */
110 xf_client_free(cd, client);
111
112 /* ...return generic out-of-memory code always (tbd) */
113 return -ENOMEM;
114 }
115
116 /* ...register component in a map */
117 cd->cmap[client].c = component;
118
119 /* ...set component "default" port specification ("destination") */
120 component->id = __XF_PORT_SPEC(core, client, 0);
121
122 /* ...adjust session-id to include newly created component-id */
123 m->id = __XF_MSG_ID(src, component->id);
124
125 /* ...do system-specific registration of component within IPC layer */
126 xf_ipc_component_addref(m->id);
127
128 TRACE(REG, _b("registered client: %u:%u (%s)"), core, client, (xf_id_t)m->buffer);
129
130 /* ...and return success to remote proxy (zero-length output) */
131 xf_response_ok(m);
132
133 return 0;
134 }
135
136 /* ...shared buffer allocation request */
xf_proxy_alloc(u32 core,xf_message_t * m)137 static int xf_proxy_alloc(u32 core, xf_message_t *m)
138 {
139 /* ...command is valid only if shared memory interface for core is specified */
140 XF_CHK_ERR(xf_shmem_enabled(core), -EPERM);
141
142 /* ...allocate shared memory buffer (system-specific function; may fail) */
143 xf_shmem_alloc(core, m);
144
145 /* ...pass result to remote proxy (on success buffer is non-null) */
146 xf_response(m);
147
148 return 0;
149 }
150
151 /* ...shared buffer freeing request */
xf_proxy_free(u32 core,xf_message_t * m)152 static int xf_proxy_free(u32 core, xf_message_t *m)
153 {
154 /* ...command is valid only if shared memory interface for core is specified */
155 XF_CHK_ERR(xf_shmem_enabled(core), -EPERM);
156
157 /* ...pass buffer freeing request to system-specific function */
158 xf_shmem_free(core, m);
159
160 /* ...return success to remote proxy (function never fails) */
161 xf_response(m);
162
163 return 0;
164 }
165
166 #if 0
167 /* ...port routing command processing */
168 static int xf_proxy_route(u32 core, xf_message_t *m)
169 {
170 xf_route_port_msg_t *cmd = m->buffer;
171 u32 src = cmd->src;
172 u32 dst = cmd->dst;
173 xf_component_t *component;
174 xf_output_port_t *port;
175
176 /* ...source component must reside on the local core */
177 XF_CHK_ERR(XF_MSG_SRC_CORE(src) == core, -EINVAL);
178
179 /* ...make sure the "src" component is valid ("dst" may reside on other core) */
180 if ((component = xf_client_lookup(XF_CORE_DATA(core), XF_PORT_CLIENT(src))) == NULL)
181 {
182 TRACE(ERROR, _x("Source port lookup failed: %x"), src);
183 return -ENOENT;
184 }
185 else if (!component->port || !(port = component->port(component, XF_PORT_ID(src))))
186 {
187 TRACE(ERROR, _b("Source port doesn't exist: %x"), src);
188 return -ENOENT;
189 }
190 else if (xf_output_port_routed(port))
191 {
192 TRACE(ERROR, _b("Source port is already routed: %x"), src);
193 return -EBUSY;
194 }
195
196 /* ...route output port with source port set as destination */
197 XF_CHK_API(xf_output_port_route(port, __XF_MSG_ID(dst, src), cmd->alloc_number, cmd->alloc_size, cmd->alloc_align));
198
199 TRACE(ROUTE, _b("Ports routed: %03x -> %03x"), src, dst);
200
201 /* ...invoke component data-processing function directly (ignore errors? - tbd) */
202 component->entry(component, NULL);
203
204 /* ...return success result code (no output attached) */
205 xf_response_ok(m);
206
207 return 0;
208 }
209
210 /* ...disconnect ports */
211 static int xf_proxy_unroute(u32 core, xf_message_t *m)
212 {
213 xf_unroute_port_msg_t *cmd = m->buffer;
214 u32 src = cmd->src;
215 xf_component_t *component;
216 xf_output_port_t *port;
217
218 /* ...source component must reside on the local core */
219 XF_CHK_ERR(XF_MSG_SRC_CORE(src) == core, -EINVAL);
220
221 /* ...lookup source (output) port */
222 if ((component = xf_client_lookup(XF_CORE_DATA(core), XF_PORT_CLIENT(src))) == NULL)
223 {
224 TRACE(ERROR, _b("Source port lookup failed: %x"), src);
225 return -ENOENT;
226 }
227 else if (!component->port || !(port = component->port(component, XF_PORT_ID(src))))
228 {
229 TRACE(ERROR, _b("Source port doesn't exist: %x"), src);
230 return -ENOENT;
231 }
232 else if (!xf_output_port_routed(port))
233 {
234 /* ...port is not routed; satisfy immediately */
235 goto done;
236 }
237 else if (!xf_output_port_idle(port))
238 {
239 TRACE(ERROR, _b("Source port is not idle: %x"), src);
240 return -EBUSY;
241 }
242
243 /* ...unroute port (call must succeed) */
244 xf_output_port_unroute(port);
245
246 /* ...we cannot satisfy the command now, and need to propagate it to a sink - tbd */
247 //return 0;
248
249 done:
250 /* ...pass success result code to caller */
251 xf_response_ok(m);
252
253 return 0;
254 }
255 #endif
256
257 /* ...fill-this-buffer command processing */
xf_proxy_output(u32 core,xf_message_t * m)258 static int xf_proxy_output(u32 core, xf_message_t *m)
259 {
260 /* ...determine destination "client" */
261 switch (XF_MSG_SRC_CLIENT(m->id))
262 {
263 #if XF_TRACE_REMOTE
264 case 0:
265 /* ...destination is a tracer facility; submit buffer to tracer */
266 xf_trace_submit(core, m);
267 return 0;
268 #endif
269
270 default:
271 /* ...unrecognized destination; return general failure response */
272 return XF_CHK_ERR(0, -EINVAL);
273 }
274 }
275
276 /* ...flush command processing */
xf_proxy_flush(u32 core,xf_message_t * m)277 static int xf_proxy_flush(u32 core, xf_message_t *m)
278 {
279 /* ...determine destination "client" */
280 switch (XF_MSG_SRC_CLIENT(m->id))
281 {
282 #if XF_TRACE_REMOTE
283 case 0:
284 /* ...destination is a tracer facility; flush current buffer */
285 xf_trace_flush(core, m);
286 return 0;
287 #endif
288
289 default:
290 /* ...unrecognized destination; return general failure response */
291 return XF_CHK_ERR(0, -EINVAL);
292 }
293 }
294
295 /* ...proxy command processing table */
296 static int (* const xf_proxy_cmd[])(u32, xf_message_t *) =
297 {
298 [XF_OPCODE_TYPE(XF_REGISTER)] = xf_proxy_register,
299 [XF_OPCODE_TYPE(XF_ALLOC)] = xf_proxy_alloc,
300 [XF_OPCODE_TYPE(XF_FREE)] = xf_proxy_free,
301 #if 0
302 [XF_OPCODE_TYPE(XF_ROUTE)] = xf_proxy_route,
303 [XF_OPCODE_TYPE(XF_UNROUTE)] = xf_proxy_unroute,
304 #endif
305 [XF_OPCODE_TYPE(XF_FILL_THIS_BUFFER)] = xf_proxy_output,
306 [XF_OPCODE_TYPE(XF_FLUSH)] = xf_proxy_flush,
307 };
308
309 /* ...total number of commands supported */
310 #define XF_PROXY_CMD_NUM (sizeof(xf_proxy_cmd) / sizeof(xf_proxy_cmd[0]))
311
312 /* ...process commands to a proxy */
xf_proxy_command(u32 core,xf_message_t * m)313 static void xf_proxy_command(u32 core, xf_message_t *m)
314 {
315 u32 opcode = m->opcode;
316 int res;
317
318 /* ...dispatch command to proper hook */
319 if (XF_OPCODE_TYPE(opcode) < XF_PROXY_CMD_NUM)
320 {
321 if ((res = xf_proxy_cmd[XF_OPCODE_TYPE(opcode)](core, m)) >= 0)
322 {
323 /* ...command processed successfully; do nothing */
324 return;
325 }
326 }
327 else
328 {
329 TRACE(ERROR, _x("invalid opcode: %x"), opcode);
330 }
331
332 /* ...command processing failed; return generic failure response */
333 xf_response_err(m);
334 }
335
336 /*******************************************************************************
337 * Message completion helper
338 ******************************************************************************/
339
340 /* ...put message into local IPC command queue on remote core (src != dst) */
xf_msg_local_ipc_put(u32 src,u32 dst,xf_message_t * m)341 static inline void xf_msg_local_ipc_put(u32 src, u32 dst, xf_message_t *m)
342 {
343 xf_core_rw_data_t *rw = XF_CORE_RW_DATA(dst);
344 int first;
345
346 /* ...flush message payload if needed */
347 if (XF_LOCAL_IPC_NON_COHERENT)
348 {
349 /* ...it may be a command with output payload only - tbd */
350 XF_PROXY_FLUSH(m->buffer, m->length);
351 }
352
353 /* ...acquire mutex to target rw-data (running on source core) */
354 xf_mutex_lock(src);
355
356 /* ...assure memory coherency as needed */
357 if (XF_LOCAL_IPC_NON_COHERENT)
358 {
359 /* ...invalidate local queue data */
360 XF_PROXY_INVALIDATE(&rw->local, sizeof(rw->local));
361
362 /* ...place message into queue */
363 first = xf_msg_enqueue(&rw->local, m);
364
365 /* ...flush both queue and message data */
366 XF_PROXY_FLUSH(&rw->local, sizeof(rw->local)), XF_PROXY_FLUSH(m, sizeof(*m));
367 }
368 else
369 {
370 /* ...just enqueue the message */
371 first = xf_msg_enqueue(&rw->local, m);
372 }
373
374 /* ...release global rw-memory access lock */
375 xf_mutex_unlock(src);
376
377 /* ...signal IPI interrupt on destination core as needed */
378 (first ? xf_ipi_assert(dst), 1 : 0);
379 }
380
381 /* ...dequeue message from core-specific dispatch queue */
xf_msg_local_ipc_get(u32 core)382 static inline xf_message_t * xf_msg_local_ipc_get(u32 core)
383 {
384 xf_core_rw_data_t *rw = XF_CORE_RW_DATA(core);
385 xf_message_t *m;
386
387 /* ...retrieve message from queue in atomic fashion */
388 xf_mutex_lock(core);
389
390 /* ...process memory coherency as required */
391 if (XF_LOCAL_IPC_NON_COHERENT)
392 {
393 /* ...inavlidate local rw-data */
394 XF_PROXY_INVALIDATE(&rw->local, sizeof(rw->local));
395
396 /* ...get message from the queue */
397 if ((m = xf_msg_dequeue(&rw->local)) != NULL)
398 {
399 /* ...flush rw-queue data */
400 XF_PROXY_FLUSH(&rw->local, sizeof(rw->local));
401 }
402 }
403 else
404 {
405 /* ...just dequeue message from the queue */
406 m = xf_msg_dequeue(&rw->local);
407 }
408
409 /* ...release rw-memory access lock */
410 xf_mutex_unlock(core);
411
412 /* ...invalidate message header and data as needed */
413 if (XF_LOCAL_IPC_NON_COHERENT && m != NULL)
414 {
415 /* ...invalidate message header */
416 XF_PROXY_INVALIDATE(m, sizeof(*m));
417
418 /* ...and data if needed (it may not be always needed - tbd) */
419 (m->length ? XF_PROXY_INVALIDATE(m->buffer, m->length) : 0);
420 }
421
422 /* ...return message */
423 return m;
424 }
425
426 /* ...retrieve message from local queue (protected from ISR) */
xf_msg_local_put(u32 core,xf_message_t * m)427 static inline int xf_msg_local_put(u32 core, xf_message_t *m)
428 {
429 xf_core_data_t *cd = XF_CORE_DATA(core);
430 int first;
431 u32 status;
432
433 /* ...use interrupt masking protocol to protect message queue */
434 status = xf_isr_disable(core);
435 first = xf_msg_enqueue(&cd->queue, m);
436 xf_isr_restore(core, status);
437
438 return first;
439 }
440
441 /* ...retrieve message from local queue (protected from ISR) */
xf_msg_local_get(u32 core)442 static inline xf_message_t * xf_msg_local_get(u32 core)
443 {
444 xf_core_data_t *cd = XF_CORE_DATA(core);
445 xf_message_t *m;
446 u32 status;
447
448 /* ...use interrupt masking protocol to protect message queue */
449 status = xf_isr_disable(core);
450 m = xf_msg_dequeue(&cd->queue);
451 xf_isr_restore(core, status);
452
453 return m;
454 }
455
456 /* ...retrieve message from local queue (protected from ISR) */
xf_msg_local_response_get(u32 core)457 static inline xf_message_t * xf_msg_local_response_get(u32 core)
458 {
459 xf_core_data_t *cd = XF_CORE_DATA(core);
460 xf_message_t *m;
461 u32 status;
462
463 /* ...use interrupt masking protocol to protect message queue */
464 status = xf_isr_disable(core);
465 m = xf_msg_dequeue(&cd->response);
466 xf_isr_restore(core, status);
467
468 return m;
469 }
470
471 /* ...call component data processing function */
xf_core_process(xf_component_t * component)472 static inline void xf_core_process(xf_component_t *component)
473 {
474 u32 id = component->id;
475
476 /* ...client look-up successfull */
477 TRACE(DISP, _b("core[%u]::client[%u]::process"), XF_PORT_CORE(id), XF_PORT_CLIENT(id));
478
479 /* ...call data-processing interface */
480 if (component->entry(component, NULL) < 0)
481 {
482 TRACE(ERROR, _b("execution error (ignored)"));
483 }
484 }
485
486 /* ...dispatch message queue execution */
xf_core_dispatch(xf_core_data_t * cd,u32 core,xf_message_t * m)487 static inline void xf_core_dispatch(xf_core_data_t *cd, u32 core, xf_message_t *m)
488 {
489 u32 client;
490 xf_component_t *component;
491
492 /* ...do client-id/component lookup */
493 if (XF_MSG_DST_PROXY(m->id))
494 {
495 TRACE(DISP, _b("core[%u]::proxy-cmd(id=%x, opcode=%x)"), core, m->id, m->opcode);
496
497 /* ...process message addressed to proxy */
498 xf_proxy_command(core, m);
499
500 /* ...do not like this return statement... - tbd */
501 return;
502 }
503
504 /* ...message goes to local component */
505 client = XF_MSG_DST_CLIENT(m->id);
506
507 /* ...check if client is alive */
508 if ((component = xf_client_lookup(cd, client)) != NULL)
509 {
510 /* ...client look-up successfull */
511 TRACE(DISP, _b("core[%u]::client[%u]::cmd(id=%x, opcode=%x)"), core, client, m->id, m->opcode);
512
513 /* ...pass message to component entry point */
514 if (component->entry(component, m) < 0)
515 {
516 /* ...call component destructor */
517 if (component->exit(component, m) == 0)
518 {
519 /* ...component cleanup completed; recycle component-id */
520 xf_client_free(cd, client);
521
522 /* ...do system-specific deregistration of component within IPC layer */
523 xf_ipc_component_rmref(__XF_PORT_SPEC(core, client, 0));
524 }
525 }
526 }
527 else
528 {
529 TRACE(DISP, _b("Discard message id=%x - client %u:%u not registered"), m->id, core, client);
530
531 /* ...complete message with general failure response */
532 xf_response_err(m);
533 }
534 }
535
536 /*******************************************************************************
537 * Entry points
538 ******************************************************************************/
539
540 /* ...submit message for instant execution on some core */
xf_msg_submit(xf_message_t * m)541 void xf_msg_submit(xf_message_t *m)
542 {
543 u32 src = XF_MSG_SRC_CORE(m->id);
544 u32 dst = XF_MSG_DST_CORE(m->id);
545
546 /* ...check if message shall go through local IPC layer */
547 if (src ^ dst)
548 {
549 /* ...put message into local IPC queue */
550 xf_msg_local_ipc_put(src, dst, m);
551 }
552 else
553 {
554 /* ...message is addressed to same core */
555 xf_msg_local_put(src, m);
556 }
557 }
558
559 /* ...complete message and pass response to a caller */
xf_msg_complete(xf_message_t * m)560 void xf_msg_complete(xf_message_t *m)
561 {
562 u32 src = XF_MSG_SRC(m->id);
563 u32 dst = XF_MSG_DST(m->id);
564
565 /* ...swap src/dst specifiers */
566 m->id = __XF_MSG_ID(dst, src);
567
568 /* ...check if message goes to remote IPC layer */
569 if (XF_MSG_DST_PROXY(m->id))
570 {
571 /* ...return message to proxy */
572 xf_msg_proxy_complete(m);
573 }
574 else
575 {
576 /* ...destination is within DSP cluster; check if that is a data buffer */
577 switch (m->opcode)
578 {
579 case XF_EMPTY_THIS_BUFFER:
580 /* ...emptied buffer goes back to the output port */
581 m->opcode = XF_FILL_THIS_BUFFER;
582 break;
583
584 case XF_FILL_THIS_BUFFER:
585 /* ...filled buffer is passed to the input port */
586 m->opcode = XF_EMPTY_THIS_BUFFER;
587 break;
588 }
589
590 /* ...submit message for execution */
591 xf_msg_submit(m);
592 }
593 }
594
595 /* ...initialize per-core framework data */
xf_core_init(u32 core)596 int xf_core_init(u32 core)
597 {
598 xf_core_data_t *cd = XF_CORE_DATA(core);
599 xf_cmap_link_t *link;
600 u32 i;
601
602 /* ...create list of free client descriptors */
603 for (link = &cd->cmap[i = 0]; i < XF_CFG_MAX_CLIENTS; i++, link++)
604 {
605 link->next = i + 1;
606 }
607
608 /* ...set head of free clients list */
609 cd->free = 0;
610
611 /* ...initialize local queue scheduler */
612 xf_sched_init(&cd->sched);
613
614 /* ...initialize IPI subsystem */
615 XF_CHK_API(xf_ipi_init(core));
616
617 /* ...initialize shared read-write memory */
618 XF_CHK_API(xf_shmem_enabled(core) ? xf_shmem_init(core) : 0);
619
620 /* ...initialize scratch memory */
621 XF_CHK_ERR(cd->scratch = xf_scratch_mem_init(core), -ENOMEM);
622
623 /* ...okay... it's all good */
624 TRACE(INIT, _b("core-%u initialized"), core);
625
626 return 0;
627 }
628
629 /* ...core executive loop function */
xf_core_service(u32 core)630 void xf_core_service(u32 core)
631 {
632 xf_core_data_t *cd = &xf_core_data[core];
633 u32 status;
634 xf_message_t *m;
635 xf_task_t *t;
636
637 #ifdef XAF_PROFILE_DSP
638 START_TIME_XA_PROFILER(prof);
639 #endif
640 do
641 {
642 /* ...clear local status change */
643 status = 0;
644
645 /* ...if core is servicing shared memory with AP, do it first - actually, they all need to support it */
646 if (xf_shmem_enabled(core))
647 {
648 /* ...process all commands */
649 xf_shmem_process_queues(core);
650 }
651
652 /* ...check if we have a backlog message placed into interim queue */
653 while ((m = xf_msg_local_ipc_get(core)) || (m = xf_msg_local_get(core)))
654 {
655 /* ...dispatch message execution */
656 xf_core_dispatch(cd, core, m);
657
658 /* ...set local status change */
659 status = 1;
660 }
661
662 /* ...check if we have pending responses (submitted from ISR) we need to process */
663 while ((m = xf_msg_local_response_get(core)) != NULL)
664 {
665 /* ...call completion handler on current stack */
666 xf_msg_complete(m);
667
668 /* ...set local status change */
669 status = 1;
670
671 }
672
673 /* ...if scheduler queue is empty, break the loop and pause the core */
674 if ((t = xf_sched_get(&cd->sched)) != NULL)
675 {
676 /* ...data-processing execution (ignore internal errors) */
677 xf_core_process((xf_component_t *)t);
678
679 /* ...set local status change */
680 status = 1;
681 }
682 }
683 while (status);
684
685 #ifdef XAF_PROFILE_DSP
686 STOP_TIME_XA_PROFILER(prof);
687
688 if(prof.g_output_bytes)
689 {
690 unsigned long output_samples = prof.g_output_bytes;
691 output_samples >>= (prof.channels == 2 ? 1 : 0);
692 output_samples >>= (prof.pcm_width == 24 ? 2 : 1);
693
694 COMPUTE_MHZ_XA_PROFILER(prof, output_samples, prof.sample_rate, 0);
695
696 prof.g_output_bytes = prof.cycles = 0; /* reset counters */
697 }
698 #endif
699
700 }
701
702 /* ...global data initialization function */
xf_global_init(void)703 int xf_global_init(void)
704 {
705 /* ...what global data we have to initialize? - tbd */
706 TRACE(INIT, _b("Global data initialized"));
707
708 return 0;
709 }
710