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