28e58fcb1349c6b32a95f2c18fa2e44e5f98ac6a
[keystone-rtos/rm-lld.git] / src / rm.c
1 /**\r
2  *   @file  rm.c\r
3  *\r
4  *   @brief   \r
5  *      This is the Resource Manager source.\r
6  *\r
7  *  \par\r
8  *  ============================================================================\r
9  *  @n   (C) Copyright 2012, Texas Instruments, Inc.\r
10  * \r
11  *  Redistribution and use in source and binary forms, with or without \r
12  *  modification, are permitted provided that the following conditions \r
13  *  are met:\r
14  *\r
15  *    Redistributions of source code must retain the above copyright \r
16  *    notice, this list of conditions and the following disclaimer.\r
17  *\r
18  *    Redistributions in binary form must reproduce the above copyright\r
19  *    notice, this list of conditions and the following disclaimer in the \r
20  *    documentation and/or other materials provided with the   \r
21  *    distribution.\r
22  *\r
23  *    Neither the name of Texas Instruments Incorporated nor the names of\r
24  *    its contributors may be used to endorse or promote products derived\r
25  *    from this software without specific prior written permission.\r
26  *\r
27  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \r
28  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT \r
29  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\r
30  *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT \r
31  *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, \r
32  *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT \r
33  *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
34  *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
35  *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT \r
36  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE \r
37  *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
38  *\r
39  *  \par\r
40 */\r
41 \r
42 /* RM Types */\r
43 #include <ti/drv/rm/rm_types.h>\r
44 \r
45 /* RM external includes */\r
46 #include <ti/drv/rm/rm.h>\r
47 #include <ti/drv/rm/rm_services.h>\r
48 #include <ti/drv/rm/rm_transport.h>\r
49 #include <ti/drv/rm/rm_policy.h>\r
50 \r
51 /* RM internal includes */\r
52 #include <ti/drv/rm/include/rm_loc.h>\r
53 #include <ti/drv/rm/include/rm_transportloc.h>\r
54 #include <ti/drv/rm/include/rm_servicesloc.h>\r
55 #include <ti/drv/rm/include/rm_nameserverloc.h>\r
56 \r
57 /* RM OSAL layer */\r
58 #include <rm_osal.h>\r
59 \r
60 /**********************************************************************\r
61  ************************** Globals ***********************************\r
62  **********************************************************************/\r
63 #if 0\r
64 /* Place QMSS PDSP permissions array */\r
65 #pragma DATA_SECTION (rmQmssPdspFirmwarePerms, ".rm");\r
66 #pragma DATA_ALIGN (rmQmssPdspFirmwarePerms, 128)\r
67 Rm_Perms rmQmssPdspFirmwarePerms[RM_ALIGN_PERMISSIONS_ARRAY(RM_QMSS_FIRMWARE_PDSPS, Rm_Perms)];\r
68 #endif\r
69 \r
70 /** @brief Global Variable which describes the RM Version Information */\r
71 const char   rmVersionStr[] = RM_VERSION_STR ":" __DATE__  ":" __TIME__;\r
72 \r
73 /**********************************************************************\r
74  ********************** Internal Functions ****************************\r
75  **********************************************************************/\r
76 \r
77 /* At the very least the transaction ID needs to be provided to create a transaction */\r
78 Rm_Transaction *Rm_transactionQueueAdd(Rm_Inst *rmInst, uint32_t transactionId)\r
79 {\r
80     Rm_Transaction *transactionQueue = (Rm_Transaction *)rmInst->transactionQueue;\r
81     Rm_Transaction *newTransaction = NULL;\r
82     void *key;\r
83 \r
84     /* Lock access to the RM instance's transaction queue */\r
85     key = Rm_osalCsEnter();\r
86 \r
87     /* Get memory for a new transaction from local memory */\r
88     newTransaction = Rm_osalMalloc(sizeof(Rm_Transaction), false);\r
89 \r
90     /* Return if the memory allocated for the transaction entry is NULL */\r
91     if (newTransaction == NULL)\r
92     {\r
93         Rm_osalCsExit(key);\r
94         return(newTransaction);\r
95     }\r
96 \r
97     /* Clear the transaction */\r
98     memset((void *)newTransaction, 0, sizeof(Rm_Transaction));\r
99 \r
100     /* Populate transaction with the provided ID */\r
101     newTransaction->id = transactionId;\r
102     /* New transaction's nextTransaction pointer will always be NULL */\r
103     newTransaction->nextTransaction = NULL;  \r
104 \r
105     /* Check if there are any transactions in the transaction queue */\r
106     if (transactionQueue)\r
107     {\r
108         /* At least one transaction in the transaction queue.  Add the new entry to the \r
109          * end of the transaction queue */\r
110         while (transactionQueue->nextTransaction != NULL)\r
111         {\r
112             /* Traverse the list until arriving at the last transaction */\r
113             transactionQueue = transactionQueue->nextTransaction;\r
114         }\r
115 \r
116         /* Add the new transaction to the end of the queue */\r
117         transactionQueue->nextTransaction = newTransaction;\r
118     }\r
119     else\r
120     {\r
121         /* The transaction queue does not currently exist.  The new transaction is the \r
122          * first transaction */\r
123         rmInst->transactionQueue = newTransaction;\r
124     }\r
125 \r
126     Rm_osalCsExit(key);\r
127     return (newTransaction);\r
128 }\r
129 \r
130 Rm_Transaction *Rm_transactionQueueFind(Rm_Inst *rmInst, uint32_t transactionId)\r
131 {\r
132     Rm_Transaction *transaction = (Rm_Transaction *)rmInst->transactionQueue;\r
133 \r
134     /* Make sure there is at least one transaction in the transaction queue */\r
135     if (transaction != NULL)\r
136     {\r
137         /* Find the transaction ID within the specified RM instance's transaction queue.\r
138          * If the end of the transaction queue is reached without finding the transaction the \r
139          * transaction pointer will be NULL */\r
140         while (transaction != NULL)\r
141         {\r
142             if (transaction->id == transactionId)\r
143             {\r
144                 /* Match: break out of loop and return the transaction */\r
145                 break;             \r
146             }\r
147             transaction = transaction->nextTransaction;\r
148         }\r
149     }\r
150 \r
151     return (transaction);\r
152 }\r
153 \r
154 int32_t Rm_transactionQueueDelete(Rm_Inst *rmInst, uint32_t transactionId)\r
155 {\r
156     Rm_Transaction *transaction = (Rm_Transaction *) rmInst->transactionQueue;\r
157     Rm_Transaction *prevTransaction = NULL;\r
158     void *key;\r
159 \r
160     /* Lock access to the RM instance's transaction queue */\r
161     key = Rm_osalCsEnter();\r
162 \r
163     /* Make sure there is at least one entry in the transaction queue */\r
164     if (transaction == NULL)\r
165     {\r
166         Rm_osalCsExit(key);\r
167         return (RM_SERVICE_ERROR_NO_TRANSACTIONS_IN_QUEUE);\r
168     }\r
169 \r
170     /* Find the transaction ID within the specified RM instance's transaction queue. */\r
171     while (transaction != NULL)\r
172     {\r
173         if (transaction->id == transactionId)\r
174         {\r
175             /* Match: break out of loop and delete the transaction */\r
176             break;             \r
177         }\r
178 \r
179         prevTransaction = transaction;\r
180         transaction = transaction->nextTransaction;\r
181     }\r
182 \r
183     /* Traversed entire queue but did not find transaction */\r
184     if (transaction == NULL)\r
185     {\r
186         Rm_osalCsExit(key);\r
187         return (RM_SERVICE_ERROR_SERVICE_TRANSACTION_DOES_NOT_EXIST);\r
188     }\r
189     else\r
190     {\r
191         /* Delete the transaction */\r
192         if ((prevTransaction == NULL) && transaction->nextTransaction)\r
193         {\r
194             /* Transaction to be deleted exists at start of transaction queue.  Map second\r
195              * transaction to be start of transaction queue as long as there are more than\r
196              * one transactions */\r
197             rmInst->transactionQueue = transaction->nextTransaction;\r
198         }\r
199         else\r
200         {\r
201             /* Transaction to be deleted is in the middle or at end of the queue.  Adjust \r
202              * adjacent transaction pointers.  This covers the case where the transaction to be \r
203              * removed is at the end of the queue. */\r
204             prevTransaction->nextTransaction = transaction->nextTransaction;\r
205         }\r
206 \r
207         /* Free the memory associated with the transaction. */\r
208         Rm_osalFree((void *)transaction, sizeof(Rm_Transaction), false);\r
209     }\r
210 \r
211     Rm_osalCsExit(key);\r
212     return (RM_SERVICE_ACTION_OKAY);\r
213 }\r
214 \r
215 uint32_t Rm_transactionGetSequenceNum(Rm_Inst *rmInst)\r
216 {\r
217     uint32_t sequenceNum = 0;\r
218     void *key;\r
219 \r
220     /* Lock access to the RM instance */\r
221     key = Rm_osalCsEnter();\r
222 \r
223     /* Get the next sequence number and then incement.  Overflow is okay since\r
224      * it just restarts the sequence number count. */\r
225     sequenceNum = rmInst->transactionSeqNum++;\r
226 \r
227     Rm_osalCsExit(key);\r
228     return (sequenceNum);\r
229 }\r
230 \r
231 /* Function used to send RM response transactions to lower level agents */\r
232 void Rm_transactionResponder (Rm_Inst *rmInst, Rm_Transaction *transaction,\r
233                               Rm_TransactionReceipt *receipt)\r
234 {\r
235     Rm_TransportNode *dstTransportNode = NULL;\r
236     Rm_Packet *rmPkt = NULL;\r
237 \r
238     /* Find the transport for the RM instance that sent the request. */\r
239     dstTransportNode = Rm_transportNodeFindRemoteName(rmInst, transaction->sourceInstName);\r
240 \r
241     /* Create a RM packet using the service information */\r
242     switch (transaction->type)\r
243     {\r
244         case Rm_service_RESOURCE_ALLOCATE:\r
245         case Rm_service_RESOURCE_BLOCK_ALLOCATE:\r
246         case Rm_service_RESOURCE_ALLOCATE_BY_NAME:\r
247         case Rm_service_RESOURCE_FREE:\r
248         case Rm_service_RESOURCE_BLOCK_FREE:\r
249         case Rm_service_RESOURCE_FREE_BY_NAME:\r
250             rmPkt = Rm_transportCreateResourceResponsePkt(rmInst, dstTransportNode, \r
251                                                           transaction, receipt);\r
252             break;\r
253         case Rm_service_RESOURCE_MAP_TO_NAME:\r
254         case Rm_service_RESOURCE_UNMAP_NAME:\r
255             rmPkt = Rm_transportCreateNsResponsePkt(rmInst, dstTransportNode,\r
256                                                     transaction, receipt);\r
257             break;\r
258         default:\r
259             /* Invalid service type.  Flag the error and return */\r
260             receipt->serviceResult = RM_SERVICE_ERROR_INVALID_SERVICE_TYPE;\r
261             break;\r
262     }\r
263 \r
264     if (receipt->serviceResult <= RM_SERVICE_ERROR_BASE)\r
265     {\r
266         /* Delete the transaction and return immediately because an error occurred \r
267          * allocating the packet */\r
268         Rm_transactionQueueDelete(rmInst, transaction->id);\r
269         return;\r
270     }\r
271 \r
272     /* Send the RM packet to the application transport */\r
273     if (rmInst->transport.rmSend((Rm_TransportHandle) dstTransportNode, rmPkt) < RM_TRANSPORT_SUCCESSFUL)\r
274     {\r
275         /* Negative value returned by transport send.  An error occurred\r
276          * in the transport while attempting to send the packet.*/\r
277         receipt->serviceResult = RM_SERVICE_ERROR_TRANPSPORT_SEND_ERROR;\r
278         /* Clean up the packet */\r
279         if (rmInst->transport.rmFreePkt((Rm_TransportHandle) dstTransportNode, rmPkt))\r
280         {\r
281             /* Non-NULL value returned by transport packet free. Flag the\r
282              * error */\r
283              receipt->serviceResult = RM_SERVICE_ERROR_TRANSPORT_FREE_PKT_ERROR;\r
284         }\r
285         return;\r
286     }\r
287 \r
288     /* Fill out the receipt information and delete the transaction */\r
289     receipt->serviceResult = transaction->details;\r
290     Rm_transactionQueueDelete(rmInst, transaction->id);\r
291 }\r
292 \r
293 void Rm_allocationHandler (Rm_Inst *rmInst, Rm_Transaction *transaction,\r
294                            Rm_TransactionReceipt *receipt)\r
295 {\r
296     if (rmInst->instType == Rm_instType_CLIENT_DELEGATE)\r
297     {\r
298 #if 0        \r
299         /* Check local policy to see if the request can be satisfied with the\r
300          * resources stored locally */\r
301          Rm_policy...API()\r
302 \r
303         if (policy check approves the resource)\r
304         {\r
305             /* call the allocator to allocate the resource */\r
306             if (allocator returns resource)\r
307             {\r
308                 /* Populate the receipt with the allocated resources and the result */\r
309                 receipt->serviceResult = approve reason;\r
310                 receipt->serviceId = transaction->id;\r
311                 return ...\r
312             }\r
313             else\r
314             {\r
315                 /* allocator ran out of resources, need to contact Server for more\r
316                  * resources */\r
317                 Rm_resourcePoolModRequest(...);\r
318             }\r
319         }\r
320         else if (policy check denies resource)\r
321         {\r
322             /* Policy check denied resource. */\r
323             receipt->serviceResult = deny reason;\r
324             receipt->serviceId = transaction->id;\r
325             return ...\r
326         }\r
327         else if (policy check says forward to Server for validation)\r
328         {\r
329             /* Forward the transaction to the Server */\r
330             Rm_transactionForwarder(rmInst, transaction, receipt);\r
331         }\r
332 #endif         \r
333     }\r
334     else if (rmInst->instType == Rm_instType_SERVER)\r
335     {\r
336 #if 0        \r
337         /* Check global policy to see if resource can be allocated. return result\r
338          * no matter what */\r
339         Rm_policy...API()\r
340 \r
341         if (policy approves)\r
342         {\r
343             /* call allocator to allocate resource */\r
344         }\r
345 \r
346         receipt->serviceResult = approve or deny reason;\r
347         receipt->serviceId = transaction->id;\r
348         receipt->resourceBase = ...;\r
349         receipt->resourceRange = ...;\r
350 \r
351         /* If source instance name does not match the current instance\r
352          * name the allocation request came from a client.  The result\r
353          * must be sent back to the Client */\r
354         if (strcmp(transaction->sourceInstName, rmInst->name))\r
355         {\r
356             /* Names don't match.  Copy the allocation response resource data \r
357              * into the original transaction and send it back to the Client */\r
358             transaction->details = transaction->details;\r
359             transaction->resourceInfo.base = receipt->resourceBase;\r
360             transaction->resourceInfo.range = receipt->resourceRange;\r
361             Rm_transactionResponder(rmInst, transaction, receipt);\r
362         }\r
363         else\r
364         {\r
365             /* Resource allocation request originated locally on the active\r
366              * instance. Send the response via the service responder. */\r
367             transaction->details = transaction->details;\r
368             transaction->resourceInfo.base = receipt->resourceBase;\r
369             transaction->resourceInfo.range = receipt->resourceRange;             \r
370             Rm_serviceResponder(rmInst, transaction, NULL, receipt);                            \r
371         }\r
372 #endif        \r
373     }   \r
374 }\r
375 \r
376 void Rm_freeHandler (Rm_Inst *rmInst, Rm_Transaction *transaction,\r
377                      Rm_TransactionReceipt *receipt)\r
378 {\r
379     if (rmInst->instType == Rm_instType_CLIENT_DELEGATE)\r
380     {\r
381 #if 0        \r
382         /* Check local policy to see if the request can be satisfied with the\r
383          * resources stored locally */\r
384          Rm_policy...API()\r
385 \r
386         if (policy check approves the free)\r
387         {\r
388             /* call the allocator to free the resource */\r
389             /* Run a resource pool check to see if the free combined a resource block\r
390              * that can be returned to the server */\r
391             if (resource block has been combined)\r
392             {\r
393                   /* allocator ran out of resources, need to contact Server for more\r
394                  * resources */\r
395                 Rm_resourcePoolModRequest(free pool block to server...);\r
396             }\r
397             else\r
398             {\r
399                 /* Populate the receipt with the freed resources and the result */\r
400                 receipt->serviceResult = approve reason;\r
401                 receipt->serviceId = transaction->id;\r
402                 return ...\r
403             }\r
404         }\r
405         else if (policy check denies resource free)\r
406         {\r
407             /* Policy check denied resource. */\r
408             receipt->serviceResult = deny reason;\r
409             receipt->serviceId = transaction->id;\r
410             return ...\r
411         }\r
412         else if (policy check says forward to Server for validation)\r
413         {\r
414             /* Forward the transaction to the Server */\r
415             Rm_transactionForwarder(rmInst, transaction, receipt);\r
416         }\r
417 #endif         \r
418     }\r
419     else if (rmInst->instType == Rm_instType_SERVER)\r
420     {\r
421 #if 0        \r
422         /* Check global policy to see if resource can be freed. return result\r
423          * no matter what */\r
424         Rm_policy...API()\r
425         if (policy approves)\r
426         {\r
427             /* call allocator to free resources */\r
428         }\r
429             \r
430         receipt->serviceResult = approve or deny reason;\r
431         receipt->serviceId = transaction->id;\r
432         receipt->resourceBase = ...;\r
433         receipt->resourceRange = ...;\r
434 \r
435         /* If source instance name does not match the current instance\r
436          * name the allocation request came from a client.  The result\r
437          * must be sent back to the Client */\r
438         if (strcmp(transaction->sourceInstName, rmInst->name))\r
439         {\r
440             /* Names don't match.  Copy the free response resource data \r
441              * into the original transaction and send it back to the Client Delegate or Client */\r
442             transaction->details = transaction->details;\r
443             transaction->resourceInfo.base = receipt->resourceBase;\r
444             transaction->resourceInfo.range = receipt->resourceRange;\r
445             Rm_transactionResponder(rmInst, transaction, receipt);\r
446         }\r
447         else\r
448         {\r
449             /* Resource allocation request originated locally on the active\r
450              * instance. Send the response via the service responder. */\r
451             transaction->details = transaction->details;\r
452             transaction->resourceInfo.base = receipt->resourceBase;\r
453             transaction->resourceInfo.range = receipt->resourceRange;\r
454             Rm_serviceResponder(rmInst, transaction, NULL, receipt);                            \r
455         }\r
456 #endif        \r
457     }   \r
458 }\r
459 \r
460 /* Function used to forward RM transactions to higher level agents */\r
461 void Rm_transactionForwarder (Rm_Inst *rmInst, Rm_Transaction *transaction,\r
462                               Rm_TransactionReceipt *receipt)\r
463 {\r
464     Rm_TransportNode *dstTransportNode = NULL;\r
465     Rm_Packet *rmPkt = NULL;\r
466 \r
467     /* Make sure the RM instance has a transport registered with a higher level agent */\r
468     if (rmInst->registeredWithDelegateOrServer == false)\r
469     {\r
470         receipt->serviceResult = RM_SERVICE_ERROR_NOT_REGISTERED_WITH_DEL_OR_SERVER;\r
471         return;\r
472     }\r
473 \r
474     /* Find the transport for the higher level agent.  Check for a connection to a Client Delegate\r
475      * or a Server.  Clients will be connected to either a Client Delegate or a Server.  Client\r
476      * Delegates will be connected to a Server. */\r
477     if (rmInst->instType == Rm_instType_CLIENT)\r
478     {\r
479         dstTransportNode = Rm_transportNodeFindRemoteInstType(rmInst, Rm_instType_CLIENT_DELEGATE);\r
480     } \r
481     else if (rmInst->instType == Rm_instType_CLIENT_DELEGATE)\r
482     {\r
483         dstTransportNode = Rm_transportNodeFindRemoteInstType(rmInst, Rm_instType_SERVER);\r
484     }\r
485 \r
486     /* Create a RM packet using the service information */\r
487     switch (transaction->type)\r
488     {\r
489         case Rm_service_RESOURCE_ALLOCATE:\r
490         case Rm_service_RESOURCE_BLOCK_ALLOCATE:\r
491         case Rm_service_RESOURCE_ALLOCATE_BY_NAME:\r
492         case Rm_service_RESOURCE_FREE:\r
493         case Rm_service_RESOURCE_BLOCK_FREE:\r
494         case Rm_service_RESOURCE_FREE_BY_NAME:\r
495             rmPkt = Rm_transportCreateResourceReqPkt(rmInst, dstTransportNode, \r
496                                                      transaction, receipt);\r
497             break;\r
498         case Rm_service_RESOURCE_MAP_TO_NAME:\r
499         case Rm_service_RESOURCE_UNMAP_NAME:\r
500             rmPkt = Rm_transportCreateNsRequestPkt(rmInst, dstTransportNode,\r
501                                                    transaction, receipt);\r
502             break;\r
503         default:\r
504             /* Invalid service type.  Flag the error and return */\r
505             receipt->serviceResult = RM_SERVICE_ERROR_INVALID_SERVICE_TYPE;\r
506             break;\r
507     }\r
508 \r
509     if (receipt->serviceResult <= RM_SERVICE_ERROR_BASE)\r
510     {\r
511         /* Return immediately because an error occurred allocating the packet */\r
512         return;\r
513     }\r
514 \r
515     /* Switch the queued transaction to the awaiting response state */\r
516     transaction->state = Rm_transactionState_AWAITING_RESPONSE;\r
517 \r
518     /* Send the RM packet to the application transport */\r
519     if (rmInst->transport.rmSend((Rm_TransportHandle) dstTransportNode, rmPkt) < RM_TRANSPORT_SUCCESSFUL)\r
520     {\r
521         /* Negative value returned by transport send.  An error occurred\r
522          * in the transport while attempting to send the packet.*/\r
523         receipt->serviceResult = RM_SERVICE_ERROR_TRANPSPORT_SEND_ERROR;\r
524         /* Clean up the packet */\r
525         if (rmInst->transport.rmFreePkt((Rm_TransportHandle) dstTransportNode, rmPkt))\r
526         {\r
527             /* Non-NULL value returned by transport packet free. Flag the\r
528              * error */\r
529              receipt->serviceResult = RM_SERVICE_ERROR_TRANSPORT_FREE_PKT_ERROR;\r
530         }\r
531         return;\r
532     }\r
533 \r
534     /* Inform requesting component that the service is being forwarded to a higher lever\r
535      * RM agent for processing.  The result of the service will be provided to the \r
536      * component via the specified callback function */\r
537     receipt->serviceResult = RM_SERVICE_PROCESSING;\r
538     receipt->serviceId = transaction->id;\r
539 }\r
540 \r
541 void Rm_transactionProcessor (Rm_Inst *rmInst, Rm_Transaction *transaction, \r
542                               Rm_TransactionReceipt *receipt)\r
543 {\r
544     Rm_Transaction *queuedTransaction = NULL;\r
545 \r
546     /* Handle auto-forwarded transactions.  These transactions include:\r
547      * - All request transactions received on Clients are forwarded to the Client Delegate\r
548      * - NameServer requests received on the Client Delegate are forwarded to the Server */\r
549     if ((rmInst->instType == Rm_instType_CLIENT) ||\r
550         ((rmInst->instType == Rm_instType_CLIENT_DELEGATE) &&\r
551          (transaction->type == Rm_service_RESOURCE_MAP_TO_NAME) ||\r
552          (transaction->type == Rm_service_RESOURCE_UNMAP_NAME)))\r
553     {\r
554         /* Check if the new transaction's ID matches any transactions waiting for\r
555          * responses.  A transaction received as a response will have an ID that \r
556          * matches the transaction that originated the request packet */\r
557         if (queuedTransaction = Rm_transactionQueueFind(rmInst, transaction->id))\r
558         {\r
559             if (queuedTransaction->state == Rm_transactionState_AWAITING_RESPONSE)\r
560             {\r
561                 if (rmInst->instType == Rm_instType_CLIENT)\r
562                 {\r
563                     /* Client found a transaction awaiting a response.  Pass both transactions\r
564                      * to the service responder for response processing */\r
565                     Rm_serviceResponder(rmInst, transaction, queuedTransaction, receipt);\r
566                 }\r
567                 else if (rmInst->instType == Rm_instType_CLIENT_DELEGATE)\r
568                 {\r
569                     /* Client Delegate found a NameServer transaction awaiting a response. Send the \r
570                      * response to either the transaction or service responder based on the \r
571                      * source instance */\r
572                     if (strcmp(queuedTransaction->sourceInstName, rmInst->name))\r
573                     {\r
574                         /* NameServer transaction originated from another instance.  Use the \r
575                          * transaction responder to send the NameServer result to the source instance.\r
576                          * Need to transfer the NameServer result details to the request transaction \r
577                          * which will be reused for the response. */\r
578                         queuedTransaction->details = transaction->details;\r
579                         Rm_transactionResponder(rmInst, queuedTransaction, receipt);\r
580                         /* Delete the response transaction */\r
581                         Rm_transactionQueueDelete(rmInst, transaction->id);                        \r
582                     }\r
583                     else\r
584                     {\r
585                         /* NameServer request originated on the Client Delegate instance.  Send to the\r
586                          * service responder */\r
587                         Rm_serviceResponder(rmInst, transaction, queuedTransaction,\r
588                                             receipt);\r
589                     }\r
590                 }\r
591             }\r
592             else\r
593             {\r
594                 /* Request transaction was not in the awaiting response state.  Flag the\r
595                  * error in the receipt and return */\r
596                 receipt->serviceResult = RM_SERVICE_ERROR_INVALID_REQUEST_TRANSACTION_STATE_UPON_RESPONSE;\r
597             }\r
598         }\r
599         else\r
600         {\r
601             /* This is a new transaction.  Make sure the transaction is not a \r
602              * response transaction sent to the wrong RM instance */\r
603             if ((transaction->state == Rm_transactionState_RESOURCE_APPROVED) ||\r
604                 (transaction->state == Rm_transactionState_RESOURCE_DENIED))\r
605             {\r
606                 /* No matching request transaction.  This transaction result was sent to the\r
607                  * wrong RM instance.  Flag the error in the receipt and return */\r
608                 receipt->serviceResult = RM_SERVICE_ERROR_INVALID_TRANSACTION_RECEIVED_ON_CLIENT;\r
609             }\r
610             else\r
611             {\r
612                 /* All service requests on Clients are forwarded to the higher level RM Client \r
613                  * Delegate.  NameServer requests on Client Delegates are forwarded to the Server. */\r
614                 Rm_transactionForwarder(rmInst, transaction, receipt);\r
615             }\r
616         }\r
617     }\r
618     else\r
619     {\r
620         /* Client Delegate and Server transaction processors. */\r
621         switch (transaction->type)\r
622         {\r
623             case Rm_service_RESOURCE_ALLOCATE:\r
624             case Rm_service_RESOURCE_BLOCK_ALLOCATE:\r
625             case Rm_service_RESOURCE_ALLOCATE_BY_NAME:\r
626                 /* Run the transaction through the response handler to take care of any\r
627                  * transactions that are responses to sent allocation requests. */\r
628                 if (queuedTransaction = Rm_transactionQueueFind(rmInst, transaction->id))\r
629                 {\r
630                     if (queuedTransaction->state == Rm_transactionState_AWAITING_RESPONSE)\r
631                     {\r
632                         /* If source instance name does not match the current instance\r
633                          * name the allocation request came from a client.  The result\r
634                          * must be sent back to the Client */\r
635                         if (strcmp(queuedTransaction->sourceInstName, rmInst->name))\r
636                         {\r
637                             /* Names don't match.  Copy the allocation response resource data \r
638                              * into the original transaction and send it back to the Client */\r
639                             queuedTransaction->details = transaction->details;\r
640                             memcpy ((void *)&(queuedTransaction->resourceInfo), \r
641                                     (void *)&(transaction->resourceInfo), sizeof(Rm_ResourceInfo));\r
642                             Rm_transactionResponder(rmInst, queuedTransaction, receipt);\r
643                             /* Delete the response transaction */\r
644                             Rm_transactionQueueDelete(rmInst, transaction->id);\r
645                         }\r
646                         else\r
647                         {\r
648                             /* Resource allocation request originated locally on Client Delegate\r
649                              * instance. Send the response via the service responder. */\r
650                             Rm_serviceResponder(rmInst, transaction, queuedTransaction,\r
651                                                 receipt);                            \r
652                         }\r
653                     }\r
654                     else\r
655                     {\r
656                         /* Request transaction was not in the awaiting response state.  Flag the\r
657                          * error in the receipt and return */\r
658                         receipt->serviceResult = RM_SERVICE_ERROR_INVALID_REQUEST_TRANSACTION_STATE_UPON_RESPONSE;\r
659                     }\r
660 \r
661                 }\r
662                 else\r
663                 {\r
664                     /* This is a new transaction request originating from an RM instance with fewer\r
665                      * allocate/free privileges.  Run the allocation handler to see if the resource\r
666                      * request can be handled locally or if it needs to be forwarded to a higher level\r
667                      * agent */\r
668                      Rm_allocationHandler(rmInst, transaction, receipt);\r
669                 }\r
670                 break;\r
671             case Rm_service_RESOURCE_FREE:\r
672             case Rm_service_RESOURCE_BLOCK_FREE:\r
673             case Rm_service_RESOURCE_FREE_BY_NAME:\r
674                 /* Run the transaction through the response handler to take care of any\r
675                  * transactions that are responses to sent free requests. */\r
676                 if (queuedTransaction = Rm_transactionQueueFind(rmInst, transaction->id))\r
677                 {\r
678                     if (queuedTransaction->state == Rm_transactionState_AWAITING_RESPONSE)\r
679                     {\r
680                         /* If source instance name does not match the current instance\r
681                          * name the allocation request came from a client.  The result\r
682                          * must be sent back to the Client */\r
683                         if (strcmp(queuedTransaction->sourceInstName, rmInst->name))\r
684                         {\r
685                             /* Names don't match.  Copy the free response resource data \r
686                              * into the original transaction and send it back to the Client */\r
687                             queuedTransaction->details = transaction->details;\r
688                             memcpy ((void *)&(queuedTransaction->resourceInfo), \r
689                                     (void *)&(transaction->resourceInfo), sizeof(Rm_ResourceInfo));\r
690                             Rm_transactionResponder(rmInst, queuedTransaction, receipt);\r
691                             /* Delete the response transaction */\r
692                             Rm_transactionQueueDelete(rmInst, transaction->id);\r
693                         }\r
694                         else\r
695                         {\r
696                             /* Resource free request originated locally on Client Delegate\r
697                              * instance. Send the response via the service responder. */\r
698                             Rm_serviceResponder(rmInst, transaction, queuedTransaction,\r
699                                                 receipt);                            \r
700                         }\r
701                     }\r
702                     else\r
703                     {\r
704                         /* Request transaction was not in the awaiting response state.  Flag the\r
705                          * error in the receipt and return */\r
706                         receipt->serviceResult = RM_SERVICE_ERROR_INVALID_REQUEST_TRANSACTION_STATE_UPON_RESPONSE;\r
707                     }\r
708 \r
709                 }\r
710                 else\r
711                 {\r
712                     /* This is a new transaction request originating from an RM instance with fewer\r
713                      * allocate/free privileges.  Run the free handler to see if the resource\r
714                      * request can be handled locally or if it needs to be forwarded to a higher level\r
715                      * agent */\r
716                      Rm_freeHandler(rmInst, transaction, receipt);\r
717                 }\r
718 \r
719                 break;\r
720             case Rm_service_RESOURCE_MAP_TO_NAME:\r
721                 /* Server is the only RM instance capable of adding NameServer objects */\r
722                 if (rmInst->instType == Rm_instType_SERVER)\r
723                 {\r
724                     /* Create a new NameServer object with the request transaction information */\r
725                     Rm_nsAddObject(rmInst, transaction, receipt);\r
726 \r
727                     /* Return the result of the NameServer addition to the RM instance\r
728                      * that requested it */\r
729                     transaction->details = receipt->serviceResult;\r
730 \r
731                     /* If source instance name does not match the current instance\r
732                      * name the NameServer request came from a Client or Client Delegate.  The \r
733                      * result must be sent back to the Client or Client Delegate */\r
734                     if (strcmp(transaction->sourceInstName, rmInst->name))\r
735                     {\r
736                         Rm_transactionResponder(rmInst, queuedTransaction, receipt);\r
737                     }\r
738                     else\r
739                     {\r
740                         /* NameServer addition request originated locally on Server\r
741                          * instance. Send the response via the service responder.  In this case\r
742                          * the request transaction will be passed as NULL since the request\r
743                          * is being reused as the response */\r
744                         Rm_serviceResponder(rmInst, transaction, NULL, receipt);                            \r
745                     }\r
746                 }\r
747                 else\r
748                 {\r
749                     receipt->serviceResult = RM_SERVICE_ERROR_NAMESERVER_OBJECT_CREATE_ON_INVALID_INSTANCE;\r
750                 }\r
751                 break;\r
752             case Rm_service_RESOURCE_UNMAP_NAME:\r
753                 /* Server is the only RM instance capable of deleting NameServer objects */\r
754                 if (rmInst->instType == Rm_instType_SERVER)\r
755                 {\r
756                     /* Delete an existing NameServer object with the request transaction information */\r
757                     Rm_nsDeleteObject(rmInst, transaction, receipt);\r
758 \r
759                     /* Return the result of the NameServer deletion to the RM instance\r
760                      * that requested it */\r
761                     transaction->details = receipt->serviceResult;\r
762 \r
763                     /* If source instance name does not match the current instance\r
764                      * name the NameServer request came from a Client or Client Delegate.  The \r
765                      * result must be sent back to the Client or Client Delegate */\r
766                     if (strcmp(transaction->sourceInstName, rmInst->name))\r
767                     {\r
768                         Rm_transactionResponder(rmInst, queuedTransaction, receipt);\r
769                     }\r
770                     else\r
771                     {\r
772                         /* NameServer delete request originated locally on Server\r
773                          * instance. Send the response via the service responder.  In this case\r
774                          * the request transaction will be passed as NULL since the request\r
775                          * is being reused as the response */\r
776                         Rm_serviceResponder(rmInst, transaction, NULL, receipt);                            \r
777                     }                    \r
778                 }\r
779                 else\r
780                 {\r
781                     receipt->serviceResult = RM_SERVICE_ERROR_NAMESERVER_OBJECT_DELETE_ON_INVALID_INSTANCE;\r
782                 }\r
783                 break;\r
784         }\r
785     }\r
786 }\r
787 \r
788 /**********************************************************************\r
789  ********************** Application visible APIs **********************\r
790  **********************************************************************/\r
791 \r
792 Rm_Handle Rm_init(Rm_InitCfg *initCfg)\r
793 {\r
794     Rm_Inst *rmInst;\r
795 \r
796     /* Instance creation checks.  Add one to strlen calculation for null character */\r
797     if ((strlen(initCfg->instName) + 1) > RM_INSTANCE_NAME_MAX_CHARS)\r
798     {\r
799         /* Failure: Instance name is too big */\r
800         return (NULL);\r
801     }\r
802     \r
803     /* Get memory for RM instance from local memory */\r
804     rmInst = Rm_osalMalloc (sizeof(Rm_Inst), false);\r
805     /* Populate instance based on input parameters */\r
806     strcpy (&rmInst->name[0], initCfg->instName);\r
807     rmInst->instType = initCfg->instType;\r
808     rmInst->instState = RM_state_IDLE;\r
809     rmInst->registeredWithDelegateOrServer = false;\r
810 \r
811     /* Initialize the transport routing map linked list pointer to NULL.  The linked list\r
812      * nodes will be created when the application registers transports */\r
813     rmInst->routeMap = NULL;\r
814 \r
815     /* Initialize the transaction queue elements.  The linked list pointer is set to NULL\r
816      * and the transaction sequence number is initialized to 0. */\r
817     rmInst->transactionSeqNum = 0;\r
818     rmInst->transactionQueue= NULL;\r
819 \r
820     /* RM Server specific actions */\r
821     if (rmInst->instType == Rm_instType_SERVER)\r
822     {\r
823        /* parse DTB, etc */\r
824     }\r
825 \r
826     /* Instance startup policies are only used for Servers and Client Delegates */\r
827     if (rmInst->instType != Rm_instType_CLIENT)\r
828     {\r
829         rmInst->instPolicy = initCfg->startupPolicy;\r
830 \r
831         /* Store policy via policy APIs ... */\r
832     }\r
833 \r
834     /* Return the RM Handle */\r
835     return ((Rm_Handle) rmInst);\r
836 }\r
837 \r
838 uint32_t Rm_getVersion (void)\r
839 {\r
840     return RM_VERSION_ID;\r
841 }\r
842 \r
843 \r
844 const char* Rm_getVersionStr (void)\r
845 {\r
846     return rmVersionStr;\r
847 }\r
848 \r
849 /**\r
850 @}\r
851 */\r