]> rtime.felk.cvut.cz Git - arc.git/blob - memory/NvM/NvM.c
Small Nvm fix
[arc.git] / memory / NvM / NvM.c
1 /* -------------------------------- Arctic Core ------------------------------\r
2  * Arctic Core - the open source AUTOSAR platform http://arccore.com\r
3  *\r
4  * Copyright (C) 2009  ArcCore AB <contact@arccore.com>\r
5  *\r
6  * This source code is free software; you can redistribute it and/or modify it\r
7  * under the terms of the GNU General Public License version 2 as published by the\r
8  * Free Software Foundation; See <http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt>.\r
9  *\r
10  * This program is distributed in the hope that it will be useful, but\r
11  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
12  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\r
13  * for more details.\r
14  * -------------------------------- Arctic Core ------------------------------*/\r
15 \r
16 /*\r
17  * RamBlockDataAddress\r
18  *   NULL is no permanent RAM block. Otherwise allocate the number of bytes in space (like the stack)\r
19  *\r
20  *\r
21  * Understanding block numbering:\r
22  *\r
23  *  NVM_DATASET_SELECTION_BIT=2\r
24  *\r
25  *    NvBlockBaseNumber\r
26  *          0     Reserved (NVM478)\r
27  *          1     NVM_BLOCK_NATIVE,    NvBlockNum=1\r
28  *          2     NVM_BLOCK_REDUNDANT, NvBlockNum=2\r
29  *          3     NVM_BLOCK_DATASET,   NvBlockNum=4\r
30  *\r
31  *   NvM_ReadBlock( 0, ... )    - Reserved for "multi block requests"\r
32  *   NvM_ReadBlock( 1, ... )    - Reserved for redundant NVRAM block which holds the configuration ID.\r
33  *   NvM_ReadBlock( 2--x, ... ) - "Normal" blocks\r
34  *\r
35  *\r
36  *  NvM_BlockIdType*)  NvBlockBaseNumber   EA_BLOCK_NUMBER\r
37  *      0**)\r
38  *      1**)                ***)\r
39  *      2                   1                           4, (5,6,7)  ****)\r
40  *      3                   2                           8, R9,(10,11)  ****)\r
41  *      4                   3                           12, D13,D14,D15 ****)\r
42  *\r
43  *  *) Type used in the API.\r
44  *  **)   Reserved ID's\r
45  *  ***)  Reserved ID\r
46  *  ****) FEE/EA_BLOCK_NUMBER = NvBlockBaseNumber << NvmDatasetSelectionBits = NvBlockBaseNumber * 4\r
47  *        () - Cannot be accesses due to NvBlockNum\r
48  *        R9 - Redundant block\r
49  *        Dx - Data blocks\r
50  *\r
51  *    SIZES\r
52  *      Both NvM and EA/FEE have block sizes. NvM have NvNvmBlockLength (NVM479) and FEE/EA have EaBlockSize.\r
53  *      FEE/EA also have virtual page that is the alignment of a block, with the smallest block=size of the virtual page.\r
54  *\r
55  *      So, who allocates space for this. FEE/EA only have EaBlockSize.\r
56  *      NvM have NvmRamBlockDataAddress, NvmRomBlockDataAddress and mapping to a MemIf Blocks (FEE/EA blocks)\r
57  *\r
58  *      ASSUME: I can't really see a point for the FEE/EA EaBlockSize.. it will just a multiple of NvNvmBlockLength*NvBlockNum + overhead?\r
59  *              Click-box in EA/FEE that leaves the size calculation to NvM?\r
60  *              This also means that enabling NvmBlockUseCrc or set a block from NVM_BLOCK_NATIVE to NVM_BLOCK_DATASET would be "automatic"\r
61  *              in calculation of the EaBlockSize.\r
62  *\r
63  *      So how much data should be read from MemIf if a CRC checksum is used. Assuming that we use a physical layout where the CRC is located\r
64  *      after the NV Block it would be BALIGN(NvNvmBlockLength,4) + 4 bytes. The same applies to the RAM block (ROM block to not have CRC, NVM127)\r
65  *\r
66  * CRC\r
67  *   NVM121: NvM_SetRamBlockStatus(), calculate CRC in background if NvmCalcRamBlockCrc==TRUE\r
68  *   NVM362: NvM_ReadAll() , if (NvmCalcRamBlockCrc == TRUE && permanent RAM block) re-calc CRC.\r
69  *\r
70  *     NvmBlockUseCrc     - Global CRC switch. Space is allocated in both RAM and NV block\r
71  *     NvmCalcRamBlockCrc - CRC re-calculation. For example during startup, you may don't want\r
72  *                          to verify all the checksums again, but instead just copy from NV\r
73  *                          to RAM.\r
74  *\r
75  *     There is also explicit RAM checksum calculations for example NVM253 (Nvm_WriteAll()) where a CRC calculation\r
76  *     is requested (although not stated should be dependent on NvmBlockUseCrc only, not NvmCalcRamBlockCrc).\r
77  *     You have to calculate the checksum at some point....\r
78  *\r
79  * QUEUES\r
80  *   NVM185: Says "successful enqueueing a request".."set to NVM_REQ_PENDING"\r
81  *   NVM380: The queue length for multi block request shall be one (NvM_ReadAll, NvM_WriteAll)\r
82  *   NVM381+NVM567 : Multi block requests shall not be interrupted.\r
83  *   NVM243+NVM245: Do not unqueue the multi block request until all single block queues are empty.\r
84  *     So, when NvmState==IDLE and we have a multi-request\r
85  *\r
86  *\r
87  *\r
88  *\r
89  *\r
90  * SPEED\r
91  *   To get some speed into this multiple thing must be done in the same MainFunction loop.\r
92  *\r
93  * MEMIF\r
94  *   The interface is actually quite strange, so you may read from any address (through MemIf_Read())\r
95  *   but MemIf_Write(..) only takes a logical block and a pointer to the data to write.\r
96  *\r
97  *   See two alternatives here:\r
98  *    1. If the NVBlock also contains the checksum after the data then writing the data needs a\r
99  *       RAM that is as big as the biggest RAM block + room for checksum.\r
100  *    2. If checksums would be kept in a separate EA/FEE block the ALL the checksum need to be written.\r
101  *       For example after a NvM_WriteBlock() the checksum block would need to be written. This\r
102  *       will probably lead consistency problems also... what happens if we fail to write the checksum\r
103  *       block?\r
104  *\r
105  *\r
106  *\r
107  * MANUAL\r
108  *\r
109  *\r
110  *\r
111  *   Provide Data for the first/initial read\r
112  *     When a block have no\r
113  *\r
114  *     NVM085\r
115  *     NVM061\r
116  *     NVM083\r
117  *\r
118  *   Configuring CRCs\r
119  *     BlockUseCrc (A):      If the block (both RAM and NV) should use CRC\r
120  *     CalcRamBlockCrc (B):  If the permanent RAM block should re-calculate it's CRC.\r
121  *\r
122  *     A B\r
123  *     ------------\r
124  *     0 0  No error detection or recovery\r
125  *     0 1  N/A\r
126  *     1 0  ?\r
127  *     1 1  ?\r
128  *\r
129  * RAM BLOCK VALID/UNCHANGED\r
130  *   Figure 8 and 9 in 3.1.5/NVM is more confusing than good.\r
131  *   What we have to know is:\r
132  *    1. Initially the RAM block is in INVALID/UNCHANGED\r
133  *    ALT 2. After a NvM_ReadAll() and all is well the state goes to VALID/UNCHANGED\r
134  *    ALT 2. If ROM values are used we go to VALID/CHANGED (We failed to read from NVRAM)\r
135  *\r
136  *   For NvM_WriteAll()\r
137  *   1. A block that is INVALID can't be written\r
138  *   2. A block that is UNCHANGED should not be written.\r
139  *   -> Write only blocks that are VALID/CHANGED.\r
140  *\r
141  *   VALID/UNCHANGED - RAM == NV\r
142  *   VALID/CHANGED   - RAM != NV   (analog to cache memories, "dirty")\r
143  *\r
144  *   Analog to cache\r
145  *     VALID/CHANGED state - Dirty (since RAM != NV)\r
146  *     WriteBlock          - Flush (Flush the RAM block to NV)\r
147  *     ReadBlock           - Invalidate (NV block is read to RAM)\r
148  */\r
149 \r
150 \r
151 /*\r
152  *  General requirements\r
153  */\r
154 /** @req NVM076 */\r
155 /** @req NVM552 */\r
156 /** @req NVM689 */\r
157 \r
158 \r
159 /*\r
160  * NB! Even though some code exist for handling RamCrc, the functionality is not complete\r
161  * and shall not be used.
162  */\r
163 \r
164 //lint -esym(522,CalcCrc) // 522 PC-Lint exception for empty functions\r
165 //lint -emacro(904,VALIDATE_RV,VALIDATE_NO_RV) //904 PC-Lint exception to MISRA 14.7 (validate macros).\r
166 \r
167 // Exception made as a result of that NVM_DATASET_SELECTION_BITS can be zero\r
168 //lint -emacro(835, BLOCK_BASE_AND_SET_TO_BLOCKNR) // 835 PC-lint: A zero has been given as right argument to operator '<<' or '>>'\r
169 \r
170 \r
171 /* ----------------------------[includes]------------------------------------*/\r
172 \r
173 #include <assert.h>\r
174 #include "NvM.h"\r
175 #include "NvM_Cbk.h"\r
176 #include "Rte.h" // ???\r
177 #if defined(USE_DEM)\r
178 #include "Dem.h"\r
179 #endif\r
180 #include "MemIf.h"\r
181 //#include "SchM_NvM.h"\r
182 #include "MemMap.h"\r
183 #include "cirq_buffer.h"\r
184 #include "Modules.h"\r
185 #include <stdio.h>\r
186 #include "io.h"\r
187 #include "Crc.h"\r
188 #include <string.h>\r
189 \r
190 //#define DEBUG_BLOCK   1\r
191 #if defined(DEBUG_BLOCK)\r
192 #define DEBUG_BLOCK_STATE(_str,_block,_state)       printf("%s BLOCK NR:%d STATE:%d\n",_str,_block, _state); fflush(stdout);\r
193 #define DEBUG_STATE(_state,_substate)                           printf("MAIN_STATE:%s/%d\n",StateToStr[_state],_substate); fflush(stdout);\r
194 #define DEBUG_PRINTF(format,...)                                        printf(format,## __VA_ARGS__ ); fflush(stdout);\r
195 #define DEBUG_CHECKSUM(_str,_crc)                                       printf("%s crc=%x\n",_str,_crc);\r
196 #else\r
197 #define DEBUG_BLOCK_STATE(_str,_block,_state)\r
198 #define DEBUG_STATE(_state,_substate)\r
199 #define DEBUG_PRINTF(format,...)\r
200 #define DEBUG_CHECKSUM(_str,_crc)\r
201 #endif\r
202 \r
203 \r
204 /* ----------------------------[private define]------------------------------*/\r
205 \r
206 \r
207 \r
208 #define NVM_BLOCK_ALIGNMENT                     4\r
209 #define NVM_CHECKSUM_LENGTH                     4\r
210 \r
211 #define NVM_BLOCK_OFFSET                2\r
212 \r
213 \r
214 \r
215 \r
216 \r
217 /* ----------------------------[private macro]-------------------------------*/\r
218 \r
219 #define NVM_ASSERT(_exp)                if( !(_exp) ) { while(1) {}; } //assert(_exp)\r
220 \r
221 #if  ( NVM_DEV_ERROR_DETECT == STD_ON )\r
222 #include "Det.h"\r
223 #define VALIDATE(_exp,_api,_err ) \\r
224         if( !(_exp) ) { \\r
225           Det_ReportError(MODULE_ID_NVM, 0, _api, _err); \\r
226         }\r
227 \r
228 \r
229 #define VALIDATE_RV(_exp,_api,_err,_rv ) \\r
230         if( !(_exp) ) { \\r
231           Det_ReportError(MODULE_ID_NVM, 0, _api, _err); \\r
232           return _rv; \\r
233         }\r
234 \r
235 #define VALIDATE_NO_RV(_exp,_api,_err ) \\r
236         if( !(_exp) ) { \\r
237           Det_ReportError(MODULE_ID_NVM, 0, _api, _err); \\r
238           return; \\r
239         }\r
240 #define DET_REPORTERROR(_module,_instance,_api,_err) Det_ReportError(_module,_instance,_api,_err)\r
241 \r
242 #else\r
243 #define VALIDATE(_exp,_api,_err )\r
244 #define VALIDATE_RV(_exp,_api,_err,_rv )\r
245 #define VALIDATE_NO_RV(_exp,_api,_err )\r
246 #define DET_REPORTERROR(_module,_instance,_api,_err)\r
247 #endif\r
248 \r
249 #define BLOCK_BASE_AND_SET_TO_BLOCKNR(_blockbase, _set) ((uint16)(_blockbase << NVM_DATASET_SELECTION_BITS) | _set)\r
250 \r
251 #if defined(USE_DEM)\r
252 #define DEM_REPORTERRORSTATUS(_err,_ev ) Dem_ReportErrorStatus(_err, DEM_EVENT_STATUS_FAILED);\r
253 #else\r
254 #define DEM_REPORTERRORSTATUS(_err,_ev )\r
255 #endif\r
256 \r
257 \r
258 #define BLOCK_NR_FROM_PTR(_bptr)                (((_bptr) - NvM_Config.BlockDescriptor + 1))   // sizeof(NvM_BlockDescriptorType))\r
259 \r
260 #define CREATE_ENTRY(_val)      [_val] = #_val\r
261 \r
262 \r
263 \r
264 \r
265 /* ----------------------------[private typedef]-----------------------------*/\r
266 \r
267 // State variable\r
268 typedef enum {\r
269   NVM_UNINITIALIZED = 0,\r
270   NVM_IDLE,\r
271   NVM_READ_ALL,\r
272   NVM_WRITE_ALL,\r
273   NVM_READ_BLOCK,\r
274   NVM_WRITE_BLOCK,\r
275   NVM_RESTORE_BLOCK_DEFAULTS,\r
276 } NvmStateType;\r
277 \r
278 char *StateToStr[20] = {\r
279         CREATE_ENTRY(NVM_UNINITIALIZED),\r
280         CREATE_ENTRY(NVM_IDLE),\r
281         CREATE_ENTRY(NVM_READ_ALL),\r
282         CREATE_ENTRY(NVM_WRITE_ALL),\r
283         CREATE_ENTRY(NVM_READ_BLOCK),\r
284         CREATE_ENTRY(NVM_WRITE_BLOCK),\r
285  };\r
286 \r
287 \r
288 typedef enum {\r
289         BLOCK_STATE_MEMIF_REQ,\r
290 //      BLOCK_STATE_START,\r
291         BLOCK_STATE_MEMIF_PROCESS,\r
292 //      BLOCK_STATE_MEMIF_CRC_PROCESS,\r
293         BLOCK_STATE_CALC_CRC,\r
294 //      BLOCK_STATE_MEMIF_PROCESS_CRC,\r
295         BLOCK_STATE_CALC_CRC_WRITE,\r
296         BLOCK_STATE_CALC_CRC_READ,\r
297 //      BLOCK_STATE_LOAD_FROM_NV,\r
298 } BlockStateType;\r
299 \r
300 typedef enum {\r
301         NS_INIT = 0,\r
302         NS_PROSSING,\r
303 //      RB_PROCESSING,\r
304 } Nvm_SubStates;\r
305 \r
306 \r
307 union Nvm_CRC {\r
308         uint16 crc16;\r
309         uint32 crc32;\r
310 };\r
311 \r
312 \r
313 typedef struct {\r
314         NvM_RequestResultType   ErrorStatus;                    // Status from multi block requests i.e. Read/Write/CancelWrite-all\r
315 } AdministrativeMultiBlockType;\r
316 \r
317 typedef struct {\r
318         BlockStateType                  BlockState;\r
319         uint8                                   DataIndex;                              // Selected data index if "Data Set" type\r
320         boolean                                 BlockWriteProtected;    // Block write protected?\r
321         NvM_RequestResultType   ErrorStatus;                    // Status of block\r
322         boolean                                 BlockChanged;                   // Block changed?\r
323         boolean                                 BlockValid;                             // Block valid? (RAM block only?)\r
324         uint8                                   NumberOfWriteFailed;    // Current write retry cycle\r
325         union Nvm_CRC                   RamCrc;\r
326         union Nvm_CRC                   NvCrc;                                  // The CRC of this block, read from NV\r
327         void *                                  savedDataPtr;                   //\r
328         uint8                                   crcLen;\r
329 \r
330 } AdministrativeBlockType;\r
331 \r
332 /*\r
333 typedef enum {\r
334         NVM_OP_READ_BLOCK,\r
335         NVM_OP_WRITE_BLOCK,\r
336         NVM_OP_RESTORE_BLOCK_DEFAULTS,\r
337 } Nvm_OpType;\r
338 */\r
339 #define OP_READ         0\r
340 #define OP_WRITE        1\r
341 #define NO_MULTIBLOCK   0\r
342 #define MULTIBLOCK              1\r
343 \r
344 \r
345 typedef struct {\r
346         NvmStateType            op;\r
347         NvM_BlockIdType blockId;\r
348         uint8 *                 dataPtr;        /* Src or Dest ptr */\r
349 } Nvm_QueueType;\r
350 \r
351 \r
352 \r
353 /* ----------------------------[private function prototypes]-----------------*/\r
354 /* ----------------------------[private variables]---------------------------*/\r
355 \r
356 static NvmStateType                             nvmState = NVM_UNINITIALIZED;\r
357 \r
358 #define RB_START                        0\r
359 #define RB_WAIT_READ            1\r
360 #define RB_CALC_CHECKSUM        2\r
361 \r
362 static int                                                      nvmSubState = 0;\r
363 //static int nvmSetNr;\r
364 static AdministrativeBlockType          AdminBlock[NVM_NUM_OF_NVRAM_BLOCKS];\r
365 static AdministrativeMultiBlockType AdminMultiBlock;\r
366 \r
367 \r
368 //static Nvm_QueueType  nvmQueueImmData[NVM_SIZE_IMMEDIATE_JOB_QUEUE];\r
369 static Nvm_QueueType  nvmQueueData[NVM_SIZE_STANDARD_JOB_QUEUE];\r
370 \r
371 uint8 Nvm_WorkBuffer[200];              /* TODO */\r
372 \r
373 #if (NVM_SIZE_STANDARD_JOB_QUEUE == 0)\r
374 #error NVM_SIZE_STANDARD_JOB_QUEUE have size 0\r
375 #endif\r
376 \r
377 \r
378 CirqBufferType nvmQueue;\r
379 \r
380 \r
381 /* ----------------------------[private functions]---------------------------*/\r
382 \r
383 static void WriteBlock( const NvM_BlockDescriptorType *blockDescriptor,\r
384                                                 AdministrativeBlockType *adminBlock,\r
385                                                 uint8 setNumber,\r
386                                                 uint8 *sourceAddress);\r
387 \r
388 /* ----------------------------[public functions]----------------------------*/\r
389 \r
390 \r
391 \r
392 /*\r
393  * This function needs to be implemented!
394  */\r
395 static void CalcCrc(void)\r
396 {\r
397         // TODO: Calculate CRC\r
398 }\r
399 \r
400 typedef struct {\r
401         boolean                                                 JobFinished;\r
402         Std_ReturnType                                  JobStatus;\r
403         MemIf_JobResultType                     JobResult;\r
404         const NvM_BlockDescriptorType * BlockDescriptor;\r
405         AdministrativeBlockType *               BlockAdmin;\r
406 } MemIfJobAdminType;\r
407 \r
408 static MemIfJobAdminType MemIfJobAdmin = {\r
409                 .JobFinished = TRUE,\r
410                 .JobStatus = E_OK,\r
411                 .JobResult = MEMIF_JOB_OK,\r
412                 .BlockDescriptor = NULL,\r
413                 .BlockAdmin = NULL\r
414 };\r
415 \r
416 enum Nvm_MultiBlockReq {\r
417         MB_REQ_NONE,\r
418         MB_REQ_READ_ALL,\r
419         MB_REQ_WRITE_ALL,\r
420 };\r
421 \r
422 typedef struct {\r
423         NvmStateType                    state;\r
424         uint16                                  currBlockIndex;         // Keeps track of next unfinished block\r
425         NvM_RequestResultType   PendingErrorStatus;     // Status from multi block requests i.e. Read/Write/CancelWrite-all\r
426 } AdminMultiReqType;\r
427 \r
428 static AdminMultiReqType AdminMultiReq;\r
429 \r
430 \r
431 /*\r
432  * Set the MemIf job as busy
433  */\r
434 static void SetMemifJobBusy()\r
435 {\r
436         MemIfJobAdmin.JobFinished = FALSE;\r
437 }\r
438 \r
439 \r
440 #if (NVM_POLLING_MODE == STD_ON)\r
441 /*\r
442  * Check if the MemIf job is finished
443  */\r
444 static boolean CheckMemIfJobFinished(void)\r
445 {\r
446         MemIf_JobResultType jobResult;\r
447 \r
448         if (!MemIfJobAdmin.JobFinished) {\r
449                 jobResult = MemIf_GetJobResult();\r
450 \r
451                 if (jobResult == MEMIF_JOB_OK) {\r
452                         MemIfJobAdmin.JobFinished = TRUE;\r
453                         MemIfJobAdmin.JobStatus = E_OK;\r
454                         MemIfJobAdmin.JobResult = jobResult;\r
455                 } else if (jobResult != MEMIF_JOB_PENDING) {\r
456                         MemIfJobAdmin.JobFinished = TRUE;\r
457                         MemIfJobAdmin.JobStatus = E_NOT_OK;\r
458                         MemIfJobAdmin.JobResult = jobResult;\r
459                 }\r
460         }\r
461 \r
462         return MemIfJobAdmin.JobFinished;\r
463 }\r
464 #else\r
465 /*\r
466  * Check if the MemIf job is finished\r
467  */\r
468 \r
469 static boolean CheckMemIfJobFinished(void)\r
470 {\r
471         return MemIfJobAdmin.JobFinished;\r
472 }\r
473 \r
474 #endif\r
475 \r
476 \r
477 /*\r
478  * Abort the MemIf job with E_NOT_OK\r
479  */\r
480 static void AbortMemIfJob(MemIf_JobResultType jobResult)\r
481 {\r
482         MemIfJobAdmin.JobFinished = TRUE;\r
483         MemIfJobAdmin.JobStatus = E_NOT_OK;\r
484         MemIfJobAdmin.JobResult = jobResult;\r
485 }\r
486 \r
487 #if 0\r
488 static boolean CheckJobFailed( void ) {\r
489         return CheckMemIfJobFinished() && (MemIfJobAdmin.JobResult == MEMIF_JOB_FAILED);\r
490 }\r
491 #endif\r
492 \r
493 /*\r
494  * Request a read of a block from MemIf
495  */\r
496 static void ReadBlock(const NvM_BlockDescriptorType *blockDescriptor,\r
497                                                         AdministrativeBlockType *adminBlock,\r
498                                                         uint8 setNumber,\r
499                                                         uint16 blockOffset,\r
500                                                         uint8 *destAddress,\r
501                                                         uint16 length )\r
502 {\r
503         Std_ReturnType returnCode;\r
504 \r
505         if (setNumber < blockDescriptor->NvBlockNum) {\r
506                 SetMemifJobBusy();\r
507                 MemIfJobAdmin.BlockAdmin = adminBlock;\r
508                 MemIfJobAdmin.BlockDescriptor = blockDescriptor;\r
509                 returnCode = MemIf_Read(blockDescriptor->NvramDeviceId, BLOCK_BASE_AND_SET_TO_BLOCKNR(blockDescriptor->NvBlockBaseNumber, setNumber), blockOffset, destAddress, length );\r
510                 if (returnCode != E_OK) {\r
511                         AbortMemIfJob(MEMIF_JOB_FAILED);\r
512                 }\r
513         } else if (setNumber < blockDescriptor->NvBlockNum + blockDescriptor->RomBlockNum) {\r
514                 // TODO: Read from ROM\r
515         } else {\r
516                 // Error: setNumber out of range\r
517                 DET_REPORTERROR(MODULE_ID_NVM, 0, NVM_LOC_READ_BLOCK_ID, NVM_PARAM_OUT_OF_RANGE);\r
518         }\r
519 }\r
520 \r
521 \r
522 /*\r
523  * Initiate the read all job
524  */\r
525 static void ReadAllInit(void)\r
526 {\r
527         /*\r
528          * Initiate the read all job
529          */\r
530         const NvM_BlockDescriptorType   *BlockDescriptorList = NvM_Config.BlockDescriptor;\r
531         AdministrativeBlockType *AdminBlockTable = AdminBlock;\r
532         uint16 i;\r
533 \r
534         // Set status to pending in the administration blocks\r
535         AdminMultiBlock.ErrorStatus = NVM_REQ_PENDING; /** @req 3.1.5/NVM304 */\r
536         AdminMultiReq.PendingErrorStatus = NVM_REQ_OK;\r
537         AdminMultiReq.currBlockIndex = 0;\r
538 \r
539         for (i = 0; i < ( NVM_NUM_OF_NVRAM_BLOCKS ); i++) {\r
540                 if ((BlockDescriptorList->SelectBlockForReadall)\r
541 #if (NVM_SET_RAM_BLOCK_STATUS_API == STD_ON)                                            /** @req NVM345 */\r
542                                 && ((!AdminBlockTable->BlockValid)                      // TODO: Check if this is to be done like this\r
543                                 || (!AdminBlockTable->BlockChanged))            // TODO: Check if this is to be done like this\r
544 #endif\r
545                                 ) {\r
546                         VALIDATE_NO_RV(BlockDescriptorList->RamBlockDataAddress != NULL, NVM_READ_ALL_ID, NVM_E_WRONG_CONFIG);\r
547                         VALIDATE_NO_RV(BlockDescriptorList->BlockManagementType != NVM_BLOCK_DATASET, NVM_READ_ALL_ID, NVM_E_WRONG_CONFIG);\r
548 \r
549                         AdminBlockTable->ErrorStatus = NVM_REQ_PENDING;\r
550                         AdminBlockTable->BlockState = BLOCK_STATE_MEMIF_REQ;\r
551                 } else {\r
552                         AdminBlockTable->ErrorStatus = NVM_REQ_BLOCK_SKIPPED;   /* @req 3.1.5/NVM287 */\r
553                 }\r
554 \r
555                 AdminBlockTable++;\r
556                 BlockDescriptorList++;\r
557         }\r
558 }\r
559 \r
560 \r
561 static void writeCrcToBuffer(   void *bufPtr,\r
562                                                                 const NvM_BlockDescriptorType *bPtr,\r
563                                                                 AdministrativeBlockType *admPtr )\r
564 {\r
565         if( bPtr->BlockUseCrc ) {\r
566                 if(bPtr->BlockCRCType == NVM_CRC16) {\r
567                         WRITE16_NA(bufPtr + bPtr->NvBlockLength,admPtr->RamCrc.crc16);\r
568                 } else {\r
569                         WRITE32_NA(bufPtr + bPtr->NvBlockLength,admPtr->RamCrc.crc32);\r
570                 }\r
571         }\r
572 }\r
573 \r
574 \r
575 /*\r
576  * Drive the read state-machine\r
577  *\r
578  *\r
579  *\r
580  */\r
581 \r
582 static void DriveBlock( const NvM_BlockDescriptorType   *bPtr,\r
583                                                         AdministrativeBlockType *admPtr,\r
584                                                         void *dataPtr,\r
585                                                         boolean write,\r
586                                                         boolean multiBlock,\r
587                                                         boolean restoreFromRom )\r
588 {\r
589         bool blockDone = 0;\r
590         static uint8 driveBlockCnt = 0;\r
591 \r
592 \r
593         NVM_ASSERT( admPtr->ErrorStatus == NVM_REQ_PENDING);\r
594 \r
595         DEBUG_BLOCK_STATE("DriveBlock", BLOCK_NR_FROM_PTR(bPtr), admPtr->BlockState );\r
596 \r
597         switch (admPtr->BlockState) {\r
598         case BLOCK_STATE_MEMIF_REQ:\r
599         {\r
600                 void *ramData = (dataPtr != NULL) ?  dataPtr : bPtr->RamBlockDataAddress;\r
601 \r
602                 admPtr->savedDataPtr = ramData;\r
603 \r
604                 if( write ) {\r
605                         if( multiBlock && (dataPtr!=NULL)) {\r
606                                 NVM_ASSERT(0);\r
607                         }\r
608                         /* Copy to work buffer */\r
609                         memcpy( Nvm_WorkBuffer, ramData, bPtr->NvBlockLength );\r
610                         /* Add the CRC to write */\r
611                         writeCrcToBuffer(Nvm_WorkBuffer, bPtr, admPtr );\r
612                         WriteBlock(bPtr, admPtr, 0, Nvm_WorkBuffer);\r
613                 } else {\r
614                         uint8 crcLen = 0;\r
615                         /* Read to workbuffer */\r
616                         if( bPtr->BlockUseCrc ) {\r
617                                 crcLen = (bPtr->BlockCRCType == NVM_CRC16) ? 2: 4;\r
618                         }\r
619 \r
620                         if( restoreFromRom ) {\r
621                                 NVM_ASSERT( bPtr->RomBlockDataAdress != NULL );\r
622                                 /* No CRC on the ROM block */\r
623                                 memcpy(ramData,bPtr->RomBlockDataAdress,bPtr->NvBlockLength);\r
624 \r
625                                 admPtr->ErrorStatus = NVM_REQ_OK;\r
626                                 blockDone = 1;\r
627                                 break;\r
628                         } else {\r
629                                 ReadBlock(bPtr, admPtr, 0, 0, bPtr->RamBlockDataAddress, bPtr->NvBlockLength+crcLen);\r
630                         }\r
631                 }\r
632 \r
633                 admPtr->BlockState = BLOCK_STATE_MEMIF_PROCESS;\r
634                 break;\r
635         }\r
636 \r
637         case BLOCK_STATE_MEMIF_PROCESS:\r
638         {\r
639                 /* Check read */\r
640                 MemIf_JobResultType jobResult = MemIf_GetJobResult(0);\r
641 \r
642                 if( MEMIF_JOB_PENDING == jobResult ) {\r
643                         /* Keep on waiting */\r
644                 } else if( MEMIF_JOB_OK == jobResult ) {\r
645                         /* We are done */\r
646 \r
647 #if 0\r
648                         if( BLOCK_STATE_MEMIF_CRC_PROCESS == admPtr->BlockState ) {\r
649                                 /* @req 3.1.5/NVM362 NvM_ReadAll*/\r
650                                 DEBUG_CHECKSUM("RAM CRC", (bPtr->BlockCRCType == NVM_CRC16) ?  admPtr->RamCrc.crc16 : admPtr->RamCrc.crc32);\r
651                                 admPtr->BlockState = BLOCK_STATE_CALC_CRC_READ;\r
652                                 break;\r
653                         }\r
654 #endif\r
655 \r
656                         if( write ) {\r
657                                 admPtr->BlockState = BLOCK_STATE_MEMIF_REQ;\r
658                                 admPtr->ErrorStatus = NVM_REQ_OK;\r
659                                 blockDone = 1;\r
660 \r
661 #if 0\r
662                                 if( bPtr->BlockUseCrc ) {\r
663                                         /* Explicit CRC calc (not dependent on NvmCalcRamBlockCrc) */\r
664                                         /* @req 3.1.5/NVM212 NvM_WriteBlock */\r
665                                         /* @req 3.1.5/NVM253 NvM_WriteAll   */\r
666                                         admPtr->BlockState = BLOCK_STATE_CALC_CRC_WRITE;\r
667                                 } else {\r
668                                         /* Done */\r
669                                         admPtr->BlockState = BLOCK_STATE_MEMIF_REQ;\r
670                                         admPtr->ErrorStatus = NVM_REQ_OK;\r
671                                         blockDone = 1;\r
672                                 }\r
673 #endif\r
674                         } else {\r
675                                 /* read */\r
676                                 uint8 crcLen = 0;\r
677                                 if( bPtr->BlockUseCrc ) {\r
678 \r
679                                         /* The read data is in the work buffer, read the CRC */\r
680                                         if( bPtr->BlockCRCType == NVM_CRC16) {\r
681                                                 admPtr->NvCrc.crc16 = READ16_NA( Nvm_WorkBuffer + bPtr->NvBlockLength );\r
682                                                 crcLen = 2;\r
683                                                 DEBUG_PRINTF(">> Nv CRC %04x\n",admPtr->NvCrc.crc16);\r
684                                                 admPtr->RamCrc.crc16 = admPtr->NvCrc.crc16;     /* Set RAM CRC = NvRAM CRC */\r
685                                         } else {\r
686                                                 admPtr->NvCrc.crc32 = READ32_NA( Nvm_WorkBuffer + bPtr->NvBlockLength );\r
687                                                 crcLen = 4;\r
688                                                 DEBUG_PRINTF(">> Nv CRC %08x\n",admPtr->NvCrc.crc16);\r
689                                                 admPtr->RamCrc.crc32 = admPtr->NvCrc.crc32;     /* Set RAM CRC = NvRAM CRC */\r
690                                         }\r
691 \r
692                                         memcpy(admPtr->savedDataPtr, Nvm_WorkBuffer, bPtr->NvBlockLength  + crcLen );\r
693 \r
694                                         /* Check if we should re-calculate the RAM checksum now when it's in RAM */\r
695                                         if( bPtr->CalcRamBlockCrc ) {\r
696                                                 /* This block want its RAM block CRC checked */\r
697                                                 DEBUG_PRINTF(">> Recalculation of RAM checksum \n",admPtr->NvCrc.crc16);\r
698                                                 assert( bPtr->BlockUseCrc == 1);\r
699                                                 admPtr->BlockState = BLOCK_STATE_CALC_CRC_READ;\r
700                                         } else {\r
701                                                 /* Done */\r
702                                                 admPtr->BlockState = BLOCK_STATE_MEMIF_REQ;\r
703                                                 admPtr->ErrorStatus = NVM_REQ_OK;\r
704                                                 blockDone = 1;\r
705                                         }\r
706 \r
707                                 } else {\r
708                                         DEBUG_PRINTF(">> Block have NO CRC\n");\r
709 \r
710                                         memcpy(admPtr->savedDataPtr, Nvm_WorkBuffer, bPtr->NvBlockLength  + crcLen );\r
711                                         /* Done */\r
712                                         admPtr->BlockState = BLOCK_STATE_MEMIF_REQ;\r
713                                         admPtr->ErrorStatus = NVM_REQ_OK;\r
714                                         blockDone = 1;\r
715                                 }\r
716 \r
717                                 /* Copy from Workbuffer to the real buffer */\r
718 \r
719                         }\r
720                         break;\r
721                 } else {\r
722                         /* Something failed */\r
723                         AdminMultiReq.PendingErrorStatus = NVM_REQ_NOT_OK;\r
724                         blockDone = 1;\r
725                         admPtr->BlockState = BLOCK_STATE_MEMIF_REQ;     /* TODO, this really true for all result below */\r
726 \r
727                         switch( jobResult ) {\r
728                         case MEMIF_BLOCK_INVALID:\r
729                                 /* @req 3.1.5/NVM342 */\r
730                                 admPtr->ErrorStatus = NVM_REQ_NV_INVALIDATED;\r
731                                 break;\r
732                         case MEMIF_BLOCK_INCONSISTENT:\r
733                                 /* @req 3.1.5/NVM360 */\r
734                                 admPtr->ErrorStatus = NVM_REQ_INTEGRITY_FAILED;\r
735                                 DEM_REPORTERRORSTATUS(NVM_E_REQ_INTEGRITY_FAILED,DEM_EVENT_STATUS_FAILED);\r
736                                 break;\r
737                         case MEMIF_JOB_FAILED:\r
738                                 /* @req 3.1.5/NVM361 */\r
739                                 admPtr->ErrorStatus = NVM_REQ_NOT_OK;\r
740                                 DEM_REPORTERRORSTATUS(NVM_E_REQ_FAILED,DEM_EVENT_STATUS_FAILED);\r
741                         default:\r
742                                 NVM_ASSERT(0);\r
743                                 break;\r
744                         }\r
745                 }\r
746                 break;\r
747         }\r
748 \r
749         case BLOCK_STATE_CALC_CRC:\r
750                 NVM_ASSERT(0);\r
751                 break;\r
752 \r
753         case BLOCK_STATE_CALC_CRC_WRITE:\r
754         {\r
755                 uint16 crc16;\r
756                 uint32 crc32;\r
757                 NVM_ASSERT(bPtr->RamBlockDataAddress != NULL );\r
758 \r
759                 /* Calculate RAM CRC checksum */\r
760                 if( bPtr->BlockCRCType == NVM_CRC16 ) {\r
761 \r
762                         crc16 = Crc_CalculateCRC16(bPtr->RamBlockDataAddress,bPtr->NvBlockLength,0xffff);\r
763                         DEBUG_CHECKSUM("RAM",crc16);\r
764 \r
765                         /* Just save the checksum */\r
766                         admPtr->RamCrc.crc16 = crc16;\r
767 \r
768 #if 0\r
769                         /* NV CRC in admin block */\r
770                         if( admPtr->RamCrc.crc16 != crc16 ) {\r
771                                 NVM_ASSERT(0);          /* TODO: Corrupt CRC */\r
772                         } else {\r
773                                 admPtr->BlockChanged = BLOCK_STATE_MEMIF_REQ;\r
774                         }\r
775 #endif\r
776 \r
777                         /* Write the block */\r
778                         admPtr->BlockState = BLOCK_STATE_MEMIF_REQ;\r
779                 } else {\r
780                         /* @req 3.1.5/NVM253 */\r
781                         crc32 = Crc_CalculateCRC32(bPtr->RamBlockDataAddress,bPtr->NvBlockLength,0xffffffffUL);\r
782                         if( crc32 !=  admPtr->RamCrc.crc32 ) {\r
783                                 /* The checksum is wrong, something have written to the RAM area without\r
784                                  * telling the NVM */\r
785                                 NVM_ASSERT(0);\r
786                         } else {\r
787                                 admPtr->BlockState = BLOCK_STATE_MEMIF_REQ;\r
788                         }\r
789                         admPtr->RamCrc.crc32 = crc32;\r
790                 }\r
791                 break;\r
792         }\r
793         case BLOCK_STATE_CALC_CRC_READ:\r
794         {\r
795                 NVM_ASSERT(bPtr->RamBlockDataAddress != NULL );\r
796                 NVM_ASSERT(bPtr->CalcRamBlockCrc == true );\r
797                 uint16 crc16;\r
798                 uint32 crc32;\r
799 \r
800                 /* Calculate RAM CRC checksum */\r
801                 if( bPtr->BlockCRCType == NVM_CRC16 ) {\r
802 \r
803 \r
804                         crc16 = Crc_CalculateCRC16(bPtr->RamBlockDataAddress,bPtr->NvBlockLength,0xffff);\r
805                         DEBUG_CHECKSUM("RAM",crc16);\r
806 \r
807                         /* NV CRC in admin block */\r
808 \r
809                         if( driveBlockCnt == 1) {\r
810                                 /* The previous "loop" we filled with default data */\r
811                                 admPtr->RamCrc.crc16 = crc16;\r
812                         }\r
813 \r
814                         /* @req 3.1.5/NVM387 */\r
815                         if( admPtr->RamCrc.crc16 != crc16 ) {\r
816 \r
817                                 /* @req 3.1.5/NVM388 Nvm_ReadAll */\r
818 \r
819                                 /* NVM387, NVM388\r
820                                  *\r
821                                  * Corrupt CRC, what choices are there:\r
822                                  * 1. Default data (=ROM) configured, just copy it.\r
823                                  * 2. Data redundancy, get it.\r
824                                  * 3. None of the above. Catastrophic failure. (NVM203)\r
825                                  */\r
826                                 if( bPtr->RomBlockDataAdress != NULL ) {\r
827                                         /* TODO: Restore block from ROM */\r
828                                         NVM_ASSERT(0);\r
829                                 } else {\r
830                                         /* @req 3.1.5/NVM469 */\r
831                                         if( bPtr->InitBlockCallback != NULL ) {\r
832 \r
833                                                 DEBUG_PRINTF("Filling block with default data\n");\r
834                                                 bPtr->InitBlockCallback();\r
835                                                 driveBlockCnt++;\r
836                                                 /* NVM085 is very vague here, but the says the application should be\r
837                                                  * able distinguish between when the init-callback have been called\r
838                                                  * or CRC is corrupt.\r
839                                                  */\r
840 \r
841                                                 /* The RAM CRC is at this point not calculated...so we must do this\r
842                                                  * .. so just stay in this state one more MainFunction.\r
843                                                  * */\r
844 \r
845                                         } else {\r
846 \r
847                                                 /* @req 3.1.5/NVM203 */\r
848                                                 DEM_REPORTERRORSTATUS(NVM_E_INTEGRITY_FAILED,DEM_EVENT_STATUS_FAILED);\r
849                                                 /* @req 3.1.5/NVM204 */\r
850                                                 admPtr->ErrorStatus = NVM_REQ_INTEGRITY_FAILED;\r
851                                                 admPtr->BlockState = BLOCK_STATE_MEMIF_REQ;\r
852                                                 blockDone = 1;\r
853                                         }\r
854                                 }\r
855                         } else {\r
856                                 DEBUG_CHECKSUM("RAM checksum ok with ",crc16);\r
857                                 admPtr->ErrorStatus = NVM_REQ_OK;\r
858                                 admPtr->BlockState = BLOCK_STATE_MEMIF_REQ;\r
859                                 blockDone = 1;\r
860                         }\r
861 \r
862                 } else {\r
863                         /* @req 3.1.5/NVM253 */\r
864                         /* Calculate CRC on the data we just read to RAM. Compare with CRC that is located in NV block */\r
865                         crc32 = Crc_CalculateCRC32(bPtr->RamBlockDataAddress,bPtr->NvBlockLength,0xffffffffUL);\r
866                         if( crc32 !=  admPtr->RamCrc.crc32 ) {\r
867                                 NVM_ASSERT(0);  /* TODO: Corrupt CRC */\r
868                         } else {\r
869                                 admPtr->BlockState = BLOCK_STATE_MEMIF_REQ;\r
870                         }\r
871                 }\r
872                 break;\r
873         }\r
874         default:\r
875                 NVM_ASSERT(0);\r
876                 break;\r
877         }\r
878 \r
879         if( blockDone  ) {\r
880 \r
881                 DEBUG_PRINTF("# Block Done\n");\r
882 \r
883                 if( admPtr->ErrorStatus == NVM_REQ_OK ) {\r
884                         admPtr->BlockChanged = FALSE;\r
885                         admPtr->BlockValid = TRUE;\r
886                 }\r
887 \r
888 \r
889                 /*  @req 3.1.5/NVM281 */\r
890                 if( bPtr->SingleBlockCallback != NULL ) {\r
891                         bPtr->SingleBlockCallback(NVM_READ_ALL_ID, admPtr->ErrorStatus);\r
892                 }\r
893 \r
894                 if( multiBlock ) {\r
895                         AdminMultiReq.currBlockIndex++;\r
896                         if( AdminMultiReq.currBlockIndex >= NVM_NUM_OF_NVRAM_BLOCKS ) {\r
897                                 AdminMultiReq.currBlockIndex = 0;\r
898 \r
899                                 /* @req 3.1.5/NVM301 */\r
900                                 if( NVM_REQ_NOT_OK == AdminMultiReq.PendingErrorStatus ) {\r
901                                         AdminMultiBlock.ErrorStatus = NVM_REQ_NOT_OK;\r
902                                 } else {\r
903                                         AdminMultiBlock.ErrorStatus = NVM_REQ_OK;\r
904                                 }\r
905                                 nvmState = NVM_IDLE;\r
906                                 nvmSubState = 0;\r
907                         }\r
908                 } else {\r
909                         nvmState = NVM_IDLE;\r
910                         nvmSubState = 0;\r
911 \r
912                 }\r
913         }\r
914 }\r
915 \r
916 /*\r
917  * Main function for the read all job
918  */\r
919 static void ReadAllMain(void)\r
920 {\r
921 \r
922         /* Cases:\r
923          * 1. We process each block until it's finished\r
924          * 2. We start to process a lot of blocks. The blocks may use different devices\r
925          *    and should be able to read a lot of them. This includes CRC.\r
926          *\r
927          *    1) is much simpler and 2) probably much faster.\r
928          *    This implementation will use 1) since it's simpler and maximum time that is\r
929          *    spent in MainFunction() can be controlled much better.\r
930          */\r
931 \r
932         /* Skip blocks that are skipped */\r
933 \r
934         while ( (AdminBlock[AdminMultiReq.currBlockIndex].ErrorStatus == NVM_REQ_BLOCK_SKIPPED) ) {\r
935                 if( (AdminMultiReq.currBlockIndex < NVM_NUM_OF_NVRAM_BLOCKS) ) {\r
936                         AdminMultiReq.currBlockIndex++;\r
937                 } else {\r
938                         return;\r
939                 }\r
940         }\r
941 \r
942         DriveBlock(     &NvM_Config.BlockDescriptor[AdminMultiReq.currBlockIndex],\r
943                                         &AdminBlock[AdminMultiReq.currBlockIndex],\r
944                                         NULL,\r
945                                         false,\r
946                                         true, false);\r
947 }\r
948 \r
949 \r
950 /*\r
951  * Request writing of a block to MemIf
952  */\r
953 static void WriteBlock( const NvM_BlockDescriptorType *blockDescriptor,\r
954                                                 AdministrativeBlockType *adminBlock,\r
955                                                 uint8 setNumber,\r
956                                                 uint8 *sourceAddress)\r
957 {\r
958         Std_ReturnType returnCode;\r
959 \r
960         if (setNumber < blockDescriptor->NvBlockNum) {\r
961                 SetMemifJobBusy();\r
962                 MemIfJobAdmin.BlockAdmin = adminBlock;\r
963                 MemIfJobAdmin.BlockDescriptor = blockDescriptor;\r
964                 returnCode = MemIf_Write(blockDescriptor->NvramDeviceId, BLOCK_BASE_AND_SET_TO_BLOCKNR(blockDescriptor->NvBlockBaseNumber, setNumber), sourceAddress);\r
965                 if (returnCode != E_OK) {\r
966                         AbortMemIfJob(MEMIF_JOB_FAILED);\r
967                 }\r
968         } else {\r
969                 // Error: setNumber out of range\r
970                 DET_REPORTERROR(MODULE_ID_NVM, 0, NVM_LOC_WRITE_BLOCK_ID, NVM_PARAM_OUT_OF_RANGE);\r
971         }\r
972 }\r
973 \r
974 \r
975 \r
976 /*\r
977  * Initiate the write all job\r
978  */\r
979 static void WriteAllInit(void)\r
980 {\r
981         const NvM_BlockDescriptorType   *BlockDescriptorList = NvM_Config.BlockDescriptor;\r
982         AdministrativeBlockType *AdminBlockTable = AdminBlock;\r
983         uint16 i;\r
984 \r
985 //      nvmState = NVM_WRITE_ALL_PROCESSING;\r
986         AdminMultiReq.PendingErrorStatus = NVM_REQ_OK;\r
987         AdminMultiReq.currBlockIndex = 0;\r
988 \r
989         for (i = 0; i < NVM_NUM_OF_NVRAM_BLOCKS; i++) {\r
990                 if ((BlockDescriptorList->RamBlockDataAddress != NULL)\r
991 #if (NVM_SET_RAM_BLOCK_STATUS_API == STD_ON)                                            /** @req NVM344 */\r
992                                 && (AdminBlockTable->BlockValid)                                        /** @req NVM682 */\r
993                                 && (AdminBlockTable->BlockChanged)                                      /** @req NVM682 */\r
994 #endif\r
995                                 && (!AdminBlockTable->BlockWriteProtected))                     /** @req NVM432 *//** @req NVM433 */\r
996                 {\r
997                         AdminBlockTable->ErrorStatus = NVM_REQ_PENDING;\r
998 \r
999                         if (BlockDescriptorList->BlockUseCrc) {\r
1000                                 AdminBlockTable->BlockState = BLOCK_STATE_CALC_CRC_WRITE;       /** @req NVM253 */\r
1001                         } else {\r
1002                                 AdminBlockTable->BlockState = BLOCK_STATE_MEMIF_REQ;\r
1003                                 AdminBlockTable->NumberOfWriteFailed = 0;\r
1004                         }\r
1005                 } else {\r
1006                         AdminBlockTable->ErrorStatus = NVM_REQ_BLOCK_SKIPPED;   /** @req NVM298 */\r
1007                 }\r
1008 \r
1009                 AdminBlockTable++;\r
1010                 BlockDescriptorList++;\r
1011         }\r
1012 }\r
1013 \r
1014 \r
1015 \r
1016 /*\r
1017  * Main function for the write all job\r
1018  */\r
1019 static void WriteAllMain(void)\r
1020 {\r
1021 \r
1022         while ( (AdminBlock[AdminMultiReq.currBlockIndex].ErrorStatus == NVM_REQ_BLOCK_SKIPPED) ) {\r
1023                 if( (AdminMultiReq.currBlockIndex < NVM_NUM_OF_NVRAM_BLOCKS) ) {\r
1024                         AdminMultiReq.currBlockIndex++;\r
1025                 } else {\r
1026                         return;\r
1027                 }\r
1028         }\r
1029 \r
1030         DriveBlock(     &NvM_Config.BlockDescriptor[AdminMultiReq.currBlockIndex],\r
1031                                         &AdminBlock[AdminMultiReq.currBlockIndex],\r
1032                                         NULL,\r
1033                                         true,\r
1034                                         true, false );\r
1035 \r
1036 }\r
1037 \r
1038 \r
1039 #if 0\r
1040 /*\r
1041  * Handles the result of one MemIf block write\r
1042  */\r
1043 static void WriteAllCheckWriteResult(void)\r
1044 {\r
1045         if (MemIfJobAdmin.JobStatus == E_OK) {\r
1046                 // TODO: Check if redundant block shall be written NVM337\r
1047 \r
1048                 if (MemIfJobAdmin.BlockDescriptor->WriteBlockOnce) {\r
1049                         MemIfJobAdmin.BlockAdmin->BlockWriteProtected = TRUE;   /** @req NVM329 */\r
1050                 }\r
1051                 MemIfJobAdmin.BlockAdmin->BlockState = BLOCK_STATE_MEMIF_REQ;\r
1052                 MemIfJobAdmin.BlockAdmin->ErrorStatus = NVM_REQ_OK;\r
1053 \r
1054                 if (MemIfJobAdmin.BlockDescriptor->SingleBlockCallback != NULL) {\r
1055                         (void)MemIfJobAdmin.BlockDescriptor->SingleBlockCallback(NVM_SERVICE_ID, MemIfJobAdmin.BlockAdmin->ErrorStatus);\r
1056                 }\r
1057         } else {\r
1058                 MemIfJobAdmin.BlockAdmin->NumberOfWriteFailed++;\r
1059                 if (MemIfJobAdmin.BlockAdmin->NumberOfWriteFailed > NVM_MAX_NUMBER_OF_WRITE_RETRIES) {\r
1060                         // TODO: Check if redundant block shall be written NVM337\r
1061 \r
1062                         // Write has failed\r
1063                         AdminMultiReq.PendingErrorStatus = NVM_REQ_NOT_OK;\r
1064 \r
1065                         MemIfJobAdmin.BlockAdmin->BlockState = BLOCK_STATE_MEMIF_REQ;\r
1066                         MemIfJobAdmin.BlockAdmin->ErrorStatus = NVM_REQ_NOT_OK; /** @req NVM296 */\r
1067 #if defined(USE_DEM)\r
1068                         Dem_ReportErrorStatus(NVM_E_REQ_FAILED,DEM_EVENT_STATUS_FAILED);\r
1069 #endif\r
1070 \r
1071                         if (MemIfJobAdmin.BlockDescriptor->SingleBlockCallback != NULL) {\r
1072                                 (void)MemIfJobAdmin.BlockDescriptor->SingleBlockCallback(NVM_SERVICE_ID, MemIfJobAdmin.BlockAdmin->ErrorStatus);\r
1073                         }\r
1074                 }\r
1075         }\r
1076         nvmState = NVM_WRITE_ALL_PROCESSING;\r
1077 }\r
1078 #endif\r
1079 \r
1080 \r
1081 \r
1082 /***************************************\r
1083  *    External accessible functions    *\r
1084  ***************************************/\r
1085 /*\r
1086  * Procedure:   NvM_Init\r
1087  * Reentrant:   No\r
1088  */\r
1089 void NvM_Init(void)\r
1090 {\r
1091         /** @req NVM399 *//** @req NVM193 */\r
1092         const NvM_BlockDescriptorType   *BlockDescriptorList = NvM_Config.BlockDescriptor;\r
1093         AdministrativeBlockType *AdminBlockTable = AdminBlock;\r
1094         uint16 i;\r
1095 \r
1096 \r
1097         CirqBuff_Init(&nvmQueue,nvmQueueData,sizeof(nvmQueueData),sizeof(Nvm_QueueType));\r
1098 \r
1099         // Initiate the administration blocks\r
1100         for (i = 0; i< NVM_NUM_OF_NVRAM_BLOCKS; i++) {\r
1101                 if (BlockDescriptorList->BlockManagementType == NVM_BLOCK_DATASET) {\r
1102                         AdminBlockTable->DataIndex = 0; /** @req NVM192 */\r
1103                 }\r
1104                 AdminBlockTable->BlockWriteProtected = BlockDescriptorList->BlockWriteProt;\r
1105                 AdminBlockTable->ErrorStatus = NVM_REQ_NOT_OK;\r
1106                 AdminBlockTable->BlockChanged = FALSE;\r
1107                 AdminBlockTable->BlockValid = FALSE;\r
1108                 AdminBlockTable->NumberOfWriteFailed = 0;\r
1109 \r
1110                 AdminBlockTable++;\r
1111                 BlockDescriptorList++;\r
1112         }\r
1113 \r
1114         AdminMultiBlock.ErrorStatus = NVM_REQ_NOT_OK;\r
1115 \r
1116         // Set status to initialized\r
1117         nvmState = NVM_IDLE;    /** @req 3.1.5/NVM399 */\r
1118 }\r
1119 \r
1120 \r
1121 /*\r
1122  * Procedure:   NvM_ReadAll\r
1123  * Reentrant:   No\r
1124  */\r
1125 void NvM_ReadAll(void)\r
1126 {\r
1127         VALIDATE_NO_RV(nvmState != NVM_UNINITIALIZED, NVM_READ_ALL_ID, NVM_E_NOT_INITIALIZED);\r
1128 \r
1129         NVM_ASSERT(nvmState == NVM_IDLE);\r
1130 \r
1131         AdminMultiReq.state = NVM_READ_ALL;\r
1132         AdminMultiBlock.ErrorStatus = NVM_REQ_PENDING;\r
1133 }\r
1134 \r
1135 \r
1136 \r
1137 /*\r
1138  * Procedure:   NvM_WriteAll\r
1139  * Reentrant:   No\r
1140  */\r
1141 void NvM_WriteAll(void)\r
1142 {\r
1143         VALIDATE_NO_RV(nvmState != NVM_UNINITIALIZED, NVM_READ_ALL_ID, NVM_E_NOT_INITIALIZED);\r
1144 \r
1145         NVM_ASSERT(nvmState == NVM_IDLE);\r
1146 \r
1147         AdminMultiReq.state = NVM_WRITE_ALL;\r
1148         AdminMultiBlock.ErrorStatus = NVM_REQ_PENDING;\r
1149 }\r
1150 \r
1151 \r
1152 /*\r
1153  * Procedure:   NvM_CancelWriteAll\r
1154  * Reentrant:   No\r
1155  */\r
1156 void NvM_CancelWriteAll(void)\r
1157 {\r
1158         \r
1159 }\r
1160 \r
1161 \r
1162 /*\r
1163  * Procedure:   NvM_GetErrorStatus\r
1164  * Reentrant:   Yes\r
1165  */\r
1166 void NvM_GetErrorStatus(NvM_BlockIdType blockId, uint8 *requestResultPtr)\r
1167 {\r
1168         VALIDATE_NO_RV(nvmState != NVM_UNINITIALIZED, NVM_GET_ERROR_STATUS_ID, NVM_E_NOT_INITIALIZED);\r
1169         VALIDATE_NO_RV(blockId < NVM_NUM_OF_NVRAM_BLOCKS+1, NVM_GET_ERROR_STATUS_ID, NVM_E_PARAM_BLOCK_ID);\r
1170 \r
1171         if (blockId == 0) {\r
1172                 // Multiblock ID\r
1173                 *requestResultPtr = AdminMultiBlock.ErrorStatus;\r
1174         } else if (blockId == 1) {\r
1175                 /* TODO */\r
1176         } else {\r
1177                 *requestResultPtr = AdminBlock[blockId-1].ErrorStatus;\r
1178         }\r
1179 \r
1180 }\r
1181 \r
1182 \r
1183 #if (NVM_SET_RAM_BLOCK_STATUS_API == STD_ON)    /** @req NVM408 */\r
1184 /*\r
1185  * Procedure:   Nvm_SetRamBlockStatus\r
1186  * Reentrant:   Yes\r
1187  */\r
1188 void NvM_SetRamBlockStatus(NvM_BlockIdType blockId, boolean blockChanged)\r
1189 {\r
1190         const NvM_BlockDescriptorType   *BlockDescriptorList = NvM_Config.BlockDescriptor;\r
1191 \r
1192         VALIDATE_NO_RV(nvmState != NVM_UNINITIALIZED, NVM_SET_RAM_BLOCK_STATUS_ID, NVM_E_NOT_INITIALIZED);      /** @req NVM497 */\r
1193         VALIDATE_NO_RV(blockId < NVM_NUM_OF_NVRAM_BLOCKS+1, NVM_SET_RAM_BLOCK_STATUS_ID, NVM_E_PARAM_BLOCK_ID);\r
1194         VALIDATE_NO_RV(blockId > 1, NVM_SET_RAM_BLOCK_STATUS_ID, NVM_E_PARAM_BLOCK_ID);\r
1195 \r
1196         if (BlockDescriptorList[blockId-1].RamBlockDataAddress != NULL) {       /** @req NVM240 */\r
1197                 if (blockChanged) {\r
1198                         AdminBlock[blockId-1].BlockChanged = TRUE;      /** @req NVM406 */\r
1199                         AdminBlock[blockId-1].BlockValid = TRUE;        /** @req NVM241 */\r
1200                         if (BlockDescriptorList[blockId-1].BlockUseCrc) {\r
1201                                 AdminBlock[blockId-1].BlockState = BLOCK_STATE_CALC_CRC;        /** @req NVM121 */\r
1202                         }\r
1203                 } else {\r
1204                         AdminBlock[blockId-1].BlockChanged = FALSE;     /** @req NVM405 */\r
1205                         AdminBlock[blockId-1].BlockValid = FALSE;\r
1206                 } // else blockChanged\r
1207         } // if permanent block\r
1208 }\r
1209 #endif\r
1210 \r
1211 \r
1212 void NvM_SetBlockLockStatus( NvM_BlockIdType blockId, boolean blockLocked ) {\r
1213         (void)blockId;\r
1214         (void)blockLocked;\r
1215 }\r
1216 \r
1217 \r
1218 /**\r
1219  * Restore default data to its corresponding RAM block.\r
1220  *
1221  * @param BlockId               NVRAM block identifier.
1222  * @param NvM_DestPtr   Pointer to the RAM block
1223  * @return
1224  */\r
1225 Std_ReturnType NvM_RestoreBlockDefaults( NvM_BlockIdType blockId, uint8* NvM_DestPtr )\r
1226 {\r
1227         /* !req 3.1.5/NVM012 */ /* !req 3.1.5/NVM267 */ /* !req 3.1.5/NVM266 */\r
1228         /* !req 3.1.5/NVM353 */ /* !req 3.1.5/NVM435 */ /* !req 3.1.5/NVM436 */ /* !req 3.1.5/NVM227 */\r
1229         /* !req 3.1.5/NVM228 */ /* !req 3.1.5/NVM229 */ /* !req 3.1.5/NVM413 */\r
1230 \r
1231         const NvM_BlockDescriptorType * bPtr;\r
1232         AdministrativeBlockType *               admPtr;\r
1233         Nvm_QueueType qEntry;\r
1234         int rv;\r
1235 \r
1236         NVM_ASSERT( blockId >= 2 );     /* No support for lower numbers, yet */\r
1237 \r
1238         /* @req 3.1.5/NVM618 */\r
1239         VALIDATE_RV(    blockId <= NVM_NUM_OF_NVRAM_BLOCKS,\r
1240                                         NVM_WRITE_BLOCK_ID,NVM_E_PARAM_BLOCK_ID,E_NOT_OK );\r
1241 \r
1242         bPtr = &NvM_Config.BlockDescriptor[blockId-1];\r
1243         admPtr = &AdminBlock[blockId-1];\r
1244 \r
1245         /** @req 3.1.5/NVM196 */ /** @req 3.1.5/NVM278 */\r
1246         if( (NvM_DestPtr == NULL) &&  ( bPtr->RamBlockDataAddress == NULL ) ) {\r
1247                 /* It must be a permanent RAM block but no RamBlockDataAddress -> error */\r
1248                 NVM_ASSERT(0);          // TODO: See NVM210, DET error\r
1249                 return E_NOT_OK;\r
1250         }\r
1251 \r
1252         /* @req 3.1.5/NVM195 */\r
1253         qEntry.blockId = blockId;\r
1254         qEntry.op = NVM_RESTORE_BLOCK_DEFAULTS;\r
1255         qEntry.blockId = blockId;\r
1256         qEntry.dataPtr = (uint8_t *)NvM_DestPtr;\r
1257         rv = CirqBuffPush(&nvmQueue,&qEntry);\r
1258         NVM_ASSERT(rv == 0 );\r
1259 \r
1260         /* @req 3.1.5/NVM620 */\r
1261         VALIDATE_RV( (admPtr->ErrorStatus != NVM_REQ_PENDING), 0, NVM_E_BLOCK_PENDING , E_NOT_OK );\r
1262 \r
1263         /* req 3.1.5/NVM185 */\r
1264         admPtr->ErrorStatus = NVM_REQ_PENDING;\r
1265 \r
1266         if( bPtr->BlockUseCrc) {\r
1267                 admPtr->BlockState = BLOCK_STATE_CALC_CRC_WRITE;\r
1268         } else {\r
1269                 admPtr->BlockState = BLOCK_STATE_MEMIF_REQ;\r
1270         }\r
1271 \r
1272 \r
1273         return E_OK;\r
1274 }\r
1275 \r
1276 /**\r
1277  * Service to copy the data NV block to the RAM block\r
1278  *
1279  * @param blockId               0 and 1 reserved. The block ID are sequential.
1280  * @param NvM_DstPtr
1281  * @return
1282  */\r
1283 \r
1284 \r
1285 Std_ReturnType NvM_ReadBlock( NvM_BlockIdType blockId, uint8* NvM_DstPtr )\r
1286 {\r
1287         /* !req 3.1.5/NVM010 */\r
1288 \r
1289 \r
1290         /* !req 3.1.5/NVM278 */\r
1291         /* !req 3.1.5/NVM340 */\r
1292         /* !req 3.1.5/NVM354 */\r
1293         /* !req 3.1.5/NVM200 */\r
1294         /* !req 3.1.5/NVM366 */\r
1295         /* !req 3.1.5/NVM206 */\r
1296         /* !req 3.1.5/NVM341 */\r
1297         /* !req 3.1.5/NVM358 */\r
1298         /* !req 3.1.5/NVM359 */\r
1299         /* !req 3.1.5/NVM279 */\r
1300         /* !req 3.1.5/NVM316 */\r
1301         /* !req 3.1.5/NVM317 */\r
1302         /* !req 3.1.5/NVM201 */\r
1303         /* !req 3.1.5/NVM202 */\r
1304         /* !req 3.1.5/NVM203 */\r
1305         /* !req 3.1.5/NVM204 */\r
1306         /* !req 3.1.5/NVM409 */\r
1307 \r
1308 \r
1309    /* logical block:\r
1310     *\r
1311     *    1 1 1 1 1 1\r
1312     *   |5 4 3 2 1 0 9 8|7 6 5 4 3 2 1 0|\r
1313     *    b b b b b b b b b b d d d d d d\r
1314     *\r
1315     * Here we have 10 bits for block id, 16-5 for DataSetSelection bits.\r
1316     * - 2^10, 1024 blocks\r
1317     * - 64 datasets for each NVRAM block\r
1318     *\r
1319     * How are the block numbers done in EA? Assume virtual page=8\r
1320     * logical\r
1321     *  Block   size\r
1322     *  1       32\r
1323     *   2\r
1324     *   3\r
1325     *   4\r
1326     *  5       12\r
1327     *   6\r
1328     *  7\r
1329     *\r
1330     *  How can NVM/NvmNvBlockLength and EA/EaBlockSize be different?\r
1331     *  It seems that EA/FEE does not care about that logical block 2 above is\r
1332     *  "blocked"\r
1333     *
1334     */\r
1335         Nvm_QueueType qEntry;\r
1336         int rv;\r
1337 \r
1338         /** @req 3.1.5/NVM196 */ /** @req 3.1.5/NVM278 */\r
1339         if( (NvM_DstPtr == NULL) &&  ( NvM_Config.BlockDescriptor[blockId-1].RamBlockDataAddress == NULL ) ) {\r
1340                 /* It must be a permanent RAM block but no RamBlockDataAddress -> error */\r
1341                 return E_NOT_OK;\r
1342         }\r
1343 \r
1344         /* @req 3.1.5/NVM195 */\r
1345         qEntry.blockId = blockId;\r
1346         qEntry.op = NVM_READ_BLOCK;\r
1347         qEntry.blockId = blockId;\r
1348         qEntry.dataPtr = NvM_DstPtr;\r
1349         rv = CirqBuffPush(&nvmQueue,&qEntry);\r
1350         NVM_ASSERT(rv == 0 );\r
1351 \r
1352         /* @req 3.1.5/NVM615 */\r
1353         VALIDATE_RV( (AdminBlock[blockId-1].ErrorStatus != NVM_REQ_PENDING), 0, NVM_E_BLOCK_PENDING , E_NOT_OK );\r
1354 \r
1355         /* req 3.1.5/NVM185 */\r
1356         AdminBlock[blockId-1].ErrorStatus = NVM_REQ_PENDING;\r
1357 \r
1358         return E_OK;\r
1359 }\r
1360 \r
1361 \r
1362 /**\r
1363  * Service to copy a RAM block to its correspnding NVRAM block\r
1364  *
1365  * @param blockId
1366  * @param NvM_SrcPtr
1367  * @return
1368  */\r
1369 Std_ReturnType NvM_WriteBlock( NvM_BlockIdType blockId, const uint8* NvM_SrcPtr ) {\r
1370 \r
1371         const NvM_BlockDescriptorType * bPtr;\r
1372         AdministrativeBlockType *               admPtr;\r
1373         Nvm_QueueType qEntry;\r
1374         int rv;\r
1375 \r
1376         NVM_ASSERT( blockId >= 2 );     /* No support for lower numbers, yet */\r
1377 \r
1378         /* @req 3.1.5/NVM618 */\r
1379         VALIDATE_RV(    blockId <= NVM_NUM_OF_NVRAM_BLOCKS,\r
1380                                         NVM_WRITE_BLOCK_ID,NVM_E_PARAM_BLOCK_ID,E_NOT_OK );\r
1381 \r
1382         bPtr = &NvM_Config.BlockDescriptor[blockId-1];\r
1383         admPtr = &AdminBlock[blockId-1];\r
1384 \r
1385         /** @req 3.1.5/NVM196 */ /** @req 3.1.5/NVM278 */\r
1386         if( (NvM_SrcPtr == NULL) &&  ( bPtr->RamBlockDataAddress == NULL ) ) {\r
1387                 /* It must be a permanent RAM block but no RamBlockDataAddress -> error */\r
1388                 NVM_ASSERT(0);          // TODO: See NVM210, DET error\r
1389                 return E_NOT_OK;\r
1390         }\r
1391 \r
1392         /* @req 3.1.5/NVM195 */\r
1393         qEntry.blockId = blockId;\r
1394         qEntry.op = NVM_WRITE_BLOCK;\r
1395         qEntry.blockId = blockId;\r
1396         qEntry.dataPtr = (uint8_t *)NvM_SrcPtr;\r
1397         rv = CirqBuffPush(&nvmQueue,&qEntry);\r
1398         NVM_ASSERT(rv == 0 );\r
1399 \r
1400         /* @req 3.1.5/NVM620 */\r
1401         VALIDATE_RV( (admPtr->ErrorStatus != NVM_REQ_PENDING), 0, NVM_E_BLOCK_PENDING , E_NOT_OK );\r
1402 \r
1403         /* req 3.1.5/NVM185 */\r
1404         admPtr->ErrorStatus = NVM_REQ_PENDING;\r
1405 \r
1406         if( bPtr->BlockUseCrc) {\r
1407                 admPtr->BlockState = BLOCK_STATE_CALC_CRC_WRITE;\r
1408         } else {\r
1409                 admPtr->BlockState = BLOCK_STATE_MEMIF_REQ;\r
1410         }\r
1411 \r
1412 \r
1413         return E_OK;\r
1414 }\r
1415 \r
1416 /* Missing from Class 2\r
1417  * - NvM_CancelWriteAll\r
1418  * - NvM_SetDataIndex\r
1419  * - NvM_GetDataIndex\r
1420  * */\r
1421 \r
1422 \r
1423 \r
1424 \r
1425 \r
1426 const NvM_BlockDescriptorType * nvmBlock;\r
1427 AdministrativeBlockType *admBlock;\r
1428 \r
1429 /**\r
1430  *
1431  */\r
1432 void NvM_MainFunction(void)\r
1433 {\r
1434         int                     rv;\r
1435         Nvm_QueueType   qEntry;\r
1436         const NvM_BlockDescriptorType * bList = NvM_Config.BlockDescriptor;\r
1437 //      const NvM_BlockDescriptorType * currBlock;\r
1438 //      static uint32 crc32;\r
1439 //      static uint32 crc32Left;\r
1440 \r
1441         /* Check for new requested state changes */\r
1442         if( nvmState == NVM_IDLE ) {\r
1443                 rv = CirqBuffPop( &nvmQueue, &qEntry );\r
1444                 if( rv == 0 ) {\r
1445                         /* Found something in buffer */\r
1446                         nvmState = qEntry.op;\r
1447                         nvmBlock = &bList[qEntry.blockId-1];\r
1448                         admBlock = &AdminBlock[qEntry.blockId-1];\r
1449                         nvmSubState = 0;\r
1450                         admBlock->ErrorStatus = NVM_REQ_PENDING;\r
1451                         DEBUG_PRINTF("### Popped Single FIFO \n");\r
1452                         DEBUG_PRINTF("### CRC On:%d Ram:%d Type:%d\n",nvmBlock->BlockUseCrc, nvmBlock->CalcRamBlockCrc, nvmBlock->BlockCRCType );\r
1453                         DEBUG_PRINTF("### RAM:%x ROM:%x\n", nvmBlock->RamBlockDataAddress, nvmBlock->RomBlockDataAdress );\r
1454                 } else {\r
1455                         /* Check multiblock req */\r
1456                         if( AdminMultiReq.state != NVM_UNINITIALIZED ) {\r
1457                                 nvmState = AdminMultiReq.state ;\r
1458                                 nvmSubState = 0;\r
1459                                 nvmBlock = 0;\r
1460                                 admBlock = 0;\r
1461                                 AdminMultiReq.state = NVM_UNINITIALIZED;\r
1462 \r
1463                                 DEBUG_PRINTF("### Popped MULTI\n");\r
1464                         }\r
1465                 }\r
1466         }\r
1467 \r
1468         DEBUG_STATE(nvmState,nvmSubState);\r
1469 \r
1470         switch (nvmState) {\r
1471         case NVM_UNINITIALIZED:\r
1472                 break;\r
1473 \r
1474         case NVM_IDLE:\r
1475         {\r
1476                 CalcCrc();\r
1477                 break;\r
1478         }\r
1479         case NVM_READ_ALL:\r
1480                 if( NS_INIT == nvmSubState ) {\r
1481                         ReadAllInit();\r
1482                         nvmSubState = NS_PROSSING;\r
1483                 } else if( NS_PROSSING == nvmSubState ) {\r
1484                         ReadAllMain();\r
1485                 }\r
1486                 break;\r
1487 \r
1488         case NVM_READ_BLOCK:\r
1489                 DriveBlock(nvmBlock,admBlock, qEntry.dataPtr, false, false, false );\r
1490                 break;\r
1491 \r
1492         case NVM_RESTORE_BLOCK_DEFAULTS:\r
1493                 DriveBlock(nvmBlock,admBlock, qEntry.dataPtr, false, false, true );\r
1494                 break;\r
1495 \r
1496         case NVM_WRITE_BLOCK:\r
1497                 DriveBlock(nvmBlock,admBlock, qEntry.dataPtr, true /*write*/, false , false );\r
1498                 break;\r
1499 \r
1500         case NVM_WRITE_ALL:\r
1501                 if( NS_INIT == nvmSubState ) {\r
1502                         WriteAllInit();\r
1503                         nvmSubState = NS_PROSSING;\r
1504                 } else if( NS_PROSSING == nvmSubState ) {\r
1505                         WriteAllMain();\r
1506                 }\r
1507                 break;\r
1508 \r
1509         default:\r
1510                 DET_REPORTERROR(MODULE_ID_NVM, 0, NVM_MAIN_FUNCTION_ID, NVM_UNEXPECTED_STATE);\r
1511                 break;\r
1512         }\r
1513 }\r
1514 \r
1515 \r
1516 /***************************************\r
1517  *  Call-back notifications functions  *\r
1518  ***************************************/\r
1519 #if (NVM_POLLING_MODE == STD_OFF)\r
1520 /*\r
1521  * Procedure:   NvM_JobEndNotification\r
1522  * Reentrant:   No\r
1523  */\r
1524 void NvM_JobEndNotification(void)\r
1525 {\r
1526         MemIfJobAdmin.JobFinished = TRUE;\r
1527         MemIfJobAdmin.JobStatus = E_OK;\r
1528         MemIfJobAdmin.JobResult = MemIf_GetJobResult();\r
1529 }\r
1530 \r
1531 /*\r
1532  * Procedure:   NvM_JobErrorNotification\r
1533  * Reentrant:   No\r
1534  */\r
1535 void NvM_JobErrorNotification(void)\r
1536 {\r
1537         MemIfJobAdmin.JobFinished = TRUE;\r
1538         MemIfJobAdmin.JobStatus = E_NOT_OK;\r
1539         MemIfJobAdmin.JobResult = MemIf_GetJobResult();\r
1540 }\r
1541 #endif\r
1542 \r