]> rtime.felk.cvut.cz Git - arc.git/blob - memory/NvM/NvM.c
NvM: Now handles when Fee/EA is busy
[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 /*\r
18  * Author: Peter+mahi\r
19  *\r
20  * Part of Release:\r
21  *   3.1.5\r
22  *\r
23  * Description:\r
24  *   Implements the NVRAM Manager module.\r
25  *\r
26  * Support:\r
27  *   General                  Have Support\r
28  *   -------------------------------------------\r
29  *   NVM_API_CONFIG_CLASS           Y NVM_API_CONFIG_CLASS_1 and NVM_API_CONFIG_CLASS_2\r
30  *   NVM_COMPILED_CONFIG_ID                     N\r
31  *   NVM_CRC_NUM_OF_BYTES               N\r
32  *   NVM_DATASET_SELECTION_BITS     Y\r
33  *   NVM_DEV_ERROR_DETECT           Y\r
34  *   NVM_DRV_MODE_SWITCH            N\r
35  *   NVM_DYNAMIC_CONFIGURATION      N\r
36  *   NVM_JOB_PRIORITIZATION         N\r
37  *   NVM_MULTI_BLOCK_CALLBACK       Y\r
38  *   NVM_POLLING_MODE               N\r
39  *   NVM_SET_RAM_BLOCK_STATUS_API   Y\r
40  *   NVM_SIZE_IMMEDIATE_JOB_QUEUE   N\r
41  *   NVM_SIZE_STANDARD_JOB_QUEUE    Y\r
42  *   NVM_VERSION_INFO_API           Y\r
43  *\r
44  *   NvmBlockDescriptor        Have Support\r
45  *   -------------------------------------------\r
46  *   NvmBlockCRCType                    Y\r
47  *   NvmBlockJobPriority                        N\r
48  *   NvmBlockManagementType             Y, All blocks supported\r
49  *   NvmBlockUseCrc                             Y\r
50  *   NvmBlockWriteProt                          N\r
51  *   NvmCalcRamBlockCrc                         Y\r
52  *   NvmInitBlockCallback                       Y\r
53  *   NvmNvBlockBaseNumber                       Y\r
54  *   NvmNvBlockLength                           Y\r
55  *   NvmNvBlockNum                                      Y\r
56  *   NvmNvramBlockIdentifier            Y\r
57  *   NvmNvramDeviceId                           N (always device Id 0)\r
58  *   NvmResistantToChangedSw            N\r
59  *   NvmRomBlockDataAddress                     Y\r
60  *   NvmRomBlockNum                                     Y\r
61  *   NvmSelectBlockForReadall           Y\r
62  *   NvmSingleBlockCallback             Y\r
63  *   NvmWriteBlockOnce                          N\r
64  *\r
65  *  Implementation notes:\r
66  *   - The Configuration ID NV Block is generated to the configuration but can't be configured.\r
67  *     The Editor should really force you to pick a block in Ea/Fee that should hold the configuration\r
68  *     ID. The NVM_COMPILED_CONFIG_ID is always generated as 0 now.\r
69  *   - You can ONLY configure one block type for the entire NvM since NvmNvramDeviceId is not supported.\r
70  *     ie "Target Block" must all be eihter FEE or EA blocks.\r
71  *   - Differences from 3.1.5 Release (Follow release 4.0.2 here)\r
72  *     NvM_SetDataIndex(), NvM_GetDataIndex, NvM_SetBlockProtection, NvM_GetErrorStatus, NvM_SetRamBlockStatus,\r
73  *     etc....all return Std_ReturnType instead of void since the RTE expects it.\r
74  *   - NvM_GetErrorStatus() uses NvM_GetErrorStatus instead of uint8 *\r
75  */\r
76 \r
77 /*\r
78  * RamBlockDataAddress\r
79  *   NULL is no permanent RAM block. Otherwise allocate the number of bytes in space (like the stack)\r
80  *\r
81  *\r
82  * Understanding block numbering:\r
83  *\r
84  *  NVM_DATASET_SELECTION_BIT=2\r
85  *\r
86  *    NvBlockBaseNumber\r
87  *          0     Reserved (NVM478)\r
88  *          1     NVM_BLOCK_NATIVE,    NvBlockNum=1\r
89  *          2     NVM_BLOCK_REDUNDANT, NvBlockNum=2\r
90  *          3     NVM_BLOCK_DATASET,   NvBlockNum=4\r
91  *\r
92  *   NvM_ReadBlock( 0, ... )    - Reserved for "multi block requests"\r
93  *   NvM_ReadBlock( 1, ... )    - Reserved for redundant NVRAM block which holds the configuration ID.\r
94  *   NvM_ReadBlock( 2--x, ... ) - "Normal" blocks\r
95  *\r
96  *\r
97  *  NvM_BlockIdType*)  NvBlockBaseNumber   EA_BLOCK_NUMBER\r
98  *      0**)\r
99  *      1**)                ***)\r
100  *      2                   1                           4, (5,6,7)  ****)\r
101  *      3                   2                           8, R9,(10,11)  ****)\r
102  *      4                   3                           12, D13,D14,D15 ****)\r
103  *\r
104  *  Should\r
105  *\r
106  *\r
107  *  *) Type used in the API.\r
108  *  **)   Reserved ID's ( 0 - multiblock, 1 - redundant NVRAM block which hold configuration ID)\r
109  *  ***)  Reserved ID\r
110  *  ****) FEE/EA_BLOCK_NUMBER = NvBlockBaseNumber << NvmDatasetSelectionBits = NvBlockBaseNumber * 4\r
111  *        () - Cannot be accesses due to NvBlockNum\r
112  *        R9 - Redundant block\r
113  *        Dx - Data blocks\r
114  *\r
115  *    SIZES\r
116  *      Both NvM and EA/FEE have block sizes. NvM have NvNvmBlockLength (NVM479) and FEE/EA have EaBlockSize.\r
117  *      FEE/EA also have virtual page that is the alignment of a block, with the smallest block=size of the virtual page.\r
118  *\r
119  *      So, who allocates space for this. FEE/EA only have EaBlockSize.\r
120  *      NvM have NvmRamBlockDataAddress, NvmRomBlockDataAddress and mapping to a MemIf Blocks (FEE/EA blocks)\r
121  *\r
122  *      ASSUME: I can't really see a point for the FEE/EA EaBlockSize.. it will just a multiple of NvNvmBlockLength*NvBlockNum + overhead?\r
123  *              Click-box in EA/FEE that leaves the size calculation to NvM?\r
124  *              This also means that enabling NvmBlockUseCrc or set a block from NVM_BLOCK_NATIVE to NVM_BLOCK_DATASET would be "automatic"\r
125  *              in calculation of the EaBlockSize.\r
126  *\r
127  *      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
128  *      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
129  *\r
130  * CRC\r
131  *   NVM121: NvM_SetRamBlockStatus(), calculate CRC in background if NvmCalcRamBlockCrc==TRUE\r
132  *   NVM362: NvM_ReadAll() , if (NvmCalcRamBlockCrc == TRUE && permanent RAM block) re-calc CRC.\r
133  *\r
134  *     NvmBlockUseCrc     - Global CRC switch. Space is allocated in both RAM and NV block\r
135  *     NvmCalcRamBlockCrc - CRC re-calculation. For example during startup, you may don't want\r
136  *                          to verify all the checksums again, but instead just copy from NV\r
137  *                          to RAM.\r
138  *\r
139  *     There is also explicit RAM checksum calculations for example NVM253 (Nvm_WriteAll()) where a CRC calculation\r
140  *     is requested (although not stated should be dependent on NvmBlockUseCrc only, not NvmCalcRamBlockCrc).\r
141  *     You have to calculate the checksum at some point....\r
142  *\r
143  * QUEUES\r
144  *   NVM185: Says "successful enqueueing a request".."set to NVM_REQ_PENDING"\r
145  *   NVM380: The queue length for multi block request shall be one (NvM_ReadAll, NvM_WriteAll)\r
146  *   NVM381+NVM567 : Multi block requests shall not be interrupted.\r
147  *   NVM243+NVM245: Do not unqueue the multi block request until all single block queues are empty.\r
148  *     So, when NvmState==IDLE and we have a multi-request\r
149  *\r
150  *\r
151  *\r
152  *\r
153  *\r
154  * SPEED\r
155  *   To get some speed into this multiple thing must be done in the same MainFunction loop.\r
156  *\r
157  * MEMIF\r
158  *   The interface is actually quite strange, so you may read from any address (through MemIf_Read())\r
159  *   but MemIf_Write(..) only takes a logical block and a pointer to the data to write.\r
160  *\r
161  *   See two alternatives here:\r
162  *    1. If the NVBlock also contains the checksum after the data then writing the data needs a\r
163  *       RAM that is as big as the biggest RAM block + room for checksum.\r
164  *    2. If checksums would be kept in a separate EA/FEE block the ALL the checksum need to be written.\r
165  *       For example after a NvM_WriteBlock() the checksum block would need to be written. This\r
166  *       will probably lead consistency problems also... what happens if we fail to write the checksum\r
167  *       block?\r
168  *\r
169  *\r
170  *\r
171  * MANUAL\r
172  *\r
173  *\r
174  *\r
175  *   Provide Data for the first/initial read\r
176  *     When a block have no\r
177  *\r
178  *     NVM085\r
179  *     NVM061\r
180  *     NVM083\r
181  *\r
182  *   Configuring CRCs\r
183  *     BlockUseCrc (A):      If the block (both RAM and NV) should use CRC\r
184  *     CalcRamBlockCrc (B):  If the permanent RAM block should re-calculate it's CRC.\r
185  *\r
186  *     A B\r
187  *     ------------\r
188  *     0 0  No error detection or recovery\r
189  *     0 1  N/A\r
190  *     1 0  ?\r
191  *     1 1  ?\r
192  *\r
193  * RAM BLOCK VALID/UNCHANGED\r
194  *   Figure 8 and 9 in 3.1.5/NVM is more confusing than good.\r
195  *   What we have to know is:\r
196  *    1. Initially the RAM block is in INVALID/UNCHANGED\r
197  *    ALT 2. After a NvM_ReadAll() and all is well the state goes to VALID/UNCHANGED\r
198  *    ALT 2. If ROM values are used we go to VALID/CHANGED (We failed to read from NVRAM)\r
199  *\r
200  *   For NvM_WriteAll()\r
201  *   1. A block that is INVALID can't be written\r
202  *   2. A block that is UNCHANGED should not be written.\r
203  *   -> Write only blocks that are VALID/CHANGED.\r
204  *\r
205  *   VALID/UNCHANGED - RAM == NV\r
206  *   VALID/CHANGED   - RAM != NV   (analog to cache memories, "dirty")\r
207  *\r
208  *   Analog to cache\r
209  *     VALID/CHANGED state - Dirty (since RAM != NV)\r
210  *     WriteBlock          - Flush (Flush the RAM block to NV)\r
211  *     ReadBlock           - Invalidate (NV block is read to RAM)\r
212  */\r
213 \r
214 \r
215 /*\r
216  *  General requirements\r
217  */\r
218 /** @req NVM076 */\r
219 /** @req NVM552 */\r
220 /** @req NVM689 */\r
221 \r
222 \r
223 /*\r
224  * NB! Even though some code exist for handling RamCrc, the functionality is not complete\r
225  * and shall not be used.
226  */\r
227 \r
228 //lint -esym(522,CalcCrc) // 522 PC-Lint exception for empty functions\r
229 //lint -emacro(904,VALIDATE_RV,VALIDATE_NO_RV) //904 PC-Lint exception to MISRA 14.7 (validate macros).\r
230 \r
231 // Exception made as a result of that NVM_DATASET_SELECTION_BITS can be zero\r
232 //lint -emacro(835, BLOCK_BASE_AND_SET_TO_BLOCKNR) // 835 PC-lint: A zero has been given as right argument to operator '<<' or '>>'\r
233 \r
234 \r
235 /* ----------------------------[includes]------------------------------------*/\r
236 \r
237 #include <assert.h>\r
238 #include "NvM.h"\r
239 #include "NvM_Cbk.h"\r
240 #if defined(CFG_NVM_USE_SERVICE_PORTS)\r
241 #include "Rte.h" // ???\r
242 #endif\r
243 #if defined(USE_DEM)\r
244 #include "Dem.h"\r
245 #endif\r
246 #include "MemIf.h"\r
247 //#include "SchM_NvM.h"\r
248 #include "MemMap.h"\r
249 #include "cirq_buffer.h"\r
250 #include "Modules.h"\r
251 #include <stdio.h>\r
252 #include "io.h"\r
253 #include "Crc.h"\r
254 #include <string.h>\r
255 #include "Cpu.h"\r
256 \r
257 #define FIXME           0\r
258 \r
259 //#define DEBUG_BLOCK   1\r
260 #if defined(DEBUG_BLOCK)\r
261 #define DEBUG_BLOCK_STATE(_str,_block,_state)       printf("%s BLOCK NR:%d STATE:%d\n",_str,_block, _state); fflush(stdout);\r
262 #define DEBUG_STATE(_state,_substate)                           printf("MAIN_STATE:%s/%d\n",StateToStr[_state],_substate); fflush(stdout);\r
263 #define DEBUG_PRINTF(format,...)                                        printf(format,## __VA_ARGS__ ); fflush(stdout);\r
264 #define DEBUG_CHECKSUM(_str,_crc)                                       printf("%s crc=%x\n",_str,_crc);\r
265 #else\r
266 #define DEBUG_BLOCK_STATE(_str,_block,_state)\r
267 #define DEBUG_STATE(_state,_substate)\r
268 #define DEBUG_PRINTF(format,...)\r
269 #define DEBUG_CHECKSUM(_str,_crc)\r
270 #endif\r
271 \r
272 \r
273 /* ----------------------------[private define]------------------------------*/\r
274 \r
275 \r
276 \r
277 #define NVM_BLOCK_ALIGNMENT                     4\r
278 #define NVM_CHECKSUM_LENGTH                     4\r
279 \r
280 #define NVM_BLOCK_OFFSET                2\r
281 \r
282 \r
283 \r
284 \r
285 \r
286 /* ----------------------------[private macro]-------------------------------*/\r
287 \r
288 #if defined(DEBUG_BLOCK)\r
289 #define NVM_ASSERT(_exp)                if( !(_exp) ) { assert(_exp); } //\r
290 #else\r
291 #define NVM_ASSERT(_exp)                if( !(_exp) ) { while(1) {}; } //assert(_exp)\r
292 #endif\r
293 \r
294 \r
295 #if  ( NVM_DEV_ERROR_DETECT == STD_ON )\r
296 #define DET_REPORT_ERROR( _api, _err) Det_ReportError(MODULE_ID_NVM, 0, _api, _err);\r
297 #else\r
298 #define DET_REPORT_ERROR( _api, _err)\r
299 #endif\r
300 \r
301 #if  ( NVM_DEV_ERROR_DETECT == STD_ON )\r
302 #include "Det.h"\r
303 #define VALIDATE(_exp,_api,_err ) \\r
304         if( !(_exp) ) { \\r
305           Det_ReportError(MODULE_ID_NVM, 0, _api, _err); \\r
306         }\r
307 \r
308 \r
309 #define VALIDATE_RV(_exp,_api,_err,_rv ) \\r
310         if( !(_exp) ) { \\r
311           Det_ReportError(MODULE_ID_NVM, 0, _api, _err); \\r
312           return _rv; \\r
313         }\r
314 \r
315 #define VALIDATE_NO_RV(_exp,_api,_err ) \\r
316         if( !(_exp) ) { \\r
317           Det_ReportError(MODULE_ID_NVM, 0, _api, _err); \\r
318           return; \\r
319         }\r
320 #define DET_REPORTERROR(_module,_instance,_api,_err) Det_ReportError(_module,_instance,_api,_err)\r
321 \r
322 #else\r
323 #define VALIDATE(_exp,_api,_err )\r
324 #define VALIDATE_RV(_exp,_api,_err,_rv )\r
325 #define VALIDATE_NO_RV(_exp,_api,_err )\r
326 #define DET_REPORTERROR(_module,_instance,_api,_err)\r
327 #endif\r
328 \r
329 #define BLOCK_BASE_AND_SET_TO_BLOCKNR(_blockbase, _set) ((uint16)(_blockbase) | _set)\r
330 \r
331 #if defined(USE_DEM)\r
332 #define DEM_REPORTERRORSTATUS(_err,_ev ) Dem_ReportErrorStatus(_err, DEM_EVENT_STATUS_FAILED);\r
333 #else\r
334 #define DEM_REPORTERRORSTATUS(_err,_ev )\r
335 #endif\r
336 \r
337 \r
338 #define BLOCK_NR_FROM_PTR(_bptr)                (((_bptr) - NvM_Config.BlockDescriptor + 1))   // sizeof(NvM_BlockDescriptorType))\r
339 \r
340 #define CREATE_ENTRY(_val)      [_val] = #_val\r
341 \r
342 \r
343 \r
344 \r
345 /* ----------------------------[private typedef]-----------------------------*/\r
346 \r
347 // State variable\r
348 typedef enum {\r
349   NVM_UNINITIALIZED = 0,\r
350   NVM_IDLE,\r
351   NVM_READ_ALL,\r
352   NVM_WRITE_ALL,\r
353   NVM_READ_BLOCK,\r
354   NVM_WRITE_BLOCK,\r
355   NVM_RESTORE_BLOCK_DEFAULTS,\r
356   NVM_SETDATAINDEX,\r
357   NVM_GETDATAINDEX,\r
358   NVM_SETRAMBLOCKSTATUS,\r
359 } NvmStateType;\r
360 \r
361 char *StateToStr[20] = {\r
362         CREATE_ENTRY(NVM_UNINITIALIZED),\r
363         CREATE_ENTRY(NVM_IDLE),\r
364         CREATE_ENTRY(NVM_READ_ALL),\r
365         CREATE_ENTRY(NVM_WRITE_ALL),\r
366         CREATE_ENTRY(NVM_READ_BLOCK),\r
367         CREATE_ENTRY(NVM_WRITE_BLOCK),\r
368         CREATE_ENTRY(NVM_RESTORE_BLOCK_DEFAULTS),\r
369         CREATE_ENTRY(NVM_SETDATAINDEX),\r
370         CREATE_ENTRY(NVM_GETDATAINDEX),\r
371         CREATE_ENTRY(NVM_SETRAMBLOCKSTATUS),\r
372  };\r
373 \r
374 \r
375 typedef enum {\r
376         BLOCK_STATE_MEMIF_REQ,\r
377 //      BLOCK_STATE_START,\r
378         BLOCK_STATE_MEMIF_PROCESS,\r
379 //      BLOCK_STATE_MEMIF_CRC_PROCESS,\r
380         BLOCK_STATE_CALC_CRC,\r
381 //      BLOCK_STATE_MEMIF_PROCESS_CRC,\r
382         BLOCK_STATE_CALC_CRC_WRITE,\r
383         BLOCK_STATE_CALC_CRC_READ,\r
384 //      BLOCK_STATE_LOAD_FROM_NV,\r
385 } BlockStateType;\r
386 \r
387 \r
388 typedef enum {\r
389         BLOCK_SUBSTATE_0,\r
390         BLOCK_SUBSTATE_1,\r
391 } BlockSubStateType;\r
392 \r
393 \r
394 typedef enum {\r
395         NS_INIT = 0,\r
396         NS_PROSSING,\r
397 //      RB_PROCESSING,\r
398 } Nvm_SubStates;\r
399 \r
400 \r
401 union Nvm_CRC {\r
402         uint16 crc16;\r
403         uint32 crc32;\r
404 };\r
405 \r
406 \r
407 typedef struct {\r
408         NvM_RequestResultType   ErrorStatus;                    // Status from multi block requests i.e. Read/Write/CancelWrite-all\r
409 } AdministrativeMultiBlockType;\r
410 \r
411 typedef struct {\r
412         BlockStateType                  BlockState;\r
413         BlockSubStateType       BlockSubState;\r
414         uint8                                   DataIndex;                              // Selected data index if "Data Set" type\r
415         boolean                                 BlockWriteProtected;    // Block write protected?\r
416         NvM_RequestResultType   ErrorStatus;                    // Status of block\r
417         boolean                                 BlockChanged;                   // Block changed?\r
418         boolean                                 BlockValid;                             // Block valid? (RAM block only?)\r
419         uint8                                   NumberOfWriteFailed;    // Current write retry cycle\r
420         union Nvm_CRC                   RamCrc;\r
421         union Nvm_CRC                   NvCrc;                                  // The CRC of this block, read from NV\r
422         void *                                  savedDataPtr;                   //\r
423         uint8                                   crcLen;\r
424         uint8                                   flags;                                  // Used for all sorts of things.\r
425 } AdministrativeBlockType;\r
426 \r
427 /*\r
428 typedef enum {\r
429         NVM_OP_READ_BLOCK,\r
430         NVM_OP_WRITE_BLOCK,\r
431         NVM_OP_RESTORE_BLOCK_DEFAULTS,\r
432 } Nvm_OpType;\r
433 */\r
434 #define OP_READ         0\r
435 #define OP_WRITE        1\r
436 #define NO_MULTIBLOCK   0\r
437 #define MULTIBLOCK              1\r
438 \r
439 \r
440 typedef struct {\r
441         NvmStateType            op;\r
442         NvM_BlockIdType blockId;\r
443         uint8 *                 dataPtr;        /* Src or Dest ptr */\r
444         uint8           dataIndex;\r
445         boolean         blockChanged;\r
446         uint8       serviceId;\r
447 } Nvm_QueueType;\r
448 \r
449 \r
450 \r
451 /* ----------------------------[private function prototypes]-----------------*/\r
452 /* ----------------------------[private variables]---------------------------*/\r
453 \r
454 static NvmStateType                             nvmState = NVM_UNINITIALIZED;\r
455 \r
456 #define RB_START                        0\r
457 #define RB_WAIT_READ            1\r
458 #define RB_CALC_CHECKSUM        2\r
459 \r
460 static int                                                      nvmSubState = 0;\r
461 static uint8                                            serviceId = NVM_INIT_ID;\r
462 //static int nvmSetNr;\r
463 static AdministrativeBlockType          AdminBlock[NVM_NUM_OF_NVRAM_BLOCKS];\r
464 static AdministrativeMultiBlockType AdminMultiBlock;\r
465 \r
466 \r
467 //static Nvm_QueueType  nvmQueueImmData[NVM_SIZE_IMMEDIATE_JOB_QUEUE];\r
468 static Nvm_QueueType  nvmQueueData[NVM_SIZE_STANDARD_JOB_QUEUE];\r
469 \r
470 uint8 Nvm_WorkBuffer[NVM_MAX_BLOCK_LENGTH+4]; /* +4 to make place for max crc length */\r
471 \r
472 #if (NVM_SIZE_STANDARD_JOB_QUEUE == 0)\r
473 #error NVM_SIZE_STANDARD_JOB_QUEUE have size 0\r
474 #endif\r
475 \r
476 \r
477 CirqBufferType nvmQueue;\r
478 \r
479 \r
480 /* ----------------------------[private functions]---------------------------*/\r
481 \r
482 static void WriteBlock( const NvM_BlockDescriptorType *blockDescriptor,\r
483                                                 AdministrativeBlockType *adminBlock,\r
484                                                 uint8 setNumber,\r
485                                                 uint8 *sourceAddress);\r
486 \r
487 static void setRamBlockStatus( const NvM_BlockDescriptorType    *bPtr,\r
488                                                                 AdministrativeBlockType *admPtr,\r
489                                                                 boolean blockChanged );\r
490 \r
491 \r
492 /* ----------------------------[public functions]----------------------------*/\r
493 \r
494 \r
495 \r
496 /*\r
497  * This function needs to be implemented!
498  */\r
499 static void CalcCrc(void)\r
500 {\r
501         // TODO: Calculate CRC\r
502 }\r
503 \r
504 typedef struct {\r
505         boolean                                                 JobFinished;\r
506         Std_ReturnType                                  JobStatus;\r
507         MemIf_JobResultType                     JobResult;\r
508         const NvM_BlockDescriptorType * BlockDescriptor;\r
509         AdministrativeBlockType *               BlockAdmin;\r
510 } MemIfJobAdminType;\r
511 \r
512 static MemIfJobAdminType MemIfJobAdmin = {\r
513                 .JobFinished = TRUE,\r
514                 .JobStatus = E_OK,\r
515                 .JobResult = MEMIF_JOB_OK,\r
516                 .BlockDescriptor = NULL,\r
517                 .BlockAdmin = NULL\r
518 };\r
519 \r
520 enum Nvm_MultiBlockReq {\r
521         MB_REQ_NONE,\r
522         MB_REQ_READ_ALL,\r
523         MB_REQ_WRITE_ALL,\r
524 };\r
525 \r
526 typedef struct {\r
527         NvmStateType                    state;\r
528         uint16                                  currBlockIndex;         // Keeps track of next unfinished block\r
529         NvM_RequestResultType   PendingErrorStatus;     // Status from multi block requests i.e. Read/Write/CancelWrite-all\r
530         uint8                                   serviceId;\r
531 } AdminMultiReqType;\r
532 \r
533 static AdminMultiReqType AdminMultiReq;\r
534 \r
535 \r
536 /*\r
537  * Set the MemIf job as busy
538  */\r
539 static void SetMemifJobBusy()\r
540 {\r
541         MemIfJobAdmin.JobFinished = FALSE;\r
542 }\r
543 \r
544 \r
545 #if (NVM_POLLING_MODE == STD_ON)\r
546 /*\r
547  * Check if the MemIf job is finished
548  */\r
549 static boolean CheckMemIfJobFinished(void)\r
550 {\r
551         MemIf_JobResultType jobResult;\r
552 \r
553         if (!MemIfJobAdmin.JobFinished) {\r
554                 jobResult = MemIf_GetJobResult(FIXME);\r
555 \r
556                 if (jobResult == MEMIF_JOB_OK) {\r
557                         MemIfJobAdmin.JobFinished = TRUE;\r
558                         MemIfJobAdmin.JobStatus = E_OK;\r
559                         MemIfJobAdmin.JobResult = jobResult;\r
560                 } else if (jobResult != MEMIF_JOB_PENDING) {\r
561                         MemIfJobAdmin.JobFinished = TRUE;\r
562                         MemIfJobAdmin.JobStatus = E_NOT_OK;\r
563                         MemIfJobAdmin.JobResult = jobResult;\r
564                 }\r
565         }\r
566 \r
567         return MemIfJobAdmin.JobFinished;\r
568 }\r
569 #else\r
570 /*\r
571  * Check if the MemIf job is finished\r
572  */\r
573 \r
574 static boolean CheckMemIfJobFinished(void)\r
575 {\r
576         return MemIfJobAdmin.JobFinished;\r
577 }\r
578 \r
579 #endif\r
580 \r
581 \r
582 /*\r
583  * Abort the MemIf job with E_NOT_OK\r
584  */\r
585 static void AbortMemIfJob(MemIf_JobResultType jobResult)\r
586 {\r
587         MemIfJobAdmin.JobFinished = TRUE;\r
588         MemIfJobAdmin.JobStatus = E_NOT_OK;\r
589         MemIfJobAdmin.JobResult = jobResult;\r
590 }\r
591 \r
592 #if 0\r
593 static boolean CheckJobFailed( void ) {\r
594         return CheckMemIfJobFinished() && (MemIfJobAdmin.JobResult == MEMIF_JOB_FAILED);\r
595 }\r
596 #endif\r
597 \r
598 /*\r
599  * Initiate the read all job
600  */\r
601 static boolean ReadAllInit(void)\r
602 {\r
603         /*\r
604          * Initiate the read all job
605          */\r
606         const NvM_BlockDescriptorType   *BlockDescriptorList = NvM_Config.BlockDescriptor;\r
607         AdministrativeBlockType *AdminBlockTable = AdminBlock;\r
608         uint16 i;\r
609         boolean needsProcessing = FALSE;\r
610 \r
611         // Set status to pending in the administration blocks\r
612         AdminMultiBlock.ErrorStatus = NVM_REQ_PENDING; /** @req 3.1.5/NVM304 */\r
613         AdminMultiReq.PendingErrorStatus = NVM_REQ_OK;\r
614         AdminMultiReq.currBlockIndex = 0;\r
615 \r
616         for (i = 0; i < ( NVM_NUM_OF_NVRAM_BLOCKS ); i++) {\r
617                 if ((BlockDescriptorList->SelectBlockForReadall)\r
618 #if (NVM_SET_RAM_BLOCK_STATUS_API == STD_ON)                                            /** @req NVM345 */\r
619                                 && ((!AdminBlockTable->BlockValid)                      // TODO: Check if this is to be done like this\r
620                                 || (!AdminBlockTable->BlockChanged))            // TODO: Check if this is to be done like this\r
621 #endif\r
622                                 ) {\r
623                         NVM_ASSERT(BlockDescriptorList->RamBlockDataAddress != NULL);\r
624                         VALIDATE_RV(BlockDescriptorList->RamBlockDataAddress != NULL, NVM_READ_ALL_ID, NVM_E_WRONG_CONFIG, FALSE );\r
625                         /* 3.1.5/NVM245 */\r
626                         NVM_ASSERT(BlockDescriptorList->BlockManagementType != NVM_BLOCK_DATASET);\r
627                         VALIDATE_RV(BlockDescriptorList->BlockManagementType != NVM_BLOCK_DATASET, NVM_READ_ALL_ID, NVM_E_WRONG_CONFIG, FALSE );\r
628 \r
629                         AdminBlockTable->ErrorStatus = NVM_REQ_PENDING;\r
630                         AdminBlockTable->BlockState = BLOCK_STATE_MEMIF_REQ;\r
631                         needsProcessing = TRUE;\r
632                 } else {\r
633                         AdminBlockTable->ErrorStatus = NVM_REQ_BLOCK_SKIPPED;   /* @req 3.1.5/NVM287 */\r
634                 }\r
635 \r
636                 AdminBlockTable++;\r
637                 BlockDescriptorList++;\r
638         }\r
639 \r
640         return needsProcessing;\r
641 }\r
642 \r
643 \r
644 static void writeCrcToBuffer(   void *bufPtr,\r
645                                                                 const NvM_BlockDescriptorType *bPtr,\r
646                                                                 AdministrativeBlockType *admPtr )\r
647 {\r
648         if( bPtr->BlockUseCrc ) {\r
649                 if(bPtr->BlockCRCType == NVM_CRC16) {\r
650                         WRITE16_NA(bufPtr + bPtr->NvBlockLength,admPtr->RamCrc.crc16);\r
651                 } else {\r
652                         WRITE32_NA(bufPtr + bPtr->NvBlockLength,admPtr->RamCrc.crc32);\r
653                 }\r
654         }\r
655 }\r
656 \r
657 #define REDUNDANT_BLOCK_OK                              0\r
658 #define REDUNDANT_BLOCK_BOTH_FAIL               1\r
659 #define REDUNDANT_BLOCK_OK                              0\r
660 \r
661 \r
662 static boolean handleRedundantBlock(const NvM_BlockDescriptorType *bPtr,\r
663                                                                         AdministrativeBlockType *admPtr ) {\r
664         boolean cont = 0;\r
665         /* According to 3.1.5/NVM137 we have 2 NV Blocks and 0..1 ROM Blocks */\r
666         /* Req 3.1.5/NVM199 , 3.1.5/NVM279 , 3.1.5/NVM317\r
667          * 3.1.5/NVM288, 3.1.5/NVM315\r
668          * */\r
669 \r
670         if ( bPtr->BlockManagementType == NVM_BLOCK_REDUNDANT ) {\r
671                 if( admPtr->flags == 1 ) {\r
672                         NVM_ASSERT(bPtr->NvBlockNum == 2);              /* Configuration error */\r
673                         admPtr->DataIndex = ((admPtr->DataIndex) ? 0 : 1);\r
674                         admPtr->BlockState = BLOCK_STATE_MEMIF_REQ;\r
675                         DEBUG_PRINTF(" # First redundant NV block failed\n");\r
676                         cont = 1;\r
677                 } else {\r
678                         DEBUG_PRINTF(" # Both redundant NV blocks failed\n");\r
679                 }\r
680                 admPtr->flags++;\r
681         }\r
682         return cont;\r
683 }\r
684 \r
685 /*\r
686  * Drive the read state-machine\r
687  *\r
688  *\r
689  *\r
690  */\r
691 \r
692 static void DriveBlock( const NvM_BlockDescriptorType   *bPtr,\r
693                                                         AdministrativeBlockType *admPtr,\r
694                                                         void *dataPtr,\r
695                                                         boolean write,\r
696                                                         boolean multiBlock,\r
697                                                         boolean restoreFromRom )\r
698 {\r
699         bool blockDone = 0;\r
700 \r
701         DEBUG_BLOCK_STATE("DriveBlock", BLOCK_NR_FROM_PTR(bPtr), admPtr->BlockState );\r
702 \r
703         NVM_ASSERT( admPtr->ErrorStatus == NVM_REQ_PENDING);\r
704 \r
705         switch (admPtr->BlockState) {\r
706         case BLOCK_STATE_MEMIF_REQ:\r
707         {\r
708                 void *ramData = (dataPtr != NULL) ?  dataPtr : bPtr->RamBlockDataAddress;\r
709 \r
710                 admPtr->savedDataPtr = ramData;\r
711 \r
712                 if( write ) {\r
713                         if( multiBlock && (dataPtr!=NULL)) {\r
714                                 NVM_ASSERT(0);\r
715                         }\r
716                         /* Copy to work buffer */\r
717                         memcpy( Nvm_WorkBuffer, ramData, bPtr->NvBlockLength );\r
718                         /* Add the CRC to write */\r
719                         writeCrcToBuffer(Nvm_WorkBuffer, bPtr, admPtr );\r
720                         WriteBlock(bPtr, admPtr, admPtr->DataIndex, Nvm_WorkBuffer);\r
721                 } else {\r
722                         uint8 crcLen = 0;\r
723                         /* Read to workbuffer */\r
724                         if( bPtr->BlockUseCrc ) {\r
725                                 crcLen = (bPtr->BlockCRCType == NVM_CRC16) ? 2: 4;\r
726                         }\r
727 \r
728                         if( restoreFromRom ) {\r
729                                 NVM_ASSERT( bPtr->RomBlockDataAdress != NULL );\r
730                                 /* No CRC on the ROM block */\r
731                                 memcpy(ramData,bPtr->RomBlockDataAdress,bPtr->NvBlockLength);\r
732 \r
733                                 admPtr->ErrorStatus = NVM_REQ_OK;\r
734                                 blockDone = 1;\r
735                                 break;          /* Do NOT advance to next state */\r
736                         } else {\r
737                                 uint8 setNumber = admPtr->DataIndex;\r
738                                 uint16 length = bPtr->NvBlockLength+crcLen;\r
739                                 Std_ReturnType rv;\r
740                                 boolean fail = FALSE;\r
741 \r
742                                 /*\r
743                                  * Read the Block\r
744                                  */\r
745 \r
746                                 if (setNumber < bPtr->NvBlockNum) {\r
747                                         SetMemifJobBusy();\r
748                                         MemIfJobAdmin.BlockAdmin = admPtr;\r
749                                         MemIfJobAdmin.BlockDescriptor = bPtr;\r
750                                         imask_t state;\r
751 \r
752                                         /* First reading the MemIf block and then checking MemIf_GetStatus() to determine\r
753                                          * if the device BUSY in anyway...is not threadsafe. The way Autosar have defined\r
754                                          * it you would have to lock over the MemIf_Read() to be sure.\r
755                                          */\r
756                                         Irq_Save(state);\r
757 \r
758                                         /* We want to read from MemIf, but the device may be busy.\r
759                                          */\r
760                                         rv = MemIf_Read(bPtr->NvramDeviceId,\r
761                                                                                         BLOCK_BASE_AND_SET_TO_BLOCKNR(bPtr->NvBlockBaseNumber, setNumber),\r
762                                                                                         0,\r
763                                                                                         Nvm_WorkBuffer,\r
764                                                                                         length );\r
765                                         if (rv != E_OK) {\r
766                                                 if ( MemIf_GetStatus(FIXME) == MEMIF_IDLE ) {\r
767                                                         AbortMemIfJob(MEMIF_JOB_FAILED);\r
768                                                         fail = TRUE;\r
769                                                 } else {\r
770                                                         /* Do nothing. For MEMIF_UNINIT, MEMIF_BUSY and MEMIF_BUSY_INTERNAL we just stay in the\r
771                                                          * same state. Better in the next run */\r
772                                                         Irq_Restore(state);\r
773                                                         break; /* Do NOT advance to next state */\r
774                                                 }\r
775                                         }\r
776                                         Irq_Restore(state);\r
777 \r
778                                 } else if (setNumber < bPtr->NvBlockNum + bPtr->RomBlockNum) {\r
779                                         // TODO: Read from ROM\r
780                                 } else {\r
781                                         // Error: setNumber out of range\r
782                                         DET_REPORTERROR(MODULE_ID_NVM, 0, NVM_LOC_READ_BLOCK_ID, NVM_PARAM_OUT_OF_RANGE);\r
783                                         fail = TRUE;\r
784                                 }\r
785 \r
786                                 if( fail ) {\r
787                                         /* Fail the job */\r
788                                         admPtr->ErrorStatus = NVM_REQ_NOT_OK;\r
789                                         blockDone = 1;\r
790                                         break; /* Do NOT advance to next state */\r
791                                 }\r
792                         }\r
793                 }\r
794 \r
795                 admPtr->BlockState = BLOCK_STATE_MEMIF_PROCESS;\r
796                 break;\r
797         }\r
798 \r
799         case BLOCK_STATE_MEMIF_PROCESS:\r
800         {\r
801                 /* Check read */\r
802                 MemIf_JobResultType jobResult = MemIf_GetJobResult(FIXME);\r
803 \r
804                 if( MEMIF_JOB_PENDING == jobResult ) {\r
805                         /* Keep on waiting */\r
806                 } else if( MEMIF_JOB_OK == jobResult ) {\r
807                         /* We are done */\r
808                         if( write ) {\r
809                                 admPtr->BlockState = BLOCK_STATE_MEMIF_REQ;\r
810                                 admPtr->ErrorStatus = NVM_REQ_OK;\r
811                                 blockDone = 1;\r
812                         } else {\r
813                                 /* read */\r
814                                 uint8 crcLen = 0;\r
815                                 if( bPtr->BlockUseCrc ) {\r
816 \r
817                                         /* The read data is in the work buffer, read the CRC */\r
818                                         if( bPtr->BlockCRCType == NVM_CRC16) {\r
819                                                 admPtr->NvCrc.crc16 = READ16_NA( Nvm_WorkBuffer + bPtr->NvBlockLength );\r
820                                                 crcLen = 2;\r
821                                                 DEBUG_PRINTF(">> Nv CRC %04x\n",admPtr->NvCrc.crc16);\r
822                                                 admPtr->RamCrc.crc16 = admPtr->NvCrc.crc16;     /* Set RAM CRC = NvRAM CRC */\r
823                                         } else {\r
824                                                 admPtr->NvCrc.crc32 = READ32_NA( Nvm_WorkBuffer + bPtr->NvBlockLength );\r
825                                                 crcLen = 4;\r
826                                                 DEBUG_PRINTF(">> Nv CRC %08x\n",admPtr->NvCrc.crc16);\r
827                                                 admPtr->RamCrc.crc32 = admPtr->NvCrc.crc32;     /* Set RAM CRC = NvRAM CRC */\r
828                                         }\r
829 \r
830                                         /* 3.1.5/NVM201 + 3.1.5/NVM292 NvM_ReadBlock() + NvM_ReadAll() should request\r
831                                          * recalculation of the RAM block data if configured with CRC.\r
832                                          */\r
833 \r
834                                         /* savedDataPtr points to the real data buffers and they do no contain the\r
835                                          * crcLen */\r
836                                         memcpy(admPtr->savedDataPtr, Nvm_WorkBuffer, bPtr->NvBlockLength  );\r
837 \r
838                                         /* Check if we should re-calculate the RAM checksum now when it's in RAM\r
839                                          * 3.1.5/NVM165 */\r
840                                         if( bPtr->CalcRamBlockCrc ) {\r
841                                                 /* This block want its RAM block CRC checked */\r
842                                                 DEBUG_PRINTF(">> Recalculation of RAM checksum \n",admPtr->NvCrc.crc16);\r
843                                                 assert( bPtr->BlockUseCrc == 1);\r
844                                                 admPtr->BlockState = BLOCK_STATE_CALC_CRC_READ;\r
845                                                 admPtr->BlockSubState = BLOCK_SUBSTATE_0;\r
846                                                 admPtr->flags = 0;\r
847 \r
848                                         } else {\r
849                                                 /* Done */\r
850                                                 admPtr->BlockState = BLOCK_STATE_MEMIF_REQ;\r
851                                                 admPtr->ErrorStatus = NVM_REQ_OK;\r
852                                                 blockDone = 1;\r
853                                         }\r
854 \r
855                                 } else {\r
856                                         DEBUG_PRINTF(">> Block have NO CRC\n");\r
857 \r
858                                         memcpy(admPtr->savedDataPtr, Nvm_WorkBuffer, bPtr->NvBlockLength  + crcLen );\r
859                                         /* Done */\r
860                                         admPtr->BlockState = BLOCK_STATE_MEMIF_REQ;\r
861                                         admPtr->ErrorStatus = NVM_REQ_OK;\r
862                                         blockDone = 1;\r
863                                 }\r
864 \r
865                                 /* Copy from Workbuffer to the real buffer */\r
866 \r
867                         }\r
868                         break;\r
869                 } else {\r
870                         /* Something failed */\r
871                         DEBUG_PRINTF(">> Read/Write FAILED\n");\r
872                         if( write ) {\r
873                                 admPtr->NumberOfWriteFailed++;\r
874                                 if( admPtr->NumberOfWriteFailed > NVM_MAX_NUMBER_OF_WRITE_RETRIES ) {\r
875                                         DEBUG_PRINTF(">> Write FAILED COMPLETELY (all retries)\n");\r
876                                         blockDone = 1;\r
877                                         admPtr->NumberOfWriteFailed = 0;\r
878                                 }\r
879                         } else {\r
880                                 blockDone = 1;\r
881                         }\r
882 \r
883                         /*\r
884                          * MEMIF have failed. Now what?\r
885                          * 1. Check if redundant, if so read the other block\r
886                          * 2. If point 1 fails and not redundant nor rom-block/initcallback,\r
887                          *   fail with MEMIF_BLOCK_INVALID, MEMIF_BLOCK_INCONSISTENT or  MEMIF_JOB_FAILED\r
888                          */\r
889                         if( blockDone == 1 ) {\r
890                                 /* All write have failed or we are reading? */\r
891                                 if( 0 == handleRedundantBlock(bPtr,admPtr) ) {\r
892                                         /* block is NOT redundant or both blocks have failed */\r
893                                         if( bPtr->RomBlockDataAdress != NULL ) {\r
894                                                 DEBUG_PRINTF("Copying ROM data to block\n");\r
895                                                 memcpy(bPtr->RamBlockDataAddress, bPtr->RomBlockDataAdress,bPtr->NvBlockLength);\r
896                                                 admPtr->ErrorStatus = NVM_REQ_OK;\r
897                                         } else if( bPtr->InitBlockCallback != NULL ) {\r
898                                                 /* @req 3.1.5/NVM469 */\r
899                                                 DEBUG_PRINTF("Filling block with default data\n");\r
900                                                 bPtr->InitBlockCallback();\r
901                                                 admPtr->ErrorStatus = NVM_REQ_OK;\r
902                                         } else {\r
903 \r
904                                                 /*\r
905                                                  *\r
906                                                  * Returned status are:\r
907                                                  *\r
908                                                  * MEMIF_BLOCK_INVALID\r
909                                                  *   The block is currenlty under some strange service (Fee_InvalidateBlock)\r
910                                                  *\r
911                                                  * MEMIF_BLOCK_INCONSISTENT\r
912                                                  *   Ea/Fee have detected that something is strange with the block. This may\r
913                                                  *   happen for a virgin unit.\r
914                                                  *\r
915                                                  * MEMIF_JOB_FAILED\r
916                                                  *   We failed for some reason.\r
917                                                  *\r
918                                                  * At this point a lot of requirements NVM360, NVM342,etc will not be active\r
919                                                  * if there is a configured ROM block/InitCallback.\r
920                                                  */\r
921 \r
922                                                 admPtr->BlockState = BLOCK_STATE_MEMIF_REQ; /* TODO, this really true for all result below */\r
923                                                 AdminMultiReq.PendingErrorStatus = NVM_REQ_NOT_OK;\r
924 \r
925                                                 switch (jobResult) {\r
926                                                 case MEMIF_BLOCK_INVALID:\r
927                                                         /* @req 3.1.5/NVM342 */\r
928                                                         admPtr->ErrorStatus = NVM_REQ_NV_INVALIDATED;\r
929                                                         break;\r
930                                                 case MEMIF_BLOCK_INCONSISTENT:\r
931                                                         /* @req 3.1.5/NVM360 but is overridden by NVM172 (implicit revovery) */\r
932                                                         admPtr->ErrorStatus = NVM_REQ_INTEGRITY_FAILED;\r
933                                                         DEM_REPORTERRORSTATUS(NVM_E_REQ_INTEGRITY_FAILED,DEM_EVENT_STATUS_FAILED);\r
934                                                         break;\r
935                                                 case MEMIF_JOB_FAILED:\r
936                                                         /* @req 3.1.5/NVM361 */\r
937                                                         admPtr->ErrorStatus = NVM_REQ_NOT_OK;\r
938                                                         DEM_REPORTERRORSTATUS(NVM_E_REQ_FAILED,DEM_EVENT_STATUS_FAILED);\r
939                                                         break;\r
940                                                 default:\r
941                                                         DEBUG_PRINTF("## Unexpected jobResult:%d\n",jobResult);\r
942                                                         NVM_ASSERT(0);\r
943                                                         break;\r
944                                                 }\r
945                                         }\r
946                                 }\r
947 \r
948                         }\r
949                 }\r
950                 break;\r
951         }\r
952 \r
953         case BLOCK_STATE_CALC_CRC:\r
954                 NVM_ASSERT(0);\r
955                 break;\r
956 \r
957         case BLOCK_STATE_CALC_CRC_WRITE:\r
958         {\r
959                 uint16 crc16;\r
960                 uint32 crc32;\r
961                 void *ramData;\r
962 \r
963                 if( bPtr->RamBlockDataAddress == NULL ) {\r
964                         /* If we have no buffer to work with something is very very wrong */\r
965                         NVM_ASSERT(dataPtr != NULL );\r
966                         ramData = dataPtr;\r
967                 } else {\r
968                         ramData = bPtr->RamBlockDataAddress;\r
969                 }\r
970 \r
971                 admPtr->savedDataPtr = ramData;\r
972 \r
973                 /* Calculate RAM CRC checksum */\r
974                 if( bPtr->BlockCRCType == NVM_CRC16 ) {\r
975 \r
976                         crc16 = Crc_CalculateCRC16(ramData,bPtr->NvBlockLength,0xffff);\r
977                         DEBUG_CHECKSUM("RAM",crc16);\r
978 \r
979                         /* Just save the checksum */\r
980                         admPtr->RamCrc.crc16 = crc16;\r
981 \r
982                         /* Write the block */\r
983                         admPtr->BlockState = BLOCK_STATE_MEMIF_REQ;\r
984                 } else {\r
985                         /* @req 3.1.5/NVM253 */\r
986                         crc32 = Crc_CalculateCRC32(ramData,bPtr->NvBlockLength,0xffffffffUL);\r
987                         DEBUG_CHECKSUM("RAM",crc32);\r
988 \r
989                         admPtr->RamCrc.crc32 = crc32;\r
990                 }\r
991                 /* Write the block */\r
992                 admPtr->BlockState = BLOCK_STATE_MEMIF_REQ;\r
993 \r
994                 break;\r
995         }\r
996         case BLOCK_STATE_CALC_CRC_READ:\r
997         {\r
998                 //NVM_ASSERT(bPtr->RamBlockDataAddress != NULL );\r
999                 NVM_ASSERT(bPtr->CalcRamBlockCrc == true );\r
1000                 uint16 crc16;\r
1001                 uint32 crc32;\r
1002                 boolean checksumOk;\r
1003 \r
1004 \r
1005                 /* @req 3.1.5/NVM253 */\r
1006                 /* Calculate CRC on the data we just read to RAM. Compare with CRC that is located in NV block */\r
1007 \r
1008                 if( bPtr->BlockCRCType == NVM_CRC16 ) {\r
1009                         crc16 = Crc_CalculateCRC16(admPtr->savedDataPtr,bPtr->NvBlockLength,0xffff);\r
1010                 } else {\r
1011                         crc32 = Crc_CalculateCRC32(admPtr->savedDataPtr,bPtr->NvBlockLength,0xffffffffUL);\r
1012                 }\r
1013 \r
1014                 switch( admPtr->BlockSubState ) {\r
1015                 case BLOCK_SUBSTATE_0:\r
1016 \r
1017                         checksumOk = ( bPtr->BlockCRCType == NVM_CRC16 ) ? ( crc16 ==  admPtr->RamCrc.crc16 ) : ( crc32 ==  admPtr->RamCrc.crc32 );\r
1018 \r
1019                         /* @req 3.1.5/NVM387 */\r
1020                         if( checksumOk ) {\r
1021                                 admPtr->BlockState = BLOCK_STATE_MEMIF_REQ;\r
1022 \r
1023                                 DEBUG_CHECKSUM("RAM checksum ok with ", ( bPtr->BlockCRCType == NVM_CRC16 ) ? crc16 : crc32 );\r
1024                                 admPtr->ErrorStatus = NVM_REQ_OK;\r
1025                                 admPtr->BlockState = BLOCK_STATE_MEMIF_REQ;\r
1026                                 blockDone = 1;\r
1027 \r
1028                         } else {\r
1029                                 /* NVM387, NVM388\r
1030                                  * Corrupt CRC, what choices are there:\r
1031                                  * 1. Default data (=ROM) configured, just copy it.\r
1032                                  * 2. Data redundancy, get it.\r
1033                                  * 3. None of the above. Catastrophic failure. (NVM203)\r
1034                                  */\r
1035 \r
1036                                 if( 0 == handleRedundantBlock(bPtr,admPtr) ) {\r
1037                                         /* block is NOT redundant or both blocks have failed */\r
1038                                         if( bPtr->RomBlockDataAdress != NULL ) {\r
1039                                                 DEBUG_PRINTF("Copying ROM data to block\n");\r
1040                                                 memcpy(bPtr->RamBlockDataAddress, bPtr->RomBlockDataAdress,bPtr->NvBlockLength);\r
1041                                                 admPtr->BlockSubState = BLOCK_SUBSTATE_1;\r
1042                                         } else {\r
1043 \r
1044                                                 /* @req 3.1.5/NVM469 */\r
1045                                                 if( bPtr->InitBlockCallback != NULL ) {\r
1046 \r
1047                                                         DEBUG_PRINTF("Filling block with default data\n");\r
1048                                                         bPtr->InitBlockCallback();\r
1049                                                         admPtr->BlockSubState = BLOCK_SUBSTATE_1;\r
1050 \r
1051                                                         /* NVM085 is very vague here, but the says the application should be\r
1052                                                          * able distinguish between when the init-callback have been called\r
1053                                                          * or CRC is corrupt.\r
1054                                                          */\r
1055 \r
1056                                                         /* The RAM CRC is at this point not calculated...so we must do this\r
1057                                                          * .. so just stay in this state one more MainFunction.\r
1058                                                          * */\r
1059 \r
1060                                                 } else {\r
1061 \r
1062                                                         /* We have CRC mismatch -> FAIL */\r
1063                                                         DEBUG_PRINTF("### Block FAILED with NVM_REQ_INTEGRITY_FAILED\n");\r
1064 \r
1065 \r
1066                                                         /* @req 3.1.5/NVM203 */\r
1067                                                         DEM_REPORTERRORSTATUS(NVM_E_INTEGRITY_FAILED,DEM_EVENT_STATUS_FAILED);\r
1068                                                         /* @req 3.1.5/NVM204 */\r
1069                                                         admPtr->ErrorStatus = NVM_REQ_INTEGRITY_FAILED;\r
1070                                                         admPtr->BlockState = BLOCK_STATE_MEMIF_REQ;\r
1071                                                         blockDone = 1;\r
1072                                                 }\r
1073                                         }\r
1074                                 }\r
1075                         }\r
1076                         break;\r
1077                 case BLOCK_SUBSTATE_1:\r
1078                         /* The checksum is on the ROM data so just save it */\r
1079                         DEBUG_CHECKSUM("RAM checksum after ROM copy ", ( bPtr->BlockCRCType == NVM_CRC16 ) ? crc16 : crc32 );\r
1080 \r
1081                         if( bPtr->BlockCRCType == NVM_CRC16 ) {\r
1082                                 admPtr->RamCrc.crc16 = crc16;\r
1083                         } else  {\r
1084                                 admPtr->RamCrc.crc32 = crc32;\r
1085                         }\r
1086                         admPtr->BlockSubState = BLOCK_SUBSTATE_0;\r
1087                         admPtr->ErrorStatus = NVM_REQ_OK;\r
1088                         admPtr->BlockState = BLOCK_STATE_MEMIF_REQ;\r
1089                         blockDone = 1;\r
1090                         break;\r
1091                 default:\r
1092                         break;\r
1093                 }\r
1094 \r
1095                 break;\r
1096         }\r
1097         default:\r
1098                 NVM_ASSERT(0);\r
1099                 break;\r
1100         }\r
1101 \r
1102         if( blockDone  ) {\r
1103 \r
1104                 DEBUG_PRINTF("# Block Done\n");\r
1105 \r
1106                 if( admPtr->ErrorStatus == NVM_REQ_OK ) {\r
1107                         admPtr->BlockChanged = FALSE;\r
1108                         admPtr->BlockValid = TRUE;\r
1109                 }\r
1110 \r
1111 \r
1112                 /*  @req 3.1.5/NVM281 */\r
1113                 if( bPtr->SingleBlockCallback != NULL ) {\r
1114                         bPtr->SingleBlockCallback(serviceId, admPtr->ErrorStatus);\r
1115                 }\r
1116 \r
1117                 if( multiBlock ) {\r
1118                         AdminMultiReq.currBlockIndex++;\r
1119                         if( AdminMultiReq.currBlockIndex >= NVM_NUM_OF_NVRAM_BLOCKS ) {\r
1120                                 AdminMultiReq.currBlockIndex = 0;\r
1121 \r
1122                                 /* @req 3.1.5/NVM301 */\r
1123                                 if( NVM_REQ_NOT_OK == AdminMultiReq.PendingErrorStatus ) {\r
1124                                         AdminMultiBlock.ErrorStatus = NVM_REQ_NOT_OK;\r
1125                                 } else {\r
1126                                         AdminMultiBlock.ErrorStatus = NVM_REQ_OK;\r
1127                                 }\r
1128                                 nvmState = NVM_IDLE;\r
1129                                 nvmSubState = 0;\r
1130 \r
1131                                 /*  @req 3.1.5/NVM468 */\r
1132                                 if( NvM_Config.Common.MultiBlockCallback != NULL ) {\r
1133                                         NvM_Config.Common.MultiBlockCallback(serviceId, AdminMultiBlock.ErrorStatus);\r
1134                                 }\r
1135                         }\r
1136                 } else {\r
1137                         nvmState = NVM_IDLE;\r
1138                         nvmSubState = 0;\r
1139 \r
1140                 }\r
1141         }\r
1142 }\r
1143 \r
1144 /*\r
1145  * Main function for the read all job
1146  */\r
1147 static void ReadAllMain(void)\r
1148 {\r
1149 \r
1150         /* Cases:\r
1151          * 1. We process each block until it's finished\r
1152          * 2. We start to process a lot of blocks. The blocks may use different devices\r
1153          *    and should be able to read a lot of them. This includes CRC.\r
1154          *\r
1155          *    1) is much simpler and 2) probably much faster.\r
1156          *    This implementation will use 1) since it's simpler and maximum time that is\r
1157          *    spent in MainFunction() can be controlled much better.\r
1158          */\r
1159 \r
1160         /* Skip blocks that are skipped */\r
1161         while ( (AdminMultiReq.currBlockIndex < NVM_NUM_OF_NVRAM_BLOCKS) ) {\r
1162 \r
1163                 if( AdminBlock[AdminMultiReq.currBlockIndex].ErrorStatus != NVM_REQ_BLOCK_SKIPPED) {\r
1164                         DriveBlock(     &NvM_Config.BlockDescriptor[AdminMultiReq.currBlockIndex],\r
1165                                                         &AdminBlock[AdminMultiReq.currBlockIndex],\r
1166                                                         NULL,\r
1167                                                         false,\r
1168                                                         true, false);\r
1169                         break;\r
1170                 }\r
1171                 AdminMultiReq.currBlockIndex++;\r
1172         }\r
1173 }\r
1174 \r
1175 /*\r
1176  * Request writing of a block to MemIf
1177  */\r
1178 static void WriteBlock( const NvM_BlockDescriptorType *blockDescriptor,\r
1179                                                 AdministrativeBlockType *adminBlock,\r
1180                                                 uint8 setNumber,\r
1181                                                 uint8 *sourceAddress)\r
1182 {\r
1183         Std_ReturnType returnCode;\r
1184 \r
1185         if (setNumber < blockDescriptor->NvBlockNum) {\r
1186                 SetMemifJobBusy();\r
1187                 MemIfJobAdmin.BlockAdmin = adminBlock;\r
1188                 MemIfJobAdmin.BlockDescriptor = blockDescriptor;\r
1189                 returnCode = MemIf_Write(blockDescriptor->NvramDeviceId, BLOCK_BASE_AND_SET_TO_BLOCKNR(blockDescriptor->NvBlockBaseNumber, setNumber), sourceAddress);\r
1190                 if (returnCode != E_OK) {\r
1191                         AbortMemIfJob(MEMIF_JOB_FAILED);\r
1192                 }\r
1193         } else {\r
1194                 // Error: setNumber out of range\r
1195                 DET_REPORTERROR(MODULE_ID_NVM, 0, NVM_LOC_WRITE_BLOCK_ID, NVM_PARAM_OUT_OF_RANGE);\r
1196         }\r
1197 }\r
1198 \r
1199 \r
1200 \r
1201 /*\r
1202  * Initiate the write all job\r
1203  */\r
1204 static boolean WriteAllInit(void)\r
1205 {\r
1206         const NvM_BlockDescriptorType   *BlockDescriptorList = NvM_Config.BlockDescriptor;\r
1207         AdministrativeBlockType *AdminBlockTable = AdminBlock;\r
1208         uint16 i;\r
1209         boolean needsProcessing = FALSE;\r
1210 \r
1211 //      nvmState = NVM_WRITE_ALL_PROCESSING;\r
1212         AdminMultiReq.PendingErrorStatus = NVM_REQ_OK;\r
1213         AdminMultiReq.currBlockIndex = 0;\r
1214 \r
1215         for (i = 0; i < NVM_NUM_OF_NVRAM_BLOCKS; i++) {\r
1216                 if ((BlockDescriptorList->RamBlockDataAddress != NULL)\r
1217 #if (NVM_SET_RAM_BLOCK_STATUS_API == STD_ON)                                            /** @req NVM344 */\r
1218                                 && (AdminBlockTable->BlockValid)                                        /** @req NVM682 */\r
1219                                 && (AdminBlockTable->BlockChanged)                                      /** @req NVM682 */\r
1220 #endif\r
1221                                 && (!AdminBlockTable->BlockWriteProtected))                     /** @req NVM432 *//** @req NVM433 */\r
1222                 {\r
1223                         AdminBlockTable->ErrorStatus = NVM_REQ_PENDING;\r
1224 \r
1225                         if (BlockDescriptorList->BlockUseCrc) {\r
1226                                 AdminBlockTable->BlockState = BLOCK_STATE_CALC_CRC_WRITE;       /** @req NVM253 */\r
1227                         } else {\r
1228                                 AdminBlockTable->BlockState = BLOCK_STATE_MEMIF_REQ;\r
1229                                 AdminBlockTable->NumberOfWriteFailed = 0;\r
1230                         }\r
1231                         needsProcessing = TRUE;\r
1232                 } else {\r
1233                         AdminBlockTable->ErrorStatus = NVM_REQ_BLOCK_SKIPPED;   /** @req NVM298 */\r
1234                 }\r
1235 \r
1236                 AdminBlockTable++;\r
1237                 BlockDescriptorList++;\r
1238         }\r
1239         return needsProcessing;\r
1240 }\r
1241 \r
1242 \r
1243 \r
1244 /*\r
1245  * Main function for the write all job\r
1246  */\r
1247 static void WriteAllMain(void)\r
1248 {\r
1249         while ( (AdminMultiReq.currBlockIndex < NVM_NUM_OF_NVRAM_BLOCKS) ) {\r
1250 \r
1251                 if( AdminBlock[AdminMultiReq.currBlockIndex].ErrorStatus != NVM_REQ_BLOCK_SKIPPED) {\r
1252                         DriveBlock(     &NvM_Config.BlockDescriptor[AdminMultiReq.currBlockIndex],\r
1253                                                         &AdminBlock[AdminMultiReq.currBlockIndex],\r
1254                                                         NULL,\r
1255                                                         true,\r
1256                                                         true, false );\r
1257                         break;\r
1258                 }\r
1259                 AdminMultiReq.currBlockIndex++;\r
1260         }\r
1261 }\r
1262 \r
1263 \r
1264 #if 0\r
1265 /*\r
1266  * Handles the result of one MemIf block write\r
1267  */\r
1268 static void WriteAllCheckWriteResult(void)\r
1269 {\r
1270         if (MemIfJobAdmin.JobStatus == E_OK) {\r
1271                 // TODO: Check if redundant block shall be written NVM337\r
1272 \r
1273                 if (MemIfJobAdmin.BlockDescriptor->WriteBlockOnce) {\r
1274                         MemIfJobAdmin.BlockAdmin->BlockWriteProtected = TRUE;   /** @req NVM329 */\r
1275                 }\r
1276                 MemIfJobAdmin.BlockAdmin->BlockState = BLOCK_STATE_MEMIF_REQ;\r
1277                 MemIfJobAdmin.BlockAdmin->ErrorStatus = NVM_REQ_OK;\r
1278 \r
1279                 if (MemIfJobAdmin.BlockDescriptor->SingleBlockCallback != NULL) {\r
1280                         (void)MemIfJobAdmin.BlockDescriptor->SingleBlockCallback(NVM_SERVICE_ID, MemIfJobAdmin.BlockAdmin->ErrorStatus);\r
1281                 }\r
1282         } else {\r
1283                 MemIfJobAdmin.BlockAdmin->NumberOfWriteFailed++;\r
1284                 if (MemIfJobAdmin.BlockAdmin->NumberOfWriteFailed > NVM_MAX_NUMBER_OF_WRITE_RETRIES) {\r
1285                         // TODO: Check if redundant block shall be written NVM337\r
1286 \r
1287                         // Write has failed\r
1288                         AdminMultiReq.PendingErrorStatus = NVM_REQ_NOT_OK;\r
1289 \r
1290                         MemIfJobAdmin.BlockAdmin->BlockState = BLOCK_STATE_MEMIF_REQ;\r
1291                         MemIfJobAdmin.BlockAdmin->ErrorStatus = NVM_REQ_NOT_OK; /** @req NVM296 */\r
1292 #if defined(USE_DEM)\r
1293                         Dem_ReportErrorStatus(NVM_E_REQ_FAILED,DEM_EVENT_STATUS_FAILED);\r
1294 #endif\r
1295 \r
1296                         if (MemIfJobAdmin.BlockDescriptor->SingleBlockCallback != NULL) {\r
1297                                 (void)MemIfJobAdmin.BlockDescriptor->SingleBlockCallback(NVM_SERVICE_ID, MemIfJobAdmin.BlockAdmin->ErrorStatus);\r
1298                         }\r
1299                 }\r
1300         }\r
1301         nvmState = NVM_WRITE_ALL_PROCESSING;\r
1302 }\r
1303 #endif\r
1304 \r
1305 \r
1306 \r
1307 /***************************************\r
1308  *    External accessible functions    *\r
1309  ***************************************/\r
1310 /*\r
1311  * Procedure:   NvM_Init\r
1312  * Reentrant:   No\r
1313  */\r
1314 void NvM_Init(void)\r
1315 {\r
1316         /** @req NVM399 *//** @req NVM193 */\r
1317         const NvM_BlockDescriptorType   *BlockDescriptorList = NvM_Config.BlockDescriptor;\r
1318         AdministrativeBlockType *AdminBlockTable = AdminBlock;\r
1319         uint16 i;\r
1320 \r
1321 \r
1322         CirqBuff_Init(&nvmQueue,nvmQueueData,sizeof(nvmQueueData)/sizeof(Nvm_QueueType),sizeof(Nvm_QueueType));\r
1323 \r
1324         // Initiate the administration blocks\r
1325         for (i = 0; i< NVM_NUM_OF_NVRAM_BLOCKS; i++) {\r
1326                 if (BlockDescriptorList->BlockManagementType == NVM_BLOCK_DATASET) {\r
1327                         AdminBlockTable->DataIndex = 0; /** @req NVM192 */\r
1328                 }\r
1329                 AdminBlockTable->BlockWriteProtected = BlockDescriptorList->BlockWriteProt;\r
1330                 AdminBlockTable->ErrorStatus = NVM_REQ_NOT_OK;\r
1331                 AdminBlockTable->BlockChanged = FALSE;\r
1332                 AdminBlockTable->BlockValid = FALSE;\r
1333                 AdminBlockTable->NumberOfWriteFailed = 0;\r
1334 \r
1335                 AdminBlockTable++;\r
1336                 BlockDescriptorList++;\r
1337         }\r
1338 \r
1339         AdminMultiBlock.ErrorStatus = NVM_REQ_NOT_OK;\r
1340 \r
1341         // Set status to initialized\r
1342         nvmState = NVM_IDLE;    /** @req 3.1.5/NVM399 */\r
1343 }\r
1344 \r
1345 \r
1346 /**\r
1347  *\r
1348  * Note!\r
1349  *   NvM_ReadAll() does not set status here or need to check status of the\r
1350  *   any blocks since it's done after all single reads are done.\r
1351  */\r
1352 void NvM_ReadAll(void)\r
1353 {\r
1354     imask_t state;\r
1355         VALIDATE_NO_RV(nvmState != NVM_UNINITIALIZED, NVM_READ_ALL_ID, NVM_E_NOT_INITIALIZED);\r
1356 \r
1357         NVM_ASSERT(nvmState == NVM_IDLE);\r
1358 \r
1359         Irq_Save(state);\r
1360         AdminMultiReq.state = NVM_READ_ALL;\r
1361         AdminMultiBlock.ErrorStatus = NVM_REQ_PENDING;\r
1362         AdminMultiReq.serviceId = NVM_READ_ALL_ID;\r
1363         Irq_Restore(state);\r
1364 }\r
1365 \r
1366 \r
1367 \r
1368 /*\r
1369  * Procedure:   NvM_WriteAll\r
1370  * Reentrant:   No\r
1371  */\r
1372 void NvM_WriteAll(void)\r
1373 {\r
1374     imask_t state;\r
1375         VALIDATE_NO_RV(nvmState != NVM_UNINITIALIZED, NVM_READ_ALL_ID, NVM_E_NOT_INITIALIZED);\r
1376 \r
1377         NVM_ASSERT(nvmState == NVM_IDLE);\r
1378 \r
1379         Irq_Save(state);\r
1380         AdminMultiReq.state = NVM_WRITE_ALL;\r
1381         AdminMultiBlock.ErrorStatus = NVM_REQ_PENDING;\r
1382         AdminMultiReq.serviceId = NVM_WRITE_ALL_ID;\r
1383         Irq_Restore(state);\r
1384 }\r
1385 \r
1386 \r
1387 /*\r
1388  * Procedure:   NvM_CancelWriteAll\r
1389  * Reentrant:   No\r
1390  */\r
1391 void NvM_CancelWriteAll(void)\r
1392 {\r
1393         \r
1394 }\r
1395 \r
1396 \r
1397 /*\r
1398  * Procedure:   NvM_GetErrorStatus\r
1399  * Reentrant:   Yes\r
1400  */\r
1401 Std_ReturnType NvM_GetErrorStatus(NvM_BlockIdType blockId, NvM_RequestResultType *requestResultPtr)\r
1402 {\r
1403         VALIDATE_RV(nvmState != NVM_UNINITIALIZED, NVM_GET_ERROR_STATUS_ID, NVM_E_NOT_INITIALIZED, E_NOT_OK );\r
1404         VALIDATE_RV(blockId < NVM_NUM_OF_NVRAM_BLOCKS+1, NVM_GET_ERROR_STATUS_ID, NVM_E_PARAM_BLOCK_ID, E_NOT_OK );\r
1405 \r
1406         if (blockId == 0) {\r
1407                 // Multiblock ID\r
1408                 *requestResultPtr = AdminMultiBlock.ErrorStatus;\r
1409         } else if (blockId == 1) {\r
1410                 /* TODO Configuration ID */\r
1411           *requestResultPtr = NVM_REQ_OK;\r
1412         } else {\r
1413                 *requestResultPtr = AdminBlock[blockId-1].ErrorStatus;\r
1414         }\r
1415         return E_OK;\r
1416 }\r
1417 \r
1418 \r
1419 #if (NVM_SET_RAM_BLOCK_STATUS_API == STD_ON)    /** @req NVM408 */\r
1420 /*\r
1421  * Procedure:   Nvm_SetRamBlockStatus\r
1422  * Reentrant:   Yes\r
1423  */\r
1424 Std_ReturnType NvM_SetRamBlockStatus(NvM_BlockIdType blockId, boolean blockChanged)\r
1425 {\r
1426         AdministrativeBlockType *               admPtr;\r
1427         Nvm_QueueType qEntry;\r
1428         int rv;\r
1429 \r
1430         VALIDATE_RV(blockId < NVM_NUM_OF_NVRAM_BLOCKS+1, NVM_SET_RAM_BLOCK_STATUS_ID, NVM_E_PARAM_BLOCK_ID, E_NOT_OK);\r
1431 \r
1432         admPtr = &AdminBlock[blockId-1];\r
1433 \r
1434         VALIDATE_RV(nvmState != NVM_UNINITIALIZED, NVM_SET_RAM_BLOCK_STATUS_ID, NVM_E_NOT_INITIALIZED, E_NOT_OK);       /** @req NVM497 */\r
1435         VALIDATE_RV(blockId > 1, NVM_SET_RAM_BLOCK_STATUS_ID, NVM_E_PARAM_BLOCK_ID, E_NOT_OK );\r
1436         VALIDATE_RV( (admPtr->ErrorStatus != NVM_REQ_PENDING), 0, NVM_E_BLOCK_PENDING , E_NOT_OK );\r
1437 \r
1438         qEntry.blockId = blockId;\r
1439         qEntry.op = NVM_SETRAMBLOCKSTATUS;\r
1440         qEntry.blockChanged = blockChanged;\r
1441         qEntry.serviceId = NVM_SET_RAM_BLOCK_STATUS_ID;\r
1442         rv = CirqBuffPush(&nvmQueue,&qEntry);\r
1443         NVM_ASSERT(rv == 0 );\r
1444 \r
1445         /* req 3.1.5/NVM185 */\r
1446         admPtr->ErrorStatus = NVM_REQ_PENDING;\r
1447 \r
1448         return E_OK;\r
1449 }\r
1450 #endif\r
1451 \r
1452 static void setRamBlockStatus( const NvM_BlockDescriptorType    *bPtr, AdministrativeBlockType *admPtr, boolean blockChanged ) {\r
1453 \r
1454         if (bPtr->RamBlockDataAddress != NULL) {        /** @req NVM240 */\r
1455                 if (blockChanged) {\r
1456                         admPtr->BlockChanged = TRUE;    /** @req NVM406 */\r
1457                         admPtr->BlockValid = TRUE;      /** @req NVM241 */\r
1458 //      TODO?   if (bPtr->BlockUseCrc) {\r
1459 //                              admPtr->BlockState = BLOCK_STATE_CALC_CRC;      /** @req NVM121 */\r
1460 //                      }\r
1461                 } else {\r
1462                         admPtr->BlockChanged = FALSE;   /** @req NVM405 */\r
1463                         admPtr->BlockValid = FALSE;\r
1464                 } // else blockChanged\r
1465         } // if permanent block\r
1466 }\r
1467 \r
1468 void NvM_SetBlockLockStatus( NvM_BlockIdType blockId, boolean blockLocked ) {\r
1469         (void)blockId;\r
1470         (void)blockLocked;\r
1471 }\r
1472 \r
1473 \r
1474 /**\r
1475  * Restore default data to its corresponding RAM block.\r
1476  *
1477  * @param BlockId               NVRAM block identifier.
1478  * @param NvM_DestPtr   Pointer to the RAM block
1479  * @return
1480  */\r
1481 Std_ReturnType NvM_RestoreBlockDefaults( NvM_BlockIdType blockId, uint8* NvM_DestPtr )\r
1482 {\r
1483         /* !req 3.1.5/NVM012 */ /* !req 3.1.5/NVM267 */ /* !req 3.1.5/NVM266 */\r
1484         /* !req 3.1.5/NVM353 */ /* !req 3.1.5/NVM435 */ /* !req 3.1.5/NVM436 */ /* !req 3.1.5/NVM227 */\r
1485         /* !req 3.1.5/NVM228 */ /* !req 3.1.5/NVM229 */ /* !req 3.1.5/NVM413 */\r
1486 \r
1487         const NvM_BlockDescriptorType * bPtr;\r
1488         AdministrativeBlockType *               admPtr;\r
1489         Nvm_QueueType qEntry;\r
1490         int rv;\r
1491 \r
1492         NVM_ASSERT( blockId >= 2 );     /* No support for lower numbers, yet */\r
1493 \r
1494         /* @req 3.1.5/NVM618 */\r
1495         VALIDATE_RV(    blockId <= NVM_NUM_OF_NVRAM_BLOCKS,\r
1496                                         NVM_WRITE_BLOCK_ID,NVM_E_PARAM_BLOCK_ID,E_NOT_OK );\r
1497 \r
1498         bPtr = &NvM_Config.BlockDescriptor[blockId-1];\r
1499         admPtr = &AdminBlock[blockId-1];\r
1500 \r
1501         /** @req 3.1.5/NVM196 */ /** @req 3.1.5/NVM278 */ /** @req 3.1.5/NVM210 */\r
1502         /* It must be a permanent RAM block but no RamBlockDataAddress -> error */\r
1503         VALIDATE_RV( !((NvM_DestPtr == NULL) &&  ( bPtr->RamBlockDataAddress == NULL )),\r
1504                                                 NVM_WRITE_BLOCK_ID,NVM_E_PARAM_BLOCK_ID,E_NOT_OK );\r
1505 \r
1506         VALIDATE_RV( (admPtr->ErrorStatus != NVM_REQ_PENDING), 0, NVM_E_BLOCK_PENDING , E_NOT_OK );\r
1507 \r
1508         /* @req 3.1.5/NVM195 */\r
1509         qEntry.blockId = blockId;\r
1510         qEntry.op = NVM_RESTORE_BLOCK_DEFAULTS;\r
1511         qEntry.blockId = blockId;\r
1512         qEntry.dataPtr = (uint8_t *)NvM_DestPtr;\r
1513         qEntry.serviceId = NVM_RESTORE_BLOCK_DEFAULTS_ID;\r
1514         rv = CirqBuffPush(&nvmQueue,&qEntry);\r
1515         NVM_ASSERT(rv == 0 );\r
1516 \r
1517         /* req 3.1.5/NVM185 */\r
1518         admPtr->ErrorStatus = NVM_REQ_PENDING;\r
1519 \r
1520         if( bPtr->BlockUseCrc) {\r
1521                 admPtr->BlockState = BLOCK_STATE_CALC_CRC_WRITE;\r
1522         } else {\r
1523                 admPtr->BlockState = BLOCK_STATE_MEMIF_REQ;\r
1524         }\r
1525 \r
1526 \r
1527         return E_OK;\r
1528 }\r
1529 \r
1530 /**\r
1531  * Service to copy the data NV block to the RAM block\r
1532  *
1533  * @param blockId               0 and 1 reserved. The block ID are sequential.
1534  * @param NvM_DstPtr
1535  * @return
1536  */\r
1537 \r
1538 \r
1539 Std_ReturnType NvM_ReadBlock( NvM_BlockIdType blockId, uint8* NvM_DstPtr )\r
1540 {\r
1541         /* !req 3.1.5/NVM010 */\r
1542 \r
1543 \r
1544         /* !req 3.1.5/NVM278 */\r
1545         /* !req 3.1.5/NVM340 */\r
1546         /* !req 3.1.5/NVM354 */\r
1547         /* !req 3.1.5/NVM200 */\r
1548         /* !req 3.1.5/NVM366 */\r
1549         /* !req 3.1.5/NVM206 */\r
1550         /* !req 3.1.5/NVM341 */\r
1551         /* !req 3.1.5/NVM358 */\r
1552         /* !req 3.1.5/NVM359 */\r
1553         /* !req 3.1.5/NVM279 */\r
1554         /* !req 3.1.5/NVM316 */\r
1555         /* !req 3.1.5/NVM317 */\r
1556         /* !req 3.1.5/NVM201 */\r
1557         /* !req 3.1.5/NVM202 */\r
1558         /* !req 3.1.5/NVM203 */\r
1559         /* !req 3.1.5/NVM204 */\r
1560         /* !req 3.1.5/NVM409 */\r
1561 \r
1562 \r
1563    /* logical block:\r
1564     *\r
1565     *    1 1 1 1 1 1\r
1566     *   |5 4 3 2 1 0 9 8|7 6 5 4 3 2 1 0|\r
1567     *    b b b b b b b b b b d d d d d d\r
1568     *\r
1569     * Here we have 10 bits for block id, 16-5 for DataSetSelection bits.\r
1570     * - 2^10, 1024 blocks\r
1571     * - 64 datasets for each NVRAM block\r
1572     *\r
1573     * How are the block numbers done in EA? Assume virtual page=8\r
1574     * logical\r
1575     *  Block   size\r
1576     *  1       32\r
1577     *   2\r
1578     *   3\r
1579     *   4\r
1580     *  5       12\r
1581     *   6\r
1582     *  7\r
1583     *\r
1584     *  How can NVM/NvmNvBlockLength and EA/EaBlockSize be different?\r
1585     *  It seems that EA/FEE does not care about that logical block 2 above is\r
1586     *  "blocked"\r
1587     *
1588     */\r
1589         Nvm_QueueType qEntry;\r
1590         int rv;\r
1591 \r
1592         /** @req 3.1.5/NVM196 */ /** @req 3.1.5/NVM278 */\r
1593     VALIDATE_RV( !(( NvM_DstPtr == NULL) &&\r
1594                         ( NvM_Config.BlockDescriptor[blockId-1].RamBlockDataAddress == NULL )),\r
1595                         0, NVM_E_PARAM_ADDRESS  , E_NOT_OK );\r
1596         VALIDATE_RV( (AdminBlock[blockId-1].ErrorStatus != NVM_REQ_PENDING), 0, NVM_E_BLOCK_PENDING , E_NOT_OK );\r
1597 \r
1598         /* @req 3.1.5/NVM195 */\r
1599         qEntry.blockId = blockId;\r
1600         qEntry.op = NVM_READ_BLOCK;\r
1601         qEntry.blockId = blockId;\r
1602         qEntry.dataPtr = NvM_DstPtr;\r
1603         qEntry.serviceId = NVM_READ_BLOCK_ID;\r
1604         rv = CirqBuffPush(&nvmQueue,&qEntry);\r
1605         NVM_ASSERT(rv == 0 );\r
1606 \r
1607 \r
1608         /* req 3.1.5/NVM185 */\r
1609         AdminBlock[blockId-1].ErrorStatus = NVM_REQ_PENDING;\r
1610 \r
1611         return E_OK;\r
1612 }\r
1613 \r
1614 \r
1615 /**\r
1616  * Service to copy a RAM block to its correspnding NVRAM block\r
1617  *
1618  * @param blockId
1619  * @param NvM_SrcPtr
1620  * @return
1621  */\r
1622 Std_ReturnType NvM_WriteBlock( NvM_BlockIdType blockId, const uint8* NvM_SrcPtr ) {\r
1623 \r
1624         const NvM_BlockDescriptorType * bPtr;\r
1625         AdministrativeBlockType *               admPtr;\r
1626         Nvm_QueueType qEntry;\r
1627         int rv;\r
1628 \r
1629         NVM_ASSERT( blockId >= 2 );     /* No support for lower numbers, yet */\r
1630 \r
1631         /* @req 3.1.5/NVM618 */\r
1632         VALIDATE_RV(    blockId <= NVM_NUM_OF_NVRAM_BLOCKS,\r
1633                                         NVM_WRITE_BLOCK_ID,NVM_E_PARAM_BLOCK_ID,E_NOT_OK );\r
1634 \r
1635         bPtr = &NvM_Config.BlockDescriptor[blockId-1];\r
1636         admPtr = &AdminBlock[blockId-1];\r
1637 \r
1638         /** @req 3.1.5/NVM196 */ /** @req 3.1.5/NVM278 */\r
1639         VALIDATE_RV( !((NvM_SrcPtr == NULL) && ( bPtr->RamBlockDataAddress == NULL )),\r
1640                                 0, NVM_E_PARAM_ADDRESS, E_NOT_OK );\r
1641         VALIDATE_RV( (admPtr->ErrorStatus != NVM_REQ_PENDING), 0, NVM_E_BLOCK_PENDING , E_NOT_OK );\r
1642 \r
1643         /* @req 3.1.5/NVM195 */\r
1644         qEntry.blockId = blockId;\r
1645         qEntry.op = NVM_WRITE_BLOCK;\r
1646         qEntry.blockId = blockId;\r
1647         qEntry.dataPtr = (uint8_t *)NvM_SrcPtr;\r
1648         qEntry.serviceId = NVM_WRITE_BLOCK_ID;\r
1649         rv = CirqBuffPush(&nvmQueue,&qEntry);\r
1650         NVM_ASSERT(rv == 0 );\r
1651 \r
1652         /* req 3.1.5/NVM185 */\r
1653         admPtr->ErrorStatus = NVM_REQ_PENDING;\r
1654 \r
1655         if( bPtr->BlockUseCrc) {\r
1656                 admPtr->BlockState = BLOCK_STATE_CALC_CRC_WRITE;\r
1657         } else {\r
1658                 admPtr->BlockState = BLOCK_STATE_MEMIF_REQ;\r
1659         }\r
1660 \r
1661 \r
1662         return E_OK;\r
1663 }\r
1664 \r
1665 /* Missing from Class 2\r
1666  * - NvM_CancelWriteAll\r
1667  * */\r
1668 \r
1669 //#if (NVM_API_CONFIG_CLASS > NVM_API_CONFIG_CLASS_1)\r
1670 \r
1671 /*\r
1672  * Note!\r
1673  * This function returns void in 3.1.5 and in 4.0 it returns Std_ReturnType.\r
1674  *\r
1675  *\r
1676  * return\r
1677  *   x NVM_E_NOT_INITIALIZED\r
1678  *   x NVM_E_BLOCK_PENDING\r
1679  *   NVM_E_PARAM_BLOCK_DATA_IDX\r
1680  *   NVM_E_PARAM_BLOCK_TYPE\r
1681  *   x NVM_E_PARAM_BLOCK_ID\r
1682  *\r
1683  */\r
1684 Std_ReturnType NvM_SetDataIndex( NvM_BlockIdType blockId, uint8 dataIndex ) {\r
1685 #if  ( NVM_DEV_ERROR_DETECT == STD_ON )\r
1686         const NvM_BlockDescriptorType * bPtr = &NvM_Config.BlockDescriptor[blockId-1];\r
1687 #endif\r
1688         AdministrativeBlockType *               admPtr = &AdminBlock[blockId-1];\r
1689 \r
1690         Nvm_QueueType qEntry;\r
1691         int rv;\r
1692 \r
1693         NVM_ASSERT( blockId >= 2 );     /* No support for lower numbers, yet */\r
1694 \r
1695         VALIDATE_RV(nvmState != NVM_UNINITIALIZED, NVM_SET_DATA_INDEX_ID, NVM_E_NOT_INITIALIZED, E_NOT_OK);\r
1696         VALIDATE_RV(blockId < NVM_NUM_OF_NVRAM_BLOCKS+1, NVM_SET_DATA_INDEX_ID, NVM_E_PARAM_BLOCK_ID, E_NOT_OK);\r
1697         VALIDATE_RV(bPtr->BlockManagementType != NVM_BLOCK_NATIVE ,  NVM_SET_DATA_INDEX_ID, NVM_E_PARAM_BLOCK_TYPE , E_NOT_OK);\r
1698         VALIDATE_RV(dataIndex < bPtr->NvBlockNum + bPtr->RomBlockNum , NVM_SET_DATA_INDEX_ID, NVM_E_PARAM_BLOCK_DATA_IDX ,E_NOT_OK);\r
1699         VALIDATE_RV( (admPtr->ErrorStatus != NVM_REQ_PENDING), NVM_SET_DATA_INDEX_ID, NVM_E_BLOCK_PENDING , E_NOT_OK);\r
1700 \r
1701         qEntry.blockId = blockId;\r
1702         qEntry.op = NVM_SETDATAINDEX;\r
1703         qEntry.blockId = blockId;\r
1704         qEntry.dataIndex = dataIndex;\r
1705         qEntry.serviceId = NVM_SET_DATA_INDEX_ID;\r
1706         rv = CirqBuffPush(&nvmQueue,&qEntry);\r
1707         NVM_ASSERT(rv == 0 );\r
1708 \r
1709         /* req 3.1.5/NVM185 */\r
1710         admPtr->ErrorStatus = NVM_REQ_PENDING;\r
1711         return E_OK;\r
1712 }\r
1713 \r
1714 \r
1715 Std_ReturnType NvM_GetDataIndex( NvM_BlockIdType blockId, uint8 *dataIndexPtr ) {\r
1716 #if  ( NVM_DEV_ERROR_DETECT == STD_ON )\r
1717         const NvM_BlockDescriptorType * bPtr = &NvM_Config.BlockDescriptor[blockId-1];\r
1718 #endif\r
1719         AdministrativeBlockType *               admPtr = &AdminBlock[blockId-1];\r
1720         Nvm_QueueType qEntry;\r
1721         int rv;\r
1722 \r
1723         NVM_ASSERT( blockId >= 2 );     /* No support for lower numbers, yet */\r
1724 \r
1725         VALIDATE_RV(nvmState != NVM_UNINITIALIZED, NVM_GET_DATA_INDEX_ID, NVM_E_NOT_INITIALIZED, E_NOT_OK);\r
1726         VALIDATE_RV(blockId < NVM_NUM_OF_NVRAM_BLOCKS+1, NVM_GET_DATA_INDEX_ID, NVM_E_PARAM_BLOCK_ID, E_NOT_OK);\r
1727         VALIDATE_RV(bPtr->BlockManagementType != NVM_BLOCK_NATIVE ,  NVM_GET_DATA_INDEX_ID, NVM_E_PARAM_BLOCK_TYPE , E_NOT_OK);\r
1728         VALIDATE_RV( (dataIndexPtr != NULL) , NVM_GET_DATA_INDEX_ID, NVM_E_PARAM_DATA  ,E_NOT_OK);\r
1729         VALIDATE_RV( (admPtr->ErrorStatus != NVM_REQ_PENDING), NVM_GET_DATA_INDEX_ID, NVM_E_BLOCK_PENDING , E_NOT_OK);\r
1730 \r
1731         qEntry.blockId = blockId;\r
1732         qEntry.op = NVM_GETDATAINDEX;\r
1733         qEntry.blockId = blockId;\r
1734         qEntry.dataPtr = dataIndexPtr;\r
1735         qEntry.serviceId = NVM_GET_DATA_INDEX_ID;\r
1736         rv = CirqBuffPush(&nvmQueue,&qEntry);\r
1737         NVM_ASSERT(rv == 0 );\r
1738 \r
1739         /* req 3.1.5/NVM185 */\r
1740         admPtr->ErrorStatus = NVM_REQ_PENDING;\r
1741         return E_OK;\r
1742 }\r
1743 //#endif\r
1744 \r
1745 const NvM_BlockDescriptorType * nvmBlock;\r
1746 AdministrativeBlockType *admBlock;\r
1747 \r
1748 /**\r
1749  *
1750  */\r
1751 void NvM_MainFunction(void)\r
1752 {\r
1753         int                     rv;\r
1754         Nvm_QueueType   qEntry;\r
1755         const NvM_BlockDescriptorType * bList = NvM_Config.BlockDescriptor;\r
1756 //      const NvM_BlockDescriptorType * currBlock;\r
1757 //      static uint32 crc32;\r
1758 //      static uint32 crc32Left;\r
1759 \r
1760         /* Check for new requested state changes */\r
1761         if( nvmState == NVM_IDLE ) {\r
1762                 rv = CirqBuffPop( &nvmQueue, &qEntry );\r
1763                 if( rv == 0 ) {\r
1764                         /* Found something in buffer */\r
1765                         nvmState = qEntry.op;\r
1766                         nvmBlock = &bList[qEntry.blockId-1];\r
1767                         admBlock = &AdminBlock[qEntry.blockId-1];\r
1768                         nvmSubState = 0;\r
1769                         admBlock->ErrorStatus = NVM_REQ_PENDING;\r
1770                         serviceId = qEntry.serviceId;\r
1771                         DEBUG_PRINTF("### Popped Single FIFO : %s\n",StateToStr[qEntry.op]);\r
1772                         DEBUG_PRINTF("### CRC On:%d Ram:%d Type:%d\n",nvmBlock->BlockUseCrc, nvmBlock->CalcRamBlockCrc, nvmBlock->BlockCRCType );\r
1773                         DEBUG_PRINTF("### RAM:%x ROM:%x\n", nvmBlock->RamBlockDataAddress, nvmBlock->RomBlockDataAdress );\r
1774                 } else {\r
1775                         /* Check multiblock req and do after all single block reads (3.1.5/NVM243) */\r
1776                         if( AdminMultiReq.state != NVM_UNINITIALIZED ) {\r
1777                                 nvmState = AdminMultiReq.state ;\r
1778                                 nvmSubState = 0;\r
1779                                 nvmBlock = 0;\r
1780                                 admBlock = 0;\r
1781                                 serviceId = AdminMultiReq.serviceId;\r
1782                                 AdminMultiReq.state = NVM_UNINITIALIZED;\r
1783 \r
1784                                 DEBUG_PRINTF("### Popped MULTI\n");\r
1785                         }\r
1786                 }\r
1787         }\r
1788 \r
1789         DEBUG_STATE(nvmState,nvmSubState);\r
1790 \r
1791         switch (nvmState) {\r
1792         case NVM_UNINITIALIZED:\r
1793                 break;\r
1794 \r
1795         case NVM_IDLE:\r
1796         {\r
1797                 CalcCrc();\r
1798                 break;\r
1799         }\r
1800         case NVM_READ_ALL:\r
1801                 if( NS_INIT == nvmSubState ) {\r
1802                         if( ReadAllInit() ) {\r
1803                                 nvmSubState = NS_PROSSING;\r
1804                         } else {\r
1805                                 /* Nothing to do, everything is OK */\r
1806                                 AdminMultiBlock.ErrorStatus = NVM_REQ_OK;\r
1807                                 nvmState = NVM_IDLE;\r
1808                                 nvmSubState = 0;\r
1809                         }\r
1810                 } else if( NS_PROSSING == nvmSubState ) {\r
1811                         ReadAllMain();\r
1812                 }\r
1813                 break;\r
1814 \r
1815         case NVM_READ_BLOCK:\r
1816                 DriveBlock(nvmBlock,admBlock, qEntry.dataPtr, false, false, false );\r
1817                 break;\r
1818 \r
1819         case NVM_RESTORE_BLOCK_DEFAULTS:\r
1820                 DriveBlock(nvmBlock,admBlock, qEntry.dataPtr, false, false, true );\r
1821                 break;\r
1822 \r
1823         case NVM_WRITE_BLOCK:\r
1824                 DriveBlock(nvmBlock,admBlock, qEntry.dataPtr, true /*write*/, false , false );\r
1825                 break;\r
1826 \r
1827         case NVM_WRITE_ALL:\r
1828                 if( NS_INIT == nvmSubState ) {\r
1829                         if( WriteAllInit() ) {\r
1830                                 nvmSubState = NS_PROSSING;\r
1831                         } else {\r
1832                                 /* Nothing to do, everything is OK */\r
1833                                 AdminMultiBlock.ErrorStatus = NVM_REQ_OK;\r
1834                                 nvmState = NVM_IDLE;\r
1835                                 nvmSubState = 0;\r
1836                         }\r
1837                 } else if( NS_PROSSING == nvmSubState ) {\r
1838                         WriteAllMain();\r
1839                 }\r
1840                 break;\r
1841         case NVM_SETDATAINDEX:\r
1842                 admBlock->DataIndex = qEntry.dataIndex;\r
1843                 nvmState = NVM_IDLE;\r
1844                 nvmSubState = 0;\r
1845                 admBlock->ErrorStatus = NVM_REQ_OK;\r
1846                 break;\r
1847         case NVM_GETDATAINDEX:\r
1848                 *qEntry.dataPtr = admBlock->DataIndex;\r
1849                 nvmState = NVM_IDLE;\r
1850                 nvmSubState = 0;\r
1851                 admBlock->ErrorStatus = NVM_REQ_OK;\r
1852                 break;\r
1853         case NVM_SETRAMBLOCKSTATUS:\r
1854                 setRamBlockStatus(nvmBlock,admBlock,qEntry.blockChanged );\r
1855                 nvmState = NVM_IDLE;\r
1856                 nvmSubState = 0;\r
1857                 admBlock->ErrorStatus = NVM_REQ_OK;\r
1858                 break;\r
1859         default:\r
1860                 DET_REPORTERROR(MODULE_ID_NVM, 0, NVM_MAIN_FUNCTION_ID, NVM_UNEXPECTED_STATE);\r
1861                 break;\r
1862         }\r
1863 }\r
1864 \r
1865 \r
1866 /***************************************\r
1867  *  Call-back notifications functions  *\r
1868  ***************************************/\r
1869 #if (NVM_POLLING_MODE == STD_OFF)\r
1870 /*\r
1871  * Procedure:   NvM_JobEndNotification\r
1872  * Reentrant:   No\r
1873  */\r
1874 void NvM_JobEndNotification(void)\r
1875 {\r
1876         MemIfJobAdmin.JobFinished = TRUE;\r
1877         MemIfJobAdmin.JobStatus = E_OK;\r
1878         MemIfJobAdmin.JobResult = MemIf_GetJobResult(FIXME);\r
1879 }\r
1880 \r
1881 /*\r
1882  * Procedure:   NvM_JobErrorNotification\r
1883  * Reentrant:   No\r
1884  */\r
1885 void NvM_JobErrorNotification(void)\r
1886 {\r
1887         MemIfJobAdmin.JobFinished = TRUE;\r
1888         MemIfJobAdmin.JobStatus = E_NOT_OK;\r
1889         MemIfJobAdmin.JobResult = MemIf_GetJobResult(FIXME);\r
1890 }\r
1891 #endif\r
1892 \r