]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - keystone-rtos/rm-lld.git/blob - src/rm.c
Coded basic test project started removing receipt construct
[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     /* Set the transaction's local ID */\r
101     newTransaction->localId = 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->localId == 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->localId == 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_transactionInitSequenceNum(void)\r
216 {\r
217     /* Sequence number can never have a value of 0 so that there are no conflicts\r
218      * when searching for transactions that received a response of a higher level RM agent */\r
219     return (1);\r
220 }\r
221 \r
222 uint32_t Rm_transactionGetSequenceNum(Rm_Inst *rmInst)\r
223 {\r
224     uint32_t sequenceNum = 0;\r
225     void *key;\r
226 \r
227     /* Lock access to the RM instance */\r
228     key = Rm_osalCsEnter();\r
229 \r
230     /* Get the next sequence number and then increment.  If there's an overflow\r
231      * assign the initial value instead of incrementing. */\r
232     if (rmInst->transactionSeqNum + 1 < rmInst->transactionSeqNum)\r
233     {\r
234         /* Overflow */\r
235         sequenceNum = rmInst->transactionSeqNum;\r
236         rmInst->transactionSeqNum = Rm_transactionInitSequenceNum();\r
237     }\r
238     else\r
239     {\r
240         sequenceNum = rmInst->transactionSeqNum++;\r
241     }    \r
242 \r
243     Rm_osalCsExit(key);\r
244     return (sequenceNum);\r
245 }\r
246 \r
247 /* Function used to send RM response transactions to lower level agents */\r
248 void Rm_transactionResponder (Rm_Inst *rmInst, Rm_Transaction *transaction,\r
249                               Rm_TransactionReceipt *receipt)\r
250 {\r
251     Rm_TransportNode *dstTransportNode = NULL;\r
252     Rm_Packet *rmPkt = NULL;\r
253 \r
254     /* Find the transport for the RM instance that sent the request. */\r
255     dstTransportNode = Rm_transportNodeFindRemoteName(rmInst, transaction->sourceInstName);\r
256 \r
257     /* Create a RM packet using the service information */\r
258     switch (transaction->type)\r
259     {\r
260         case Rm_service_RESOURCE_ALLOCATE:\r
261         case Rm_service_RESOURCE_BLOCK_ALLOCATE:\r
262         case Rm_service_RESOURCE_ALLOCATE_BY_NAME:\r
263         case Rm_service_RESOURCE_FREE:\r
264         case Rm_service_RESOURCE_BLOCK_FREE:\r
265         case Rm_service_RESOURCE_FREE_BY_NAME:\r
266             rmPkt = Rm_transportCreateResourceResponsePkt(rmInst, dstTransportNode, \r
267                                                           transaction, receipt);\r
268             break;\r
269         case Rm_service_RESOURCE_MAP_TO_NAME:\r
270         case Rm_service_RESOURCE_UNMAP_NAME:\r
271             rmPkt = Rm_transportCreateNsResponsePkt(rmInst, dstTransportNode,\r
272                                                     transaction, receipt);\r
273             break;\r
274         default:\r
275             /* Invalid service type.  Flag the error and return */\r
276             receipt->serviceResult = RM_SERVICE_ERROR_INVALID_SERVICE_TYPE;\r
277             break;\r
278     }\r
279 \r
280     if (receipt->serviceResult <= RM_SERVICE_ERROR_BASE)\r
281     {\r
282         /* Delete the transaction and return immediately because an error occurred \r
283          * allocating the packet */\r
284         Rm_transactionQueueDelete(rmInst, transaction->id);\r
285         return;\r
286     }\r
287 \r
288     /* Send the RM packet to the application transport */\r
289     if (rmInst->transport.rmSend((Rm_TransportHandle) dstTransportNode, rmPkt) < RM_TRANSPORT_SUCCESSFUL)\r
290     {\r
291         /* Negative value returned by transport send.  An error occurred\r
292          * in the transport while attempting to send the packet.*/\r
293         receipt->serviceResult = RM_SERVICE_ERROR_TRANPSPORT_SEND_ERROR;\r
294         /* Clean up the packet */\r
295         if (rmInst->transport.rmFreePkt((Rm_TransportHandle) dstTransportNode, rmPkt))\r
296         {\r
297             /* Non-NULL value returned by transport packet free. Flag the\r
298              * error */\r
299              receipt->serviceResult = RM_SERVICE_ERROR_TRANSPORT_FREE_PKT_ERROR;\r
300         }\r
301         return;\r
302     }\r
303 \r
304     /* Fill out the receipt information and delete the transaction */\r
305     receipt->serviceResult = transaction->details;\r
306     Rm_transactionQueueDelete(rmInst, transaction->id);\r
307 }\r
308 \r
309 void Rm_allocationHandler (Rm_Inst *rmInst, Rm_Transaction *transaction,\r
310                            Rm_TransactionReceipt *receipt)\r
311 {\r
312     if (rmInst->instType == Rm_instType_CLIENT_DELEGATE)\r
313     {\r
314 #if 0        \r
315         /* Check local policy to see if the request can be satisfied with the\r
316          * resources stored locally */\r
317          Rm_policy...API()\r
318 \r
319         if (policy check approves the resource)\r
320         {\r
321             /* call the allocator to allocate the resource */\r
322             if (allocator returns resource)\r
323             {\r
324                 /* Populate the receipt with the allocated resources and the result */\r
325                 receipt->serviceResult = approve reason;\r
326                 receipt->serviceId = transaction->id;\r
327                 return ...\r
328             }\r
329             else\r
330             {\r
331                 /* allocator ran out of resources, need to contact Server for more\r
332                  * resources */\r
333                 Rm_resourcePoolModRequest(...);\r
334             }\r
335         }\r
336         else if (policy check denies resource)\r
337         {\r
338             /* Policy check denied resource. */\r
339             receipt->serviceResult = deny reason;\r
340             receipt->serviceId = transaction->id;\r
341             return ...\r
342         }\r
343         else if (policy check says forward to Server for validation)\r
344         {\r
345             /* Forward the transaction to the Server */\r
346             Rm_transactionForwarder(rmInst, transaction, receipt);\r
347         }\r
348 #endif         \r
349     }\r
350     else if (rmInst->instType == Rm_instType_SERVER)\r
351     {\r
352 #if 0        \r
353         /* Check global policy to see if resource can be allocated. return result\r
354          * no matter what */\r
355         Rm_policy...API()\r
356 \r
357         if (policy approves)\r
358         {\r
359             /* call allocator to allocate resource */\r
360         }\r
361 \r
362         receipt->serviceResult = approve or deny reason;\r
363         receipt->serviceId = transaction->id;\r
364         receipt->resourceBase = ...;\r
365         receipt->resourceRange = ...;\r
366 \r
367         /* If source instance name does not match the current instance\r
368          * name the allocation request came from a client.  The result\r
369          * must be sent back to the Client */\r
370         if (strcmp(transaction->sourceInstName, rmInst->name))\r
371         {\r
372             /* Names don't match.  Copy the allocation response resource data \r
373              * into the original transaction and send it back to the Client */\r
374             transaction->details = transaction->details;\r
375             transaction->resourceInfo.base = receipt->resourceBase;\r
376             transaction->resourceInfo.range = receipt->resourceRange;\r
377             Rm_transactionResponder(rmInst, transaction, receipt);\r
378         }\r
379         else\r
380         {\r
381             /* Resource allocation request originated locally on the active\r
382              * instance. Send the response via the service responder. */\r
383             transaction->details = transaction->details;\r
384             transaction->resourceInfo.base = receipt->resourceBase;\r
385             transaction->resourceInfo.range = receipt->resourceRange;             \r
386             Rm_serviceResponder(rmInst, transaction, NULL, receipt);                            \r
387         }\r
388 #endif        \r
389     }   \r
390 }\r
391 \r
392 void Rm_freeHandler (Rm_Inst *rmInst, Rm_Transaction *transaction,\r
393                      Rm_TransactionReceipt *receipt)\r
394 {\r
395     if (rmInst->instType == Rm_instType_CLIENT_DELEGATE)\r
396     {\r
397 #if 0        \r
398         /* Check local policy to see if the request can be satisfied with the\r
399          * resources stored locally */\r
400          Rm_policy...API()\r
401 \r
402         if (policy check approves the free)\r
403         {\r
404             /* call the allocator to free the resource */\r
405             /* Run a resource pool check to see if the free combined a resource block\r
406              * that can be returned to the server */\r
407             if (resource block has been combined)\r
408             {\r
409                   /* allocator ran out of resources, need to contact Server for more\r
410                  * resources */\r
411                 Rm_resourcePoolModRequest(free pool block to server...);\r
412             }\r
413             else\r
414             {\r
415                 /* Populate the receipt with the freed resources and the result */\r
416                 receipt->serviceResult = approve reason;\r
417                 receipt->serviceId = transaction->id;\r
418                 return ...\r
419             }\r
420         }\r
421         else if (policy check denies resource free)\r
422         {\r
423             /* Policy check denied resource. */\r
424             receipt->serviceResult = deny reason;\r
425             receipt->serviceId = transaction->id;\r
426             return ...\r
427         }\r
428         else if (policy check says forward to Server for validation)\r
429         {\r
430             /* Forward the transaction to the Server */\r
431             Rm_transactionForwarder(rmInst, transaction, receipt);\r
432         }\r
433 #endif         \r
434     }\r
435     else if (rmInst->instType == Rm_instType_SERVER)\r
436     {\r
437 #if 0        \r
438         /* Check global policy to see if resource can be freed. return result\r
439          * no matter what */\r
440         Rm_policy...API()\r
441         if (policy approves)\r
442         {\r
443             /* call allocator to free resources */\r
444         }\r
445             \r
446         receipt->serviceResult = approve or deny reason;\r
447         receipt->serviceId = transaction->id;\r
448         receipt->resourceBase = ...;\r
449         receipt->resourceRange = ...;\r
450 \r
451         /* If source instance name does not match the current instance\r
452          * name the allocation request came from a client.  The result\r
453          * must be sent back to the Client */\r
454         if (strcmp(transaction->sourceInstName, rmInst->name))\r
455         {\r
456             /* Names don't match.  Copy the free response resource data \r
457              * into the original transaction and send it back to the Client Delegate or Client */\r
458             transaction->details = transaction->details;\r
459             transaction->resourceInfo.base = receipt->resourceBase;\r
460             transaction->resourceInfo.range = receipt->resourceRange;\r
461             Rm_transactionResponder(rmInst, transaction, receipt);\r
462         }\r
463         else\r
464         {\r
465             /* Resource allocation request originated locally on the active\r
466              * instance. Send the response via the service responder. */\r
467             transaction->details = transaction->details;\r
468             transaction->resourceInfo.base = receipt->resourceBase;\r
469             transaction->resourceInfo.range = receipt->resourceRange;\r
470             Rm_serviceResponder(rmInst, transaction, NULL, receipt);                            \r
471         }\r
472 #endif        \r
473     }   \r
474 }\r
475 \r
476 /* Function used to forward RM transactions to higher level agents */\r
477 void Rm_transactionForwarder (Rm_Inst *rmInst, Rm_Transaction *transaction,\r
478                               Rm_TransactionReceipt *receipt)\r
479 {\r
480     Rm_TransportNode *dstTransportNode = NULL;\r
481     Rm_Packet *rmPkt = NULL;\r
482 \r
483     /* Make sure the RM instance has a transport registered with a higher level agent */\r
484     if (rmInst->registeredWithDelegateOrServer == false)\r
485     {\r
486         receipt->serviceResult = RM_SERVICE_ERROR_NOT_REGISTERED_WITH_DEL_OR_SERVER;\r
487         return;\r
488     }\r
489 \r
490     /* Find the transport for the higher level agent.  Check for a connection to a Client Delegate\r
491      * or a Server.  Clients will be connected to either a Client Delegate or a Server.  Client\r
492      * Delegates will be connected to a Server. */\r
493     if (rmInst->instType == Rm_instType_CLIENT)\r
494     {\r
495         dstTransportNode = Rm_transportNodeFindRemoteInstType(rmInst, Rm_instType_CLIENT_DELEGATE);\r
496     } \r
497     else if (rmInst->instType == Rm_instType_CLIENT_DELEGATE)\r
498     {\r
499         dstTransportNode = Rm_transportNodeFindRemoteInstType(rmInst, Rm_instType_SERVER);\r
500     }\r
501 \r
502     /* Create a RM packet using the service information */\r
503     switch (transaction->type)\r
504     {\r
505         case Rm_service_RESOURCE_ALLOCATE:\r
506         case Rm_service_RESOURCE_BLOCK_ALLOCATE:\r
507         case Rm_service_RESOURCE_ALLOCATE_BY_NAME:\r
508         case Rm_service_RESOURCE_FREE:\r
509         case Rm_service_RESOURCE_BLOCK_FREE:\r
510         case Rm_service_RESOURCE_FREE_BY_NAME:\r
511             rmPkt = Rm_transportCreateResourceReqPkt(rmInst, dstTransportNode, \r
512                                                      transaction, receipt);\r
513             break;\r
514         case Rm_service_RESOURCE_MAP_TO_NAME:\r
515         case Rm_service_RESOURCE_UNMAP_NAME:\r
516             rmPkt = Rm_transportCreateNsRequestPkt(rmInst, dstTransportNode,\r
517                                                    transaction, receipt);\r
518             break;\r
519         default:\r
520             /* Invalid service type.  Flag the error and return */\r
521             receipt->serviceResult = RM_SERVICE_ERROR_INVALID_SERVICE_TYPE;\r
522             break;\r
523     }\r
524 \r
525     if (receipt->serviceResult <= RM_SERVICE_ERROR_BASE)\r
526     {\r
527         /* Return immediately because an error occurred allocating the packet */\r
528         return;\r
529     }\r
530 \r
531     /* Switch the queued transaction to the awaiting response state */\r
532     transaction->state = Rm_transactionState_AWAITING_RESPONSE;\r
533 \r
534     /* Send the RM packet to the application transport */\r
535     if (rmInst->transport.rmSend((Rm_TransportHandle) dstTransportNode, rmPkt) < RM_TRANSPORT_SUCCESSFUL)\r
536     {\r
537         /* Negative value returned by transport send.  An error occurred\r
538          * in the transport while attempting to send the packet.*/\r
539         receipt->serviceResult = RM_SERVICE_ERROR_TRANPSPORT_SEND_ERROR;\r
540         /* Clean up the packet */\r
541         if (rmInst->transport.rmFreePkt((Rm_TransportHandle) dstTransportNode, rmPkt))\r
542         {\r
543             /* Non-NULL value returned by transport packet free. Flag the\r
544              * error */\r
545              receipt->serviceResult = RM_SERVICE_ERROR_TRANSPORT_FREE_PKT_ERROR;\r
546         }\r
547         return;\r
548     }\r
549 \r
550     /* Inform requesting component that the service is being forwarded to a higher lever\r
551      * RM agent for processing.  The result of the service will be provided to the \r
552      * component via the specified callback function */\r
553     receipt->serviceResult = RM_SERVICE_PROCESSING;\r
554     receipt->serviceId = transaction->id;\r
555 }\r
556 \r
557 void Rm_transactionProcessor (Rm_Inst *rmInst, Rm_Transaction *transaction, \r
558                               Rm_TransactionReceipt *receipt)\r
559 {\r
560     Rm_Transaction *queuedTransaction = NULL;\r
561 \r
562     /* Handle auto-forwarded transactions.  These transactions include:\r
563      * - All request transactions received on Clients are forwarded to the Client Delegate\r
564      * - NameServer requests received on the Client Delegate are forwarded to the Server */\r
565     if ((rmInst->instType == Rm_instType_CLIENT) ||\r
566         ((rmInst->instType == Rm_instType_CLIENT_DELEGATE) &&\r
567          (transaction->type == Rm_service_RESOURCE_MAP_TO_NAME) ||\r
568          (transaction->type == Rm_service_RESOURCE_UNMAP_NAME)))\r
569     {\r
570         /* Check if the new transaction's ID matches any transactions waiting for\r
571          * responses.  A transaction received as a response will have an ID that \r
572          * matches the transaction that originated the request packet */\r
573         if (queuedTransaction = Rm_transactionQueueFind(rmInst, transaction->id))\r
574         {\r
575             if (queuedTransaction->state == Rm_transactionState_AWAITING_RESPONSE)\r
576             {\r
577                 if (rmInst->instType == Rm_instType_CLIENT)\r
578                 {\r
579                     /* Client found a transaction awaiting a response.  Pass both transactions\r
580                      * to the service responder for response processing */\r
581                     Rm_serviceResponder(rmInst, transaction, queuedTransaction, receipt);\r
582                 }\r
583                 else if (rmInst->instType == Rm_instType_CLIENT_DELEGATE)\r
584                 {\r
585                     /* Client Delegate found a NameServer transaction awaiting a response. Send the \r
586                      * response to either the transaction or service responder based on the \r
587                      * source instance */\r
588                     if (strcmp(queuedTransaction->sourceInstName, rmInst->name))\r
589                     {\r
590                         /* NameServer transaction originated from another instance.  Use the \r
591                          * transaction responder to send the NameServer result to the source instance.\r
592                          * Need to transfer the NameServer result details to the request transaction \r
593                          * which will be reused for the response. */\r
594                         queuedTransaction->details = transaction->details;\r
595                         Rm_transactionResponder(rmInst, queuedTransaction, receipt);\r
596                         /* Delete the response transaction */\r
597                         Rm_transactionQueueDelete(rmInst, transaction->id);                        \r
598                     }\r
599                     else\r
600                     {\r
601                         /* NameServer request originated on the Client Delegate instance.  Send to the\r
602                          * service responder */\r
603                         Rm_serviceResponder(rmInst, transaction, queuedTransaction,\r
604                                             receipt);\r
605                     }\r
606                 }\r
607             }\r
608             else\r
609             {\r
610                 /* Request transaction was not in the awaiting response state.  Flag the\r
611                  * error in the receipt and return */\r
612                 receipt->serviceResult = RM_SERVICE_ERROR_INVALID_REQUEST_TRANSACTION_STATE_UPON_RESPONSE;\r
613             }\r
614         }\r
615         else\r
616         {\r
617             /* This is a new transaction.  Make sure the transaction is not a \r
618              * response transaction sent to the wrong RM instance */\r
619             if ((transaction->state == Rm_transactionState_RESOURCE_APPROVED) ||\r
620                 (transaction->state == Rm_transactionState_RESOURCE_DENIED))\r
621             {\r
622                 /* No matching request transaction.  This transaction result was sent to the\r
623                  * wrong RM instance.  Flag the error in the receipt and return */\r
624                 receipt->serviceResult = RM_SERVICE_ERROR_INVALID_TRANSACTION_RECEIVED_ON_CLIENT;\r
625             }\r
626             else\r
627             {\r
628                 /* All service requests on Clients are forwarded to the higher level RM Client \r
629                  * Delegate.  NameServer requests on Client Delegates are forwarded to the Server. */\r
630                 Rm_transactionForwarder(rmInst, transaction, receipt);\r
631             }\r
632         }\r
633     }\r
634     else\r
635     {\r
636         /* Client Delegate and Server transaction processors. */\r
637         switch (transaction->type)\r
638         {\r
639             case Rm_service_RESOURCE_ALLOCATE:\r
640             case Rm_service_RESOURCE_BLOCK_ALLOCATE:\r
641             case Rm_service_RESOURCE_ALLOCATE_BY_NAME:\r
642                 /* Run the transaction through the response handler to take care of any\r
643                  * transactions that are responses to sent allocation requests. */\r
644                 if (queuedTransaction = Rm_transactionQueueFind(rmInst, transaction->id))\r
645                 {\r
646                     if (queuedTransaction->state == Rm_transactionState_AWAITING_RESPONSE)\r
647                     {\r
648                         /* If source instance name does not match the current instance\r
649                          * name the allocation request came from a client.  The result\r
650                          * must be sent back to the Client */\r
651                         if (strcmp(queuedTransaction->sourceInstName, rmInst->name))\r
652                         {\r
653                             /* Names don't match.  Copy the allocation response resource data \r
654                              * into the original transaction and send it back to the Client */\r
655                             queuedTransaction->details = transaction->details;\r
656                             memcpy ((void *)&(queuedTransaction->resourceInfo), \r
657                                     (void *)&(transaction->resourceInfo), sizeof(Rm_ResourceInfo));\r
658                             Rm_transactionResponder(rmInst, queuedTransaction, receipt);\r
659                             /* Delete the response transaction */\r
660                             Rm_transactionQueueDelete(rmInst, transaction->id);\r
661                         }\r
662                         else\r
663                         {\r
664                             /* Resource allocation request originated locally on Client Delegate\r
665                              * instance. Send the response via the service responder. */\r
666                             Rm_serviceResponder(rmInst, transaction, queuedTransaction,\r
667                                                 receipt);                            \r
668                         }\r
669                     }\r
670                     else\r
671                     {\r
672                         /* Request transaction was not in the awaiting response state.  Flag the\r
673                          * error in the receipt and return */\r
674                         receipt->serviceResult = RM_SERVICE_ERROR_INVALID_REQUEST_TRANSACTION_STATE_UPON_RESPONSE;\r
675                     }\r
676 \r
677                 }\r
678                 else\r
679                 {\r
680                     /* This is a new transaction request originating from an RM instance with fewer\r
681                      * allocate/free privileges.  Run the allocation handler to see if the resource\r
682                      * request can be handled locally or if it needs to be forwarded to a higher level\r
683                      * agent */\r
684                      Rm_allocationHandler(rmInst, transaction, receipt);\r
685                 }\r
686                 break;\r
687             case Rm_service_RESOURCE_FREE:\r
688             case Rm_service_RESOURCE_BLOCK_FREE:\r
689             case Rm_service_RESOURCE_FREE_BY_NAME:\r
690                 /* Run the transaction through the response handler to take care of any\r
691                  * transactions that are responses to sent free requests. */\r
692                 if (queuedTransaction = Rm_transactionQueueFind(rmInst, transaction->id))\r
693                 {\r
694                     if (queuedTransaction->state == Rm_transactionState_AWAITING_RESPONSE)\r
695                     {\r
696                         /* If source instance name does not match the current instance\r
697                          * name the allocation request came from a client.  The result\r
698                          * must be sent back to the Client */\r
699                         if (strcmp(queuedTransaction->sourceInstName, rmInst->name))\r
700                         {\r
701                             /* Names don't match.  Copy the free response resource data \r
702                              * into the original transaction and send it back to the Client */\r
703                             queuedTransaction->details = transaction->details;\r
704                             memcpy ((void *)&(queuedTransaction->resourceInfo), \r
705                                     (void *)&(transaction->resourceInfo), sizeof(Rm_ResourceInfo));\r
706                             Rm_transactionResponder(rmInst, queuedTransaction, receipt);\r
707                             /* Delete the response transaction */\r
708                             Rm_transactionQueueDelete(rmInst, transaction->id);\r
709                         }\r
710                         else\r
711                         {\r
712                             /* Resource free request originated locally on Client Delegate\r
713                              * instance. Send the response via the service responder. */\r
714                             Rm_serviceResponder(rmInst, transaction, queuedTransaction,\r
715                                                 receipt);                            \r
716                         }\r
717                     }\r
718                     else\r
719                     {\r
720                         /* Request transaction was not in the awaiting response state.  Flag the\r
721                          * error in the receipt and return */\r
722                         receipt->serviceResult = RM_SERVICE_ERROR_INVALID_REQUEST_TRANSACTION_STATE_UPON_RESPONSE;\r
723                     }\r
724 \r
725                 }\r
726                 else\r
727                 {\r
728                     /* This is a new transaction request originating from an RM instance with fewer\r
729                      * allocate/free privileges.  Run the free handler to see if the resource\r
730                      * request can be handled locally or if it needs to be forwarded to a higher level\r
731                      * agent */\r
732                      Rm_freeHandler(rmInst, transaction, receipt);\r
733                 }\r
734 \r
735                 break;\r
736             case Rm_service_RESOURCE_MAP_TO_NAME:\r
737                 /* Server is the only RM instance capable of adding NameServer objects */\r
738                 if (rmInst->instType == Rm_instType_SERVER)\r
739                 {\r
740                     /* Create a new NameServer object with the request transaction information */\r
741                     Rm_nsAddObject(rmInst, transaction, receipt);\r
742 \r
743                     /* Return the result of the NameServer addition to the RM instance\r
744                      * that requested it */\r
745                     transaction->details = receipt->serviceResult;\r
746 \r
747                     /* If source instance name does not match the current instance\r
748                      * name the NameServer request came from a Client or Client Delegate.  The \r
749                      * result must be sent back to the Client or Client Delegate */\r
750                     if (strcmp(transaction->sourceInstName, rmInst->name))\r
751                     {\r
752                         Rm_transactionResponder(rmInst, queuedTransaction, receipt);\r
753                     }\r
754                     else\r
755                     {\r
756                         /* NameServer addition request originated locally on Server\r
757                          * instance. Send the response via the service responder.  In this case\r
758                          * the request transaction will be passed as NULL since the request\r
759                          * is being reused as the response */\r
760                         Rm_serviceResponder(rmInst, transaction, NULL, receipt);                            \r
761                     }\r
762                 }\r
763                 else\r
764                 {\r
765                     receipt->serviceResult = RM_SERVICE_ERROR_NAMESERVER_OBJECT_CREATE_ON_INVALID_INSTANCE;\r
766                 }\r
767                 break;\r
768             case Rm_service_RESOURCE_UNMAP_NAME:\r
769                 /* Server is the only RM instance capable of deleting NameServer objects */\r
770                 if (rmInst->instType == Rm_instType_SERVER)\r
771                 {\r
772                     /* Delete an existing NameServer object with the request transaction information */\r
773                     Rm_nsDeleteObject(rmInst, transaction, receipt);\r
774 \r
775                     /* Return the result of the NameServer deletion to the RM instance\r
776                      * that requested it */\r
777                     transaction->details = receipt->serviceResult;\r
778 \r
779                     /* If source instance name does not match the current instance\r
780                      * name the NameServer request came from a Client or Client Delegate.  The \r
781                      * result must be sent back to the Client or Client Delegate */\r
782                     if (strcmp(transaction->sourceInstName, rmInst->name))\r
783                     {\r
784                         Rm_transactionResponder(rmInst, queuedTransaction, receipt);\r
785                     }\r
786                     else\r
787                     {\r
788                         /* NameServer delete request originated locally on Server\r
789                          * instance. Send the response via the service responder.  In this case\r
790                          * the request transaction will be passed as NULL since the request\r
791                          * is being reused as the response */\r
792                         Rm_serviceResponder(rmInst, transaction, NULL, receipt);                            \r
793                     }                    \r
794                 }\r
795                 else\r
796                 {\r
797                     receipt->serviceResult = RM_SERVICE_ERROR_NAMESERVER_OBJECT_DELETE_ON_INVALID_INSTANCE;\r
798                 }\r
799                 break;\r
800         }\r
801     }\r
802 }\r
803 \r
804 /**********************************************************************\r
805  ********************** Application visible APIs **********************\r
806  **********************************************************************/\r
807 \r
808 Rm_Handle Rm_init(Rm_InitCfg *initCfg)\r
809 {\r
810     Rm_Inst *rmInst;\r
811 \r
812     /* Instance creation checks.  Add one to strlen calculation for null character */\r
813     if ((strlen(initCfg->instName) + 1) > RM_INSTANCE_NAME_MAX_CHARS)\r
814     {\r
815         /* Failure: Instance name is too big */\r
816         return (NULL);\r
817     }\r
818     \r
819     /* Get memory for RM instance from local memory */\r
820     rmInst = Rm_osalMalloc (sizeof(Rm_Inst), false);\r
821     /* Populate instance based on input parameters */\r
822     strcpy (&rmInst->name[0], initCfg->instName);\r
823     rmInst->instType = initCfg->instType;\r
824     rmInst->registeredWithDelegateOrServer = false;\r
825 \r
826     /* Initialize the transport routing map linked list pointer to NULL.  The linked list\r
827      * nodes will be created when the application registers transports */\r
828     rmInst->routeMap = NULL;\r
829 \r
830     /* Initialize the transaction queue elements. */\r
831     rmInst->transactionSeqNum = Rm_transactionInitSequenceNum();\r
832     rmInst->transactionQueue= NULL;\r
833 \r
834     /* RM Server specific actions */\r
835     if (rmInst->instType == Rm_instType_SERVER)\r
836     {\r
837        /* parse DTB, etc */\r
838     }\r
839 \r
840     /* Instance startup policies are only used for Servers and Client Delegates */\r
841     if (rmInst->instType != Rm_instType_CLIENT)\r
842     {\r
843         rmInst->instPolicy = initCfg->startupPolicy;\r
844 \r
845         /* Store policy via policy APIs ... */\r
846     }\r
847 \r
848     /* Return the RM Handle */\r
849     return ((Rm_Handle) rmInst);\r
850 }\r
851 \r
852 uint32_t Rm_getVersion (void)\r
853 {\r
854     return RM_VERSION_ID;\r
855 }\r
856 \r
857 \r
858 const char* Rm_getVersionStr (void)\r
859 {\r
860     return rmVersionStr;\r
861 }\r
862 \r
863 /**\r
864 @}\r
865 */\r