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