Integrate PSI KPI profiler
[gstreamer-omap:libdce.git] / ducati / ti / dce / dce.c
1 /*
2  * Copyright (c) 2011, Texas Instruments Incorporated
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
7  * are met:
8  *
9  * *  Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * *  Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * *  Neither the name of Texas Instruments Incorporated nor the names of
17  *    its contributors may be used to endorse or promote products derived
18  *    from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #include <stdlib.h>
34 #include <stdint.h>
35 #include <string.h>
36 #include <stdio.h>
37
38 #include <xdc/std.h>
39 #include <xdc/cfg/global.h>
40 #include <xdc/runtime/System.h>
41 #include <xdc/runtime/Diags.h>
42 #include <xdc/runtime/Memory.h>
43 #include <xdc/runtime/IHeap.h>
44 #include <ti/sdo/fc/global/FCSettings.h>
45 #include <ti/sdo/ce/global/CESettings.h>
46 #include <xdc/runtime/knl/Thread.h>
47
48 #include <ti/sysbios/BIOS.h>
49 #include <ti/sysbios/knl/Task.h>
50 #include <ti/ipc/MultiProc.h>
51 #include <ti/ipc/rpmsg/VirtQueue.h>
52 #include <ti/pm/IpcPower.h>
53
54 #include <ti/sdo/ce/Engine.h>
55 #include <ti/sdo/ce/video3/viddec3.h>
56 #include <ti/sdo/ce/video2/videnc2.h>
57 #include <ti/sdo/fc/utils/fcutils.h>
58 #include <ti/xdais/dm/xdm.h>
59 #include <ti/sysbios/hal/Cache.h>
60
61 #include <ti/ipc/rpmsg/MessageQCopy.h>
62 #include <ti/srvmgr/NameMap.h>
63
64 #include "dce_priv.h"
65 #include "dce_rpc.h"
66
67 #define DCE_PORT 42     /* so long, and thanks for all the fish */
68
69 uint32_t suspend_initialised = 0;
70 uint32_t dce_debug = 1;
71
72 #define MEMORYSTATS_DEBUG
73 #define KPI_PROFILER
74
75 #ifdef KPI_PROFILER
76 # include "profile.h"
77 #endif
78
79 /* AFAIK both TILER and heap are cached on ducati side.. so from wherever a9
80  * allocates, we need to deal with cache to avoid coherency issues..
81  *
82  * Hmm, when block is allocated, we need to somehow invalidate it.
83  */
84
85 static void dce_clean(void *ptr)
86 {
87     Cache_wbInv (ptr, P2H(ptr)->size, Cache_Type_ALL, TRUE);
88 }
89
90 enum omap_dce_codec {
91     OMAP_DCE_VIDENC2 = 1,
92     OMAP_DCE_VIDDEC3 = 2,
93 };
94
95 typedef void * (*CreateFxn)(Engine_Handle, String, void *);
96 typedef Int32  (*ControlFxn)(void *, int, void *, void *);
97 typedef Int32  (*ProcessFxn)(void *, void *, void *, void *, void *);
98 typedef Int32  (*RelocFxn)(void *, uint8_t *ptr, uint32_t len);
99 typedef void   (*DeleteFxn)(void *);
100
101 static VIDENC2_Handle videnc2_create(Engine_Handle engine, String name, VIDENC2_Params *params);
102 static XDAS_Int32 videnc2_control(VIDENC2_Handle codec, VIDENC2_Cmd id, VIDENC2_DynamicParams *dynParams,
103     VIDENC2_Status *status);
104 static VIDDEC3_Handle viddec3_create(Engine_Handle engine, String name, VIDDEC3_Params *params);
105 static int videnc2_reloc(VIDDEC3_Handle handle, uint8_t *ptr, uint32_t len);
106 static int viddec3_reloc(VIDDEC3_Handle handle, uint8_t *ptr, uint32_t len);
107
108 #ifdef KPI_PROFILER
109 /* track codec create/delete usage */
110 static int create_count = 0;
111 #endif
112
113 static struct {
114     CreateFxn  create;
115     ControlFxn control;
116     ProcessFxn process;
117     DeleteFxn  delete;
118     RelocFxn   reloc;   /* handle buffer relocation table */
119 } codec_fxns[] = {
120         [OMAP_DCE_VIDENC2] = {
121                 (CreateFxn)videnc2_create,   (ControlFxn)videnc2_control,
122                 (ProcessFxn)VIDENC2_process, (DeleteFxn)VIDENC2_delete,
123                 (RelocFxn)videnc2_reloc,
124         },
125         [OMAP_DCE_VIDDEC3] = {
126                 (CreateFxn)viddec3_create,   (ControlFxn)VIDDEC3_control,
127                 (ProcessFxn)VIDDEC3_process, (DeleteFxn)VIDDEC3_delete,
128                 (RelocFxn)viddec3_reloc,
129         },
130 };
131
132 /* Static version string buffer.
133  * Note: codec version can be large. For example, h264vdec needs more than
134  * 58 characters, or the query will fail. */
135 #define VERSION_SIZE 128
136 static char version_buffer[VERSION_SIZE];
137
138 /* the following callbacks are needed for suspend/resume
139  * on the linux side.
140  * - FC_suspend() waits for all algorithms to get deactivated and
141  * and takes care of the resources acquired.
142  * - FC_resume() does nothing for now, but we add it just in case
143  * it gets populated in the future versions of framework components.
144  *
145  * Forced off mode during video decode/encode is not supported. */
146 static void dce_suspend()
147 {
148         INFO("Preparing for suspend...");
149         FC_suspend();
150 }
151
152 static void dce_resume()
153 {
154         INFO("Restoring after suspend...");
155         FC_resume();
156 }
157
158 static void get_videnc2_version(VIDENC2_Handle h, char *buffer, unsigned size)
159 {
160     VIDENC2_DynamicParams params = {
161             .size = sizeof(VIDENC2_DynamicParams),
162     };
163
164     VIDENC2_Status status = {
165             .size = sizeof(VIDENC2_Status),
166             .data = {
167                     .buf = (XDAS_Int8 *)buffer,
168                     .bufSize = (XDAS_Int32)size,
169             },
170     };
171
172     XDAS_Int32 s;
173
174     memset(buffer, 0, size);
175     s = VIDENC2_control(h, XDM_GETVERSION, &params, &status);
176
177     if (s != VIDENC2_EOK)
178         snprintf(buffer, size, "<unknown version (rc = %x)>", s);
179 }
180
181 // VIDENC2_create wrapper, to display version string in the trace.
182 static VIDENC2_Handle videnc2_create(Engine_Handle engine, String name, VIDENC2_Params *params)
183 {
184     VIDENC2_Handle h;
185     h = VIDENC2_create(engine, name, params);
186
187     if (h) {
188         get_videnc2_version(h, version_buffer, VERSION_SIZE);
189         INFO("Created videnc2 %s: version %s", name, version_buffer);
190     }
191
192     return h;
193 }
194
195 static XDAS_Int32 getBufferFxnStub(XDM_DataSyncHandle handle, XDM_DataSyncDesc *desc)
196 {
197     return 0;
198 }
199
200 static XDAS_Int32 videnc2_control(VIDENC2_Handle codec, VIDENC2_Cmd id,
201         VIDENC2_DynamicParams *dynParams, VIDENC2_Status *status)
202 {
203     dynParams->getBufferFxn = getBufferFxnStub;
204     return VIDENC2_control(codec, id, dynParams, status);
205 }
206
207 static void get_viddec3_version(VIDDEC3_Handle h, char *buffer, unsigned size)
208 {
209     VIDDEC3_DynamicParams params = {
210             .size = sizeof(VIDDEC3_DynamicParams),
211     };
212
213     VIDDEC3_Status status = {
214             .size = sizeof(VIDDEC3_Status),
215             .data = {
216                     .buf = (XDAS_Int8 *)buffer,
217                     .bufSize = (XDAS_Int32)size,
218             },
219     };
220
221     XDAS_Int32 s;
222
223     memset(buffer, 0, size);
224     s = VIDDEC3_control(h, XDM_GETVERSION, &params, &status);
225
226     if (s != VIDDEC3_EOK)
227         snprintf(buffer, size, "<unknown version (rc = %x)>", s);
228 }
229
230 // VIDDEC3_create wrapper, to display version string in the trace.
231 static VIDDEC3_Handle viddec3_create(Engine_Handle engine, String name, VIDDEC3_Params *params)
232 {
233     VIDDEC3_Handle h;
234     h = VIDDEC3_create(engine, name, params);
235
236     if (h) {
237         get_viddec3_version(h, version_buffer, VERSION_SIZE);
238         INFO("Created viddec3 %s: version %s", name, version_buffer);
239     }
240
241     return h;
242 }
243
244 static int videnc2_reloc(VIDENC2_Handle handle, uint8_t *ptr, uint32_t len)
245 {
246     return -1; // TODO
247 }
248
249 /* needs to be updated when it is enabled in omapdce */
250 static int viddec3_reloc(VIDDEC3_Handle handle, uint8_t *ptr, uint32_t len)
251 {
252     static VIDDEC3_DynamicParams params = {
253             .size = sizeof(VIDDEC3_DynamicParams),
254     };
255     VIDDEC3_Status status = {
256             .size = sizeof(VIDDEC3_Status),
257             .data = {
258                     .buf = (XDAS_Int8 *)ptr,
259                     .bufSize = (XDAS_Int32)len,
260             },
261     };
262 INFO("status.size=%d", status.size);
263     return VIDDEC3_control(handle, XDM_MOVEBUFS, &params, &status);
264 }
265
266
267 /*
268  * RPC message handlers
269  */
270
271 static int connect(void *msg)
272 {
273     struct dce_rpc_connect_req *req = msg;
274
275     DEBUG(">> chipset_id=0x%x, debug=%d", req->chipset_id, req->debug);
276     dce_debug = req->debug;
277
278     if (dce_debug <= 1) {
279         DEBUG("enabling extra debug");
280
281         FCSettings_init();
282         Diags_setMask(FCSETTINGS_MODNAME"+12345678LEXAIZFS");
283         CESettings_init();
284         Diags_setMask(CESETTINGS_MODNAME"+12345678LEXAIZFS");
285
286         /*
287          * Enable use of runtime Diags_setMask per module:
288          *
289          * Codes: E = ENTRY, X = EXIT, L = LIFECYCLE, F = INFO, S = STATUS
290          */
291         Diags_setMask("ti.ipc.rpmsg.MessageQCopy=EXLFS");
292         Diags_setMask("ti.ipc.rpmsg.VirtQueue=EXLFS");
293     }
294
295     ivahd_init(req->chipset_id);
296
297     if (!suspend_initialised) {
298
299     /* registering sysbios-rpmsg callbacks for suspend/resume */
300     IpcPower_registerCallback(IpcPower_Event_SUSPEND, dce_suspend, 0);
301     IpcPower_registerCallback(IpcPower_Event_RESUME, dce_resume, 0);
302     suspend_initialised++;
303     }
304
305 #ifdef KPI_PROFILER
306     kpi_set_chipset_id(req->chipset_id);
307 #endif
308
309     DEBUG("<<");
310
311     return 0;
312 }
313
314 static int engine_open(void *msg)
315 {
316     struct dce_rpc_engine_open_req *req = msg;
317     struct dce_rpc_engine_open_rsp *rsp = msg;
318     Engine_Error ec;
319
320     DEBUG(">> name=%s", req->name);
321     rsp->engine = (uint32_t)Engine_open(req->name, NULL, &ec);
322     rsp->error_code = ec;
323     DEBUG("<< engine=%08x, ec=%d", rsp->engine, rsp->error_code);
324
325     return sizeof(*rsp);
326 }
327
328 static int engine_close(void *msg)
329 {
330     struct dce_rpc_engine_close_req *req = msg;
331     DEBUG(">> engine=%08x", req->engine);
332     Engine_close((Engine_Handle)req->engine);
333     DEBUG("<<");
334     return 0;
335 }
336
337 static int codec_create(void *msg)
338 {
339 #ifdef KPI_PROFILER
340     extern unsigned long kpi_control;
341 #endif
342
343 #ifdef MEMORYSTATS_DEBUG
344     Memory_Stats stats;
345 #endif
346     struct dce_rpc_codec_create_req *req = msg;
347     struct dce_rpc_codec_create_rsp *rsp = msg;
348     void *sparams = H2P((MemHeader *)req->sparams);
349
350     DEBUG(">> engine=%08x, name=%s, sparams=%p, codec_id=%d",
351             req->engine, req->name, sparams, req->codec_id);
352     DEBUG("   sparams size: %d", ((int32_t *)sparams)[0]);
353     ivahd_acquire();
354     rsp->codec = (uint32_t)codec_fxns[req->codec_id].create(
355             (Engine_Handle)req->engine, req->name, sparams);
356     dce_clean(sparams);
357     ivahd_release();
358     DEBUG("<< codec=%08x", rsp->codec);
359
360 #ifdef KPI_PROFILER
361     /* We initialize only for the first create. TODO: make it work when other
362      * task can create codecs, too. */
363     if (create_count++ == 0) {
364         kpi_control = KPI_END_SUMMARY /*| KPI_IVA_DETAILS | KPI_CPU_DETAILS*/;
365         kpi_instInit();
366     }
367 #endif
368 #ifdef MEMORYSTATS_DEBUG
369     Memory_getStats(NULL, &stats);
370     INFO("Total: %d\tFree: %d\tLargest: %d", stats.totalSize,
371          stats.totalFreeSize, stats.largestFreeSize);
372 #endif
373
374     return sizeof(*rsp);
375 }
376
377 static int codec_control(void *msg)
378 {
379     struct dce_rpc_codec_control_req *req = msg;
380     struct dce_rpc_codec_control_rsp *rsp = msg;
381     void *dparams = H2P((MemHeader *)req->dparams);
382     void *status  = H2P((MemHeader *)req->status);
383
384     DEBUG(">> codec=%08x, cmd_id=%d, dynParams=%p, status=%p, codec_id=%d",
385             req->codec, req->cmd_id, dparams, status, req->codec_id);
386     DEBUG("   dparams size: %d", ((int32_t *)dparams)[0]);
387     DEBUG("   status size:  %d", ((int32_t *)status)[0]);
388     ivahd_acquire();
389     rsp->result = codec_fxns[req->codec_id].control(
390             (void *)req->codec, req->cmd_id, dparams, status);
391     dce_clean(dparams);
392     dce_clean(status);
393     ivahd_release();
394     DEBUG("<< ret=%d", rsp->result);
395
396     return sizeof(*rsp);
397 }
398
399 static int codec_get_version(void *msg)
400 {
401     struct dce_rpc_codec_get_version_req *req = msg;
402     struct dce_rpc_codec_get_version_rsp *rsp = msg;
403     void *dparams  = H2P((MemHeader *)req->dparams);
404     void *status  = H2P((MemHeader *)req->status);
405     void *version  = H2P((MemHeader *)req->version);
406     void *ptr = ((IVIDDEC3_Status*)status)->data.buf;
407
408     DEBUG(">> codec=%08x, status=%p, version=%p, codec_id=%d",
409             req->codec, status, version, req->codec_id);
410     DEBUG("   status size:  %d", ((int32_t *)status)[0]);
411     ((IVIDDEC3_Status*)status)->data.buf = version;
412     rsp->result = codec_fxns[req->codec_id].control(
413             (void *)req->codec, XDM_GETVERSION, dparams, status);
414     ((IVIDDEC3_Status*)status)->data.buf = ptr;
415     dce_clean(dparams);
416     dce_clean(status);
417     dce_clean(version);
418     DEBUG("<< ret=%d", rsp->result);
419
420     return sizeof(*rsp);
421 }
422
423 /* Notes about serialization of process command:
424  *
425  * Since codec_process code on kernel side is doing buffer mapping/unmapping,
426  * and keeping track of codec's locked buffers, it is necessary for it to
427  * look into the contents of some of the parameter structs, and in some cases
428  * re-write them.  For this reason inArgs/outBufs/inBufs are serialized within
429  * the rpmsg rather than just passed by pointer.
430
431 XDAS_Int32 VIDDEC3_process(VIDDEC3_Handle handle, XDM2_BufDesc *inBufs,
432     XDM2_BufDesc *outBufs, VIDDEC3_InArgs *inArgs, VIDDEC3_OutArgs *outArgs);
433
434   REQ:
435     struct dce_rpc_hdr hdr   -> 4
436     codec_id                 -> 4
437     codec                    -> 4
438     reloc length             -> 1   (length/4)
439     inArgs length            -> 1   (length/4)
440     outBufs length           -> 1   (length/4)
441     inBufs length            -> 1   (length/4)
442     VIDDEC3_OutArgs *outArgs -> 4   (pass by pointer)
443     reloc table              -> 12 * nreloc (typically <= 16)
444     VIDDEC3_InArgs   inArgs  -> 12  (need inputID from userspace)
445     XDM2_BufDesc     outBufs -> 44  (4 + 2 * 20)
446     XDM2_BufDesc     inBufs  -> 24  (4 + 1 * 20)
447     -------------------------------
448                                99
449
450   RSP
451     struct dce_rpc_hdr hdr   -> 4
452     result                   -> 4
453     inBufs length            -> 1   (length/4)
454     XDAS_Int32 freeBufID[]   -> 4*n (n typically 0 or 2, but could be up to 20)
455     -------------------------------
456                                9-89
457     Note: freeBufID[] duplicates what is returned in outArgs, but avoids
458     needing to create kernel mappings of these objects which are to big
459     to copy inline.  Also it avoids differences between VIDDEC3/VIDDENC2.
460
461
462 XDAS_Int32 VIDENC2_process(VIDENC2_Handle handle, IVIDEO2_BufDesc *inBufs,
463     XDM2_BufDesc *outBufs, IVIDENC2_InArgs *inArgs, IVIDENC2_OutArgs *outArgs);
464
465   REQ:
466     struct dce_rpc_hdr hdr   -> 4
467     codec_id                 -> 4
468     codec                    -> 4
469     reloc length             -> 1   (length/4)
470     inArgs length            -> 1   (length/4)
471     outBufs length           -> 1   (length/4)
472     inBufs length            -> 1   (length/4)
473     VIDENC2_OutArgs *outArgs -> 4   (pass by pointer)
474     reloc table              -> ???
475     VIDENC2_InArgs   inArgs  -> 12  (need inputID from userspace)
476     XDM2_BufDesc     outBufs -> 24  (4 + 1 * 20)
477     IVIDEO2_BufDesc  inBufs  -> 252
478     -------------------------------
479                               307
480
481   RSP
482     struct dce_rpc_hdr hdr   -> 4
483     result                   -> 4
484     inBufs length            -> 1   (length/4)
485     XDAS_Int32 freeBufID[]   -> 4*n (n typically 0 or 2, but could be up to 20)
486     -------------------------------
487                                9-89
488  */
489
490 static int codec_process(void *msg)
491 {
492     struct dce_rpc_codec_process_req *req = msg;
493     struct dce_rpc_codec_process_rsp *rsp = msg;
494     void *out_args = H2P((MemHeader *)req->out_args);
495     uint32_t codec_id = req->codec_id;
496     uint8_t *ptr = req->data;
497     void *reloc, *in_args, *out_bufs, *in_bufs;
498
499     reloc = ptr;
500     ptr += (req->reloc_len * 4);
501
502     in_args = ptr;
503     ptr += (req->in_args_len * 4);
504
505     out_bufs = ptr;
506     ptr += (req->out_bufs_len * 4);
507
508     in_bufs = ptr;
509     ptr += (req->in_bufs_len * 4);
510
511     DEBUG(">> codec=%p, inBufs=%p, outBufs=%p, inArgs=%p, outArgs=%p, codec_id=%d",
512             req->codec, in_bufs, out_bufs, in_args, out_args, codec_id);
513
514     /* Clear out buffers to free list, in case some codecs do not
515        initialize it when erroring out (see below). */
516     switch(codec_id) {
517     case OMAP_DCE_VIDENC2:
518         ((VIDENC2_OutArgs *)out_args)->freeBufID[0] = 0;
519         break;
520     case OMAP_DCE_VIDDEC3:
521         ((VIDDEC3_OutArgs *)out_args)->freeBufID[0] = 0;
522         break;
523     }
524
525     rsp->result = IALG_EOK;
526
527     ivahd_acquire();
528     if (req->reloc_len)
529         rsp->result = codec_fxns[codec_id].reloc(
530                 (void *)req->codec, reloc, (req->reloc_len * 4));
531
532     if (rsp->result == IALG_EOK) {
533 #ifdef KPI_PROFILER
534         kpi_before_codec();
535 #endif
536
537         rsp->result = codec_fxns[codec_id].process(
538                 (void *)req->codec, in_bufs, out_bufs, in_args, out_args);
539
540 #ifdef KPI_PROFILER
541         kpi_after_codec();
542 #endif
543     } else {
544         DEBUG("reloc failed");
545     }
546     ivahd_release();
547
548     DEBUG("<< ret=%d", rsp->result);
549
550     rsp->count = 0;
551
552     /* We used to transfer the freeBufID array only when no error occured,
553        but at least the MPEG2 decoder uses it even when erroring out. */
554     {
555         int32_t *free_buf_ids;
556         int i;
557
558         switch(codec_id) {
559         case OMAP_DCE_VIDENC2:
560             free_buf_ids = &((VIDENC2_OutArgs *)out_args)->freeBufID[0];
561             break;
562         case OMAP_DCE_VIDDEC3:
563             free_buf_ids = &((VIDDEC3_OutArgs *)out_args)->freeBufID[0];
564             break;
565         }
566
567         for (i = 0; free_buf_ids[i] && (i < IVIDEO2_MAX_IO_BUFFERS); i++) {
568             rsp->freebuf_ids[i] = free_buf_ids[i];
569         }
570         rsp->count = i;
571     }
572
573     DEBUG("freebuf count: %d", rsp->count);
574     dce_clean(out_args);
575
576     return sizeof(*rsp) + (4 * rsp->count);
577 }
578
579 static int codec_delete(void *msg)
580 {
581 #ifdef MEMORYSTATS_DEBUG
582     Memory_Stats stats;
583 #endif
584     struct dce_rpc_codec_delete_req *req = msg;
585
586     DEBUG(">> codec=%08x, codec_id=%d", req->codec, req->codec_id);
587     ivahd_acquire();
588     codec_fxns[req->codec_id].delete((void *)req->codec);
589     ivahd_release();
590     DEBUG("<<");
591
592 #ifdef KPI_PROFILER
593     /* We de-initialize only for the last delete. TODO: make it work when other
594      * task can delete codecs, too. */
595     if (--create_count == 0) {
596         kpi_instDeinit();
597     }
598 #endif
599 #ifdef MEMORYSTATS_DEBUG
600     Memory_getStats(NULL, &stats);
601     INFO("Total: %d\tFree: %d\tLargest: %d", stats.totalSize,
602          stats.totalFreeSize, stats.largestFreeSize);
603 #endif
604
605     return 0;
606 }
607
608 /*
609  * RPC msg dispatch table
610  */
611
612 #define FXN(f) { .name = #f, .fxn = (f) }
613 static struct {
614     int (*fxn)(void *msg);
615     const char *name;
616 } fxns[] = {
617         [DCE_RPC_CONNECT]       = FXN(connect),
618         [DCE_RPC_ENGINE_OPEN]   = FXN(engine_open),
619         [DCE_RPC_ENGINE_CLOSE]  = FXN(engine_close),
620         [DCE_RPC_CODEC_CREATE]  = FXN(codec_create),
621         [DCE_RPC_CODEC_CONTROL] = FXN(codec_control),
622         [DCE_RPC_CODEC_PROCESS] = FXN(codec_process),
623         [DCE_RPC_CODEC_DELETE]  = FXN(codec_delete),
624         [DCE_RPC_CODEC_GET_VERSION] = FXN(codec_get_version),
625 };
626
627 static void dce_main(uint32_t arg0, uint32_t arg1)
628 {
629     MessageQCopy_Handle handle;
630     UInt32 ep, rep;
631     Uint16 dst;
632
633     INFO("Creating DCE MessageQ...");
634
635     dst = MultiProc_getId("HOST");
636     MessageQCopy_init(dst);
637
638     /* Create the messageQ for receiving (and get our endpoint for sending). */
639     handle = MessageQCopy_create(DCE_PORT, &ep);
640     NameMap_register("rpmsg-dce", DCE_PORT);
641
642     INFO("Ready to receive requests");
643
644     /* Dispatch loop */
645     while (TRUE) {
646         UInt16 len;
647         static char buffer[512];
648         struct dce_rpc_hdr *msg = (struct dce_rpc_hdr *)buffer;
649         int ret;
650
651         ret = MessageQCopy_recv(handle, buffer, &len, &rep, MessageQCopy_FOREVER);
652         if (ret) {
653             ERROR("MessageQ recv error: %d", ret);
654             break;
655         }
656
657         if (msg->msg_id >= DIM(fxns)) {
658             ERROR("invalid msg id: %d", msg->msg_id);
659             break;
660         }
661
662         DEBUG(">>> %s", fxns[msg->msg_id].name);
663         len = fxns[msg->msg_id].fxn(msg);
664         DEBUG("<<< %s -> %d", fxns[msg->msg_id].name, len);
665
666         if (len > 0) {
667             ret = MessageQCopy_send(dst, rep, ep, buffer, len);
668             if (ret) {
669                 ERROR("MessageQ send error: %d", ret);
670                 break;
671             }
672         }
673     }
674
675     /* Teardown our side: */
676     MessageQCopy_delete(&handle);
677 }
678
679 Bool dce_init(void)
680 {
681     Task_Params params;
682
683     INFO("Creating DCE server thread...");
684
685     /* Create DCE task. */
686     Task_Params_init(&params);
687     params.instance->name = "dce-server";
688     params.priority = Thread_Priority_ABOVE_NORMAL;
689     Task_create(dce_main, &params, NULL);
690
691     return TRUE;
692 }