summaryrefslogtreecommitdiff
path: root/drivers/staging/nmf-cm/cm/engine/memory/src/migration.c
blob: d68898d830e3d00d8834426d500b7331058d34ad (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
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
/*
 * 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/inc/cm_type.h>
#include <inc/type.h>
#include <inc/nmf-limits.h>

#include <cm/engine/communication/fifo/inc/nmf_fifo_arm.h>
#include <cm/engine/dsp/inc/dsp.h>
#include <cm/engine/memory/inc/domain.h>
#include <cm/engine/memory/inc/memory.h>
#include <cm/engine/memory/inc/migration.h>
#include <cm/engine/trace/inc/trace.h>
#include <cm/engine/utils/inc/mem.h>

#if defined(__STN_8500) && (__STN_8500 > 10)

typedef enum {
    CM_MIGRATION_OK = 0,
    CM_MIGRATION_INVALID_ARGUMENT = 1,
    CM_MIGRATION_ERROR = 2,
} t_cm_migration_error;

extern t_nmf_fifo_arm_desc* mpc2mpcComsFifoId[NB_CORE_IDS][NB_CORE_IDS];

/*!
 * \brief Data structure representing a segment to migrate
 *
 * segment:
 *      - used to determine which mmdsp-hw base is to be updated, index in mpcDesc->segments[] structure
 *      * this is hard-coded in cm_migrate(), could be computed (would be nice) LIMITATION
 * srcAdr.physical:
 *      - new base setting
 *      * computed from the src domain in cm_DM_GetAbsAdresses() which uses the start of the allocator for the memory
 *        this is a LIMITATION, as this information is valid only before migration
 * srcAdr.logical:
 *      - cm_MemCopy()
 *      * computed as srcAdr.logical
 * dstAdr.physical: see srcAdr.physical
 * dstAdr.logical:  see srcAdr.logical
 * size:
 *      - cm_MemCopy()
 *      - setting the top when new base is set
 */
typedef struct {
    t_dsp_segment_type       segment; //!< the link to the segment type
    t_cm_system_address      srcAdr;  //!< source address
    t_cm_system_address      dstAdr;  //!< destination address
    t_uint32                 size;    //!< size of the segment
} t_cm_migration_segment;

/*!
 * \brief Internal data structure 1/ during migration, and 2/ between migration and unmigration calls
 *
 * all needed information are computed before calling _cm_migration_move()
 */
typedef struct {
    t_cm_migration_state    state;                            //!< migration state
    t_nmf_core_id           coreId;                           //!< migration only on one mpc
    t_cm_migration_segment  segments[NB_MIGRATION_SEGMENT];   //!< segments to migrate (selected on migration_move)
    t_memory_handle         handles[NB_MIGRATION_SEGMENT];    //!< memory handles for destination chunks allocated prior migration
} t_cm_migration_internal_state;

static t_cm_migration_internal_state migrationState = {STATE_NORMAL, };

static t_cm_error _cm_migration_initSegment(
        t_dsp_segment_type      dspSegment,
        t_cm_system_address    *srcAdr,
        t_uint32                size,
        t_cm_domain_id          dst,
        t_cm_migration_internal_state *info
        )
{
    t_cm_system_address      dstAdr;
    t_cm_migration_segment  *segment = &info->segments[dspSegment];
    t_memory_handle          handle;

    handle = cm_DM_Alloc(dst, ESRAM_EXT16, size >> 1, CM_MM_ALIGN_AHB_BURST, TRUE); //note: byte to half-word conversion
    if (handle == 0) {
        ERROR("CM_NO_MORE_MEMORY: Unable to init segment for migration\n", 0, 0, 0, 0, 0, 0);
        return CM_NO_MORE_MEMORY;
    }

    info->handles[dspSegment] = handle;

    cm_DSP_GetHostSystemAddress(handle, &dstAdr);

    segment->segment   = dspSegment; //this is redundant and could be avoided by recoding move(), but nice to have for debug
    segment->size      = size;
    segment->srcAdr    = *srcAdr;
    segment->dstAdr    = dstAdr;

    return CM_OK;
}

static void _cm_migration_releaseSegment(t_cm_migration_internal_state *info, t_dsp_segment_type segId)
{
    cm_DM_Free(info->handles[segId], TRUE);
}

static t_cm_migration_error _cm_migration_release(t_cm_migration_internal_state *info)
{
    t_uint32 i = 0;
    for (i = 0; i < NB_MIGRATION_SEGMENT; i++) {
        cm_DM_Free(info->handles[i], TRUE);
    }

    return CM_MIGRATION_OK;
}

#define SEGMENT_START(seg) \
    seg.offset

#define SEGMENT_END(seg) \
    seg.offset + seg.size

static t_cm_error _cm_migration_check(
        const t_cm_domain_id srcShared,
        const t_cm_domain_id src,
        const t_cm_domain_id dst,
        t_cm_migration_internal_state *info
        )
{
    t_cm_error error = CM_OK;
    t_cm_domain_info domainInfoSrc;
    t_cm_domain_info domainInfoShared;
    t_cm_domain_desc *domainEE;
    t_cm_domain_desc *domainShared;
    t_nmf_core_id coreId = cm_DM_GetDomainCoreId(src);

    //coreIds in src, srcShared and dst match
    if (!((domainDesc[src].domain.coreId == domainDesc[srcShared].domain.coreId)
        && (domainDesc[src].domain.coreId == domainDesc[dst].domain.coreId))) {
        return CM_INVALID_PARAMETER;
    }

    //check srcShared starts at 0
    //FIXME, juraj, today EE code is in SDRAM, but this is flexible, so must find out where EE is instantiated
    if (domainDesc[srcShared].domain.sdramCode.offset != 0x0) {
        return CM_INVALID_PARAMETER;
    }

    //check srcShared contains EE domain
    domainEE = &domainDesc[cm_DSP_GetState(coreId)->domainEE];
    domainShared = &domainDesc[srcShared];
    if ((SEGMENT_START(domainEE->domain.esramCode) < SEGMENT_START(domainShared->domain.esramCode))
      ||(SEGMENT_END(domainEE->domain.esramCode) > SEGMENT_END(domainShared->domain.esramCode))
      ||(SEGMENT_START(domainEE->domain.esramData) < SEGMENT_START(domainShared->domain.esramData))
      ||(SEGMENT_END(domainEE->domain.esramData) > SEGMENT_END(domainShared->domain.esramData))
      ||(SEGMENT_START(domainEE->domain.sdramCode) < SEGMENT_START(domainShared->domain.sdramCode))
      ||(SEGMENT_END(domainEE->domain.sdramCode) > SEGMENT_END(domainShared->domain.sdramCode))
      ||(SEGMENT_START(domainEE->domain.sdramData) < SEGMENT_START(domainShared->domain.sdramData))
      ||(SEGMENT_END(domainEE->domain.sdramData) > SEGMENT_END(domainShared->domain.sdramData))
        ) {
        return CM_INVALID_PARAMETER;
    }

    info->coreId = coreId;
    cm_DM_GetDomainAbsAdresses(srcShared, &domainInfoShared);
    cm_DM_GetDomainAbsAdresses(src, &domainInfoSrc);

    if ((error = _cm_migration_initSegment(SDRAM_CODE_EE, &domainInfoShared.sdramCode,
                                           domainDesc[srcShared].domain.sdramCode.size, dst, info)) != CM_OK)
            goto _migration_error1;
    if ((error = _cm_migration_initSegment(SDRAM_CODE_USER, &domainInfoSrc.sdramCode,
                                           domainDesc[src].domain.sdramCode.size, dst, info)) != CM_OK)
            goto _migration_error2;
    if ((error = _cm_migration_initSegment(SDRAM_DATA_EE, &domainInfoShared.sdramData,
                                           domainDesc[srcShared].domain.sdramData.size, dst, info)) != CM_OK)
            goto _migration_error3;
    if ((error = _cm_migration_initSegment(SDRAM_DATA_USER, &domainInfoSrc.sdramData,
                                           domainDesc[src].domain.sdramData.size, dst, info)) != CM_OK)
            goto _migration_error4;
    return error;

_migration_error4: _cm_migration_releaseSegment(info, SDRAM_DATA_EE);
_migration_error3: _cm_migration_releaseSegment(info, SDRAM_CODE_USER);
_migration_error2: _cm_migration_releaseSegment(info, SDRAM_CODE_EE);
_migration_error1:
    OSAL_Log("Couldn't allocate memory for migration\n", 0, 0, 0, 0, 0, 0);
    return CM_NO_MORE_MEMORY;
}

typedef t_cm_error (*updateBase_t)(t_nmf_core_id, t_dsp_segment_type, t_cm_system_address, t_cm_system_address);

static t_cm_migration_error _cm_migration_move(
        t_nmf_core_id           coreId,
        t_cm_migration_segment *seg,
        updateBase_t            updateBase,
        char*                   name
        )
{
    LOG_INTERNAL(1, "##### Migration %s: 0x%x -> 0x%x\n", name, seg->srcAdr.logical, seg->dstAdr.logical, 0, 0, 0);
    cm_MemCopy((void*)seg->dstAdr.logical, (void*)seg->srcAdr.logical, seg->size);
    updateBase(coreId, seg->segment, seg->srcAdr, seg->dstAdr);
    cm_MemSet((void*)seg->srcAdr.logical, 0xdead, seg->size); //for debug, to be sure that we have actually moved the code and bases

    return CM_MIGRATION_OK;
}

static t_cm_migration_error _cm_migration_update_internal(
        t_cm_migration_internal_state *info,
        t_cm_migration_state state
        )
{
    t_nmf_fifo_arm_desc *pArmFifo;

    migrationState.state = state;

    switch(state) {
    case STATE_MIGRATED:
        //move fifos
        pArmFifo = mpc2mpcComsFifoId[ARM_CORE_ID][info->coreId];
        pArmFifo->fifoDesc = (t_nmf_fifo_desc*)cm_migration_translate(pArmFifo->dspAddressInfo.segmentType, (t_shared_addr)pArmFifo->fifoDescShadow);
        pArmFifo = mpc2mpcComsFifoId[info->coreId][ARM_CORE_ID];
        pArmFifo->fifoDesc = (t_nmf_fifo_desc*)cm_migration_translate(pArmFifo->dspAddressInfo.segmentType, (t_shared_addr)pArmFifo->fifoDescShadow);
        break;

    case STATE_NORMAL:
        //move fifos
        pArmFifo = mpc2mpcComsFifoId[ARM_CORE_ID][info->coreId];
        pArmFifo->fifoDesc = pArmFifo->fifoDescShadow;
        pArmFifo = mpc2mpcComsFifoId[info->coreId][ARM_CORE_ID];
        pArmFifo->fifoDesc = pArmFifo->fifoDescShadow;
        break;

    default:
        OSAL_Log("unknown state", 0, 0, 0, 0, 0, 0);
        CM_ASSERT(0);
    }

    return CM_MIGRATION_OK;
}

PUBLIC t_cm_error cm_migrate(const t_cm_domain_id srcShared, const t_cm_domain_id src, const t_cm_domain_id dst)
{
    t_cm_migration_error mError;
    t_cm_error error;

    if ((error = _cm_migration_check(srcShared, src, dst, &migrationState)) != CM_OK) {
        return error;
    }

    /* stop DSP execution */
    cm_DSP_Stop(migrationState.coreId);

    /* migrate EE and FX */
    mError = _cm_migration_move(migrationState.coreId, &migrationState.segments[SDRAM_CODE_EE], cm_DSP_updateCodeBase, "code");
    if (mError) {
        OSAL_Log("EE code migration failed", 0, 0, 0, 0, 0, 0);
        CM_ASSERT(0);
    }
    mError = _cm_migration_move(migrationState.coreId, &migrationState.segments[SDRAM_DATA_EE], cm_DSP_updateDataBase, "data");
    if (mError) {
        OSAL_Log("EE data migration failed", 0, 0, 0, 0, 0, 0);
        CM_ASSERT(0);
    }
    /* migrate user domain */
    mError = _cm_migration_move(migrationState.coreId, &migrationState.segments[SDRAM_CODE_USER], cm_DSP_updateCodeBase, "code");
    if (mError) {
        OSAL_Log("User code migration failed", 0, 0, 0, 0, 0, 0);
        CM_ASSERT(0);
    }
    mError = _cm_migration_move(migrationState.coreId, &migrationState.segments[SDRAM_DATA_USER], cm_DSP_updateDataBase, "data");
    if (mError) {
        OSAL_Log("User data migration failed", 0, 0, 0, 0, 0, 0);
        CM_ASSERT(0);
   }
    /* update CM internal structures */
    mError = _cm_migration_update_internal(&migrationState, STATE_MIGRATED);
    if (mError) {
        OSAL_Log("Update internal data failed", 0, 0, 0, 0, 0, 0);
        CM_ASSERT(0);
    }

    /* Be sure everything has been write before restarting mmdsp */
    OSAL_mb();

    /* resume DSP execution */
    cm_DSP_Start(migrationState.coreId);

    return CM_OK;
}

static void _cm_migration_swapSegments(
        t_cm_migration_segment *segment
        )
{
    t_cm_system_address tmp;
    tmp = segment->dstAdr;
    segment->dstAdr = segment->srcAdr;
    segment->srcAdr = tmp;
}

PUBLIC t_cm_error cm_unmigrate(void)
{
    t_cm_migration_error merror;

    if (migrationState.state != STATE_MIGRATED)
        return CM_INVALID_PARAMETER; //TODO, juraj, define a proper error for this migration case

    cm_DSP_Stop(migrationState.coreId);

    _cm_migration_swapSegments(&migrationState.segments[SDRAM_CODE_EE]);
    _cm_migration_swapSegments(&migrationState.segments[SDRAM_DATA_EE]);
    _cm_migration_swapSegments(&migrationState.segments[SDRAM_CODE_USER]);
    _cm_migration_swapSegments(&migrationState.segments[SDRAM_DATA_USER]);

    merror = _cm_migration_move(migrationState.coreId, &migrationState.segments[SDRAM_CODE_EE], cm_DSP_updateCodeBase, "code");
    if (merror) {
        OSAL_Log("EE code unmigration failed", 0, 0, 0, 0, 0, 0);
        CM_ASSERT(0);
    }
    merror = _cm_migration_move(migrationState.coreId, &migrationState.segments[SDRAM_DATA_EE], cm_DSP_updateDataBase, "data");
    if (merror) {
        OSAL_Log("EE data unmigration failed", 0, 0, 0, 0, 0, 0);
        CM_ASSERT(0);
    }
    merror = _cm_migration_move(migrationState.coreId, &migrationState.segments[SDRAM_CODE_USER], cm_DSP_updateCodeBase, "code");
    if (merror) {
        OSAL_Log("User code unmigration failed", 0, 0, 0, 0, 0, 0);
        CM_ASSERT(0);
    }
    merror = _cm_migration_move(migrationState.coreId, &migrationState.segments[SDRAM_DATA_USER], cm_DSP_updateDataBase, "data");
    if (merror) {
        OSAL_Log("User data unmigration failed", 0, 0, 0, 0, 0, 0);
        CM_ASSERT(0);
    }

    /* update CM internal structures */
    merror = _cm_migration_update_internal(&migrationState, STATE_NORMAL);
    if (merror) {
        OSAL_Log("Update internal data failed", 0, 0, 0, 0, 0, 0);
        CM_ASSERT(0);
    }

    /* Be sure everything has been write before restarting mmdsp */
    OSAL_mb();

    cm_DSP_Start(migrationState.coreId);

    /* update CM internal structures */
    merror = _cm_migration_release(&migrationState);
    if (merror) {
        OSAL_Log("Update internal data failed", 0, 0, 0, 0, 0, 0);
        CM_ASSERT(0);
    }

    return CM_OK;
}

// here we make the assumption that the offset doesn't depend from the dsp!!
PUBLIC t_uint32 cm_migration_translate(t_dsp_segment_type segmentType, t_uint32 addr)
{
    //TODO, juraj, save delta instead of recalculating it
    t_sint32 offset;
    if (migrationState.state == STATE_MIGRATED) {
        offset = migrationState.segments[segmentType].dstAdr.logical - migrationState.segments[segmentType].srcAdr.logical;
    } else {
        offset = 0;
    }
    return addr + offset;
}

PUBLIC void cm_migration_check_state(t_nmf_core_id coreId, t_cm_migration_state expected)
{
    CM_ASSERT(migrationState.state == expected);
}

#else
PUBLIC t_cm_error cm_migrate(const t_cm_domain_id srcShared, const t_cm_domain_id src, const t_cm_domain_id dst)
{
    return CM_OK;
}

PUBLIC t_cm_error cm_unmigrate(void)
{
    return CM_OK;
}

PUBLIC t_uint32 cm_migration_translate(t_dsp_segment_type segmentType, t_uint32 addr)
{
    return addr;
}

PUBLIC void cm_migration_check_state(t_nmf_core_id coreId, t_cm_migration_state expected)
{
    return;
}
#endif