summaryrefslogtreecommitdiff
path: root/drivers/staging/nmf-cm/cm/engine/memory/src/remote_allocator_utils.c
blob: 4e800376dbb42c7b1bb00f1bae676fbcd52c4586 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
/*
 * Copyright (C) ST-Ericsson SA 2010
 * Author: Jean-Philippe FASSINO <jean-philippe.fassino@stericsson.com> for ST-Ericsson.
 * License terms: GNU General Public License (GPL) version 2.
 */
#include <cm/engine/memory/inc/remote_allocator_utils.h>
#include <cm/engine/trace/inc/trace.h>

/***************************************************************************/
/*
 * linkChunk
 * param prev     : Pointer on previous chunk where the chunk will be added
 * param add      : Pointer on chunk to add
 *
 * Add a chunk in the memory list
 *
 */
/***************************************************************************/
PUBLIC void linkChunk(t_cm_allocator_desc* alloc, t_cm_chunk* prev, t_cm_chunk* add)
{
    // Link previous
    if(prev == 0)
    {
        add->next = alloc->chunks;
        alloc->chunks = add;
    }
    else
    {
        add->prev = prev;
        add->next = prev->next;
        prev->next = add;
    }

    // Link next
    if(add->next == 0)
    {
        // Link at the end
        alloc->lastChunk = add;
    }
    else
        add->next->prev = add;
}

/***************************************************************************/
/*
 * unlinkChunk
 * param allocHandle : Allocator handle
 * param current     : Pointer on chunk to remove
 *
 * Remove a chunk in the memory list and update first pointer
 *
 */
/***************************************************************************/
PUBLIC void unlinkChunk(t_cm_allocator_desc* alloc, t_cm_chunk* current)
{
    /* Link previous with next */
    if (current->prev != 0)
        current->prev->next = current->next;
    else
    {
        CM_ASSERT(alloc->chunks == current);

        // We remove the first, update chunks
        alloc->chunks = current->next;
    }

    /* Link next with previous */
    if(current->next != 0)
        current->next->prev= current->prev;
    else
    {
        CM_ASSERT(alloc->lastChunk == current);

        // We remove the last, update lastChunk
        alloc->lastChunk = current->prev;
    }
}


/***************************************************************************/
/*
 * unlinkFreeMem() unlinks chunk from free memory double-linked list
 *   makes the previous and next chunk in the list point to each other..
 * param allocHandle : Allocator handle
 * param current     : Pointer on chunk to remove
 *
 * Remove a chunk in the free memory list and update pointer
 *
 */
/***************************************************************************/
PUBLIC void unlinkFreeMem(t_cm_allocator_desc* alloc ,t_cm_chunk* current)
{
    int bin = bin_index(current->size);

    /* unlink previous */
    if (current->prev_free_mem != 0)
    {
        current->prev_free_mem->next_free_mem = current->next_free_mem;
    }

    /* Unlink next */
    if (current->next_free_mem !=0 )
    {
        current->next_free_mem->prev_free_mem = current->prev_free_mem;
    }

    /* update first free pointer */
    if (alloc->free_mem_chunks[bin] == current)
    {
        alloc->free_mem_chunks[bin] = current->next_free_mem;
    }

    current->prev_free_mem = 0;
    current->next_free_mem = 0;
}

/***************************************************************************/
/*
 * linkFreeMemBefore
 * param add      : Pointer on chunk to add
 * param next     : Pointer on next chunk where the chunk will be added before
 *
 * Add a chunk in the free memory list
 *
 */
/***************************************************************************/
PUBLIC void linkFreeMemBefore(t_cm_chunk* add, t_cm_chunk* next)
{
    /* Link next */
    add->prev_free_mem = next->prev_free_mem;
    add->next_free_mem = next;

    /* Link previous */
    if (next->prev_free_mem != 0)
    {
        next->prev_free_mem->next_free_mem = add;
    }
    next->prev_free_mem = add;
}

/***************************************************************************/
/*
 * linkFreeMemAfter
 * param add      : Pointer on chunk to add
 * param prev     : Pointer on previous chunk where the chunk will be added after
 *
 * Add a chunk in the free memory list
 *
 */
/***************************************************************************/
PUBLIC void linkFreeMemAfter(t_cm_chunk* prev,t_cm_chunk* add)
{
    /* Link previous */
    add->prev_free_mem = prev;
    add->next_free_mem = prev->next_free_mem;

    /* Link next */
    if (prev->next_free_mem != 0)
    {
        prev->next_free_mem->prev_free_mem = add;
    }
    prev->next_free_mem = add;
}


/***************************************************************************/
/*
 * updateFreeList
 * param allocHandle : Allocator handle
 * param offset      : Pointer on chunk
 *
 * Update free memory list, ordered by size
 *
 */
/***************************************************************************/
PUBLIC void updateFreeList(t_cm_allocator_desc* alloc , t_cm_chunk* chunk)
{
    t_cm_chunk* free_chunk;
    int bin = bin_index(chunk->size);

    /* check case with no more free block */
    if (alloc->free_mem_chunks[bin] == 0)
    {
        alloc->free_mem_chunks[bin] = chunk;
        return ;
    }

    /* order list */
    free_chunk = alloc->free_mem_chunks[bin];
    while ((free_chunk->next_free_mem != 0) && (chunk->size > free_chunk->size))
    {
        free_chunk = free_chunk->next_free_mem;
    }

    /* Add after free chunk if smaller -> we are the last */
    if(free_chunk->size <= chunk->size)
    {
        linkFreeMemAfter(free_chunk,chunk);
    }
    else // This mean that we are smaller
    {
        linkFreeMemBefore(chunk,free_chunk);

        /* Update first free chunk */
        if (alloc->free_mem_chunks[bin] == free_chunk)
        {
            alloc->free_mem_chunks[bin] = chunk;
        }
    }
}


/***************************************************************************/
/*
 * splitChunk
 * param allocHandle : Allocator handle
 * param chunk       : Current chunk (modified in place)
 * param offset      : Offset address of the start memory
 * return            : New chunk handle or 0 if an error occurs
 *
 * Create new chunk before/after the current chunk with the size
 */
/***************************************************************************/
PUBLIC t_cm_chunk* splitChunk(t_cm_allocator_desc* alloc ,t_cm_chunk *chunk,
        t_uint32 offset, t_mem_split_position position)
{
    t_cm_chunk *free;
    t_cm_chunk *returned;

    t_cm_chunk* new_chunk = allocChunk();

    if (position == FREE_CHUNK_AFTER) {
        returned = chunk;
        free = new_chunk;
    } else { //FREE_CHUNK_BEFORE
        returned = new_chunk;
        free = chunk;
    }

    new_chunk->offset = offset;
    new_chunk->size   = chunk->offset + chunk->size - offset;
    new_chunk->alloc  = alloc;
    chunk->size = offset - chunk->offset;

    linkChunk(alloc, chunk, new_chunk);
    unlinkFreeMem(alloc, free);
    updateFreeList(alloc, free);

    return returned;
}