]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - ipc/ipcdev.git/blob - packages/ti/sdo/ipc/heaps/HeapMemMP.c
3c188f208b42cd62554f18383826d2dec3aa71b3
[ipc/ipcdev.git] / packages / ti / sdo / ipc / heaps / HeapMemMP.c
1 /*
2  * Copyright (c) 2012-2019 Texas Instruments Incorporated - http://www.ti.com
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * *  Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * *  Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * *  Neither the name of Texas Instruments Incorporated nor the names of
17  *    its contributors may be used to endorse or promote products derived
18  *    from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
33 /*
34  *  ======== HeapMemMP.c ========
35  */
37 #include <xdc/std.h>
38 #include <xdc/runtime/Error.h>
39 #include <xdc/runtime/Assert.h>
40 #include <xdc/runtime/Memory.h>
41 #include <xdc/runtime/IHeap.h>
43 #include <ti/sysbios/hal/Cache.h>
45 #include <ti/sdo/ipc/_Ipc.h>
46 #include <ti/sdo/utils/_NameServer.h>
47 #include <ti/sdo/utils/_MultiProc.h>
48 #include <ti/sdo/ipc/heaps/_HeapMemMP.h>
49 #include <ti/sdo/ipc/_SharedRegion.h>
50 #include <ti/sdo/ipc/_GateMP.h>
52 #include "package/internal/HeapMemMP.xdc.h"
54 #ifdef __ti__
55     #pragma FUNC_EXT_CALLED(HeapMemMP_Params_init);
56     #pragma FUNC_EXT_CALLED(HeapMemMP_alloc);
57     #pragma FUNC_EXT_CALLED(HeapMemMP_close);
58     #pragma FUNC_EXT_CALLED(HeapMemMP_create);
59     #pragma FUNC_EXT_CALLED(HeapMemMP_delete);
60     #pragma FUNC_EXT_CALLED(HeapMemMP_free);
61     #pragma FUNC_EXT_CALLED(HeapMemMP_getExtendedStats);
62     #pragma FUNC_EXT_CALLED(HeapMemMP_getStats);
63     #pragma FUNC_EXT_CALLED(HeapMemMP_open);
64     #pragma FUNC_EXT_CALLED(HeapMemMP_openByAddr);
65     #pragma FUNC_EXT_CALLED(HeapMemMP_restore);
66     #pragma FUNC_EXT_CALLED(HeapMemMP_sharedMemReq);
67 #endif
69 /*
70  *  ======== HeapMemMP_getSharedParams ========
71  */
72 static Void HeapMemMP_getSharedParams(HeapMemMP_Params *sparams,
73         const ti_sdo_ipc_heaps_HeapMemMP_Params *params)
74 {
75     sparams->gate        = (GateMP_Handle)params->gate;
76     sparams->name        = params->name;
77     sparams->regionId    =  params->regionId;
78     sparams->sharedAddr  =  params->sharedAddr;
79     sparams->sharedBufSize = params->sharedBufSize;
80 }
82 /*
83  *  ======== HeapMemMP_getRTSCParams ========
84  */
85 static Void HeapMemMP_getRTSCParams(
86         ti_sdo_ipc_heaps_HeapMemMP_Params *params,
87         const HeapMemMP_Params *sparams)
88 {
89     ti_sdo_ipc_heaps_HeapMemMP_Params_init(params);
91     params->gate = (ti_sdo_ipc_GateMP_Handle)sparams->gate;
92     params->name = sparams->name;
93     params->regionId = sparams->regionId;
94     params->sharedAddr  =  sparams->sharedAddr;
95     params->sharedBufSize = sparams->sharedBufSize;
96 }
98 /*
99  *************************************************************************
100  *                       Common Header Functions
101  *************************************************************************
102  */
104 /*
105  *  ======== HeapMemMP_Params_init ========
106  */
107 Void HeapMemMP_Params_init(HeapMemMP_Params *sparams)
109     ti_sdo_ipc_heaps_HeapMemMP_Params params;
111     ti_sdo_ipc_heaps_HeapMemMP_Params_init(&params);
112     HeapMemMP_getSharedParams(sparams, &params);
115 /*
116  *  ======== HeapMemMP_alloc ========
117  */
118 Ptr HeapMemMP_alloc(HeapMemMP_Handle handle, SizeT size, SizeT align)
120     Error_Block eb;
122     Error_init(&eb);
124     return (ti_sdo_ipc_heaps_HeapMemMP_alloc(
125             (ti_sdo_ipc_heaps_HeapMemMP_Handle)handle, size, align, &eb));
128 /*
129  *  ======== HeapMemMP_create ========
130  */
131 HeapMemMP_Handle HeapMemMP_create(const HeapMemMP_Params *sparams)
133     ti_sdo_ipc_heaps_HeapMemMP_Params params;
134     ti_sdo_ipc_heaps_HeapMemMP_Object *obj;
135     Error_Block eb;
137     Error_init(&eb);
139     if (sparams != NULL) {
140         HeapMemMP_getRTSCParams(&params, (Ptr)sparams);
142         /* call the module create */
143         obj = ti_sdo_ipc_heaps_HeapMemMP_create(&params, &eb);
144     }
145     else {
146         obj = ti_sdo_ipc_heaps_HeapMemMP_create(NULL, &eb);
147     }
149     return ((HeapMemMP_Handle)obj);
152 /*
153  *  ======== HeapMemMP_close ========
154  */
155 Int HeapMemMP_close(HeapMemMP_Handle *handlePtr)
157     HeapMemMP_delete(handlePtr);
159     return (HeapMemMP_S_SUCCESS);
162 /*
163  *  ======== HeapMemMP_delete ========
164  */
165 Int HeapMemMP_delete(HeapMemMP_Handle *handlePtr)
167     ti_sdo_ipc_heaps_HeapMemMP_delete(
168             (ti_sdo_ipc_heaps_HeapMemMP_Handle *)handlePtr);
170     return (HeapMemMP_S_SUCCESS);
173 /*
174  *  ======== HeapMemMP_free ========
175  */
176 Void HeapMemMP_free(HeapMemMP_Handle handle, Ptr addr, SizeT size)
178     ti_sdo_ipc_heaps_HeapMemMP_free(
179             (ti_sdo_ipc_heaps_HeapMemMP_Handle)handle, addr, size);
182 /*
183  *  ======== HeapMemMP_getExtendedStats ========
184  */
185 Void HeapMemMP_getExtendedStats(HeapMemMP_Handle handle,
186         HeapMemMP_ExtendedStats *stats)
188     ti_sdo_ipc_heaps_HeapMemMP_Object *obj =
189             (ti_sdo_ipc_heaps_HeapMemMP_Object *)handle;
191     stats->buf   = obj->buf;
192     stats->size  = obj->bufSize;
195 /*
196  *  ======== HeapMemMP_getStats ========
197  */
198 Void HeapMemMP_getStats(HeapMemMP_Handle handle, Ptr stats)
200     ti_sdo_ipc_heaps_HeapMemMP_getStats(
201         (ti_sdo_ipc_heaps_HeapMemMP_Handle)handle, (Memory_Stats *)stats);
204 /*
205  *  ======== HeapMemMP_open ========
206  */
207 Int HeapMemMP_open(String name, HeapMemMP_Handle *handlePtr)
209     SharedRegion_SRPtr sharedShmBase;
210     Int status;
211     Ptr sharedAddr;
212     Error_Block eb;
214     Error_init(&eb);
216     /* Assert that a pointer has been supplied */
217     Assert_isTrue(handlePtr != NULL, ti_sdo_ipc_Ipc_A_nullArgument);
219     /* Assert that a name has been supplied */
220     Assert_isTrue(name != NULL, ti_sdo_ipc_Ipc_A_invParam);
222     /* Open by name */
223     status = NameServer_getUInt32(
224             (NameServer_Handle)HeapMemMP_module->nameServer, name,
225             &sharedShmBase, MultiProc_getClusterProcList());
227     if (status < 0) {
228         /* Name not found. */
229         *handlePtr = NULL;
230         return (HeapMemMP_E_NOTFOUND);
231     }
233     sharedAddr = SharedRegion_getPtr(sharedShmBase);
234     /* Assert if sharedAddr is NULL */
235     Assert_isTrue(sharedAddr != NULL,
236             ti_sdo_ipc_Ipc_A_internal);
237     /* Double check to cover case when Assert disabled */
238     if (sharedAddr == NULL) {
239         /* Shared address not found */
240         *handlePtr = NULL;
241         return (HeapMemMP_E_NOTFOUND);
242     }
244     status = HeapMemMP_openByAddr(sharedAddr, handlePtr);
246     return (status);
249 /*
250  *  ======== HeapMemMP_openByAddr ========
251  */
252 Int HeapMemMP_openByAddr(Ptr sharedAddr,
253                          HeapMemMP_Handle *handlePtr)
255     ti_sdo_ipc_heaps_HeapMemMP_Params params;
256     ti_sdo_ipc_heaps_HeapMemMP_Attrs *attrs;
257     Int status;
258     Error_Block eb;
260     Error_init(&eb);
262     ti_sdo_ipc_heaps_HeapMemMP_Params_init(&params);
264     /* Tell Instance_init() that we're opening */
265     params.openFlag = TRUE;
267     params.sharedAddr = sharedAddr;
268     attrs = (ti_sdo_ipc_heaps_HeapMemMP_Attrs *)sharedAddr;
270     if (SharedRegion_isCacheEnabled(SharedRegion_getId(sharedAddr))) {
271         Cache_inv(attrs, sizeof(ti_sdo_ipc_heaps_HeapMemMP_Attrs),
272                 Cache_Type_ALL, TRUE);
273     }
275     if (attrs->status != ti_sdo_ipc_heaps_HeapMemMP_CREATED) {
276         *handlePtr = NULL;
277         status = HeapMemMP_E_NOTFOUND;
278     }
279     else {
280         *handlePtr = (HeapMemMP_Handle)ti_sdo_ipc_heaps_HeapMemMP_create(
281                 &params, &eb);
282         if (*handlePtr == NULL) {
283             status = HeapMemMP_E_FAIL;
284         }
285         else {
286             status = HeapMemMP_S_SUCCESS;
287         }
288     }
290     return (status);
293 /*
294  *  ======== HeapMemMP_restore ========
295  *  The buffer should have the properly alignment at this
296  *  point (either from instance$static$init in HeapMemMP.xs or
297  *  from the above HeapMemMP_Instance_init).
298  */
299 Void HeapMemMP_restore(HeapMemMP_Handle handle)
301     ti_sdo_ipc_heaps_HeapMemMP_Object *obj =
302             (ti_sdo_ipc_heaps_HeapMemMP_Object *)handle;
304     ti_sdo_ipc_heaps_HeapMemMP_Header *begHeader;
306     /*
307      *  Fill in the top of the memory block
308      *  next: pointer will be NULL (end of the list)
309      *  size: size of this block
310      *  NOTE: no need to Cache_inv because obj->attrs->bufPtr should be const
311      */
312     begHeader = (ti_sdo_ipc_heaps_HeapMemMP_Header *)obj->buf;
313     begHeader->next = ti_sdo_ipc_SharedRegion_INVALIDSRPTR;
314     begHeader->size = obj->bufSize;
316     obj->attrs->head.next = obj->attrs->bufPtr;
317     if (obj->cacheEnabled) {
318         Cache_wbInv(&(obj->attrs->head),
319                 sizeof(ti_sdo_ipc_heaps_HeapMemMP_Header), Cache_Type_ALL,
320                 FALSE);
321         Cache_wbInv(begHeader, sizeof(ti_sdo_ipc_heaps_HeapMemMP_Header),
322                 Cache_Type_ALL, TRUE);
323     }
326 /*
327  *  ======== HeapMemMP_sharedMemReq ========
328  */
329 SizeT HeapMemMP_sharedMemReq(const HeapMemMP_Params *params)
331     SizeT memReq, minAlign;
332     UInt16 regionId;
334     /* Ensure that the sharedBufSize param has been set */
335     Assert_isTrue(params->sharedBufSize != 0, ti_sdo_ipc_Ipc_A_invParam);
337     if (params->sharedAddr == NULL) {
338         regionId = params->regionId;
339     }
340     else {
341         regionId = SharedRegion_getId(params->sharedAddr);
342     }
344     Assert_isTrue(regionId != SharedRegion_INVALIDREGIONID,
345             ti_sdo_ipc_Ipc_A_internal);
347     minAlign = sizeof(ti_sdo_ipc_heaps_HeapMemMP_Header);
348     if (SharedRegion_getCacheLineSize(regionId) > minAlign) {
349         minAlign = SharedRegion_getCacheLineSize(regionId);
350     }
352     /* Add size of HeapBufMP Attrs */
353     memReq = _Ipc_roundup(sizeof(ti_sdo_ipc_heaps_HeapMemMP_Attrs), minAlign);
355     /* Add the buffer size */
356     memReq += params->sharedBufSize;
358     /* Make sure the size is a multiple of minAlign (round down) */
359     memReq = (memReq / minAlign) * minAlign;
361     return((SizeT)memReq);
364 /*
365  *************************************************************************
366  *                      Instance functions
367  *************************************************************************
368  */
370 /*
371  *  ======== ti_sdo_ipc_heaps_HeapMemMP_Instance_init ========
372  */
373 Int ti_sdo_ipc_heaps_HeapMemMP_Instance_init(
374         ti_sdo_ipc_heaps_HeapMemMP_Object *obj,
375         const ti_sdo_ipc_heaps_HeapMemMP_Params *params,
376         Error_Block *eb)
378     SharedRegion_SRPtr sharedShmBase;
379     Ptr localAddr;
380     Int status;
382     /* Assert that sharedBufSize is sufficient */
383     Assert_isTrue(params->openFlag == TRUE ||
384                   params->sharedBufSize != 0,
385                   ti_sdo_ipc_Ipc_A_invParam);
387     obj->nsKey          = NULL;
388     obj->allocSize      = 0;
390     if (params->openFlag == TRUE) {
391         /* Opening the gate */
392         obj->attrs      = (ti_sdo_ipc_heaps_HeapMemMP_Attrs *)
393             params->sharedAddr;
395         /* No need to Cache_inv- already done in openByAddr() */
396         obj->buf            = (Char *)SharedRegion_getPtr(
397                                     obj->attrs->bufPtr);
398         obj->bufSize        = obj->attrs->head.size;
399         obj->objType        = ti_sdo_ipc_Ipc_ObjType_OPENDYNAMIC;
400         obj->regionId       = SharedRegion_getId(obj->buf);
401         obj->cacheEnabled   = SharedRegion_isCacheEnabled(obj->regionId);
403         /* Set minAlign */
404         obj->minAlign = sizeof(ti_sdo_ipc_heaps_HeapMemMP_Header);
405         if (SharedRegion_getCacheLineSize(obj->regionId) > obj->minAlign) {
406             obj->minAlign = SharedRegion_getCacheLineSize(obj->regionId);
407         }
409         localAddr = SharedRegion_getPtr(obj->attrs->gateMPAddr);
410         if (localAddr == NULL) {
411             Error_raise(eb, ti_sdo_ipc_Ipc_E_internal, 0, 0);
412             return(1);
413         }
415         status = GateMP_openByAddr(localAddr, (GateMP_Handle *)&(obj->gate));
416         if (status != GateMP_S_SUCCESS) {
417             Error_raise(eb, ti_sdo_ipc_Ipc_E_internal, 0, 0);
418             return(1);
419         }
421         return(0);
422     }
424     /* Creating the heap */
425     if (params->gate != NULL) {
426         obj->gate       = params->gate;
427     }
428     else {
429         /* If no gate specified, get the default system gate */
430         obj->gate       = (ti_sdo_ipc_GateMP_Handle)GateMP_getDefaultRemote();
431     }
433     obj->bufSize        = params->sharedBufSize;
435     if (params->sharedAddr == NULL) {
436         /* Creating using a shared region ID */
437         obj->objType    = ti_sdo_ipc_Ipc_ObjType_CREATEDYNAMIC_REGION;
438         obj->attrs      = NULL; /* Will be alloc'ed in postInit */
439         obj->regionId   = params->regionId;
440     }
441     else {
442         /* Creating using sharedAddr */
443         obj->regionId   = SharedRegion_getId(params->sharedAddr);
445         /* Assert that the buffer is in a valid shared region */
446         Assert_isTrue(obj->regionId != SharedRegion_INVALIDREGIONID,
447                       ti_sdo_ipc_Ipc_A_addrNotInSharedRegion);
449         /* Assert that sharedAddr is cache aligned */
450         Assert_isTrue(((UArg)params->sharedAddr %
451                       SharedRegion_getCacheLineSize(obj->regionId) == 0),
452                       ti_sdo_ipc_Ipc_A_addrNotCacheAligned);
454         obj->objType    = ti_sdo_ipc_Ipc_ObjType_CREATEDYNAMIC;
456         /* obj->buf will get alignment-adjusted in postInit */
457         obj->buf        = (Ptr)((UArg)params->sharedAddr +
458                           sizeof(ti_sdo_ipc_heaps_HeapMemMP_Attrs));
459         obj->attrs     = (ti_sdo_ipc_heaps_HeapMemMP_Attrs *)params->sharedAddr;
460     }
462     obj->cacheEnabled = SharedRegion_isCacheEnabled(obj->regionId);
464     /* Set minAlign */
465     obj->minAlign = sizeof(ti_sdo_ipc_heaps_HeapMemMP_Header);
466     if (SharedRegion_getCacheLineSize(obj->regionId) > obj->minAlign) {
467         obj->minAlign = SharedRegion_getCacheLineSize(obj->regionId);
468     }
470     HeapMemMP_postInit(obj, eb);
471     if (Error_check(eb)) {
472         return(2);
473     }
475     /* Add entry to NameServer */
476     if (params->name != NULL) {
477         /* We will store a shared pointer in the NameServer */
478         sharedShmBase = SharedRegion_getSRPtr(obj->attrs,
479                                               obj->regionId);
480         obj->nsKey = NameServer_addUInt32((NameServer_Handle)
481                 HeapMemMP_module->nameServer, params->name,
482                 (UInt32)sharedShmBase);
484         if (obj->nsKey == NULL) {
485             /* NameServer_addUInt32 failed */
486             Error_raise(eb, ti_sdo_ipc_Ipc_E_nameFailed, params->name, 0);
487             return (3);
488         }
489     }
491     return (0);
494 /*
495  *  ======== ti_sdo_ipc_heaps_HeapMemMP_Instance_finalize ========
496  */
497 Void ti_sdo_ipc_heaps_HeapMemMP_Instance_finalize(
498         ti_sdo_ipc_heaps_HeapMemMP_Object *obj, Int status)
500     if (obj->objType & (ti_sdo_ipc_Ipc_ObjType_CREATEDYNAMIC |
501                         ti_sdo_ipc_Ipc_ObjType_CREATEDYNAMIC_REGION)) {
502         /* Remove entry from NameServer */
503         if (obj->nsKey != NULL) {
504             NameServer_removeEntry((NameServer_Handle)
505                     HeapMemMP_module->nameServer, obj->nsKey);
506         }
508         if (obj->attrs != NULL) {
509             /* Set status to 'not created' */
510             obj->attrs->status = 0;
511             if (obj->cacheEnabled) {
512                 Cache_wbInv(obj->attrs,
513                             sizeof(ti_sdo_ipc_heaps_HeapMemMP_Attrs),
514                             Cache_Type_ALL, TRUE);
515             }
516         }
518         /*
519          *  Free the shared memory back to the region heap. If NULL, then the
520          *  Memory_alloc failed.
521          */
522         if (obj->objType == ti_sdo_ipc_Ipc_ObjType_CREATEDYNAMIC_REGION
523             && obj->attrs != NULL) {
524             Memory_free(SharedRegion_getHeap(obj->regionId), obj->attrs,
525                         obj->allocSize);
526         }
527     }
528     else {
529         /* Heap is being closed */
530         /* Close the gate. If NULL, then GateMP_openByAddr failed. */
531         if (obj->gate != NULL) {
532             GateMP_close((GateMP_Handle *)&(obj->gate));
533         }
534     }
537 /*
538  * NOTE:
539  * Embedded within the code for HeapMemMP_alloc and HeapMemMP_free are comments
540  * that can be used to match a shared memory reference with its required
541  * cache call.  This is done because the code for alloc and free is complex.
542  * These two-character comments indicate
543  * 1) The type of cache operation that is being performed {A, B}
544  *    A = Cache_inv
545  *    B = Cache_wbInv
546  * 2) A numerical id of the specific cache call that is performed.
547  *    1, 2, 3
548  *    For example, the comment 'A2' indicates that the corresponding cache call
549  *    is a Cache_inv operation identified by the number '2'
550  */
552 /*
553  *  ======== ti_sdo_ipc_heaps_HeapMemMP_alloc ========
554  *  HeapMemMP is implemented such that all of the memory and blocks it works
555  *  with have an alignment that is a multiple of the minimum alignment and have
556  *  a size which is a multiple of the minAlign. Maintaining this requirement
557  *  throughout the implementation ensures that there are never any odd
558  *  alignments or odd block sizes to deal with.
559  *
560  *  Specifically:
561  *  The buffer managed by HeapMemMP:
562  *    1. Is aligned on a multiple of obj->minAlign
563  *    2. Has an adjusted size that is a multiple of obj->minAlign
564  *  All blocks on the freelist:
565  *    1. Are aligned on a multiple of obj->minAlign
566  *    2. Have a size that is a multiple of obj->minAlign
567  *  All allocated blocks:
568  *    1. Are aligned on a multiple of obj->minAlign
569  *    2. Have a size that is a multiple of obj->minAlign
570  *
571  */
572 Ptr ti_sdo_ipc_heaps_HeapMemMP_alloc(ti_sdo_ipc_heaps_HeapMemMP_Object *obj,
573     SizeT reqSize, SizeT reqAlign, Error_Block *eb)
575     IArg key;
576     ti_sdo_ipc_heaps_HeapMemMP_Header *prevHeader, *newHeader, *curHeader;
577     Char *allocAddr;
578     Memory_Size curSize, adjSize;
579     SizeT remainSize; /* free memory after allocated memory */
580     SizeT adjAlign, offset;
582     /* Assert that requested align is a power of 2 */
583     Assert_isTrue((reqAlign & (reqAlign - 1)) == 0,
584         ti_sdo_ipc_heaps_HeapMemMP_A_align);
586     /* Assert that requested block size is non-zero */
587     Assert_isTrue(reqSize != 0, ti_sdo_ipc_heaps_HeapMemMP_A_zeroBlock);
589     adjSize = (Memory_Size)reqSize;
591     /* Make size requested a multiple of obj->minAlign */
592     if ((offset = (adjSize & (obj->minAlign - 1))) != 0) {
593         adjSize = adjSize + (obj->minAlign - offset);
594     }
596     /*
597      *  Make sure the alignment is at least as large as obj->minAlign
598      *  Note: adjAlign must be a power of 2 (by function constraint) and
599      *  obj->minAlign is also a power of 2,
600      */
601     adjAlign = reqAlign;
602     if (adjAlign & (obj->minAlign - 1)) {
603         /* adjAlign is less than obj->minAlign */
604         adjAlign = obj->minAlign;
605     }
607     /* No need to Cache_inv Attrs- 'head' should be constant */
608     prevHeader = &(obj->attrs->head);
610     key = GateMP_enter((GateMP_Handle)obj->gate);
612     /*
613      *  The block will be allocated from curHeader. Maintain a pointer to
614      *  prevHeader so prevHeader->next can be updated after the alloc.
615      */
616     if (obj->cacheEnabled) {
617         Cache_inv(prevHeader, sizeof(ti_sdo_ipc_heaps_HeapMemMP_Header),
618                   Cache_Type_ALL, TRUE); /* A1 */
619     }
620     curHeader = (ti_sdo_ipc_heaps_HeapMemMP_Header *)
621         SharedRegion_getPtr(prevHeader->next); /* A1 */
623     /* Loop over the free list. */
624     while (curHeader != NULL) {
625         /* Invalidate curHeader */
626         if (obj->cacheEnabled) {
627             Cache_inv(curHeader, sizeof(ti_sdo_ipc_heaps_HeapMemMP_Header),
628                       Cache_Type_ALL, TRUE); /* A2 */
629         }
630         curSize = curHeader->size;
632         /*
633          *  Determine the offset from the beginning to make sure
634          *  the alignment request is honored.
635          */
636         offset = (Memory_Size)curHeader & (adjAlign - 1);
637         if (offset) {
638             offset = adjAlign - offset;
639         }
641         /* Internal Assert that offset is a multiple of obj->minAlign */
642         Assert_isTrue(((offset & (obj->minAlign - 1)) == 0),
643                 ti_sdo_ipc_Ipc_A_internal);
645         /* big enough? */
646         if (curSize >= (adjSize + offset)) {
648             /* Set the pointer that will be returned. Alloc from front */
649             allocAddr = (Char *)((Memory_Size)curHeader + offset);
651             /*
652              *  Determine the remaining memory after the allocated block.
653              *  Note: this cannot be negative because of above comparison.
654              */
655             remainSize = curSize - adjSize - offset;
657             /* Internal Assert that remainSize is a multiple of obj->minAlign */
658             Assert_isTrue(((remainSize & (obj->minAlign - 1)) == 0),
659                            ti_sdo_ipc_Ipc_A_internal);
661             /*
662              *  If there is memory at the beginning (due to alignment
663              *  requirements), maintain it in the list.
664              *
665              *  offset and remainSize must be multiples of
666              *  sizeof(HeapMemMP_Header). Therefore the address of the newHeader
667              *  below must be a multiple of the sizeof(HeapMemMP_Header), thus
668              *  maintaining the requirement.
669              */
670             if (offset) {
672                 /* Adjust the curHeader size accordingly */
673                 curHeader->size = offset; /* B2 */
674                 /* Cache wb at end of this if block */
676                 /*
677                  *  If there is remaining memory, add into the free list.
678                  *  Note: no need to coalesce and we have HeapMemMP locked so
679                  *        it is safe.
680                  */
681                 if (remainSize) {
682                     newHeader = (ti_sdo_ipc_heaps_HeapMemMP_Header *)
683                         ((Memory_Size)allocAddr + adjSize);
685                     /* curHeader has been inv at top of 'while' loop */
686                     newHeader->next = curHeader->next;  /* B1 */
687                     newHeader->size = remainSize;       /* B1 */
688                     if (obj->cacheEnabled) {
689                         /* Writing back curHeader will cache-wait */
690                         Cache_wbInv(newHeader,
691                                 sizeof(ti_sdo_ipc_heaps_HeapMemMP_Header),
692                                 Cache_Type_ALL, FALSE); /* B1 */
693                     }
695                     curHeader->next = SharedRegion_getSRPtr(newHeader,
696                                                             obj->regionId);
697                 }
698                 /* Write back (and invalidate) newHeader and curHeader */
699                 if (obj->cacheEnabled) {
700                     /* B2 */
701                     Cache_wbInv(curHeader,
702                             sizeof(ti_sdo_ipc_heaps_HeapMemMP_Header),
703                             Cache_Type_ALL, TRUE);
704                 }
705             }
706             else {
707                 /*
708                  *  If there is any remaining, link it in,
709                  *  else point to the next free block.
710                  *  Note: no need to coalesce and we have HeapMemMP locked so
711                  *        it is safe.
712                  */
713                 if (remainSize) {
714                     newHeader = (ti_sdo_ipc_heaps_HeapMemMP_Header *)
715                         ((Memory_Size)allocAddr + adjSize);
717                     newHeader->next  = curHeader->next; /* A2, B3  */
718                     newHeader->size  = remainSize;      /* B3      */
720                     if (obj->cacheEnabled) {
721                         /* Writing back prevHeader will cache-wait */
722                         Cache_wbInv(newHeader,
723                                 sizeof(ti_sdo_ipc_heaps_HeapMemMP_Header),
724                                 Cache_Type_ALL, FALSE); /* B3 */
725                     }
727                     /* B4 */
728                     prevHeader->next = SharedRegion_getSRPtr(newHeader,
729                                                              obj->regionId);
730                 }
731                 else {
732                     /* curHeader has been inv at top of 'while' loop */
733                     prevHeader->next = curHeader->next; /* A2, B4 */
734                 }
736                 if (obj->cacheEnabled) {
737                     /* B4 */
738                     Cache_wbInv(prevHeader,
739                             sizeof(ti_sdo_ipc_heaps_HeapMemMP_Header),
740                             Cache_Type_ALL, TRUE);
741                 }
742             }
744             GateMP_leave((GateMP_Handle)obj->gate, key);
746             /* Success, return the allocated memory */
747             return ((Ptr)allocAddr);
748         }
749         else {
750             prevHeader = curHeader;
751             curHeader = SharedRegion_getPtr(curHeader->next);
752         }
753     }
755     GateMP_leave((GateMP_Handle)obj->gate, key);
757     Error_raise(eb, ti_sdo_ipc_heaps_HeapMemMP_E_memory, (IArg)obj,
758             (IArg)reqSize);
760     return (NULL);
763 /*
764  *  ======== ti_sdo_ipc_heaps_HeapMemMP_free ========
765  */
766 Void ti_sdo_ipc_heaps_HeapMemMP_free(ti_sdo_ipc_heaps_HeapMemMP_Object *obj,
767         Ptr addr, SizeT size)
769     IArg key;
770     ti_sdo_ipc_heaps_HeapMemMP_Header *curHeader, *newHeader, *nextHeader;
771     SizeT offset;
773     /* Assert that 'addr' is cache aligned  */
774     Assert_isTrue(((UArg)addr % obj->minAlign == 0),
775             ti_sdo_ipc_Ipc_A_addrNotCacheAligned);
777     /* Restore size to actual allocated size */
778     offset = size & (obj->minAlign - 1);
779     if (offset != 0) {
780         size += obj->minAlign - offset;
781     }
783     newHeader = (ti_sdo_ipc_heaps_HeapMemMP_Header *)addr;
785     /*
786      *  Invalidate entire buffer being freed to ensure that stale cache
787      *  data in block isn't evicted later
788      */
789     if (obj->cacheEnabled) {
790         Cache_inv(newHeader, size, Cache_Type_ALL, FALSE);
791     }
793     /*
794      * obj->attrs never changes, doesn't need Gate protection
795      * and Cache invalidate
796      */
797     curHeader = &(obj->attrs->head);
799     key = GateMP_enter((GateMP_Handle)obj->gate);
801     if (obj->cacheEnabled) {
802         /* A1 */
803         Cache_inv(curHeader, sizeof(ti_sdo_ipc_heaps_HeapMemMP_Header),
804                 Cache_Type_ALL, TRUE);
805     }
807     nextHeader = SharedRegion_getPtr(curHeader->next);
809     /* Make sure the entire buffer is in the range of the heap. */
810     Assert_isTrue((((SizeT)newHeader >= (SizeT)obj->buf) &&
811                    ((SizeT)newHeader + size <=
812                     (SizeT)obj->buf + obj->bufSize)),
813                    ti_sdo_ipc_heaps_HeapMemMP_A_invalidFree);
815     /* Go down freelist and find right place for buf */
816     while (nextHeader != NULL && nextHeader < newHeader) {
817         if (obj->cacheEnabled) {
818             Cache_inv(nextHeader, sizeof(ti_sdo_ipc_heaps_HeapMemMP_Header),
819                       Cache_Type_ALL, FALSE); /* A2 */
820         }
822         /* Make sure the addr is not in this free block */
823         Assert_isTrue((SizeT)newHeader >= (SizeT)nextHeader + nextHeader->size,
824                        ti_sdo_ipc_heaps_HeapMemMP_A_invalidFree); /* A2 */
825         curHeader = nextHeader;
826         /* A2 */
827         nextHeader = SharedRegion_getPtr(nextHeader->next);
828     }
830     /* B2 */
831     newHeader->next = SharedRegion_getSRPtr(nextHeader, obj->regionId);
832     newHeader->size = size;
834     /* B1, A1 */
835     curHeader->next = SharedRegion_getSRPtr(newHeader, obj->regionId);
837     /* Join contiguous free blocks */
838     if (nextHeader != NULL) {
839         /*
840          *  Verify the free size is not overlapping. Not all cases are
841          *  detectable, but it is worth a shot. Note: only do this
842          *  assert if nextHeader is non-NULL.
843          */
844         Assert_isTrue(((SizeT)newHeader + size) <= (SizeT)nextHeader,
845                       ti_sdo_ipc_heaps_HeapMemMP_A_invalidFree);
847         /* Join with upper block */
848         if (((Memory_Size)newHeader + size) == (Memory_Size)nextHeader) {
849             if (obj->cacheEnabled) {
850                 Cache_inv(nextHeader, sizeof(ti_sdo_ipc_heaps_HeapMemMP_Header),
851                           Cache_Type_ALL, TRUE);
852             }
853             newHeader->next = nextHeader->next; /* A2, B2 */
854             newHeader->size += nextHeader->size; /* A2, B2 */
855             size += obj->minAlign;
857             /* Don't Cache_wbInv, this will be done later */
858         }
859     }
861     /*
862      *  Join with lower block. Make sure to check to see if not the
863      *  first block. No need to invalidate attrs since head shouldn't change.
864      */
865     if ((curHeader != &obj->attrs->head) &&
866         ((Memory_Size)curHeader + curHeader->size == (Memory_Size)newHeader)) {
867         /*
868          * Don't Cache_inv newHeader since newHeader has data that
869          * hasn't been written back yet (B2)
870          */
871         curHeader->next = newHeader->next; /* B1, B2 */
872         curHeader->size += newHeader->size; /* B1, B2 */
873     }
875     if (obj->cacheEnabled) {
876         Cache_wbInv(curHeader, sizeof(ti_sdo_ipc_heaps_HeapMemMP_Header),
877              Cache_Type_ALL, FALSE); /* B1 */
878         /*
879          *  writeback invalidate the new header
880          */
881         Cache_wbInv(newHeader, sizeof(ti_sdo_ipc_heaps_HeapMemMP_Header),
882              Cache_Type_ALL, TRUE);  /* B2 */
883        /*
884         *  Invalidate entire buffer being freed to ensure that stale cache
885         *  data in block isn't evicted later
886         */
887         Cache_inv(newHeader, size, Cache_Type_ALL, TRUE);  /* B2 */
888     }
890     GateMP_leave((GateMP_Handle)obj->gate, key);
893 /*
894  *  ======== HeapMemMP_isBlocking ========
895  */
896 Bool ti_sdo_ipc_heaps_HeapMemMP_isBlocking(
897         ti_sdo_ipc_heaps_HeapMemMP_Object *obj)
899     Bool flag = FALSE;
901     // TODO figure out how to determine whether the gate is blocking...
902     return (flag);
905 /*
906  *  ======== HeapMemMP_getStats ========
907  */
908 Void ti_sdo_ipc_heaps_HeapMemMP_getStats(ti_sdo_ipc_heaps_HeapMemMP_Object *obj,
909         Memory_Stats *stats)
911     IArg key;
912     ti_sdo_ipc_heaps_HeapMemMP_Header *curHeader;
914     stats->totalSize         = obj->bufSize;
915     stats->totalFreeSize     = 0;  /* determined later */
916     stats->largestFreeSize   = 0;  /* determined later */
918     key = GateMP_enter((GateMP_Handle)obj->gate);
920     if (obj->cacheEnabled) {
921         Cache_inv(&(obj->attrs->head),
922                 sizeof(ti_sdo_ipc_heaps_HeapMemMP_Header), Cache_Type_ALL,
923                 TRUE);
924     }
926     curHeader = SharedRegion_getPtr(obj->attrs->head.next);
928     while (curHeader != NULL) {
929         /* Invalidate curHeader */
930         if (obj->cacheEnabled) {
931             Cache_inv(curHeader, sizeof(ti_sdo_ipc_heaps_HeapMemMP_Header),
932                       Cache_Type_ALL, TRUE);
933         }
934         stats->totalFreeSize += curHeader->size;
935         if (stats->largestFreeSize < curHeader->size) {
936             stats->largestFreeSize = curHeader->size;
937         }
938         curHeader = SharedRegion_getPtr(curHeader->next);
939     }
941     GateMP_leave((GateMP_Handle)obj->gate, key);
944 /*
945  *************************************************************************
946  *                       Internal functions
947  *************************************************************************
948  */
950 /*
951  *  ======== ti_sdo_ipc_heaps_HeapMemMP_postInit ========
952  */
953 Void ti_sdo_ipc_heaps_HeapMemMP_postInit(ti_sdo_ipc_heaps_HeapMemMP_Object *obj,
954         Error_Block *eb)
956     HeapMemMP_Params params;
957     IHeap_Handle regionHeap;
959     if (obj->attrs == NULL) {
960         /* Need to allocate from the heap */
961         HeapMemMP_Params_init(&params);
962         params.regionId = obj->regionId;
963         params.sharedBufSize = obj->bufSize;
964         obj->allocSize = HeapMemMP_sharedMemReq(&params);
966         regionHeap = SharedRegion_getHeap(obj->regionId);
967         Assert_isTrue(regionHeap != NULL, ti_sdo_ipc_SharedRegion_A_noHeap);
968         obj->attrs = Memory_alloc(regionHeap,
969                                   obj->allocSize,
970                                   obj->minAlign, eb);
971         if (obj->attrs == NULL) {
972             return;
973         }
975         obj->buf = (Ptr)((UArg)obj->attrs +
976                 sizeof(ti_sdo_ipc_heaps_HeapMemMP_Attrs));
977     }
979     /* Round obj->buf up by obj->minAlign */
980     obj->buf = (Ptr)_Ipc_ptrRoundup(obj->buf, obj->minAlign);
982     /* Verify the buffer is large enough */
983     Assert_isTrue((obj->bufSize >=
984             SharedRegion_getCacheLineSize(obj->regionId)),
985             ti_sdo_ipc_heaps_HeapMemMP_A_heapSize);
987     /* Make sure the size is a multiple of obj->minAlign */
988     obj->bufSize = (obj->bufSize / obj->minAlign) * obj->minAlign;
990     obj->attrs->gateMPAddr = ti_sdo_ipc_GateMP_getSharedAddr(obj->gate);
991     obj->attrs->bufPtr = SharedRegion_getSRPtr(obj->buf, obj->regionId);
993     /* Store computed obj->bufSize in shared mem */
994     obj->attrs->head.size = obj->bufSize;
996     /* Place the initial header */
997     HeapMemMP_restore((HeapMemMP_Handle)obj);
999     /* Last thing, set the status */
1000     obj->attrs->status = ti_sdo_ipc_heaps_HeapMemMP_CREATED;
1002     if (obj->cacheEnabled) {
1003         Cache_wbInv(obj->attrs, sizeof(ti_sdo_ipc_heaps_HeapMemMP_Attrs),
1004                 Cache_Type_ALL, TRUE);
1005     }