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 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 #include <ti/drv/rm/include/rm_pvt.h>\r
51 \r
52 /* RM OSAL layer */\r
53 #include <rm_osal.h>\r
54 \r
55 /**********************************************************************\r
56 ************************** Globals ***********************************\r
57 **********************************************************************/\r
58 \r
59 /* Place QMSS PDSP permissions array */\r
60 #pragma DATA_SECTION (rmQmssPdspFirmwarePerms, ".rm");\r
61 #pragma DATA_ALIGN (rmQmssPdspFirmwarePerms, 128)\r
62 Rm_Perms rmQmssPdspFirmwarePerms[RM_ALIGN_PERMISSIONS_ARRAY(RM_QMSS_FIRMWARE_PDSPS, Rm_Perms)];\r
63 \r
64 \r
65 /** @brief Global Variable which describes the RM Version Information */\r
66 const char rmVersionStr[] = RM_VERSION_STR ":" __DATE__ ":" __TIME__;\r
67 \r
68 /**********************************************************************\r
69 ********************** Internal Functions ****************************\r
70 **********************************************************************/\r
71 \r
72 void Rm_transactionQueueAdd(Rm_Inst *rmInst, uint32_t transactionId, \r
73 Rm_TransportHandle transportHandle, void *callbackFunc)\r
74 {\r
75 Rm_TransactionQueueEntry *transactionQueue = (Rm_TransactionQueueEntry *) rmInst->transactionQueue;\r
76 Rm_TransactionQueueEntry *newEntry;\r
77 void *key;\r
78 \r
79 /* Lock access to the RM instance's transaction queue */\r
80 key = Rm_osalLocalCsEnter();\r
81 \r
82 /* Get memory for a new transaction queue entry from local memory */\r
83 newEntry = Rm_osalMalloc (sizeof(Rm_TransactionQueueNode), false);\r
84 \r
85 /* Populate the new entry. */\r
86 newEntry->transactionId = transactionId;\r
87 newEntry->transportHandle = transportHandle;\r
88 newEntry->transactionCallback = callbackFunc;\r
89 newEntry->nextEntry = NULL; /* New entry's nextEntry pointer will always be NULL */\r
90 \r
91 /* Check if there are any entries in the transaction queue */\r
92 if (transactionQueue)\r
93 {\r
94 /* At least one entry in the transaction queue. Add the new entry to the end of the\r
95 * transaction queue */\r
96 while (transactionQueue->nextEntry != NULL)\r
97 {\r
98 /* Traverse the list until arriving at the last entry */\r
99 transactionQueue = transactionQueue->nextEntry;\r
100 }\r
101 \r
102 /* Add the new entry to the end of the queue */\r
103 transactionQueue->nextEntry = newEntry;\r
104 }\r
105 else\r
106 {\r
107 /* The transaction queue does not currently exist. The new entry is the first entry */\r
108 rmInst->routeMap = newEntry;\r
109 }\r
110 \r
111 Rm_osalLocalCsExit(key);\r
112 }\r
113 \r
114 Rm_TransactionQueueEntry *Rm_transactionQueueFind(Rm_Inst *rmInst, uint32_t transactionId)\r
115 {\r
116 Rm_TransactionQueueEntry *entry = (Rm_TransactionQueueEntry *) rmInst->transactionQueue;\r
117 void *key;\r
118 \r
119 /* Lock access to the RM instance's transaction queue */\r
120 key = Rm_osalLocalCsEnter();\r
121 \r
122 /* Make sure there is at least one entry in the transaction queue */\r
123 if (entry != NULL)\r
124 {\r
125 /* Find the transaction ID within the specified RM instance's transaction queue.\r
126 * If the end of the transaction queue is reached without finding the entry the \r
127 * entry pointer will be NULL */\r
128 while (entry != NULL)\r
129 {\r
130 if (entry->transactionId == transactionId)\r
131 {\r
132 /* Match: break out of loop and return the entry */\r
133 break; \r
134 }\r
135 entry = entry->nextEntry;\r
136 }\r
137 }\r
138 \r
139 Rm_osalLocalCsExit(key);\r
140 return (entry);\r
141 }\r
142 \r
143 uint32_t Rm_transactionQueueDelete(Rm_Inst *rmInst, uint32_t transactionId)\r
144 {\r
145 Rm_TransactionQueueEntry *currentEntry = (Rm_TransactionQueueEntry *) rmInst->transactionQueue;\r
146 Rm_TransactionQueueEntry *prevEntry = NULL;\r
147 void *key;\r
148 \r
149 /* Lock access to the RM instance's transaction queue */\r
150 key = Rm_osalLocalCsEnter();\r
151 \r
152 /* Make sure there is at least one entry in the transaction queue */\r
153 if (currentEntry == NULL)\r
154 {\r
155 Rm_osalLocalCsExit(key);\r
156 return (-1); /* TEMP ERROR RETURN */\r
157 }\r
158 \r
159 /* Find the transaction ID within the specified RM instance's transaction queue. */\r
160 while (currentEntry != NULL)\r
161 {\r
162 if (currentEntry->transactionId == transactionId)\r
163 {\r
164 /* Match: break out of loop and delete the entry */\r
165 break; \r
166 }\r
167 \r
168 prevEntry = currentEntry;\r
169 currentEntry = currentEntry->nextEntry;\r
170 }\r
171 \r
172 /* Traversed entire queue but did not find transaction */\r
173 if (currentEntry == NULL)\r
174 {\r
175 Rm_osalLocalCsExit(key);\r
176 return (-2); /* TEMP ERROR RETURN */\r
177 }\r
178 else\r
179 {\r
180 /* Delete the transaction queue entry */\r
181 if ((prevEntry == NULL) && currentEntry->nextEntry)\r
182 {\r
183 /* Entry to be deleted exists at start of transaction queue. Map second\r
184 * entry to be start of transaction queue as long as there are more than\r
185 * one entries */\r
186 rmInst->transactionQueue = currentEntry->nextNode;\r
187 }\r
188 else\r
189 {\r
190 /* Entry to be deleted is in the middle or at end of the queue. Adjust adjacent\r
191 * entry pointers. This covers the case where the entry to be removed is at the\r
192 * end of the queue. */\r
193 prevEntry->nextNode = currentEntry->nextNode;\r
194 }\r
195 \r
196 /* Delete the node, free the memory associated with the node. */\r
197 Rm_osalFree((void *) currentEntry, sizeof(Rm_TransactionQueueEntry), false);\r
198 }\r
199 \r
200 Rm_osalLocalCsExit(key);\r
201 return (0); /* RETURN OKAY - FIX MAGIC NUMBER */\r
202 }\r
203 \r
204 /* Used in Client Delegate case where it forwarded requests from Client to Server\r
205 * callback will direct to internal function that forwards response from server back\r
206 * to client */\r
207 void Rm_internalCallback (Rm_ServiceRespInfo *responseInfo)\r
208 {\r
209 \r
210 }\r
211 \r
212 /* Function used to send RM response transactions to lower level agents */\r
213 void Rm_transactionResponder (Rm_Inst *rmInst, Rm_Transaction *transaction,\r
214 Rm_TransactionReceipt *receipt)\r
215 {\r
216 Rm_TransactionQueueEntry *transactionEntry;\r
217 Rm_Packet *rmPkt = NULL;\r
218 Rm_ProtocolPkt *rmProtPkt = NULL;\r
219 \r
220 /* Find the transaction request that matches the received response */\r
221 transactionEntry = Rm_transactionQueueFind(rmInst,transaction->pktId);\r
222 \r
223 if (transactionEntry == NULL)\r
224 {\r
225 /* No transaction request matching the transaction ID was forwarded from\r
226 * this RM instace */\r
227 receipt->transactionResult = RM_SERVICE_ERROR_TRANSACTION_DOES_NOT_EXST_FOR_THIS_RM_INSTANCE;\r
228 return;\r
229 }\r
230 \r
231 /* Create a RM packet using the transaction information */\r
232 if (rmInst->transport.rmAllocPkt)\r
233 {\r
234 rmPkt = rmInst->transport.rmAllocPkt(transactionEntry->transportHandle, sizeof(Rm_Packet));\r
235 }\r
236 else\r
237 {\r
238 /* The transport packet alloc API is not plugged */\r
239 receipt->transactionResult = RM_SERVICE_ERROR_TRANSPORT_PKT_ALLOC_API_NULL;\r
240 return;\r
241 }\r
242 \r
243 /* Make sure a buffer for the packet was allocated */\r
244 if (rmPkt == NULL)\r
245 {\r
246 receipt->transactionResult = RM_SERVICE_ERROR_TRANSPORT_NULL_PKT_BUF;\r
247 return;\r
248 }\r
249 \r
250 /* Make sure allocated buffer is large enough to fit the protocol packet plus the \r
251 * rmPktLen field */\r
252 if (rmPkt->rmPktLen < (sizeof(Rm_ProtocolPkt) + sizeof(uint32_t))\r
253 { \r
254 receipt->transactionResult = RM_SERVICE_ERROR_TRANSPORT_PKT_BUF_TOO_SMALL;\r
255 return;\r
256 }\r
257 \r
258 \r
259 /* Initialize the rmPkt. Do not assume the transport code will do it */ \r
260 memset((void *)rmPkt, 0, sizeof(Rm_Packet));\r
261 \r
262 /* Assign the rmData field to be the rmProtPkt */\r
263 rmProtPkt = &(rmPkt->rmData[0]);\r
264 \r
265 /* Populate the response packet with the transaction response details for\r
266 * the lower leverl RM instance */\r
267 rmProtPkt->rmPktId = transactionEntry->transactionId;\r
268 strcpy((void *)rmProtPkt->rmInstName,(void *)rmInst->name);\r
269 rmProtPkt->rmCmd = (uint32_t) transaction->command;\r
270 rmProtPkt->rmDetails = transaction->details;\r
271 if (transaction->command == Rm_command_POLICY_RESPONSE)\r
272 {\r
273 /* Copy the policy data if the transaction is policy based */\r
274 memcpy ((void *)rmProtPkt->u.rmPolicyData, (void *)transaction->u.policyData,\r
275 RM_MAX_POLICY_SIZE_BYTES);\r
276 }\r
277 else\r
278 {\r
279 /* Otherwise copy the resource data */\r
280 memcpy ((void *)&(rmProtPkt->u.resInfo), (void *) &(transaction->u.resourceInfo),\r
281 sizeof(Rm_ResourceInfo));\r
282 }\r
283 \r
284 /* Send the RM packet to the application transport */\r
285 if (rmInst->transport.rmSend)\r
286 {\r
287 if (!(rmInst->transport.rmSend(transactionEntry->transportHandle, rmPkt))\r
288 {\r
289 /* Transport returned an error */\r
290 \r
291 /* SHOULD TRANSPORT ERROR SOMEHOW BE OR'D WITH THE SERVICE ERROR ??? */\r
292 receipt->transactionResult = RM_SERVICE_ERROR_TRANPSPORT_SEND_ERROR;\r
293 return;\r
294 }\r
295 }\r
296 else\r
297 {\r
298 /* The transport packet send API is not plugged */\r
299 receipt->transactionResult = RM_SERVICE_ERROR_TRANSPORT_PKT_SEND_API_NULL;\r
300 return;\r
301 } \r
302 \r
303 receipt->transactionResult = RM_RESPONSE_PACKET_SENT;\r
304 \r
305 /* Delete the transaction entry from the transaction queue */\r
306 Rm_transactionQueueDelete(rmInst,transaction->pktId);\r
307 \r
308 return;\r
309 }\r
310 \r
311 /* Function used to forward RM transactions to higher level agents */\r
312 void Rm_transactionForwarder (Rm_Inst *rmInst, Rm_Transaction *transaction,\r
313 Rm_TransactionReceipt *receipt)\r
314 {\r
315 Rm_TransRouteMapNode *routeMap = (Rm_TransRouteMapNode *) rmInst->routeMap;\r
316 uint32_t transactionId;\r
317 Rm_Packet *rmPkt = NULL;\r
318 Rm_ProtocolPkt *rmProtPkt = NULL;\r
319 \r
320 /* Make sure at least one transport has been registered */\r
321 if (routeMap == NULL)\r
322 {\r
323 receipt->transactionResult = RM_SERVICE_ERROR_NO_TRANSPORT_REGISTERED;\r
324 return;\r
325 }\r
326 \r
327 /* Make sure the RM instance has a transport registered with a higher level agent */\r
328 if (!rmInst->registeredWithDelegateOrServer)\r
329 {\r
330 receipt->transactionResult = RM_SERVICE_ERROR_NOT_REGISTERED_WITH_DEL_OR_SERVER;\r
331 return;\r
332 }\r
333 \r
334 /* Parse the RM instance's routing map to find the higher level agent for forwarding */\r
335 while ((routeMap->remoteInstType != Rm_instType_CLIENT_DELEGATE) || \r
336 (routeMap->remoteInstType != Rm_instType_SERVER))\r
337 {\r
338 /* Traverse the list until arriving at the upper level agent node */\r
339 routeMap = routeMap->nextNode;\r
340 }\r
341 \r
342 /* Create a RM packet using the service information */\r
343 if (rmInst->transport.rmAllocPkt)\r
344 {\r
345 rmPkt = rmInst->transport.rmAllocPkt(routeMap->transHandle, sizeof(Rm_Packet));\r
346 }\r
347 else\r
348 {\r
349 /* The transport packet alloc API is not plugged */\r
350 receipt->transactionResult = RM_SERVICE_ERROR_TRANSPORT_PKT_ALLOC_API_NULL;\r
351 return;\r
352 }\r
353 \r
354 /* Make sure a buffer for the packet was allocated */\r
355 if (rmPkt == NULL)\r
356 {\r
357 receipt->transactionResult = RM_SERVICE_ERROR_TRANSPORT_NULL_PKT_BUF;\r
358 return;\r
359 }\r
360 \r
361 /* Make sure allocated buffer is large enough to fit the protocol packet plus the \r
362 * rmPktLen field */\r
363 if (rmPkt->rmPktLen < (sizeof(Rm_ProtocolPkt) + sizeof(uint32_t))\r
364 { \r
365 receipt->transactionResult = RM_SERVICE_ERROR_TRANSPORT_PKT_BUF_TOO_SMALL;\r
366 return;\r
367 }\r
368 \r
369 /* Create an ID for this transaction. The ID will be used for two purposes:\r
370 * 1) Matching the response from the higher level RM agent to the request\r
371 * 2) Provided to the service requesting component so that it can match the\r
372 * service request with the response it receives via its callback function */\r
373 transactionId = ...; /* NEED SCHEME FOR CREATING A MUTUALLY EXCLUSIVE PKT ID. CAN'T\r
374 * CONFLICT WITH PCKT IDS CREATED ON OTHER RM INSTANCES */\r
375 /* Initialize the rmPkt. Do not assume the transport code will do it */ \r
376 memset((void *)rmPkt, 0, sizeof(Rm_Packet));\r
377 \r
378 /* Assign the rmData field to be the rmProtPkt */\r
379 rmProtPkt = &(rmPkt->rmData[0]);\r
380 /* Populate the RM packet using the service information */\r
381 rmProtPkt->rmPktId = transactionId;\r
382 strcpy((void *)rmProtPkt->rmInstName,(void *)rmInst->name);\r
383 rmProtPkt->rmCmd = (uint32_t) transaction->command;\r
384 if ((transaction->command == Rm_command_POLICY_REQUEST) ||\r
385 (transaction->command == Rm_command_POLICY_RESPONSE)\r
386 {\r
387 /* Copy the policy data if the transaction is policy based */\r
388 memcpy ((void *)rmProtPkt->u.rmPolicyData, (void *)transaction->u.policyData,\r
389 RM_MAX_POLICY_SIZE_BYTES);\r
390 }\r
391 else\r
392 {\r
393 /* Otherwise copy the resource data */\r
394 memcpy ((void *)&(rmProtPkt->u.resInfo), (void *) &(transaction->u.resourceInfo),\r
395 sizeof(Rm_ResourceInfo));\r
396 }\r
397 \r
398 /* Create an entry in the transaction queue */\r
399 Rm_transactionQueueAdd(rmInst, transactionId, transaction->callback);\r
400 \r
401 /* Send the RM packet to the application transport */\r
402 if (rmInst->transport.rmSend)\r
403 {\r
404 if (!(rmInst->transport.rmSend(routeMap->transHandle, rmPkt))\r
405 {\r
406 /* Transport returned an error */\r
407 \r
408 /* SHOULD TRANSPORT ERROR SOMEHOW BE OR'D WITH THE SERVICE ERROR ??? */\r
409 receipt->transactionResult = RM_SERVICE_ERROR_TRANPSPORT_SEND_ERROR;\r
410 return;\r
411 }\r
412 }\r
413 else\r
414 {\r
415 /* The transport packet send API is not plugged */\r
416 receipt->transactionResult = RM_SERVICE_ERROR_TRANSPORT_PKT_SEND_API_NULL;\r
417 return;\r
418 } \r
419 \r
420 /* Inform requesting component that the service is being forwarded to a higher lever\r
421 * RM agent for processing. The result of the service will be provided to the \r
422 * component via the specified callback function */\r
423 receipt->transactionResult = RM_SERVICE_PROCESSING;\r
424 receipt->transactionId = transactionId;\r
425 return;\r
426 }\r
427 \r
428 void Rm_transactionProcessor (Rm_Inst *rmInst, Rm_Transaction *transaction, \r
429 Rm_TransactionReceipt *receipt)\r
430 {\r
431 if (rmInst->instType == Rm_instType_CLIENT)\r
432 {\r
433 if (transaction->command == Rm_command_RESOURCE_RESPONSE)\r
434 {\r
435 /* Responses received by the Client must be issued back to the requesting\r
436 * component */\r
437 Rm_serviceResponder (rmInst, transaction, receipt);\r
438 }\r
439 else\r
440 {\r
441 /* All service requests on Clients are forwarded to the higher level RM agent\r
442 * either a Client Delegate or Server, based on the RM system architecture */\r
443 Rm_transactionForwarder(rmInst, transaction, receipt);\r
444 }\r
445 }\r
446 else\r
447 {\r
448 /* Execute a command processor based on the command type */\r
449 switch (transaction->transCommand)\r
450 {\r
451 case Rm_command_ALLOCATE:\r
452 case Rm_command_BLOCK_ALLOCATE:\r
453 case Rm_command_ALLOCATE_NAMED:\r
454 Rm_allocate(rmInst, transaction, receipt);\r
455 break;\r
456 case Rm_command_FREE:\r
457 case Rm_command_BLOCK_FREE:\r
458 case Rm_command_FREE_NAMED:\r
459 Rm_free(rmInst, transaction, receipt);\r
460 break;\r
461 case Rm_command_MAP_NAME:\r
462 Rm_nsAddObject(rmInst, transaction, receipt);\r
463 break;\r
464 case Rm_command_UNMAP_NAME:\r
465 Rm_nsDeleteObject(rmInst, transaction, receipt);\r
466 break;\r
467 case Rm_command_RESOURCE_STATUS:\r
468 Rm_getResourceStatus(rmInst, transaction, receipt);\r
469 break;\r
470 case Rm_command_RESOURCE_RESPONSE:\r
471 \r
472 break;\r
473 case Rm_command_POLICY_REQUEST:\r
474 break;\r
475 case Rm_command_POLICY_RESPONSE:\r
476 break;\r
477 }\r
478 \r
479 }\r
480 \r
481 }\r
482 \r
483 void Rm_serviceHandler (void *rmHandle, Rm_ServiceReqInfo *requestInfo,\r
484 Rm_ServiceRespInfo *responseInfo)\r
485 {\r
486 Rm_Inst *rmInst = (Rm_Inst *) rmHandle;\r
487 Rm_Transaction transaction;\r
488 Rm_TransactionReceipt receipt;\r
489 void *key;\r
490 \r
491 /* Prevent another component using the same instance from wiping out the current\r
492 * service request */\r
493 key = Rm_osalLocalCsEnter();\r
494 \r
495 /* Make sure serviceType is valid and that a callback function has been provided */\r
496 if ((requestInfo->serviceType < Rm_service_FIRST) || \r
497 (requestInfo->serviceType > Rm_service_LAST))\r
498 {\r
499 responseInfo->serviceResult = RM_SERVICE_ERROR_INVALID_SERVICE_TYPE;\r
500 Rm_osalLocalCsExit(key);\r
501 return;\r
502 }\r
503 else if (requestInfo->serviceCallback == NULL)\r
504 {\r
505 /* RM Client's and Client Delegate's use blocking transports to consult with a \r
506 * high-level RM agent prior to providing a response to the component. It is \r
507 * assumed the component's cannot block. Therefore, all responses must go\r
508 * through the callback function provided by the component. Return an error \r
509 * if the component does not provide a callback function. */\r
510 responseInfo->serviceResult = RM_SERVICE_ERROR_CALLBACK_NOT_PROVIDED;\r
511 Rm_osalLocalCsExit(key);\r
512 return;\r
513 }\r
514 \r
515 /* Clear the transaction and receipt prior to using them */\r
516 memset((void *) &transaction, 0, sizeof(Rm_Transaction));\r
517 memset((void *) &transactionReceipt, 0, sizeof(Rm_TransactionReceipt));\r
518 \r
519 /* Transfer request information into the internal transaction format */\r
520 transaction.command = (Rm_Command) requestInfo->serviceType;\r
521 transaction.callback = requestInfo->serviceCallback;\r
522 /* Policy modifications will never originate from components */\r
523 strcpy ((void *) &(transaction.u.resourceInfo.resName)[0], (void *)requestInfo->resName);\r
524 transaction.u.resourceInfo.resBase = requestInfo->resourceBase;\r
525 transaction.u.resourceInfo.resNum = requestInfo->resourceNum;\r
526 transaction.u.resourceInfo.resAlign = requestInfo->resourceAlign;\r
527 strcpy ((void *) &(transaction.u.resourceInfo.resNsName)[0], (void *)requestInfo->resNsName);\r
528 \r
529 /* Pass the new transaction to the transaction processor */\r
530 Rm_transactionProcessor (rmInst, &transaction, &receipt);\r
531 \r
532 /* Copy transaction receipt information into the response info fields for the \r
533 * component based on the result of the transaction. Denied service requests\r
534 * will have only a valid serviceResult field */\r
535 responseInfo->serviceResult = receipt->transactionResult;\r
536 if (responseInfo->serviceResult == RM_SERVICE_APPROVED)\r
537 {\r
538 /* Service was approved. The resource data should be passed back\r
539 * to the component */\r
540 responseInfo->resBase = receipt.resBase;\r
541 responseInfo->resNum = receipt.resNum;\r
542 }\r
543 else if (responseInfo->serviceResult == RM_SERVICE_PROCESSING)\r
544 {\r
545 /* The service is still being processed. Provide the transaction ID\r
546 * back to the component so that it can sort service responses received\r
547 * via the provided callback function */\r
548 responseInfo->requestId = receipt.transactionId;\r
549 }\r
550 \r
551 Rm_osalLocalCsExit(key);\r
552 \r
553 return;\r
554 }\r
555 \r
556 /* This function is executed when a RM instance receives a response to one of it's requests\r
557 * and the information in the request must be provided to the original requesting component */\r
558 void Rm_serviceResponder (Rm_Inst *rmInst, Rm_Transaction *transaction, \r
559 Rm_TransactionReceipt *receipt)\r
560 {\r
561 Rm_TransactionQueueEntry *transactionEntry;\r
562 Rm_ServiceRespInfo responseInfo;\r
563 \r
564 /* Find the transaction request that matches the received response */\r
565 transactionEntry = Rm_transactionQueueFind(rmInst,transaction->pktId);\r
566 \r
567 if (transactionEntry == NULL)\r
568 {\r
569 /* No transaction request matching the transaction ID was forwarded from\r
570 * this RM instace */\r
571 receipt->transactionResult = RM_SERVICE_ERROR_TRANSACTION_DOES_NOT_EXST_FOR_THIS_RM_INSTANCE;\r
572 return;\r
573 }\r
574 \r
575 /* Populate the service response with the transaction response details for\r
576 * the component */\r
577 responseInfo.requestId = transaction->pktId;\r
578 responseInfo.serviceResult = transaction->details;\r
579 responseInfo.resBase = transaction->u.resourceInfo.resBase;\r
580 responseInfo.resNum = transaction->u.resourceInfo.resNum;\r
581 \r
582 /* Issue the callback to the requesting component with the response information */\r
583 transactionEntry->transactionCallback(&responseInfo);\r
584 \r
585 /* Delete the transaction entry from the transaction queue */\r
586 Rm_transactionQueueDelete(rmInst,transaction->pktId);\r
587 \r
588 return;\r
589 }\r
590 \r
591 /**********************************************************************\r
592 *********************** Application visible APIs ***************************\r
593 **********************************************************************/\r
594 \r
595 Rm_Handle Rm_init(Rm_InitCfg *initCfg)\r
596 {\r
597 Rm_Inst *rmInst;\r
598 \r
599 /* Instance creation checks. Add one to strlen calculation for null character */\r
600 if ((strlen(initCfg->instName) + 1) > RM_INSTANCE_NAME_MAX_CHARS)\r
601 {\r
602 /* Failure: Instance name is too big */\r
603 return (NULL);\r
604 }\r
605 \r
606 /* Get memory for RM instance from local memory */\r
607 rmInst = Rm_osalMalloc (sizeof(Rm_Inst), false);\r
608 /* Populate instance based on input parameters */\r
609 strcpy (&rmInst->name[0], initCfg->instName);\r
610 rmInst->instType = initCfg->instType;\r
611 rmInst->instState = RM_state_IDLE;\r
612 rmInst->registeredWithDelegateOrServer = false;\r
613 rmInst->serviceCallback = NULL;\r
614 \r
615 /* Populate the instance transport callouts */\r
616 rmInst->transport.rmAllocPkt = initCfg->rmAllocPktFuncPtr;\r
617 rmInst->transport.rmFreePkt = initCfg->rmFreePktFuncPtr;\r
618 rmInst->transport.rmSend = initCfg->rmSendFuncPtr;\r
619 rmInst->transport.rmReceive = initCfg->rmReceiveFuncPtr;\r
620 rmInst->transport.rmNumPktsReceived = initCfg->rmNumPktsReceivedFuncPtr;\r
621 \r
622 /* Initialize the transport routing map linked list pointer to NULL. The linked list\r
623 * nodes will be created when the application registers transports */\r
624 rmInst->routeMap = NULL;\r
625 \r
626 /* Initialize the transaction queue linked list pointer to NULL. The linked list\r
627 * nodes will be created when the transactions are forwarded to higher level RM\r
628 * agents. */\r
629 rmInst->transactionQueue= NULL;\r
630 \r
631 /* RM Server specific actions */\r
632 if (rmInst->instType == Rm_instType_SERVER)\r
633 {\r
634 /* parse DTB, etc */\r
635 }\r
636 \r
637 /* Instance startup policies are only used for Servers and Client Delegates */\r
638 if (rmInst->instType != Rm_instType_CLIENT)\r
639 {\r
640 rmInst->instPolicy = initCfg->startupPolicy;\r
641 \r
642 /* Store policy via policy APIs ... */\r
643 }\r
644 \r
645 /* Return the RM Handle */\r
646 return ((Rm_Handle) rmInst);\r
647 }\r
648 \r
649 Rm_Result Rm_preMainAllocResource(Rm_PreMainAllocInfo *preMainAllocInfo)\r
650 {\r
651 \r
652 }\r
653 \r
654 Rm_ServiceHandle Rm_getServiceHandle(Rm_Handle rmHandle)\r
655 {\r
656 Rm_Inst *rmInst = (Rm_Inst *) rmHandle;\r
657 Rm_ServicesPort *newServicePort;\r
658 \r
659 /* Create a new service handle for the specified RM instance */\r
660 \r
661 /* Get memory for a new service port from local memory */\r
662 newServicePort = Rm_osalMalloc (sizeof(Rm_ServicesPort), false);\r
663 \r
664 newServicePort->rmHandle = rmHandle;\r
665 newServicePort->rmService = rmServiceHandler;\r
666 \r
667 return ((Rm_ServiceHandle) newServicePort);\r
668 }\r
669 \r
670 Rm_TransportHandle Rm_registerTransport (Rm_Handle rmHandle, Rm_TransCfg *transCfg)\r
671 {\r
672 Rm_Inst *rmInst = (Rm_Inst *) rmHandle;\r
673 Rm_TransRouteMapNode *existingRouteMap = (Rm_TransRouteMapNode *) rmInst->routeMap;\r
674 Rm_TransRouteMapNode *newRouteMapNode;\r
675 \r
676 /* RM Servers cannot connect to other Servers */\r
677 if ((rmInst->instType == Rm_instType_SERVER) &&\r
678 (transCfg->rmRemoteInstType == Rm_instType_SERVER))\r
679 {\r
680 return (NULL); /* Error -return null */\r
681 }\r
682 \r
683 /* Verify Clients and Client Delegates are not registering with more than one \r
684 * Client Delegate or Server. Assuming a Client Delegate can register with another \r
685 * Client Delegate that can "act" as a server */\r
686 if (((rmInst->instType == Rm_instType_CLIENT) || \r
687 (rmInst->instType == Rm_instType_CLIENT_DELEGATE)) &&\r
688 ((transCfg->rmRemoteInstType == Rm_instType_CLIENT_DELEGATE) ||\r
689 (transCfg->rmRemoteInstType == Rm_instType_SERVER)) &&\r
690 rmInst->registeredWithDelegateOrServer)\r
691 {\r
692 return (NULL); /* Error -return null */\r
693 } \r
694 \r
695 /* Error checks passed - Create a new transport handle for the specified RM instance */\r
696 \r
697 /* Get memory for a new routing map node from local memory */\r
698 newRouteMapNode = Rm_osalMalloc (sizeof(Rm_TransRouteMapNode), false);\r
699 \r
700 /* Populate the new node. The address of the node itself is stored since this address is returned\r
701 * to the application as the Rm_TransportHandle */\r
702 newRouteMapNode->transHandle = newRouteMapNode;\r
703 newRouteMapNode->remoteInstType = transCfg->rmRemoteInstType;\r
704 newRouteMapNode->nextNode = NULL; /* New node will always be NULL */\r
705 \r
706 /* Check if there are any entries in the routing map */\r
707 if (existingRouteMap)\r
708 {\r
709 /* At least one entry in the routing map. Add the new routing map node to the end of the\r
710 * routing map node list */\r
711 while (existingRouteMap->nextNode != NULL)\r
712 {\r
713 /* Traverse the list until arriving at the last node */\r
714 existingRouteMap = existingRouteMap->nextNode;\r
715 }\r
716 \r
717 /* Add the new node to the end of the list */\r
718 existingRouteMap->nextNode = newRouteMapNode;\r
719 }\r
720 else\r
721 {\r
722 /* A routing map does not currently exist. The new node is the first entry */\r
723 rmInst->routeMap = newRouteMapNode;\r
724 }\r
725 \r
726 /* Specify RM instance has registered with a higher level agent */\r
727 if ((newRouteMapNode->remoteInstType == Rm_instType_CLIENT_DELEGATE) ||\r
728 (newRouteMapNode->remoteInstType == Rm_instType_SERVER))\r
729 {\r
730 rmInst->registeredWithDelegateOrServer = true;\r
731 }\r
732 \r
733 return ((Rm_TransportHandle) newRouteMapNode);\r
734 }\r
735 \r
736 Rm_Result Rm_unregisterTransport (Rm_Handle rmHandle, Rm_TransportHandle transHandle)\r
737 {\r
738 Rm_Inst *rmInst = (Rm_Inst *) rmHandle;\r
739 Rm_TransRouteMapNode *routeMapNode = (Rm_TransRouteMapNode *) rmInst->routeMap;\r
740 Rm_TransRouteMapNode *prevNode = NULL;\r
741 \r
742 /* Make sure a routing map exists for the RM instance */\r
743 if (routeMapNode == NULL)\r
744 {\r
745 return (-1); /* TEMP ERROR RETURN */\r
746 }\r
747 \r
748 /* Find the transport handle within the specified RM instance's routing map. */\r
749 while (1)\r
750 {\r
751 if (routeMapNode->transHandle == transHandle)\r
752 {\r
753 /* Match: break out of loop and delete the node */\r
754 break; \r
755 }\r
756 else if (routeMapNode->nextNode == NULL)\r
757 {\r
758 return (-1); /* TEMP ERROR: transhandle does not exist for RM instance */\r
759 }\r
760 \r
761 prevNode = routeMapNode;\r
762 routeMapNode = routeMapNode->nextNode;\r
763 }\r
764 \r
765 /* Delete the routing map node */\r
766 if ((prevNode == NULL) && routeMapNode->nextNode)\r
767 {\r
768 /* Node to be deleted exists at start of route map. Map second node to be start of\r
769 * node list as long as there are more than one routing map nodes */\r
770 rmInst->routeMap = routeMapNode->nextNode;\r
771 }\r
772 else\r
773 {\r
774 /* Node to be deleted is in the middle or at end of the list. Adjust adjacent\r
775 * nodes pointers. This covers the case where the node to be removed is at the\r
776 * end of the list. */\r
777 prevNode->nextNode = routeMapNode->nextNode;\r
778 }\r
779 \r
780 /* Remove specification in RM instance that it has been connected to an upper level agent\r
781 * if the node to be deleted has a remote instance type of Client Delegate or Server */\r
782 if ((routeMapNode->remoteInstType == Rm_instType_CLIENT_DELEGATE) ||\r
783 (routeMapNode->remoteInstType == Rm_instType_SERVER))\r
784 {\r
785 rmInst->registeredWithDelegateOrServer = false;\r
786 }\r
787 \r
788 /* Delete the node, free the memory associated with the node. */\r
789 Rm_osalFree((void *) routeMapNode, sizeof(Rm_TransRouteMapNode), false);\r
790 \r
791 return (RM_OK);\r
792 }\r
793 \r
794 \r
795 Rm_TransVerifyResult Rm_verifyTransport (Rm_Handle rmHandle, uint32_t timeout, \r
796 Rm_TransFailData *failData)\r
797 {\r
798 \r
799 }\r
800 \r
801 /* Resource requests that come directly from application go through this API */\r
802 void Rm_requestService (void *rmHandle, Rm_ServiceReqInfo *requestInfo,\r
803 Rm_ServiceRespInfo *responseInfo)\r
804 {\r
805 Rm_serviceHandler(rmHandle, requestInfo, responseInfo);\r
806 }\r
807 \r
808 /* Used by the application to pass RM packets received from a transport to RM.\r
809 * CODE THE FUNCTION SUCH THAT IT CAN BE CALLED DIRECTLY BY APP OR BE PLUGGED\r
810 * AS PART OF AN ISR HANDLER FOR THE TRANSACTION RECEIVE */\r
811 Rm_Result Rm_receiveRmPkt(Rm_Handle rmHandle, Rm_TransportHandle transHandle, Rm_Packet *pkt)\r
813 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;\r
814 Rm_ProtocolPkt rmProtPkt = &(pkt->rmData)[0];\r
815 Rm_Transaction transaction;\r
816 Rm_TransactionReceipt receipt;\r
817 void *key;\r
818 \r
819 /* Lock access to the RM instance's transaction queue */\r
820 key = Rm_osalLocalCsEnter(); \r
821 \r
822 /* Initialize the transaction and receipt */\r
823 memset((void *)&transaction, 0, sizeof(Rm_Transaction));\r
824 memset((void *)&receipt, 0, sizeof(Rm_TransactionReceipt));\r
825 \r
826 /* Create a new transaction based on the packet details */\r
827 transaction.pktId = rmProtPkt->rmPktId;\r
828 transaction.command = (Rm_Command) rmProtPkt->rmCmd;\r
829 transaction.details = rmProtPkt->rmDetails;\r
830 transaction.receivedTransport = transHandle;\r
831 if ((transaction->command == Rm_command_POLICY_REQUEST) ||\r
832 (transaction->command == Rm_command_POLICY_RESPONSE)\r
833 {\r
834 /* Copy the policy data if the transaction is policy based */\r
835 memcpy ((void *)transInfo->u.policyData, (void *)rmProtPkt->u.rmPolicyData,\r
836 RM_MAX_POLICY_SIZE_BYTES);\r
837 }\r
838 else\r
839 {\r
840 /* Otherwise copy the resource data */\r
841 memcpy((void *)transaction.u.resourceInfo,(void *)rmProtPkt->u.resInfo, \r
842 sizeof(Rm_ResourceInfo));\r
843 }\r
844 \r
845 /* Process the transaction */\r
846 Rm_transactionProcessor(rmInst,&transaction,&receipt)\r
847 \r
848 /* IS RECEIPT DATA NEEDED FOR ANYTHING HERE??*/\r
849 \r
850 Rm_osalLocalCsExit(key);\r
851 return (0); \r
852 }\r
853 \r
854 /* Application can call this API so that RM handles reception of packets based on\r
855 * the RM handle and transport handle provided */\r
856 Rm_Result Rm_getRmPkt(Rm_Handle rmHandle, Rm_TransportHandle transHandle)\r
857 {\r
858 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;\r
859 Rm_TransRouteMapNode *transNode = rmInst->routeMap;\r
860 Rm_Packet *rmPkt = NULL;\r
861 Rm_Result retVal = 0;\r
862 void *key;\r
863 \r
864 /* Lock access to the RM instance's transaction queue */\r
865 key = Rm_osalLocalCsEnter(); \r
866 \r
867 /* Verify the transport handle is registered with the RM handle */\r
868 while (transNode != NULL)\r
869 {\r
870 if (transNode->transHandle == transHandle)\r
871 {\r
872 /* Break out of loop if an entry in the route map has been found */\r
873 break;\r
874 }\r
875 transNode = transNode->nextNode;\r
876 }\r
877 \r
878 if (transNode == NULL)\r
879 {\r
880 Rm_osalLocalCsExit(key);\r
881 return (-1) /* ERROR: THE TRANSPORT HANDLE IS NOT REGISTERED WITH THE RM HANDLE */\r
882 }\r
883 \r
884 /* Check to see if any RM packets are available. Process any available packets. */\r
885 while (rmInst->transport.rmNumPktsReceived(transHandle))\r
886 {\r
887 rmInst->transport.rmReceive(transHandle, rmPkt);\r
888 \r
889 if (rmPkt == NULL)\r
890 {\r
891 retVal = -1; /* ERROR - PACKET RECEIVED FROM TRANSPORT IS NULL */\r
892 }\r
893 \r
894 /* Pass the packet to RM */\r
895 retVal = Rm_receiveRmPkt(rmHandle, transHandle, rmPkt);\r
896 /* Delete the packet */\r
897 rmInst->transport.rmFreePkt(transHandle, rmPkt);\r
898 \r
899 if (retVal)\r
900 {\r
901 /* If retVal is not 0 (Okay) there was an error so break out of loop and return */\r
902 break;\r
903 }\r
904 }\r
905 \r
906 Rm_osalLocalCsExit(key);\r
907 return (retVal); \r
908 }\r
909 \r
910 uint32_t Rm_getVersion (void)\r
911 {\r
912 return RM_VERSION_ID;\r
913 }\r
914 \r
915 \r
916 const char* Rm_getVersionStr (void)\r
917 {\r
918 return rmVersionStr;\r
919 }\r
920 \r
921 /**\r
922 @}\r
923 */\r