3754b6d0051b2fdad70c26ee463ce1a0c5625700
[keystone-rtos/rm-lld.git] / src / rm_dtb_util.c
1 /**
2  *   @file  rm_dtb_util.c
3  *
4  *   @brief   
5  *      This is the Resource Manager Resource List and Policy DTB parsing 
6  *      utility source
7  *
8  *  \par
9  *  ============================================================================
10  *  @n   (C) Copyright 2012-2013, Texas Instruments, Inc.
11  * 
12  *  Redistribution and use in source and binary forms, with or without 
13  *  modification, are permitted provided that the following conditions 
14  *  are met:
15  *
16  *    Redistributions of source code must retain the above copyright 
17  *    notice, this list of conditions and the following disclaimer.
18  *
19  *    Redistributions in binary form must reproduce the above copyright
20  *    notice, this list of conditions and the following disclaimer in the 
21  *    documentation and/or other materials provided with the   
22  *    distribution.
23  *
24  *    Neither the name of Texas Instruments Incorporated nor the names of
25  *    its contributors may be used to endorse or promote products derived
26  *    from this software without specific prior written permission.
27  *
28  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
29  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
30  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31  *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
32  *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
33  *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
34  *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35  *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36  *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
37  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
38  *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39  *
40  *  \par
41 */
43 /* Standard includes */
44 #include <string.h>
46 /* RM external API includes */
47 #include <ti/drv/rm/rm.h>
49 /* RM internal API includes */
50 #include <ti/drv/rm/include/rm_dtb_utilloc.h>
52 /* RM OSAL layer */
53 #include <rm_osal.h>
55 /* LIBFDT includes */
56 #include <ti/drv/rm/util/libfdt/libfdt.h>
57 #include <ti/drv/rm/util/libfdt/libfdt_env.h>
59 /**********************************************************************
60  ******************** Common DTB Parsing Globals **********************
61  **********************************************************************/
63 /**********************************************************************
64  *************** Global Resource List Parsing Globals *****************
65  **********************************************************************/
67 /* Resource List Properties - These are the property values used
68  * by an application integrator to define the properties of resources
69  * listed in the Device Global Resource List */
70 const char dtbUtilResRangeProp[]        = "resource-range";
71 const char dtbUtilResLinuxAliasProp[]   = "linux-dtb-alias";
72 const char dtbUtilResNsAssignmentProp[] = "ns-assignment";
74 /**********************************************************************
75  *********************** Policy Parsing Globals ***********************
76  **********************************************************************/
78 /* Policy Properties - These are the property values used
79  * by an application integrator to define the properties of resources
80  * listed in a Resource Manager Policy */
81 const char dtbUtilPolicyValidInstances[]      = "valid-instances";
82 const char dtbUtilPolicyAssignments[]         = "assignments";
83 const char dtbUtilPolicyAllocationSize[]      = "allocation-size";
84 const char dtbUtilPolicyAllocationAlignment[] = "allocation-alignment";
86 /**********************************************************************
87  ******************* Common DTB Parsing Functions *********************
88  **********************************************************************/
90 /* Construct and return a list of ranges as specified in either the Resource
91  * DTB or a Policy DTB */
92 static Rm_ResourceRange *dtbUtilCommonExtractRange(const void *dtbDataPtr, int32_t dtbDataLen)
93 {
94     uint32_t         *dtbRangeData = (uint32_t *)dtbDataPtr;
95     Rm_ResourceRange *startRange = NULL;
96     Rm_ResourceRange *newRange = NULL;
97     Rm_ResourceRange *prevRange = NULL;
98     uint32_t i;
99     
100     /* Ranges are stored in the DTB as a list of 32-bit words.  The number of 32-bit
101      * words in the DTB ranges field should be even since ranges are specified in a 
102      * base, lenth format. The DTB gives properties lengths in bytes so the length
103      * returned from the DTB should be a multiple of the number of bytes in two
104      * uint32_ts. */
105     if (dtbDataLen % (2 * sizeof(uint32_t))) {
106         return (NULL);
107     }
109     for (i = 0; i < (dtbDataLen / sizeof(uint32_t)); i+=2) {
110         newRange = (Rm_ResourceRange *) Rm_osalMalloc(sizeof(Rm_ResourceRange));
111         newRange->base = fdt32_to_cpu(dtbRangeData[i]);
112         newRange->length = fdt32_to_cpu(dtbRangeData[i+1]);
113         newRange->nextRange = NULL;
114         
115         if (prevRange == NULL) {
116             startRange = newRange;
117         }
118         else {
119             prevRange->nextRange = newRange;
120         }
121         prevRange = newRange;
122     }
123     return (startRange);
126 /* Function to clean up the memory allocated for a linked list of extracted ranges */
127 static void dtbUtilCommonFreeRangeList(Rm_ResourceRange *rangeList)
129     Rm_ResourceRange *nextRange;
130     
131     while (rangeList) {
132         nextRange = rangeList->nextRange;
133         Rm_osalFree((void *)rangeList, sizeof(Rm_ResourceRange));
134         rangeList = nextRange;
135     }
138 /* Construct and return a list of values as specified in the Policy DTB */
139 static Rm_ResourceValue *dtbUtilCommonExtractValueList(const void *dtbDataPtr, int32_t dtbDataLen)
141     uint32_t         *dtbRangeData = (uint32_t *)dtbDataPtr;
142     Rm_ResourceValue *startValue = NULL;
143     Rm_ResourceValue *newValue = NULL;
144     Rm_ResourceValue *prevValue = NULL;
145     uint32_t          i;
146     
147     /* Values are stored in the DTB as a list of 32-bit words. The DTB 
148      * gives properties lengths in bytes so the length returned from the DTB 
149      * should be a multiple of the number of bytes a uint32_t. */
150     if (dtbDataLen % sizeof(uint32_t)) {
151         return (NULL);
152     }
153     
154     for (i = 0; i < (dtbDataLen / sizeof(uint32_t)); i++) {
155         newValue = (Rm_ResourceValue *) Rm_osalMalloc(sizeof(Rm_ResourceValue));
156         newValue->value = fdt32_to_cpu(dtbRangeData[i]);
157         newValue->nextValue = NULL;
158         
159         if (prevValue == NULL) {
160             startValue = newValue;
161         }
162         else {
163             prevValue->nextValue = newValue;
164         }
165         prevValue = newValue;
166     }
167     return (startValue);
170 /* Function to clean up the memory allocated for a linked list of extracted values */
171 static void dtbUtilCommonFreeValueList (Rm_ResourceValue *valueList)
173     Rm_ResourceValue *nextValue;
174     
175     while (valueList) {
176         nextValue = valueList->nextValue;
177         Rm_osalFree((void *)valueList, sizeof(Rm_ResourceValue));
178         valueList = nextValue;
179     }
182 /**********************************************************************
183  ************** Global Resource List Parsing Functions ****************
184  **********************************************************************/
186 Rm_ResourcePropType rmDtbUtilResGetPropertyType(const char * propertyName)
188     Rm_ResourcePropType propertyType = Rm_resourcePropType_UNKNOWN;
190     if(strcmp(dtbUtilResRangeProp, propertyName) == 0) {
191         propertyType = Rm_resourcePropType_RESOURCE_RANGE;
192     }
193     else if(strcmp(dtbUtilResLinuxAliasProp, propertyName) == 0) {
194         propertyType = Rm_resourcePropType_RESOURCE_LINUX_ALIAS;
195     }    
196     else if(strcmp(dtbUtilResNsAssignmentProp, propertyName) == 0) {
197         propertyType = Rm_resourcePropType_NSASSIGNMENT;
198     }
199     return (propertyType);
202 Rm_ResourceRange *rmDtbUtilResExtractRange(const void *dtbDataPtr, int32_t dtbDataLen)
204     return(dtbUtilCommonExtractRange(dtbDataPtr, dtbDataLen));
207 void rmDtbUtilResFreeRange(Rm_ResourceRange *rangeList)
209     dtbUtilCommonFreeRangeList(rangeList);
212 Rm_LinuxAlias *rmDtbUtilResExtractLinuxAlias(const void *dtbDataPtr, int32_t dtbDataLen, int32_t *result)
214     uint8_t       *dtbAliasData = (uint8_t *)dtbDataPtr;
215     uint32_t       pathLenBytes;
216     uint32_t       extractedValue;
217     uint8_t       *extractedValueBytePtr;        
218     Rm_LinuxAlias *startAlias = NULL;
219     Rm_LinuxAlias *newAlias = NULL;
220     Rm_LinuxAlias *prevAlias = NULL;
221     uint32_t       numOffsets;
222     int32_t        i = 0;
223     uint16_t       j;
224     
225     /* Linux aliases are stored in the DTB as a list space-separated path node names within
226      * null terminated string.  Following the path string 
227      * will be two or three values specifying the fields in the linux DTB property
228      * that contain the relevant data.  The first value specifies the number of offsets
229      * that follow.  If two field offsets are specified the 
230      * Linux DTB contains a base + length. If   one field offset is specified the 
231      * Linux DTB contains a single value for reservation.  There is no padding between
232      * the path string and the 32-bit offsets.  Therefore the 32-bit offsets may not be on
233      * a 4-byte boundary and must be constructed upon extraction */
234     while(i < dtbDataLen) {
235         newAlias = (Rm_LinuxAlias *) Rm_osalMalloc(sizeof(Rm_LinuxAlias));
236         
237         pathLenBytes = strlen((char *) &dtbAliasData[i]) + 1;
238         newAlias->path = (char *) Rm_osalMalloc(pathLenBytes);
239         strncpy(newAlias->path, ((char *) &dtbAliasData[i]), pathLenBytes);
240         
241         /* Extract 32-bit value specifying number of offsets that follow */
242         i += pathLenBytes;
243         extractedValueBytePtr = (uint8_t *)&extractedValue;
244         for (j = 0; j < sizeof(uint32_t); j++, i++) {
245             extractedValueBytePtr[j] = dtbAliasData[i];
246         }
247         numOffsets = fdt32_to_cpu(extractedValue);
249         if ((numOffsets == 1) || (numOffsets == 2)) {
250             /* Always extract the base value */
251             extractedValueBytePtr = (uint8_t *)&extractedValue;
252             for (j = 0; j < sizeof(uint32_t); j++, i++) {
253                 extractedValueBytePtr[j] = dtbAliasData[i];
254             }            
255             newAlias->baseOffset = fdt32_to_cpu(extractedValue);
257             if (numOffsets == 2) {
258                 for (j = 0; j < sizeof(uint32_t); j++, i++) {
259                     extractedValueBytePtr[j] = dtbAliasData[i];
260                 }
261                 newAlias->lengthOffset = fdt32_to_cpu(extractedValue);
262             }
263             else {
264                 newAlias->lengthOffset = RM_DTB_LINUX_ALIAS_OFFSET_NOT_SET;
265             }            
266             
267             newAlias->nextLinuxAlias = NULL;
268             if (prevAlias == NULL) {
269                 startAlias = newAlias;
270             }
271             else {
272                 prevAlias->nextLinuxAlias = newAlias;
273             }
274             prevAlias = newAlias;
275         }
276         else {
277             Rm_osalFree((void *)newAlias->path, pathLenBytes);
278             Rm_osalFree((void *)newAlias, sizeof(Rm_LinuxAlias));
279             while (startAlias) {
280                 newAlias = startAlias->nextLinuxAlias;
281                 pathLenBytes = strlen(startAlias->path);        
282                 Rm_osalFree((void *)startAlias->path, pathLenBytes + 1);
283                 Rm_osalFree((void *)startAlias, sizeof(Rm_LinuxAlias));
284                 startAlias = newAlias;
285             }   
286             *result = RM_ERROR_GRL_INVALID_LINUX_ALIAS_FORMAT;
287             return(NULL);
288         }
289     }
290     return (startAlias);
293 /* Function to clean up the memory allocated for a linked list of extracted Linux
294  * aliases. */
295 void rmDtbUtilResFreeLinuxAlias(Rm_LinuxAlias *aliasList)
297     Rm_LinuxAlias *nextAlias;
298     int32_t        pathSize;
299        
300     while (aliasList) {
301         nextAlias = aliasList->nextLinuxAlias;
302         pathSize = strlen(aliasList->path);        
303         Rm_osalFree((void *)aliasList->path, pathSize + 1);
304         Rm_osalFree((void *)aliasList, sizeof(Rm_LinuxAlias));
305         aliasList = nextAlias;
306     }
309 /* Construct and return a list of NameServer assignments as specified in the Resource DTB */
310 Rm_NsAssignment *rmDtbUtilResExtractNsAssignment(const void *dtbDataPtr, int32_t dtbDataLen, int32_t *result)
312     uint8_t         *dtbNsAssignmentData = (uint8_t *)dtbDataPtr;
313     uint32_t         nameLenBytes;
314     uint32_t         extractedValue;
315     uint8_t         *extractedValueBytePtr;        
316     Rm_NsAssignment *startAssignment = NULL;
317     Rm_NsAssignment *newAssignment = NULL;
318     Rm_NsAssignment *prevAssignment = NULL;
319     int32_t          i = 0;
320     uint16_t         j;
321     
322     /* NameServer assignments are stored in the DTB as a null-terminated character
323      * string followed by a 32-bit word containing the value to be assigned to the
324      * name in the string.  There is no padding between the string and the 32-bit 
325      * word.  Therefore the 32-bit word may not be on a 4-byte boundary and must
326      * be constructed upon extraction */
327     while(i < dtbDataLen) {
328         newAssignment = (Rm_NsAssignment *) Rm_osalMalloc(sizeof(Rm_NsAssignment));
329         
330         nameLenBytes = strlen((char *) &dtbNsAssignmentData[i]) + 1;
331         if (nameLenBytes > RM_NAME_MAX_CHARS) {
332             Rm_osalFree((void *)newAssignment, sizeof(Rm_NsAssignment));
333             while (startAssignment) {
334                 newAssignment = startAssignment->nextNsAssignment;
335                 Rm_osalFree((void *)startAssignment, sizeof(Rm_NsAssignment));
336                 startAssignment = newAssignment;
337             }
338             *result = RM_ERROR_GRL_NS_ASSIGNMENT_NAME_TOO_LONG;
339             return(NULL);
340         }        
341         strncpy(newAssignment->nsName, ((char *) &dtbNsAssignmentData[i]), RM_NAME_MAX_CHARS);
342         
343         /* Extract 32-bit base value and flip endian */
344         i += nameLenBytes;
345         extractedValueBytePtr = (uint8_t *)&extractedValue;
346         for (j = 0; j < sizeof(uint32_t); j++, i++) {
347             extractedValueBytePtr[j] = dtbNsAssignmentData[i];
348         }
349         newAssignment->resourceBase = fdt32_to_cpu(extractedValue);
351         /* Extract 32-bit length value and flip endian */
352         for (j = 0; j < sizeof(uint32_t); j++, i++) {
353             extractedValueBytePtr[j] = dtbNsAssignmentData[i];
354         }
355         newAssignment->resourceLength = fdt32_to_cpu(extractedValue);
356         
357         newAssignment->nextNsAssignment = NULL;
358         if (prevAssignment == NULL) {
359             startAssignment = newAssignment;
360         }
361         else {
362             prevAssignment->nextNsAssignment = newAssignment;
363         }
364         prevAssignment = newAssignment;
365     }
366     
367     return (startAssignment);
370 /* Function to clean up the memory allocated for a linked list of extracted NameServer
371  * assignments. */
372 void rmDtbUtilResFreeNsAssignmentList (Rm_NsAssignment *nsAssignmentList)
374     Rm_NsAssignment *nextAssignment;
375     
376     while (nsAssignmentList) {
377         nextAssignment = nsAssignmentList->nextNsAssignment;
378         Rm_osalFree((void *)nsAssignmentList, sizeof(Rm_NsAssignment));
379         nsAssignmentList = nextAssignment;
380     }
383 /**********************************************************************
384  ********************** Policy Parsing Functions **********************
385  **********************************************************************/
387 Rm_PolicyPropType rmDtbUtilPolicyGetPropertyType(const char * propertyName)
389     Rm_PolicyPropType propertyType = Rm_policyPropType_UNKNOWN;
391     if(strcmp(dtbUtilPolicyAssignments, propertyName) == 0) {
392         propertyType = Rm_policyPropType_ASSIGNMENTS;
393     }
394     else if(strcmp(dtbUtilPolicyAllocationSize, propertyName) == 0) {
395         propertyType = Rm_policyPropType_ALLOCATION_SIZE;
396     }
397     else if(strcmp(dtbUtilPolicyAllocationAlignment, propertyName) == 0) {
398         propertyType = Rm_policyPropType_ALLOCATION_ALIGNMENT;
399     }    
400     else if(strcmp(dtbUtilPolicyValidInstances, propertyName) == 0) {
401         propertyType = Rm_policyPropType_VALID_INSTANCES;
402     }       
403     return (propertyType);
406 Rm_PolicyAssignment *rmDtbUtilPolicyExtractAssignments(const void *dtbDataPtr, int32_t dtbDataLen)
408     uint8_t             *dtbAssignmentData = (uint8_t *)dtbDataPtr;
409     uint32_t             permissionsLenBytes;
410     uint32_t             extractedValue;
411     uint8_t             *extractedValueBytePtr;        
412     Rm_PolicyAssignment *startAssignment = NULL;
413     Rm_PolicyAssignment *newAssignment = NULL;
414     Rm_PolicyAssignment *prevAssignment = NULL;
415     int32_t              i = 0;
416     uint16_t             j;
417     
418     /* Policy assignments are stored in the DTB as two 32-bit words containing a 
419      * resource base and length to be assigned the permissions in the defined in
420      * the string that follows.  There is no padding between the 32-bit words and the 
421      * string.  Therefore the 32-bit word may not be on a 4-byte boundary and must
422      * be constructed upon extraction */
423     while(i < dtbDataLen) {
424         newAssignment = (Rm_PolicyAssignment *) Rm_osalMalloc(sizeof(Rm_PolicyAssignment));
426         /* Extract 32-bit resource base value and flip endianness */
427         extractedValueBytePtr = (uint8_t *)&extractedValue;
428         for (j = 0; j < sizeof(uint32_t); j++, i++) {
429             extractedValueBytePtr[j] = dtbAssignmentData[i];
430         }
431         newAssignment->resourceBase = fdt32_to_cpu(extractedValue);
433         /* Extract 32-bit resource length value and flip endianness */
434         for (j = 0; j < sizeof(uint32_t); j++, i++) {
435             extractedValueBytePtr[j] = dtbAssignmentData[i];
436         }
437         newAssignment->resourceLength = fdt32_to_cpu(extractedValue);
439         permissionsLenBytes = strlen((char *) &dtbAssignmentData[i]) + 1;
440         newAssignment->permissionsList = (char *) Rm_osalMalloc(permissionsLenBytes);
441         strncpy(newAssignment->permissionsList, ((char *) &dtbAssignmentData[i]), permissionsLenBytes);
442         i += permissionsLenBytes;
444         newAssignment->nextAssignment = NULL;
445         if (prevAssignment == NULL) {
446             startAssignment = newAssignment;
447         }
448         else {
449             prevAssignment->nextAssignment = newAssignment;
450         }
451         prevAssignment = newAssignment;
452     }
453     return (startAssignment);
456 void rmDtbUtilPolicyFreeAssignments(Rm_PolicyAssignment *assignmentList)
458     Rm_PolicyAssignment *nextAssignment;
459     int32_t              permissionsSize;
460     
461     while (assignmentList) {
462         nextAssignment = assignmentList->nextAssignment;
463         permissionsSize = strlen(assignmentList->permissionsList);
464         Rm_osalFree((void *)assignmentList->permissionsList, permissionsSize+1);
465         Rm_osalFree((void *)assignmentList, sizeof(Rm_PolicyAssignment));
466         assignmentList = nextAssignment;
467     }
470 /* Construct and return a list of allocation sizes as specified in the Policy DTB */
471 Rm_ResourceValue *rmDtbUtilPolicyExtractAllocationSizes(const void *dtbDataPtr, int32_t dtbDataLen)
473     return(dtbUtilCommonExtractValueList(dtbDataPtr, dtbDataLen));
476 /* Function to clean up the memory allocated for a linked list of extracted allocation sizes */
477 void rmDtbUtilPolicyFreeAllocationSizes (Rm_ResourceValue *allocationSizeList)
479     dtbUtilCommonFreeValueList(allocationSizeList);
482 /* Construct and return a list of allocation alignments as specified in the Policy DTB */
483 Rm_ResourceValue *rmDtbUtilPolicyExtractResourceAlignments(const void *dtbDataPtr, int32_t dtbDataLen)
485     return(dtbUtilCommonExtractValueList(dtbDataPtr, dtbDataLen));
488 /* Function to clean up the memory allocated for a linked list of extracted allocation alignments */
489 void rmDtbUtilPolicyFreeResourceAlignments (Rm_ResourceValue *alignmentList)
491     dtbUtilCommonFreeValueList(alignmentList);
494 Rm_PolicyValidInst *rmDtbUtilPolicyExtractValidInstances(const void *dtbDataPtr, int32_t dtbDataLen,
495                                                          int32_t *result)
497     uint8_t            *dtbValidInstData = (uint8_t *)dtbDataPtr;
498     uint32_t            instLenBytes;       
499     Rm_PolicyValidInst *startInst = NULL;
500     Rm_PolicyValidInst *newInst = NULL;
501     Rm_PolicyValidInst *prevInst = NULL;
502     int32_t             i = 0;
503     
504     /* Valid RM instances are stored in the DTB as a list of null-terminated character
505      * strings. */
506     while(i < dtbDataLen) {
507         newInst = (Rm_PolicyValidInst *) Rm_osalMalloc(sizeof(Rm_PolicyValidInst));
509         instLenBytes = strlen((char *) &dtbValidInstData[i]) + 1;
510         if (instLenBytes > RM_NAME_MAX_CHARS) {
511             Rm_osalFree((void *)newInst, sizeof(Rm_PolicyValidInst));
512             while (startInst) {
513                 newInst = startInst->nextValidInst;
514                 Rm_osalFree((void *)startInst, sizeof(Rm_PolicyValidInst));
515                 startInst = newInst;
516             }
517             *result = RM_ERROR_VALID_INST_NAME_TOO_LONG;
518             return(NULL);
519         }
520         strncpy(newInst->instName, ((char *) &dtbValidInstData[i]), instLenBytes);
521         
522         i += instLenBytes;
524         newInst->nextValidInst = NULL;
526         if (prevInst == NULL) {
527             startInst = newInst;
528         }
529         else {
530             prevInst->nextValidInst = newInst;
531         }
532         prevInst = newInst;
533     }
534     return (startInst);
537 void rmDtbUtilPolicyFreeValidInstances (Rm_PolicyValidInst *validInstList)
539     Rm_PolicyValidInst *nextInst;
540     
541     while (validInstList) {
542         nextInst = validInstList->nextValidInst;
543         Rm_osalFree((void *)validInstList, sizeof(Rm_PolicyValidInst));
544         validInstList = nextInst;
545     }
548 /**********************************************************************
549  ****************Linux DTB Parsing Defines and Functions***************
550  **********************************************************************/
552 Rm_LinuxValueRange *rmDtbUtilLinuxExtractValues(const void *dtbDataPtr, int32_t dtbDataLen)
554     uint32_t           *dtbValueData = (uint32_t *)dtbDataPtr;
555     Rm_LinuxValueRange *startValue = NULL;
556     Rm_LinuxValueRange *newValue = NULL;
557     Rm_LinuxValueRange *prevValue = NULL;
558     uint32_t            i;
559     
560     /* Values are stored in the Linux DTB as a list of 32-bit words.  The number of 32-bit
561      * words in the value field can differ.  depending on the number of values specified. */
562     for (i = 0; i < (dtbDataLen / sizeof(uint32_t)); i++) {
563         newValue = (Rm_LinuxValueRange *) Rm_osalMalloc(sizeof(Rm_LinuxValueRange));
564         /* Endianness of extracted value must be flipped */
565         newValue->value = fdt32_to_cpu(dtbValueData[i]);
566         newValue->nextValue = NULL;
567         
568         if (prevValue == NULL) {
569             startValue = newValue;
570         }
571         else {
572             prevValue->nextValue = newValue;
573         }
574         prevValue = newValue;
575     }
576     return (startValue);
579 void rmDtbUtilLinuxFreeValues(Rm_LinuxValueRange *valueList)
581     Rm_LinuxValueRange *nextValue;
582     
583     while (valueList) {
584         nextValue = valueList->nextValue;
585         Rm_osalFree((void *)valueList, sizeof(Rm_LinuxValueRange));
586         valueList = nextValue;
587     }