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