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