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 #include <ti/drv/rm/include/rm_dtb_utilloc.h>\r
57 \r
58 /* RM LIBFDT includes */\r
59 #include <ti/drv/rm/src/libfdt/libfdt.h>\r
60 \r
61 /* RM OSAL layer */\r
62 #include <rm_osal.h>\r
63 \r
64 /**********************************************************************\r
65 ************************** Globals ***********************************\r
66 **********************************************************************/\r
67 #if 0\r
68 /* Place QMSS PDSP permissions array */\r
69 #pragma DATA_SECTION (rmQmssPdspFirmwarePerms, ".rm");\r
70 #pragma DATA_ALIGN (rmQmssPdspFirmwarePerms, 128)\r
71 Rm_Perms rmQmssPdspFirmwarePerms[RM_ALIGN_PERMISSIONS_ARRAY(RM_QMSS_FIRMWARE_PDSPS, Rm_Perms)];\r
72 #endif\r
73 \r
74 char rmIntegerAllocator[] = "integer";\r
75 char rmTreeAllocator[] = "tree";\r
76 \r
77 extern char rmDtbStartingNode[];\r
78 \r
79 /** @brief Global Variable which describes the RM Version Information */\r
80 const char rmVersionStr[] = RM_VERSION_STR ":" __DATE__ ":" __TIME__;\r
81 \r
82 /**********************************************************************\r
83 ********************** Internal Functions ****************************\r
84 **********************************************************************/\r
85 \r
86 Rm_Transaction *Rm_transactionQueueAdd(Rm_Inst *rmInst)\r
87 {\r
88 Rm_Transaction *transactionQueue = (Rm_Transaction *)rmInst->transactionQueue;\r
89 Rm_Transaction *newTransaction = NULL;\r
90 void *key;\r
91 \r
92 /* Lock access to the RM instance's transaction queue */\r
93 key = Rm_osalMtCsEnter();\r
94 \r
95 /* Get memory for a new transaction from local memory */\r
96 newTransaction = Rm_osalMalloc(sizeof(Rm_Transaction));\r
97 \r
98 /* Return if the memory allocated for the transaction entry is NULL */\r
99 if (newTransaction == NULL)\r
100 {\r
101 /* Clear the transaction */\r
102 memset((void *)newTransaction, 0, sizeof(Rm_Transaction));\r
103 \r
104 /* Create an ID for the new transaction. The ID will be used for two purposes:\r
105 * 1) Matching responses from higher level RM agents to requests\r
106 * 2) Provided to the component that requested the service so that it can match its\r
107 * request with the response it receives via its callback function it provided */\r
108 newTransaction->localId = Rm_transactionGetSequenceNum(rmInst);\r
109 /* New transaction's nextTransaction pointer will always be NULL */\r
110 newTransaction->nextTransaction = NULL; \r
111 \r
112 /* Check if there are any transactions in the transaction queue */\r
113 if (transactionQueue)\r
114 {\r
115 /* At least one transaction in the transaction queue. Add the new entry to the \r
116 * end of the transaction queue */\r
117 while (transactionQueue->nextTransaction != NULL)\r
118 {\r
119 /* Traverse the list until arriving at the last transaction */\r
120 transactionQueue = transactionQueue->nextTransaction;\r
121 }\r
122 \r
123 /* Add the new transaction to the end of the queue */\r
124 transactionQueue->nextTransaction = newTransaction;\r
125 }\r
126 else\r
127 {\r
128 /* The transaction queue does not currently exist. The new transaction is the \r
129 * first transaction */\r
130 rmInst->transactionQueue = newTransaction;\r
131 }\r
132 }\r
133 \r
134 Rm_osalMtCsExit(key);\r
135 return (newTransaction);\r
136 }\r
137 \r
138 Rm_Transaction *Rm_transactionQueueFind(Rm_Inst *rmInst, uint32_t transactionId)\r
139 {\r
140 Rm_Transaction *transaction = (Rm_Transaction *)rmInst->transactionQueue;\r
141 \r
142 /* Make sure there is at least one transaction in the transaction queue */\r
143 if (transaction != NULL)\r
144 {\r
145 /* Find the transaction ID within the specified RM instance's transaction queue.\r
146 * If the end of the transaction queue is reached without finding the transaction the \r
147 * transaction pointer will be NULL */\r
148 while (transaction != NULL)\r
149 {\r
150 if (transaction->localId == transactionId)\r
151 {\r
152 /* Match: break out of loop and return the transaction */\r
153 break; \r
154 }\r
155 transaction = transaction->nextTransaction;\r
156 }\r
157 }\r
158 \r
159 return (transaction);\r
160 }\r
161 \r
162 int32_t Rm_transactionQueueDelete(Rm_Inst *rmInst, uint32_t transactionId)\r
163 {\r
164 Rm_Transaction *transaction = (Rm_Transaction *) rmInst->transactionQueue;\r
165 Rm_Transaction *prevTransaction = NULL;\r
166 int32_t retVal = RM_SERVICE_STATE_OKAY;\r
167 void *key;\r
168 \r
169 /* Lock access to the RM instance's transaction queue */\r
170 key = Rm_osalMtCsEnter();\r
171 \r
172 /* Find the transaction ID within the specified RM instance's transaction queue. */\r
173 while (transaction != NULL)\r
174 {\r
175 if (transaction->localId == transactionId)\r
176 {\r
177 /* Match: break out of loop and delete the transaction */\r
178 break; \r
179 }\r
180 \r
181 prevTransaction = transaction;\r
182 transaction = transaction->nextTransaction;\r
183 }\r
184 \r
185 /* Traversed entire queue but did not find transaction */\r
186 if (transaction == NULL)\r
187 {\r
188 retVal = RM_SERVICE_ERROR_SERVICE_TRANSACTION_DOES_NOT_EXIST;\r
189 }\r
190 else\r
191 {\r
192 /* Delete the transaction */\r
193 if ((prevTransaction == NULL) && transaction->nextTransaction)\r
194 {\r
195 /* Transaction to be deleted exists at start of transaction queue. Map second\r
196 * transaction to be start of transaction queue as long as there are more than\r
197 * one transactions. */\r
198 rmInst->transactionQueue = transaction->nextTransaction;\r
199 }\r
200 else\r
201 {\r
202 /* Transaction to be deleted is in the middle or at end of the queue. Adjust \r
203 * adjacent transaction pointers. This covers the case where the transaction to be \r
204 * removed is at the end of the queue. */\r
205 prevTransaction->nextTransaction = transaction->nextTransaction;\r
206 }\r
207 \r
208 /* Free the memory associated with the transaction. */\r
209 Rm_osalFree((void *)transaction, sizeof(Rm_Transaction));\r
210 }\r
211 \r
212 Rm_osalMtCsExit(key);\r
213 return (retVal);\r
214 }\r
215 \r
216 uint32_t Rm_transactionInitSequenceNum(void)\r
217 {\r
218 /* Sequence number can never have a value of zero so that there are no conflicts\r
219 * with transactions that have a remoteOriginatingId of zero */\r
220 return (1);\r
221 }\r
222 \r
223 uint32_t Rm_transactionGetSequenceNum(Rm_Inst *rmInst)\r
224 {\r
225 uint32_t sequenceNum = 0;\r
226 \r
227 /* Get the next sequence number and then increment. If there's an overflow\r
228 * assign the initial value instead of incrementing. */\r
229 if (rmInst->transactionSeqNum + 1 < rmInst->transactionSeqNum)\r
230 {\r
231 /* Overflow */\r
232 sequenceNum = rmInst->transactionSeqNum;\r
233 rmInst->transactionSeqNum = Rm_transactionInitSequenceNum();\r
234 }\r
235 else\r
236 {\r
237 sequenceNum = rmInst->transactionSeqNum++;\r
238 } \r
239 \r
240 return (sequenceNum);\r
241 }\r
242 \r
243 /* Function used to send RM response transactions to lower level agents */\r
244 void Rm_transactionResponder (Rm_Inst *rmInst, Rm_Transaction *transaction)\r
245 {\r
246 Rm_TransportNode *dstTransportNode = NULL;\r
247 Rm_Packet *rmPkt = NULL;\r
248 \r
249 /* Find the transport for the RM instance that sent the request. */\r
250 dstTransportNode = Rm_transportNodeFindRemoteName(rmInst, transaction->sourceInstName);\r
251 \r
252 /* Create a RM packet using the service information */\r
253 switch (transaction->type)\r
254 {\r
255 case Rm_service_RESOURCE_ALLOCATE:\r
256 case Rm_service_RESOURCE_BLOCK_ALLOCATE:\r
257 case Rm_service_RESOURCE_ALLOCATE_BY_NAME:\r
258 case Rm_service_RESOURCE_FREE:\r
259 case Rm_service_RESOURCE_BLOCK_FREE:\r
260 case Rm_service_RESOURCE_FREE_BY_NAME:\r
261 rmPkt = Rm_transportCreateResourceResponsePkt(rmInst, dstTransportNode, \r
262 transaction);\r
263 break;\r
264 case Rm_service_RESOURCE_MAP_TO_NAME:\r
265 case Rm_service_RESOURCE_UNMAP_NAME:\r
266 rmPkt = Rm_transportCreateNsResponsePkt(rmInst, dstTransportNode,\r
267 transaction);\r
268 break;\r
269 default:\r
270 /* Invalid service type. Flag the error and return */\r
271 transaction->state = RM_SERVICE_ERROR_INVALID_SERVICE_TYPE;\r
272 break;\r
273 }\r
274 \r
275 if (transaction->state <= RM_SERVICE_ERROR_BASE)\r
276 {\r
277 /* Delete the transaction and return immediately because an error occurred \r
278 * allocating the packet */\r
279 Rm_transactionQueueDelete(rmInst, transaction->localId);\r
280 return;\r
281 }\r
282 \r
283 /* Send the RM packet to the application transport */\r
284 if (rmInst->transport.rmSend((Rm_TransportHandle) dstTransportNode, rmPkt) < RM_TRANSPORT_SUCCESSFUL)\r
285 {\r
286 /* Negative value returned by transport send. An error occurred\r
287 * in the transport while attempting to send the packet.*/\r
288 transaction->state = RM_SERVICE_ERROR_TRANPSPORT_SEND_ERROR;\r
289 /* Clean up the packet */\r
290 if (rmInst->transport.rmFreePkt((Rm_TransportHandle) dstTransportNode, rmPkt))\r
291 {\r
292 /* Non-NULL value returned by transport packet free. Flag the\r
293 * error */\r
294 transaction->state = RM_SERVICE_ERROR_TRANSPORT_FREE_PKT_ERROR;\r
295 }\r
296 return;\r
297 }\r
298 \r
299 /* NEED TO DO SOMETHING IF GET AN ERROR IN THE transaction->state FIELD. CREATE\r
300 * NEW TRANSACTION WITH DATA FROM ORIGINAL? THEN TRY TO SEND FAILED REQUEST BACK\r
301 * TO REQUESTER??? KEEP RETRYING SEND OF RESPONSE??? */\r
302 \r
303 /* Delete the transaction */\r
304 Rm_transactionQueueDelete(rmInst, transaction->localId);\r
305 }\r
306 \r
307 Rm_Allocator *Rm_allocatorAdd(Rm_Inst *rmInst, const char *resourceName, Rm_AllocatorType type)\r
308 {\r
309 Rm_Allocator *allocators = (Rm_Allocator *)rmInst->allocators;\r
310 Rm_Allocator *newAllocator = NULL;\r
311 void *key;\r
312 \r
313 /* Lock access to the RM instance's allocator list */\r
314 key = Rm_osalMtCsEnter();\r
315 \r
316 /* Get memory for a new allocator from local memory */\r
317 newAllocator = Rm_osalMalloc(sizeof(Rm_Allocator));\r
318 \r
319 /* Return if the memory allocated for the allocator is NULL */\r
320 if (newAllocator != NULL)\r
321 {\r
322 /* Clear the allocator */\r
323 memset((void *)newAllocator, 0, sizeof(Rm_Allocator));\r
324 \r
325 /* Populate the allocator */\r
326 newAllocator->type = type;\r
327 strcpy(newAllocator->resourceName, resourceName);\r
328 /* allocator's root entry will be created by the invoking function */\r
329 newAllocator->allocatorRootEntry = NULL;\r
330 /* New allocator's nextAllocator pointer will always be NULL */\r
331 newAllocator->nextAllocator = NULL; \r
332 \r
333 /* Check if there are any allocators in the allocator list */\r
334 if (allocators)\r
335 {\r
336 /* At least one allocator in the allocator list. Add the new allocator to the \r
337 * end of the allocator list */\r
338 while (allocators->nextAllocator != NULL)\r
339 {\r
340 /* Traverse the list until arriving at the last allocator */\r
341 allocators = allocators->nextAllocator;\r
342 }\r
343 \r
344 /* Add the new allocator to the end of the list */\r
345 allocators->nextAllocator = newAllocator;\r
346 }\r
347 else\r
348 {\r
349 /* The allocator list does not currently exist. The new allocator is the \r
350 * first allocator */\r
351 rmInst->allocators = newAllocator;\r
352 }\r
353 }\r
354 \r
355 Rm_osalMtCsExit(key);\r
356 return (newAllocator);\r
357 }\r
358 \r
359 int32_t Rm_allocatorDelete(Rm_Inst *rmInst, char *resourceName)\r
360 {\r
361 Rm_Allocator *allocator = (Rm_Allocator *) rmInst->allocators;\r
362 Rm_Allocator *prevAllocator = NULL;\r
363 int32_t retVal = RM_SERVICE_STATE_OKAY;\r
364 void *key;\r
365 \r
366 /* Lock access to the RM instance's allocator list */\r
367 key = Rm_osalMtCsEnter();\r
368 \r
369 /* Find the resource within the specified RM instance's allocator list. */\r
370 while (allocator != NULL)\r
371 {\r
372 if (strcmp(allocator->resourceName, resourceName) == 0)\r
373 {\r
374 /* Match: break out of loop and delete the transaction */\r
375 break; \r
376 }\r
377 \r
378 prevAllocator = allocator;\r
379 allocator = allocator->nextAllocator;\r
380 }\r
381 \r
382 /* Traversed entire list but did not find allocator. */\r
383 if (allocator == NULL)\r
384 {\r
385 retVal = -22; /* TEMP ERROR: Can't conflict with LIBFDT errors */\r
386 }\r
387 else\r
388 {\r
389 /* Delete the allocator */\r
390 if ((prevAllocator == NULL) && allocator->nextAllocator)\r
391 {\r
392 /* Allocator to be deleted exists at start of allocator list. Map second\r
393 * allocator to be start of allocator list as long as there are more than\r
394 * one allocators. */\r
395 rmInst->allocators = allocator->nextAllocator;\r
396 }\r
397 else\r
398 {\r
399 /* Allocator to be deleted is in the middle or at end of the list. Adjust \r
400 * adjacent allocator pointers. This covers the case where the allocator to be \r
401 * removed is at the end of the list. */\r
402 prevAllocator->nextAllocator = allocator->nextAllocator;\r
403 }\r
404 \r
405 /* Free the memory associated with the allocator. */\r
406 Rm_osalFree((void *)allocator, sizeof(Rm_Allocator));\r
407 }\r
408 \r
409 Rm_osalMtCsExit(key);\r
410 return (retVal);\r
411 }\r
412 \r
413 int32_t Rm_createIntegerAllocator(Rm_Inst *rmInst, const char *resourceName, Rm_ResourceRange *range)\r
414 {\r
415 Rm_Allocator *allocator = NULL;\r
416 Rm_ResourceRange *rangeBasePtr = range;\r
417 Rm_IntegerAllocatorRootEntry *intRootEntry = NULL;\r
418 uint16_t i, entryIndex;\r
419 \r
420 /* Create the new base integer allocator */\r
421 allocator = Rm_allocatorAdd(rmInst, resourceName, Rm_allocatorType_INTEGER);\r
422 \r
423 /* Construct the integer allocator root entry */\r
424 intRootEntry = Rm_osalMalloc(sizeof(Rm_IntegerAllocatorRootEntry));\r
425 intRootEntry->numResourceElements = 0;\r
426 \r
427 /* Get the number of entries to allocate based on the lengths in the ranges */\r
428 while (range != NULL)\r
429 {\r
430 intRootEntry->numResourceElements += range->length;\r
431 range = range->nextRange;\r
432 }\r
433 \r
434 /* Initialize the entries using the range information */\r
435 if (intRootEntry->numResourceElements)\r
436 {\r
437 intRootEntry->resourceArrayBase = Rm_osalMalloc(sizeof(Rm_IntegerEntry) * intRootEntry->numResourceElements);\r
438 memset((void *)intRootEntry->resourceArrayBase, 0, sizeof(Rm_IntegerEntry) * intRootEntry->numResourceElements);\r
439 \r
440 /* Reset the range pointer */\r
441 range = rangeBasePtr;\r
442 entryIndex = 0;\r
443 \r
444 while (range != NULL)\r
445 {\r
446 /* Initialize each entry */\r
447 for (i = range->base; i < (range->base + range->length); i++, entryIndex++)\r
448 {\r
449 intRootEntry->resourceArrayBase[entryIndex].value = i;\r
450 }\r
451 \r
452 range = range->nextRange;\r
453 }\r
454 \r
455 allocator->allocatorRootEntry = intRootEntry;\r
456 }\r
457 else\r
458 {\r
459 /* No resource entries were created. Free the memory associated with the\r
460 * allocator and the root entry */\r
461 Rm_osalFree((void *)intRootEntry, sizeof(Rm_IntegerAllocatorRootEntry));\r
462 Rm_allocatorDelete(rmInst, allocator->resourceName);\r
463 }\r
464 \r
465 return(0); /* TODO: FIX THIS RETURN */\r
466 }\r
467 \r
468 int32_t Rm_createAndInitAllocator(Rm_Inst *rmInst, const char *resourceName, \r
469 Rm_ResourceProperties *resourceProperties)\r
470 {\r
471 char *allocatorType = NULL;\r
472 Rm_ResourceRange *range = NULL;\r
473 Rm_ResourceRange *rangeBasePtr = NULL;\r
474 Rm_NsAssignment *nsAssignments = NULL;\r
475 Rm_NsAssignment *nsAssignmentBasePtr = NULL;\r
476 int32_t retVal = RM_DTB_UTIL_RESULT_OKAY;\r
477 \r
478 /* TODO: NEED CHECKS FOR VALIDITY OF ALL THE resourceProperties FIELDS */\r
479 \r
480 /* Extract the resource properties from the DTB */\r
481 allocatorType = Rm_resourceExtractResourceAllocator(resourceProperties->allocatorData, \r
482 resourceProperties->allocatorLen);\r
483 range = rangeBasePtr = Rm_resourceExtractResourceRange(resourceProperties->rangeData, \r
484 resourceProperties->rangeLen);\r
485 \r
486 /* Create an allocator based on the allocator type specified */\r
487 if (strcmp(allocatorType, &rmIntegerAllocator[0]) == 0)\r
488 {\r
489 /* Create an integer allocator using the resource properties */\r
490 retVal = Rm_createIntegerAllocator(rmInst, resourceName, range); \r
491 }\r
492 else if (strcmp(allocatorType, &rmTreeAllocator[0]) == 0)\r
493 {\r
494 /* Create a tree allocator using the resource properties */\r
495 }\r
496 else\r
497 {\r
498 /* Allocator type not recognized. Free the resource properties and return */\r
499 retVal = -21; /* TEMP ERROR: Can't conflict with LIBFDT errors */\r
500 }\r
501 \r
502 if (retVal >= RM_DTB_UTIL_RESULT_OKAY)\r
503 {\r
504 /* Create entries in the NameServer if any NameServer assignments were specified */\r
505 if (resourceProperties->nsAssignData && resourceProperties->nsAssignLen)\r
506 {\r
507 nsAssignments = Rm_resourceExtractNsAssignment(resourceProperties->nsAssignData, \r
508 resourceProperties->nsAssignLen);\r
509 \r
510 /* Cycle through the list of assignments and add them to the NameServer */\r
511 nsAssignmentBasePtr = nsAssignments;\r
512 while (nsAssignments)\r
513 {\r
514 /* TODO: RETURN IF ANY OF THE ADDS FAIL??? */\r
515 Rm_nsAddObject(rmInst, nsAssignments->nsName, nsAssignments->resourceValue);\r
516 nsAssignments = nsAssignments->nextNsAssignment;\r
517 }\r
518 /* Free the memory allocated for the NameServer assignments */\r
519 Rm_resourceFreeNsAssignmentList(nsAssignmentBasePtr);\r
520 }\r
521 }\r
522 \r
523 /* Free the memory allocated for the resource properties */\r
524 Rm_resourceFreeResourceAllocator(allocatorType);\r
525 Rm_resourceFreeResourceRange(rangeBasePtr);\r
526 \r
527 return(retVal);\r
528 }\r
529 \r
530 int32_t Rm_parseResourceProperty(void *globalResourceDtb, int32_t offset, Rm_ResourceProperties *propertyInfo)\r
531 {\r
532 int32_t propertyLen;\r
533 const char *propertyName;\r
534 const void *propertyData;\r
535 Rm_ResourcePropType propertyType;\r
536 int32_t retVal = RM_DTB_UTIL_RESULT_OKAY;\r
537 \r
538 /* Get the property data and store it in the corresponding propertyInfo field */\r
539 propertyData = fdt_getprop_by_offset(globalResourceDtb, offset, &propertyName, &propertyLen);\r
540 if (propertyData)\r
541 {\r
542 propertyType = Rm_resourceGetPropertyType(propertyName);\r
543 if (propertyType == Rm_resourcePropType_RESOURCE_ALLOCATOR)\r
544 {\r
545 if (propertyInfo->allocatorData || propertyInfo->allocatorLen)\r
546 {\r
547 /* The allocator fields have already been populated. Return an error.\r
548 * The resource list has specified a property field more than once\r
549 * for a resource node */\r
550 retVal = -17; /* TEMP ERROR: Can't conflict with LIBFDT errors */\r
551 }\r
552 else\r
553 {\r
554 propertyInfo->allocatorData = propertyData;\r
555 propertyInfo->allocatorLen = propertyLen;\r
556 }\r
557 }\r
558 else if (propertyType == Rm_resourcePropType_RESOURCE_RANGE)\r
559 {\r
560 if (propertyInfo->rangeData || propertyInfo->rangeLen)\r
561 {\r
562 /* The range fields have already been populated. Return an error.\r
563 * The resource list has specified a property field more than once\r
564 * for a resource node */\r
565 retVal = -18; /* TEMP ERROR: Can't conflict with LIBFDT errors */\r
566 }\r
567 else\r
568 {\r
569 propertyInfo->rangeData = propertyData;\r
570 propertyInfo->rangeLen = propertyLen;\r
571 }\r
572 }\r
573 else if (propertyType == Rm_resourcePropType_NSASSIGNMENT)\r
574 {\r
575 if (propertyInfo->nsAssignData || propertyInfo->nsAssignLen)\r
576 {\r
577 /* The nsAssign fields have already been populated. Return an error.\r
578 * The resource list has specified a property field more than once\r
579 * for a resource node */\r
580 retVal = -19; /* TEMP ERROR: Can't conflict with LIBFDT errors */\r
581 }\r
582 else\r
583 {\r
584 propertyInfo->nsAssignData = propertyData;\r
585 propertyInfo->nsAssignLen = propertyLen;\r
586 }\r
587 }\r
588 else\r
589 {\r
590 retVal = -20; /* TEMP ERROR: Can't conflict with LIBFDT errors */\r
591 }\r
592 }\r
593 else\r
594 {\r
595 retVal = -16; /* TEMP ERROR: Can't conflict with LIBFDT errors */\r
596 }\r
597 \r
598 /* Don't get anymore properties if error occurred */\r
599 if (retVal == RM_DTB_UTIL_RESULT_OKAY)\r
600 {\r
601 offset = fdt_next_property_offset(globalResourceDtb, offset);\r
602 if (offset >= 0)\r
603 {\r
604 retVal = Rm_parseResourceProperty(globalResourceDtb, offset, propertyInfo);\r
605 }\r
606 else if (offset != -FDT_ERR_NOTFOUND)\r
607 {\r
608 /* Error was returned by LIBFDT when parsing the properties */\r
609 retVal = offset;\r
610 }\r
611 }\r
612 \r
613 return (retVal);\r
614 }\r
615 \r
616 int32_t Rm_parseResourceNode(Rm_Inst *rmInst, void *globalResourceDtb, int32_t nodeOffset, int32_t depth)\r
617 {\r
618 const char *resourceName = fdt_get_name(globalResourceDtb, nodeOffset, NULL);\r
619 Rm_ResourceProperties resourceProperties;\r
620 int32_t error = RM_DTB_UTIL_RESULT_OKAY;\r
621 int32_t offset;\r
622 \r
623 /* Initialize the resource properties structure */\r
624 memset((void *)&resourceProperties, 0, sizeof(Rm_ResourceProperties));\r
625 \r
626 /* Ignore properties of the base node */\r
627 if (strcmp(resourceName, rmDtbStartingNode))\r
628 {\r
629 /* Get the properties for the resource node if any exist */\r
630 offset = fdt_first_property_offset(globalResourceDtb, nodeOffset);\r
631 if (offset >= RM_DTB_UTIL_STARTING_NODE_OFFSET)\r
632 {\r
633 /* Since at least one property exists attempt to parse the property nodes and \r
634 * use them to create and initialize a resource allocator */\r
635 error = Rm_parseResourceProperty(globalResourceDtb, offset, &resourceProperties);\r
636 if (error < -FDT_ERR_NOTFOUND)\r
637 {\r
638 return (error);\r
639 }\r
640 \r
641 /* Initialize an allocator with the resource properties if no error was returned */\r
642 Rm_createAndInitAllocator(rmInst, resourceName, &resourceProperties);\r
643 }\r
644 else if (offset != -FDT_ERR_NOTFOUND)\r
645 {\r
646 /* Error was returned by LIBFDT when parsing the properties */\r
647 return (offset);\r
648 }\r
649 }\r
650 \r
651 /* Get the next resource node */\r
652 offset = fdt_next_node(globalResourceDtb, nodeOffset, &depth);\r
653 /* Check the offset and depth of the next node to make sure the current node\r
654 * wasn't the last node in the Resource List. A depth less than the depth set\r
655 * at the start of the recursion will signal the end of the resource list */\r
656 if ((offset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) && (depth >= RM_DTB_UTIL_STARTING_DEPTH))\r
657 {\r
658 error = Rm_parseResourceNode(rmInst, globalResourceDtb, offset, depth);\r
659 if (error < -FDT_ERR_NOTFOUND)\r
660 {\r
661 return (error);\r
662 }\r
663 }\r
664 else if (offset != -FDT_ERR_NOTFOUND)\r
665 {\r
666 /* Error was returned by LIBFDT when parsing the nodes */\r
667 return (offset);\r
668 }\r
669 \r
670 return (RM_DTB_UTIL_RESULT_OKAY);\r
671 }\r
672 \r
673 int32_t Rm_initializeAllocators(Rm_Inst *rmInst, void *globalResourceDtb)\r
674 {\r
675 int32_t nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;\r
676 int32_t startDepth = RM_DTB_UTIL_STARTING_DEPTH;\r
677 int32_t result = RM_DTB_UTIL_RESULT_OKAY;\r
678 \r
679 /* Recursively parse the Global Resource List, creating an allocator for\r
680 * each resource as specified in the node */\r
681 result = Rm_parseResourceNode(rmInst, globalResourceDtb, nodeOffset, startDepth);\r
682 \r
683 return(result);\r
684 }\r
685 \r
686 int32_t Rm_reserveLinuxResources(void *linuxResourceDtb)\r
687 {\r
688 return(0);\r
689 \r
690 }\r
691 \r
692 void Rm_allocationHandler (Rm_Inst *rmInst, Rm_Transaction *transaction)\r
693 {\r
694 if (rmInst->instType == Rm_instType_CLIENT_DELEGATE)\r
695 {\r
696 #if 0 \r
697 /* Check local policy to see if the request can be satisfied with the\r
698 * resources stored locally */\r
699 Rm_policy...API()\r
700 \r
701 if (policy check approves the resource)\r
702 {\r
703 /* call the allocator to allocate the resource */\r
704 if (allocator returns resource)\r
705 {\r
706 /* Populate the transaction with the allocated resources and the result */\r
707 transaction->state = approve reason;\r
708 return ...\r
709 }\r
710 else\r
711 {\r
712 /* allocator ran out of resources, need to contact Server for more\r
713 * resources */\r
714 Rm_resourcePoolModRequest(...);\r
715 }\r
716 }\r
717 else if (policy check denies resource)\r
718 {\r
719 /* Policy check denied resource. */\r
720 transaction->state= deny reason;\r
721 return ...\r
722 }\r
723 else if (policy check says forward to Server for validation)\r
724 {\r
725 /* Forward the transaction to the Server */\r
726 Rm_transactionForwarder(rmInst, transaction);\r
727 }\r
728 #endif \r
729 }\r
730 else if (rmInst->instType == Rm_instType_SERVER)\r
731 {\r
732 #if 0 \r
733 /* Check global policy to see if resource can be allocated. return result\r
734 * no matter what */\r
735 Rm_policy...API()\r
736 \r
737 if (policy approves)\r
738 {\r
739 /* call allocator to allocate resource */\r
740 }\r
741 \r
742 transaction->state = approve or deny reason;\r
743 transaction->resourceInfo.base = ...;\r
744 transaction->resourceInfo.range = ...;\r
745 \r
746 /* If source instance name does not match the current instance\r
747 * name the allocation request came from a Client. The result\r
748 * must be sent back to the Client */\r
749 if (strcmp(transaction->sourceInstName, rmInst->name))\r
750 {\r
751 /* Names don't match. Send the transaction back to the Client */\r
752 Rm_transactionResponder(rmInst, transaction);\r
753 }\r
754 else\r
755 {\r
756 /* Resource allocation request originated locally on the active\r
757 * instance. Send the response via the service responder. */ \r
758 Rm_serviceResponder(rmInst, transaction); \r
759 }\r
760 #endif \r
761 } \r
762 }\r
763 \r
764 void Rm_freeHandler (Rm_Inst *rmInst, Rm_Transaction *transaction)\r
765 {\r
766 if (rmInst->instType == Rm_instType_CLIENT_DELEGATE)\r
767 {\r
768 #if 0 \r
769 /* Check local policy to see if the request can be satisfied with the\r
770 * resources stored locally */\r
771 Rm_policy...API()\r
772 \r
773 if (policy check approves the free)\r
774 {\r
775 /* call the allocator to free the resource */\r
776 /* Run a resource pool check to see if the free combined a resource block\r
777 * that can be returned to the server */\r
778 if (resource block has been combined)\r
779 {\r
780 /* allocator ran out of resources, need to contact Server for more\r
781 * resources */\r
782 Rm_resourcePoolModRequest(free pool block to server...);\r
783 }\r
784 else\r
785 {\r
786 /* Populate the receipt with the freed resources and the result */\r
787 transaction->state = approve reason;\r
788 return ...\r
789 }\r
790 }\r
791 else if (policy check denies resource free)\r
792 {\r
793 /* Policy check denied resource. */\r
794 transaction->state = deny reason;\r
795 return ...\r
796 }\r
797 else if (policy check says forward to Server for validation)\r
798 {\r
799 /* Forward the transaction to the Server */\r
800 Rm_transactionForwarder(rmInst, transaction);\r
801 }\r
802 #endif \r
803 }\r
804 else if (rmInst->instType == Rm_instType_SERVER)\r
805 {\r
806 #if 0 \r
807 /* Check global policy to see if resource can be freed. return result\r
808 * no matter what */\r
809 Rm_policy...API()\r
810 if (policy approves)\r
811 {\r
812 /* call allocator to free resources */\r
813 }\r
814 \r
815 transaction->state = approve or deny reason;\r
816 transaction->resourceInfo.base = ...;\r
817 transaction->resourceInfo.range = ...;\r
818 \r
819 /* If source instance name does not match the current instance\r
820 * name the allocation request came from a client. The result\r
821 * must be sent back to the Client */\r
822 if (strcmp(transaction->sourceInstName, rmInst->name))\r
823 {\r
824 /* Names don't match. Send the transaction back to the Client Delegate or Client */\r
825 Rm_transactionResponder(rmInst, transaction);\r
826 }\r
827 else\r
828 {\r
829 /* Resource allocation request originated locally on the active\r
830 * instance. Send the response via the service responder. */\r
831 Rm_serviceResponder(rmInst, transaction); \r
832 }\r
833 #endif \r
834 } \r
835 }\r
836 \r
837 /* Function used to forward RM transactions to higher level agents */\r
838 void Rm_transactionForwarder (Rm_Inst *rmInst, Rm_Transaction *transaction)\r
839 {\r
840 Rm_TransportNode *dstTransportNode = NULL;\r
841 Rm_Packet *rmPkt = NULL;\r
842 \r
843 /* Make sure the RM instance has a transport registered with a higher level agent */\r
844 if (rmInst->registeredWithDelegateOrServer == false)\r
845 {\r
846 transaction->state = RM_SERVICE_ERROR_NOT_REGISTERED_WITH_DEL_OR_SERVER;\r
847 return;\r
848 }\r
849 \r
850 /* Find the transport for the higher level agent. Check for a connection to a Client Delegate\r
851 * or a Server. Clients will be connected to either a Client Delegate or a Server. Client\r
852 * Delegates will be connected to a Server. */\r
853 if (rmInst->instType == Rm_instType_CLIENT)\r
854 {\r
855 dstTransportNode = Rm_transportNodeFindRemoteInstType(rmInst, Rm_instType_CLIENT_DELEGATE);\r
856 } \r
857 else if (rmInst->instType == Rm_instType_CLIENT_DELEGATE)\r
858 {\r
859 dstTransportNode = Rm_transportNodeFindRemoteInstType(rmInst, Rm_instType_SERVER);\r
860 }\r
861 \r
862 /* Create a RM packet using the service information */\r
863 switch (transaction->type)\r
864 {\r
865 case Rm_service_RESOURCE_ALLOCATE:\r
866 case Rm_service_RESOURCE_BLOCK_ALLOCATE:\r
867 case Rm_service_RESOURCE_ALLOCATE_BY_NAME:\r
868 case Rm_service_RESOURCE_FREE:\r
869 case Rm_service_RESOURCE_BLOCK_FREE:\r
870 case Rm_service_RESOURCE_FREE_BY_NAME:\r
871 rmPkt = Rm_transportCreateResourceReqPkt(rmInst, dstTransportNode, \r
872 transaction);\r
873 break;\r
874 case Rm_service_RESOURCE_MAP_TO_NAME:\r
875 case Rm_service_RESOURCE_UNMAP_NAME:\r
876 rmPkt = Rm_transportCreateNsRequestPkt(rmInst, dstTransportNode,\r
877 transaction);\r
878 break;\r
879 default:\r
880 /* Invalid service type. Flag the error and return */\r
881 transaction->state = RM_SERVICE_ERROR_INVALID_SERVICE_TYPE;\r
882 break;\r
883 }\r
884 \r
885 if (transaction->state <= RM_SERVICE_ERROR_BASE)\r
886 {\r
887 /* Return immediately because an error occurred allocating the packet */\r
888 return;\r
889 }\r
890 \r
891 /* Send the RM packet to the application transport */\r
892 if (rmInst->transport.rmSend((Rm_TransportHandle) dstTransportNode, rmPkt) < RM_TRANSPORT_SUCCESSFUL)\r
893 {\r
894 /* Negative value returned by transport send. An error occurred\r
895 * in the transport while attempting to send the packet.*/\r
896 transaction->state = RM_SERVICE_ERROR_TRANPSPORT_SEND_ERROR;\r
897 /* Clean up the packet */\r
898 if (rmInst->transport.rmFreePkt((Rm_TransportHandle) dstTransportNode, rmPkt))\r
899 {\r
900 /* Non-NULL value returned by transport packet free. Flag the\r
901 * error */\r
902 transaction->state = RM_SERVICE_ERROR_TRANSPORT_FREE_PKT_ERROR;\r
903 }\r
904 return;\r
905 }\r
906 \r
907 /* Transaction is not deleted because it is awaiting a response from the higher level\r
908 * RM instance */\r
909 }\r
910 \r
911 void Rm_transactionProcessor (Rm_Inst *rmInst, Rm_Transaction *transaction)\r
912 {\r
913 /* Handle auto-forwarded transactions. These transactions include:\r
914 * - All request transactions received on Clients are forwarded to the Client Delegate\r
915 * - NameServer requests received on the Client Delegate are forwarded to the Server */\r
916 if ((rmInst->instType == Rm_instType_CLIENT) ||\r
917 ((rmInst->instType == Rm_instType_CLIENT_DELEGATE) &&\r
918 (transaction->type == Rm_service_RESOURCE_MAP_TO_NAME) ||\r
919 (transaction->type == Rm_service_RESOURCE_UNMAP_NAME)))\r
920 {\r
921 /* Check if the transaction is a transaction that received a response to its\r
922 * request. */\r
923 if (transaction->state != RM_SERVICE_PROCESSING)\r
924 {\r
925 \r
926 /* A transaction has received a response. Send the response to either the \r
927 * transaction or service responder based on the source instance */\r
928 if (strcmp(transaction->sourceInstName, rmInst->name))\r
929 {\r
930 /* Transaction originated from another instance. Use the \r
931 * transaction responder to send the result to the source instance. This\r
932 * is not possible on RM Clients since they can't forward RM services */\r
933 Rm_transactionResponder(rmInst, transaction);\r
934 }\r
935 else\r
936 {\r
937 /* Transaction originated on this instance. Send to the\r
938 * service responder */\r
939 Rm_serviceResponder(rmInst, transaction);\r
940 }\r
941 }\r
942 else\r
943 {\r
944 /* This is a new transaction that must be forwarded to a higher level RM instance. */\r
945 Rm_transactionForwarder(rmInst, transaction);\r
946 }\r
947 }\r
948 else\r
949 {\r
950 /* Client Delegate and Server transaction processors. */\r
951 switch (transaction->type)\r
952 {\r
953 case Rm_service_RESOURCE_ALLOCATE:\r
954 case Rm_service_RESOURCE_BLOCK_ALLOCATE:\r
955 case Rm_service_RESOURCE_ALLOCATE_BY_NAME:\r
956 case Rm_service_RESOURCE_FREE:\r
957 case Rm_service_RESOURCE_BLOCK_FREE:\r
958 case Rm_service_RESOURCE_FREE_BY_NAME: \r
959 /* Check if the transaction is fulfilled request */\r
960 if (transaction->state != RM_SERVICE_PROCESSING)\r
961 {\r
962 /* If source instance name does not match the current instance\r
963 * name the allocation request came from a client. The result\r
964 * must be sent back to the Client */\r
965 if (strcmp(transaction->sourceInstName, rmInst->name))\r
966 {\r
967 Rm_transactionResponder(rmInst, transaction);\r
968 }\r
969 else\r
970 {\r
971 /* Resource allocation request originated locally. Send the response\r
972 * via the service responder. */\r
973 Rm_serviceResponder(rmInst, transaction); \r
974 }\r
975 }\r
976 else\r
977 {\r
978 /* This is a new transaction request originating from an RM instance with fewer\r
979 * allocate/free privileges. Run the allocation or free handler to see if the resource\r
980 * request can be handled locally or if it needs to be forwarded to a higher level\r
981 * agent */\r
982 if ((transaction->type == Rm_service_RESOURCE_ALLOCATE) ||\r
983 (transaction->type == Rm_service_RESOURCE_BLOCK_ALLOCATE) ||\r
984 (transaction->type == Rm_service_RESOURCE_ALLOCATE_BY_NAME))\r
985 {\r
986 Rm_allocationHandler(rmInst, transaction);\r
987 }\r
988 else\r
989 {\r
990 Rm_freeHandler(rmInst, transaction);\r
991 }\r
992 }\r
993 break;\r
994 case Rm_service_RESOURCE_MAP_TO_NAME:\r
995 case Rm_service_RESOURCE_UNMAP_NAME: \r
996 /* Server is the only RM instance capable of adding NameServer objects */\r
997 if (rmInst->instType == Rm_instType_SERVER)\r
998 {\r
999 if (transaction->type == Rm_service_RESOURCE_MAP_TO_NAME)\r
1000 {\r
1001 /* Create a new NameServer object with the request transaction information.\r
1002 * Transaction will contain the state result of the NameServer addition. */\r
1003 if (Rm_nsAddObject(rmInst, transaction->resourceInfo.nsName,\r
1004 transaction->resourceInfo.base) == RM_NS_ACTION_APPROVED)\r
1005 {\r
1006 transaction->state = RM_SERVICE_APPROVED;\r
1007 }\r
1008 else\r
1009 {\r
1010 /* TEMP: UPDATE THIS STATE VALUE */\r
1011 transaction->state = RM_SERVICE_DENIED_BEGIN;\r
1012 }\r
1013 }\r
1014 else\r
1015 {\r
1016 /* Delete an existing NameServer object with the request transaction information\r
1017 * Transaction will contain the state result of the NameServer addition. */\r
1018 if (Rm_nsDeleteObject(rmInst, transaction->resourceInfo.nsName) == \r
1019 RM_NS_ACTION_APPROVED)\r
1020 {\r
1021 transaction->state = RM_SERVICE_APPROVED;\r
1022 }\r
1023 else\r
1024 {\r
1025 /* TEMP: UPDATE THIS STATE VALUE */\r
1026 transaction->state = RM_SERVICE_DENIED_BEGIN;\r
1027 }\r
1028 }\r
1029 \r
1030 /* If source instance name does not match the local instance\r
1031 * name the NameServer request came from a Client or Client Delegate. The \r
1032 * result must be sent back to the Client or Client Delegate. Just return if it does\r
1033 * match since the NameServer transaction result can be returned immediately by the\r
1034 * Rm_serviceHandler. */\r
1035 if (strcmp(transaction->sourceInstName, rmInst->name))\r
1036 {\r
1037 Rm_transactionResponder(rmInst, transaction);\r
1038 }\r
1039 }\r
1040 else\r
1041 {\r
1042 transaction->state = RM_SERVICE_ERROR_NAMESERVER_OBJECT_MOD_ON_INVALID_INSTANCE;\r
1043 }\r
1044 break;\r
1045 }\r
1046 }\r
1047 }\r
1048 \r
1049 /**********************************************************************\r
1050 ********************** Application visible APIs **********************\r
1051 **********************************************************************/\r
1052 \r
1053 Rm_Handle Rm_init(Rm_InitCfg *initCfg)\r
1054 {\r
1055 Rm_Inst *rmInst;\r
1056 void *globalResourceDtb = NULL;\r
1057 void *linuxResourceDtb = NULL;\r
1058 \r
1059 /* Instance creation checks. Add one to strlen calculation for null character */\r
1060 if ((strlen(initCfg->instName) + 1) > RM_INSTANCE_NAME_MAX_CHARS)\r
1061 {\r
1062 /* Failure: Instance name is too big */\r
1063 return (NULL);\r
1064 }\r
1065 \r
1066 /* Get memory for RM instance from local memory */\r
1067 rmInst = Rm_osalMalloc (sizeof(Rm_Inst));\r
1068 /* Populate instance based on input parameters */\r
1069 strcpy (&rmInst->name[0], initCfg->instName);\r
1070 rmInst->instType = initCfg->instType;\r
1071 rmInst->registeredWithDelegateOrServer = false;\r
1072 rmInst->policyDtb = NULL;\r
1073 \r
1074 /* Initialize the transport routing map linked list pointer to NULL. The linked list\r
1075 * nodes will be created when the application registers transports */\r
1076 rmInst->routeMap = NULL;\r
1077 \r
1078 /* Initialize the allocators linked list pointer to NULL. The linked list nodes will\r
1079 * be created on the Server instance when the application reads in the resource list.\r
1080 * Nodes will also be created on Client Delegates when blocks of resources are requested\r
1081 * for allocation to clients. */\r
1082 rmInst->allocators = NULL;\r
1083 \r
1084 /* Initialize the transaction queue elements. */\r
1085 rmInst->transactionSeqNum = Rm_transactionInitSequenceNum();\r
1086 rmInst->transactionQueue= NULL;\r
1087 \r
1088 /* RM Server specific actions */\r
1089 if (rmInst->instType == Rm_instType_SERVER)\r
1090 {\r
1091 /* Open the ResourceList file and provide it to the resource initializer. */\r
1092 if (initCfg->globalResourceList)\r
1093 {\r
1094 globalResourceDtb = initCfg->globalResourceList;\r
1095 fdt_open_into(globalResourceDtb, globalResourceDtb, fdt_totalsize(globalResourceDtb)); \r
1096 Rm_initializeAllocators(rmInst, globalResourceDtb);\r
1097 }\r
1098 \r
1099 /* Parse the Linux DTB for the resources reserved by the Linux kernel. These resources\r
1100 * will be marked as used in the resource allocators. */\r
1101 if (initCfg->linuxDtb)\r
1102 {\r
1103 linuxResourceDtb = initCfg->linuxDtb;\r
1104 fdt_open_into(linuxResourceDtb, linuxResourceDtb, fdt_totalsize(linuxResourceDtb)); \r
1105 Rm_reserveLinuxResources(linuxResourceDtb);\r
1106 }\r
1107 }\r
1108 \r
1109 /* Instance startup policies are only used for Servers and Client Delegates */\r
1110 if (rmInst->instType != Rm_instType_CLIENT)\r
1111 {\r
1112 /* Open the instance's policy and store it */\r
1113 if (initCfg->startupPolicy)\r
1114 {\r
1115 rmInst->policyDtb = initCfg->startupPolicy;\r
1116 fdt_open_into(rmInst->policyDtb, rmInst->policyDtb, fdt_totalsize(rmInst->policyDtb)); \r
1117 }\r
1118 \r
1119 /* Store policy via policy APIs ... */\r
1120 }\r
1121 \r
1122 /* Return the RM Handle */\r
1123 return ((Rm_Handle) rmInst);\r
1124 }\r
1125 \r
1126 uint32_t Rm_getVersion (void)\r
1127 {\r
1128 return RM_VERSION_ID;\r
1129 }\r
1130 \r
1131 \r
1132 const char* Rm_getVersionStr (void)\r
1133 {\r
1134 return rmVersionStr;\r
1135 }\r
1136 \r
1137 /**\r
1138 @}\r
1139 */\r