]> rtime.felk.cvut.cz Git - arc.git/blob - memory/Fee/Fee.c
rebase
[arc.git] / memory / Fee / Fee.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 \r
19 \r
20 \r
21 \r
22 \r
23 \r
24 #include <string.h>\r
25 #include "Fee.h"\r
26 #include "Fee_Cbk.h"\r
27 #include "Fee_Memory_Cfg.h"\r
28 #include "NvM.h"\r
29 #include "Fls.h"\r
30 #include "Rte.h" // ???\r
31 #if defined(USE_DEM)\r
32 #include "Dem.h"\r
33 #endif\r
34 //#include "SchM_NvM.h"\r
35 #include "MemMap.h"\r
36 \r
37 /*\r
38  * Local definitions\r
39  */\r
40 \r
41 /*\r
42  *  Validation macros\r
43  */\r
44 #if  ( FEE_DEV_ERROR_DETECT == STD_ON )\r
45 #include "Det.h"\r
46 #define VALIDATE(_exp,_api,_err ) \\r
47         if( !(_exp) ) { \\r
48           Det_ReportError(MODULE_ID_FEE, 0, _api, _err); \\r
49         }\r
50 \r
51 #define VALIDATE_RV(_exp,_api,_err,_rv ) \\r
52         if( !(_exp) ) { \\r
53           Det_ReportError(MODULE_ID_FEE, 0, _api, _err); \\r
54           /* PC-Lint exception (MISRA 14.7) - Allow return statement before end of function in validate macros */ \\r
55           /*lint -e(904)*/return _rv; \\r
56         }\r
57 \r
58 #define VALIDATE_NO_RV(_exp,_api,_err ) \\r
59   if( !(_exp) ) { \\r
60           Det_ReportError(MODULE_ID_FEE, 0, _api, _err); \\r
61           /* PC-Lint exception (MISRA 14.7)- Allow return statement before end of function in validate macros */ \\r
62           /*lint -e(904)*/ return; \\r
63         }\r
64 \r
65 #define DET_REPORTERROR(_module,_instance,_api,_err) Det_ReportError(_module,_instance,_api,_err)\r
66 \r
67 #define MIN_BLOCKNR             ((uint16)((uint16)1 << NVM_DATASET_SELECTION_BITS))\r
68 \r
69 #else\r
70 #define VALIDATE(_exp,_api,_err )\r
71 #define VALIDATE_RV(_exp,_api,_err,_rv )\r
72 #define VALIDATE_NO_RV(_exp,_api,_err )\r
73 #define DET_REPORTERROR(_module,_instance,_api,_err)\r
74 #endif\r
75 \r
76 \r
77 /*\r
78  * Block numbering recalculation macros
79  */\r
80 #define GET_BLOCK_INDEX_FROM_BLOCK_NUMBER(_blocknr)     (((_blocknr) >> NVM_DATASET_SELECTION_BITS) - 1u)\r
81 #define GET_DATASET_FROM_BLOCK_NUMBER(_blocknr) ((_blocknr) & ((uint16)((uint16)1u << NVM_DATASET_SELECTION_BITS) - 1u))\r
82 #define BLOCK_INDEX_AND_SET_TO_BLOCKNR(_blocknr, _set)  ((uint16)((_blocknr + 1u) << NVM_DATASET_SELECTION_BITS) | set)\r
83 \r
84 /*\r
85  * Page alignment macros
86  */\r
87 #define PAGE_ALIGN(_size)       ((uint16)((((_size) + FEE_VIRTUAL_PAGE_SIZE - 1) / FEE_VIRTUAL_PAGE_SIZE) * FEE_VIRTUAL_PAGE_SIZE))\r
88 \r
89 /*\r
90  * Bank properties list
91  */\r
92 #define NUM_OF_BANKS    2\r
93 typedef struct {\r
94         Fls_AddressType         Start;\r
95         Fls_LengthType          End;\r
96 } BankPropType;\r
97 \r
98 static const BankPropType BankProp[NUM_OF_BANKS] = {\r
99         {\r
100                 .Start = FEE_BANK1_OFFSET,\r
101                 .End = FEE_BANK1_OFFSET + FEE_BANK1_LENGTH\r
102         },\r
103         {\r
104                 .Start = FEE_BANK2_OFFSET,\r
105                 .End = FEE_BANK2_OFFSET + FEE_BANK2_LENGTH\r
106         },\r
107 };\r
108 \r
109 \r
110 \r
111 /*\r
112  * Macros and variables for flash bank administration
113  */\r
114 #define BANK_STATUS_OLD         0x00\r
115 #define BANK_STATUS_NEW         0xFF\r
116 typedef uint8 FlsBankStatusType;\r
117 \r
118 #define BANK_CTRL_PAGE_SIZE             PAGE_ALIGN(sizeof(FlsBankStatusType))\r
119 \r
120 typedef union {\r
121         FlsBankStatusType       BankStatus;\r
122         uint8                           Data[BANK_CTRL_PAGE_SIZE];\r
123 } FlsBankCtrlPageType;\r
124 \r
125 \r
126 /*\r
127  * Macros and variables for flash block administration in flash
128  */\r
129 #define BLOCK_STATUS_INUSE                      0x00\r
130 #define BLOCK_STATUS_INVALIDATED        0x02\r
131 #define BLOCK_STATUS_EMPTY                      0xFF\r
132 typedef uint8 BlockStatusType;\r
133 \r
134 typedef struct {\r
135         BlockStatusType         Status;\r
136         uint16                          BlockNo;\r
137         Fls_AddressType         BlockDataAddress;\r
138         uint16                          BlockDataLength;\r
139 } FlsBlockCtrlDataType;\r
140 \r
141 #define BLOCK_CTRL_DATA_PAGE_SIZE               PAGE_ALIGN(sizeof(FlsBlockCtrlDataType))\r
142 \r
143 typedef union {\r
144         FlsBlockCtrlDataType    Data;\r
145         uint8                                   Byte[BLOCK_CTRL_DATA_PAGE_SIZE];\r
146 } FlsBlockCtrlDataPageType;\r
147 \r
148 \r
149 #define BLOCK_MAGIC_LEN         4\r
150 static const uint8 BlockMagicMaster[BLOCK_MAGIC_LEN] = { 0xeb, 0xba, 0xba, 0xbe };\r
151 #define BLOCK_CTRL_MAGIC_PAGE_SIZE      PAGE_ALIGN(BLOCK_MAGIC_LEN)\r
152 \r
153 \r
154 typedef union {\r
155         uint8           Magic[BLOCK_MAGIC_LEN];\r
156         uint8           Byte[BLOCK_CTRL_MAGIC_PAGE_SIZE];\r
157 } FlsBlockCtrlMagicPageType;\r
158 \r
159 typedef struct {\r
160         FlsBlockCtrlDataPageType        DataPage;\r
161         FlsBlockCtrlMagicPageType       MagicPage;\r
162 } FlsBlockControlType;\r
163 \r
164 #define BLOCK_CTRL_PAGE_SIZE    PAGE_ALIGN(sizeof(FlsBlockControlType))\r
165 \r
166 #define BLOCK_CTRL_DATA_POS_OFFSET              (/*lint --e(835)*/0)            // Inform PC-Lint that I want the constant to be zero\r
167 #define BLOCK_CTRL_MAGIC_POS_OFFSET             BLOCK_CTRL_DATA_PAGE_SIZE\r
168 \r
169 typedef union {\r
170         FlsBlockControlType     BlockCtrl;\r
171         FlsBankCtrlPageType BankCtrl;\r
172         uint8                           Byte[BLOCK_CTRL_PAGE_SIZE];\r
173 } ReadWriteBufferType;\r
174 \r
175 static ReadWriteBufferType RWBuffer;\r
176 \r
177 #define RWBUFFER_SIZE   sizeof(ReadWriteBufferType)\r
178 \r
179 \r
180 /*\r
181  * Variables for flash administration\r
182  */\r
183 typedef struct {\r
184         BlockStatusType         Status;\r
185         Fls_AddressType         BlockAdminAddress;\r
186         Fls_AddressType         BlockDataAddress;\r
187 } AdminFlsBlockType;\r
188 \r
189 typedef struct {\r
190         uint8                           BankNumber;\r
191         Fls_AddressType         NewBlockAdminAddress;\r
192         Fls_AddressType         NewBlockDataAddress;\r
193         FlsBankStatusType       BankStatus[NUM_OF_BANKS];\r
194         AdminFlsBlockType       BlockDescrTbl[FEE_NUM_OF_BLOCKS][FEE_MAX_NUM_SETS];\r
195 } AdminFlsType;\r
196 \r
197 static AdminFlsType AdminFls;\r
198 \r
199 \r
200 /*\r
201  * Variables for quick reporting of status and job result
202  */\r
203 static MemIf_StatusType ModuleStatus = MEMIF_UNINIT;\r
204 static MemIf_JobResultType JobResult = MEMIF_JOB_OK;\r
205 \r
206 /*\r
207  * Variables for the current job
208  */\r
209 typedef enum {\r
210   FEE_UNINITIALIZED = 0,\r
211   FEE_STARTUP_REQUESTED,\r
212   FEE_STARTUP_READ_BANK1_STATUS,\r
213   FEE_STARTUP_READ_BANK2_STATUS_REQUESTED,\r
214   FEE_STARTUP_READ_BANK2_STATUS,\r
215   FEE_STARTUP_READ_BLOCK_ADMIN_REQUESTED,\r
216   FEE_STARTUP_READ_BLOCK_ADMIN,\r
217 \r
218   FEE_IDLE,\r
219 \r
220   FEE_WRITE_REQUESTED,\r
221   FEE_WRITE_MARK_BANK_OLD,\r
222   FEE_WRITE_HEADER_REQUESTED,\r
223   FEE_WRITE_HEADER,\r
224   FEE_WRITE_DATA_REQUESTED,\r
225   FEE_WRITE_DATA,\r
226   FEE_WRITE_MAGIC_REQUESTED,\r
227   FEE_WRITE_MAGIC,\r
228 \r
229   FEE_READ_REQUESTED,\r
230   FEE_READ,\r
231 \r
232   FEE_INVALIDATE_REQUESTED,\r
233   FEE_INVALIDATE_MARK_BANK_OLD,\r
234   FEE_WRITE_INVALIDATE_HEADER_REQUESTED,\r
235   FEE_WRITE_INVALIDATE_HEADER,\r
236 \r
237   FEE_GARBAGE_COLLECT_REQUESTED,\r
238   FEE_GARBAGE_COLLECT_HEADER_WRITE,\r
239   FEE_GARBAGE_COLLECT_DATA_READ_REQUESTED,\r
240   FEE_GARBAGE_COLLECT_DATA_READ,\r
241   FEE_GARBAGE_COLLECT_DATA_WRITE_REQUESTED,\r
242   FEE_GARBAGE_COLLECT_DATA_WRITE,\r
243   FEE_GARBAGE_COLLECT_MAGIC_WRITE_REQUESTED,\r
244   FEE_GARBAGE_COLLECT_MAGIC_WRITE,\r
245   FEE_GARBAGE_COLLECT_ERASE\r
246 } CurrentJobStateType;\r
247 \r
248 typedef struct {\r
249         CurrentJobStateType                     State;\r
250         uint16                                          InStateCounter;\r
251         uint16                                          BlockNumber;\r
252         uint16                                          Length;\r
253         const Fee_BlockConfigType       *BlockConfigPtr;\r
254         AdminFlsBlockType                       *AdminFlsBlockPtr;\r
255         union {\r
256                 struct {\r
257                         uint8                           NrOfBanks;\r
258                         uint8                           BankNumber;\r
259                         Fls_AddressType         BlockAdminAddress;\r
260                 }Startup;\r
261                 struct {\r
262                         uint16                          Offset;\r
263                         uint8                           *RamPtr;\r
264                 }Read;\r
265                 struct {\r
266                         uint8                           *RamPtr;\r
267                         Fls_AddressType         WriteAdminAddress;\r
268                         Fls_AddressType         WriteDataAddress;\r
269                 }Write;\r
270                 struct {\r
271                         Fls_AddressType         WriteAdminAddress;\r
272                         Fls_AddressType         WriteDataAddress;\r
273                 }Invalidate;\r
274                 struct {\r
275                         uint8                           BankNumber;\r
276                         Fls_AddressType         WriteAdminAddress;\r
277                         Fls_AddressType         WriteDataAddress;\r
278                         uint16                          BytesLeft;\r
279                         uint16                          DataOffset;\r
280                 }GarbageCollect;\r
281         } Op;\r
282 } CurrentJobType;\r
283 \r
284 static CurrentJobType CurrentJob = {\r
285                 .State = FEE_IDLE,\r
286                 .InStateCounter = 0\r
287                 //lint -e{785}          PC-Lint (785) - rest of structure members is initialized when used.\r
288 };\r
289 \r
290 /*\r
291  * Misc definitions
292  */\r
293 #define STATE_COUNTER_MAX                               0xffff\r
294 #define GARBAGE_COLLECTION_DELAY                10\r
295 \r
296 /***************************************\r
297  *           Local functions           *\r
298  ***************************************/\r
299 \r
300 #if (FEE_POLLING_MODE == STD_ON)\r
301 #define SetFlsJobBusy()                 /* Nothing needs to be done here */\r
302 \r
303 static boolean CheckFlsJobFinnished(void)\r
304 {\r
305         MemIf_JobResultType flsJobResult;\r
306 \r
307         flsJobResult = Fls_GetJobResult();\r
308         return (flsJobResult != MEMIF_JOB_PENDING);\r
309 }\r
310 #else\r
311 static boolean FlsJobReady = TRUE;\r
312 \r
313 static void SetFlsJobBusy()\r
314 {\r
315         FlsJobReady = FALSE;\r
316 }\r
317 \r
318 static boolean CheckFlsJobFinnished(void)\r
319 {\r
320         return (FlsJobReady);\r
321 }\r
322 \r
323 #endif\r
324 \r
325 \r
326 static void FinnishStartup(void)\r
327 {\r
328         CurrentJob.State = FEE_IDLE;\r
329         ModuleStatus = MEMIF_IDLE;\r
330         JobResult = MEMIF_JOB_OK;\r
331 }\r
332 \r
333 \r
334 static void AbortStartup(MemIf_JobResultType result)\r
335 {\r
336         CurrentJob.State = FEE_IDLE;\r
337         ModuleStatus = MEMIF_IDLE;\r
338         JobResult = result;\r
339 }\r
340 \r
341 \r
342 static void FinnishJob(void)\r
343 {\r
344         CurrentJob.State = FEE_IDLE;\r
345         ModuleStatus = MEMIF_IDLE;\r
346         JobResult = MEMIF_JOB_OK;\r
347 \r
348         if (Fee_Config.General.NvmJobEndCallbackNotificationCallback != NULL) {\r
349                 Fee_Config.General.NvmJobEndCallbackNotificationCallback();\r
350         }\r
351 }\r
352 \r
353 \r
354 static void AbortJob(MemIf_JobResultType result)\r
355 {\r
356         CurrentJob.State = FEE_IDLE;\r
357         ModuleStatus = MEMIF_IDLE;\r
358         JobResult = result;\r
359 \r
360         if (Fee_Config.General.NvmJobErrorCallbackNotificationCallback != NULL) {\r
361                 Fee_Config.General.NvmJobErrorCallbackNotificationCallback();\r
362         }\r
363 }\r
364 \r
365 \r
366 /*\r
367  * Start of bank status 1 read\r
368  */\r
369 static void StartupStartJob(void)\r
370 {\r
371         if (Fls_GetStatus() == MEMIF_IDLE) {\r
372                 CurrentJob.State = FEE_STARTUP_READ_BANK1_STATUS;\r
373                 /* Read bank status of bank 1 */\r
374                 // PC-Lint exception (MISRA 11.4) - Pointer to pointer conversion ok by AUTOSAR\r
375                 if (Fls_Read(BankProp[0].End - BANK_CTRL_PAGE_SIZE, /*lint -e(926)*/(uint8*)&AdminFls.BankStatus[0], sizeof(FlsBankStatusType)) == E_OK) {\r
376                         SetFlsJobBusy();\r
377                 } else {\r
378                         AbortStartup(Fls_GetJobResult());\r
379                 }\r
380         }\r
381 }\r
382 \r
383 \r
384 /*\r
385  *  Check job result of bank 1 status read, if ok request for bank 2 status read\r
386  */\r
387 static void StartupReadBank1Status(void)\r
388 {\r
389         if (CheckFlsJobFinnished()) {\r
390                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
391                         CurrentJob.State = FEE_STARTUP_READ_BANK2_STATUS_REQUESTED;\r
392                 } else {\r
393                         AbortStartup(Fls_GetJobResult());\r
394                 }\r
395         }\r
396 }\r
397 \r
398 \r
399 /*\r
400  * Start of bank status 2 read\r
401  */\r
402 static void StartupReadBank2StatusRequested(void)\r
403 {\r
404         if (Fls_GetStatus() == MEMIF_IDLE) {\r
405                 /* Read bank status of bank 2 */\r
406                 CurrentJob.State = FEE_STARTUP_READ_BANK2_STATUS;\r
407                 // PC-Lint exception (MISRA 11.4) - Pointer to pointer conversion ok by AUTOSAR\r
408                 if (Fls_Read(BankProp[1].End - BANK_CTRL_PAGE_SIZE, /*lint -e(926)*/(uint8*)&AdminFls.BankStatus[1], sizeof(FlsBankStatusType)) == E_OK) {\r
409                         SetFlsJobBusy();\r
410                 } else {\r
411                         AbortStartup(Fls_GetJobResult());\r
412                 }\r
413         }\r
414 }\r
415 \r
416 \r
417 /*\r
418  * Check job result of bank status 2 read - request for block status reading
419  */\r
420 static void StartupReadBank2Status(void)\r
421 {\r
422         MemIf_JobResultType jobResult;\r
423 \r
424         if (CheckFlsJobFinnished()) {\r
425                 jobResult = Fls_GetJobResult();\r
426                 if (jobResult == MEMIF_JOB_OK) {\r
427                         /* Select which bank to start with */\r
428                         if ((AdminFls.BankStatus[0] != BANK_STATUS_OLD) && (AdminFls.BankStatus[1] != BANK_STATUS_OLD)){\r
429                                 /* None is marked as old, just start with one of them */\r
430                                 CurrentJob.Op.Startup.BankNumber = 0;\r
431                                 CurrentJob.Op.Startup.NrOfBanks = 2;\r
432                         } else if ((AdminFls.BankStatus[0] == BANK_STATUS_OLD) && (AdminFls.BankStatus[1] == BANK_STATUS_OLD) ) {\r
433                                 /* Both banks are marked as old, this shall not be possible */\r
434                                 DET_REPORTERROR(MODULE_ID_FEE, 0, FEE_STARTUP_ID, FEE_FLASH_CORRUPT);\r
435                                 jobResult = MEMIF_JOB_FAILED;\r
436                         } else if (AdminFls.BankStatus[0] == BANK_STATUS_OLD) {\r
437                                 CurrentJob.Op.Startup.BankNumber = 0;\r
438                                 CurrentJob.Op.Startup.NrOfBanks = 2;\r
439                         } else {\r
440                                 CurrentJob.Op.Startup.BankNumber = 1;\r
441                                 CurrentJob.Op.Startup.NrOfBanks = 2;\r
442                         }\r
443                 }\r
444 \r
445                 if (jobResult != MEMIF_JOB_OK) {\r
446                         AbortStartup(jobResult);\r
447                 } else {\r
448                         CurrentJob.Op.Startup.BlockAdminAddress = BankProp[CurrentJob.Op.Startup.BankNumber].End - (BLOCK_CTRL_PAGE_SIZE + BANK_CTRL_PAGE_SIZE);\r
449                         CurrentJob.State = FEE_STARTUP_READ_BLOCK_ADMIN_REQUESTED;\r
450                 }\r
451         }\r
452 }\r
453 \r
454 /*\r
455  * Start of block admin read
456  */\r
457 static void StartupReadBlockAdminRequested(void)\r
458 {\r
459         if (Fls_GetStatus() == MEMIF_IDLE) {\r
460                 /* Start reading the banks */\r
461                 CurrentJob.State = FEE_STARTUP_READ_BLOCK_ADMIN;\r
462                 if (Fls_Read(CurrentJob.Op.Startup.BlockAdminAddress, RWBuffer.Byte, BLOCK_CTRL_PAGE_SIZE) == E_OK) {\r
463                         SetFlsJobBusy();\r
464                 } else {\r
465                         AbortStartup(Fls_GetJobResult());\r
466                 }\r
467         }\r
468 }\r
469 \r
470 \r
471 /*\r
472  * Check job result of block admin read, if all block processed finish\r
473  * otherwise request for a new block admin read
474  */\r
475 static void StartupReadBlockAdmin(void)\r
476 {\r
477         if (CheckFlsJobFinnished()) {\r
478                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
479                         if (RWBuffer.BlockCtrl.DataPage.Data.Status == BLOCK_STATUS_EMPTY) {\r
480                                 VALIDATE(CurrentJob.Op.Startup.NrOfBanks != 0, FEE_STARTUP_ID, FEE_FLASH_CORRUPT);\r
481                                 CurrentJob.Op.Startup.NrOfBanks--;\r
482                                 CurrentJob.Op.Startup.BankNumber = (CurrentJob.Op.Startup.BankNumber + 1) % 2;\r
483                                 CurrentJob.Op.Startup.BlockAdminAddress = BankProp[CurrentJob.Op.Startup.BankNumber].End - (BLOCK_CTRL_PAGE_SIZE + BANK_CTRL_PAGE_SIZE);\r
484                         } else { /* Block not empty */\r
485                                 if ((memcmp(RWBuffer.BlockCtrl.MagicPage.Magic, BlockMagicMaster, BLOCK_MAGIC_LEN) == 0) &&\r
486                                                 ((RWBuffer.BlockCtrl.DataPage.Data.Status == BLOCK_STATUS_INUSE) || (RWBuffer.BlockCtrl.DataPage.Data.Status == BLOCK_STATUS_INVALIDATED))) {\r
487                                         /* This is a valid admin block */\r
488                                         uint16 blockIndex;\r
489                                         uint16 dataSet;\r
490 \r
491                                         blockIndex = GET_BLOCK_INDEX_FROM_BLOCK_NUMBER(RWBuffer.BlockCtrl.DataPage.Data.BlockNo);\r
492                                         dataSet = GET_DATASET_FROM_BLOCK_NUMBER(RWBuffer.BlockCtrl.DataPage.Data.BlockNo);\r
493 \r
494                                         if ((blockIndex < FEE_NUM_OF_BLOCKS) && (dataSet < FEE_MAX_NUM_SETS)) {\r
495                                                 AdminFls.BlockDescrTbl[blockIndex][dataSet].BlockAdminAddress = CurrentJob.Op.Startup.BlockAdminAddress;\r
496                                                 AdminFls.BlockDescrTbl[blockIndex][dataSet].BlockDataAddress = RWBuffer.BlockCtrl.DataPage.Data.BlockDataAddress;\r
497                                                 AdminFls.BlockDescrTbl[blockIndex][dataSet].Status = RWBuffer.BlockCtrl.DataPage.Data.Status;\r
498 \r
499                                                 AdminFls.BankNumber = CurrentJob.Op.Startup.BankNumber;\r
500                                                 AdminFls.NewBlockDataAddress = RWBuffer.BlockCtrl.DataPage.Data.BlockDataAddress + RWBuffer.BlockCtrl.DataPage.Data.BlockDataLength;\r
501                                                 if (CurrentJob.Op.Startup.BlockAdminAddress <= AdminFls.NewBlockDataAddress) {\r
502                                                         /* This shall never happen */\r
503                                                         DET_REPORTERROR(MODULE_ID_FEE, 0, FEE_STARTUP_ID, FEE_FLASH_CORRUPT);\r
504                                                 }\r
505                                         }\r
506                                 }\r
507                                 CurrentJob.Op.Startup.BlockAdminAddress -= BLOCK_CTRL_PAGE_SIZE;\r
508                                 AdminFls.NewBlockAdminAddress = CurrentJob.Op.Startup.BlockAdminAddress;\r
509                         }\r
510 \r
511                         if (CurrentJob.Op.Startup.NrOfBanks == 0) {\r
512                                 /* If current bank is marked as old we need to switch to a new bank */\r
513                                 if (AdminFls.BankStatus[AdminFls.BankNumber] == BANK_STATUS_OLD) {\r
514                                         AdminFls.BankNumber = (AdminFls.BankNumber + 1) % 2;\r
515                                         AdminFls.NewBlockAdminAddress = BankProp[AdminFls.BankNumber].End - (BLOCK_CTRL_PAGE_SIZE + BANK_CTRL_PAGE_SIZE);\r
516                                         AdminFls.NewBlockDataAddress = BankProp[AdminFls.BankNumber].Start;\r
517                                 }\r
518                                 /* We are done! */\r
519                                 FinnishStartup();\r
520                         } else {\r
521                                 CurrentJob.State = FEE_STARTUP_READ_BLOCK_ADMIN_REQUESTED;\r
522                         }\r
523 \r
524 \r
525                 } else { /* ErrorStatus not E_OK */\r
526                         AbortStartup(Fls_GetJobResult());\r
527                 }\r
528         }\r
529 }\r
530 \r
531 \r
532 /*\r
533  * Start of read block data\r
534  */\r
535 static void ReadStartJob(void)\r
536 {\r
537         if (Fls_GetStatus() == MEMIF_IDLE) {\r
538                 if (CurrentJob.AdminFlsBlockPtr->Status != BLOCK_STATUS_EMPTY) {\r
539                         if (CurrentJob.AdminFlsBlockPtr->Status != BLOCK_STATUS_INVALIDATED) {\r
540                                 CurrentJob.State = FEE_READ;\r
541                                 /* Read the actual data */\r
542                                 if (Fls_Read(CurrentJob.AdminFlsBlockPtr->BlockDataAddress + CurrentJob.Op.Read.Offset, CurrentJob.Op.Read.RamPtr, CurrentJob.Length) == E_OK) {\r
543                                         SetFlsJobBusy();\r
544                                 } else {\r
545                                         AbortJob(Fls_GetJobResult());\r
546                                 }\r
547                         } else {\r
548                                 /* Invalid */\r
549                                 AbortJob(MEMIF_BLOCK_INVALID);\r
550                         }\r
551                 } else {\r
552                         /* Inconsistent */\r
553                         AbortJob(MEMIF_BLOCK_INCONSISTENT);\r
554                 }\r
555         }\r
556 }\r
557 \r
558 /*\r
559  * Check job result of block data read
560  */\r
561 static void Reading(void)\r
562 {\r
563         if (CheckFlsJobFinnished()) {\r
564                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
565                         FinnishJob();\r
566                 } else {\r
567                         AbortJob(Fls_GetJobResult());\r
568                 }\r
569         }\r
570 }\r
571 \r
572 \r
573 /*\r
574  * Write bank header\r
575  */\r
576 static void BankHeaderOldWrite(uint8 bank)\r
577 {\r
578         /* Mark the bank as old */\r
579         memset(RWBuffer.BankCtrl.Data, 0xff, BANK_CTRL_PAGE_SIZE);\r
580         RWBuffer.BankCtrl.BankStatus = BANK_STATUS_OLD;\r
581         if (Fls_Write(BankProp[bank].End - BANK_CTRL_PAGE_SIZE, RWBuffer.BankCtrl.Data, BANK_CTRL_PAGE_SIZE) == E_OK) {\r
582                 SetFlsJobBusy();\r
583         } else {\r
584                 AbortJob(Fls_GetJobResult());\r
585         }\r
586 }\r
587 \r
588 \r
589 /*\r
590  * Write block header\r
591  */\r
592 static void BlockHeaderDataWrite(void)\r
593 {\r
594         /* Write the header excluding the magic */\r
595         memset(RWBuffer.BlockCtrl.DataPage.Byte, 0xff, BLOCK_CTRL_DATA_PAGE_SIZE);\r
596         RWBuffer.BlockCtrl.DataPage.Data.Status = BLOCK_STATUS_INUSE;\r
597         RWBuffer.BlockCtrl.DataPage.Data.BlockNo = CurrentJob.BlockNumber;\r
598         RWBuffer.BlockCtrl.DataPage.Data.BlockDataAddress = AdminFls.NewBlockDataAddress;\r
599         RWBuffer.BlockCtrl.DataPage.Data.BlockDataLength = CurrentJob.Length;\r
600         if (Fls_Write(CurrentJob.Op.Write.WriteAdminAddress + BLOCK_CTRL_DATA_POS_OFFSET, RWBuffer.Byte, BLOCK_CTRL_DATA_PAGE_SIZE) == E_OK) {\r
601                 SetFlsJobBusy();\r
602                 AdminFls.NewBlockDataAddress += CurrentJob.Length;\r
603                 AdminFls.NewBlockAdminAddress -= BLOCK_CTRL_PAGE_SIZE;\r
604         } else {\r
605                 AbortJob(Fls_GetJobResult());\r
606         }\r
607 }\r
608 \r
609 \r
610 /*\r
611  * Check if bank switch needed:\r
612  * - Yes, start mark current bank as old\r
613  * - No, start of header write\r
614  */\r
615 static void WriteStartJob(void)\r
616 {\r
617         if (Fls_GetStatus() == MEMIF_IDLE) {\r
618                 if (AdminFls.NewBlockDataAddress + CurrentJob.BlockConfigPtr->BlockSize > AdminFls.NewBlockAdminAddress - BLOCK_CTRL_PAGE_SIZE) {\r
619                         /* Bank switch needed, mark current bank as "old" */\r
620                         CurrentJob.State = FEE_WRITE_MARK_BANK_OLD;\r
621                         BankHeaderOldWrite(AdminFls.BankNumber);\r
622                 } else {\r
623                         CurrentJob.Op.Write.WriteDataAddress = AdminFls.NewBlockDataAddress;\r
624                         CurrentJob.Op.Write.WriteAdminAddress = AdminFls.NewBlockAdminAddress;\r
625 \r
626                         CurrentJob.State = FEE_WRITE_HEADER;\r
627                         BlockHeaderDataWrite();\r
628                 }\r
629         }\r
630 }\r
631 \r
632 \r
633 /*\r
634  * Check job result of mark bank as old, if ok request for header write\r
635  */\r
636 static void WriteMarkBankOldState(void)\r
637 {\r
638         if (CheckFlsJobFinnished()) {\r
639                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
640                         /* Mark for garbage collection */\r
641                         AdminFls.BankStatus[AdminFls.BankNumber] = BANK_STATUS_OLD;\r
642 \r
643                         /* Change of bank */\r
644                         AdminFls.BankNumber ^= 0x1u;\r
645                         AdminFls.NewBlockDataAddress = BankProp[AdminFls.BankNumber].Start;\r
646                         AdminFls.NewBlockAdminAddress = BankProp[AdminFls.BankNumber].End - (BLOCK_CTRL_PAGE_SIZE + BANK_CTRL_PAGE_SIZE);\r
647 \r
648                         CurrentJob.Op.Write.WriteDataAddress = AdminFls.NewBlockDataAddress;\r
649                         CurrentJob.Op.Write.WriteAdminAddress = AdminFls.NewBlockAdminAddress;\r
650 \r
651                         CurrentJob.State = FEE_WRITE_HEADER_REQUESTED;\r
652                 } else {\r
653                         AbortJob(Fls_GetJobResult());\r
654                 }\r
655         }\r
656 }\r
657 \r
658 \r
659 /*\r
660  * Start of header write
661  */\r
662 static void WriteHeaderRequested()\r
663 {\r
664         if (Fls_GetStatus() == MEMIF_IDLE) {\r
665                 CurrentJob.State = FEE_WRITE_HEADER;\r
666                 BlockHeaderDataWrite();\r
667         }\r
668 }\r
669 \r
670 \r
671 /*\r
672  * Check job result of write header, if ok request for block data write\r
673  */\r
674 static void WriteHeaderState(void)\r
675 {\r
676         if (CheckFlsJobFinnished()) {\r
677                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
678                         CurrentJob.State = FEE_WRITE_DATA_REQUESTED;\r
679                 } else {\r
680                         AbortJob(Fls_GetJobResult());\r
681                 }\r
682         }\r
683 }\r
684 \r
685 \r
686 /*\r
687  * Start block data write
688  */\r
689 static void WriteDataRequested(void)\r
690 {\r
691         if (Fls_GetStatus() == MEMIF_IDLE) {\r
692                 CurrentJob.State = FEE_WRITE_DATA;\r
693                 /* Write the actual data */\r
694                 if (Fls_Write(CurrentJob.Op.Write.WriteDataAddress, CurrentJob.Op.Write.RamPtr, CurrentJob.Length) == E_OK) {\r
695                         SetFlsJobBusy();\r
696                 } else {\r
697                         AbortJob(Fls_GetJobResult());\r
698                 }\r
699         }\r
700 }\r
701 \r
702 \r
703 /*\r
704  * Check job result of data write - request for magic write\r
705  */\r
706 static void WriteDataState(void)\r
707 {\r
708         if (CheckFlsJobFinnished()) {\r
709                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
710                         CurrentJob.State = FEE_WRITE_MAGIC_REQUESTED;\r
711                 } else {\r
712                         AbortJob(Fls_GetJobResult());\r
713                 }\r
714         }\r
715 }\r
716 \r
717 \r
718 /*\r
719  * Start magic write
720  */\r
721 static void WriteMagicRequested(void)\r
722 {\r
723         if (Fls_GetStatus() == MEMIF_IDLE) {\r
724                 CurrentJob.State = FEE_WRITE_MAGIC;\r
725                 memset(RWBuffer.BlockCtrl.MagicPage.Byte, 0xff, BLOCK_CTRL_MAGIC_PAGE_SIZE);\r
726                 memcpy(RWBuffer.BlockCtrl.MagicPage.Magic, BlockMagicMaster, BLOCK_MAGIC_LEN);\r
727                 if (Fls_Write(CurrentJob.Op.Write.WriteAdminAddress + BLOCK_CTRL_MAGIC_POS_OFFSET, RWBuffer.BlockCtrl.MagicPage.Byte, BLOCK_CTRL_MAGIC_PAGE_SIZE) == E_OK) {\r
728                         SetFlsJobBusy();\r
729                 } else {\r
730                         AbortJob(Fls_GetJobResult());\r
731                 }\r
732         }\r
733 }\r
734 \r
735 \r
736 /*\r
737  * Check job result of write magic, if ok update the block admin table and finish\r
738  */\r
739 static void WriteMagicState(void)\r
740 {\r
741         if (CheckFlsJobFinnished()) {\r
742                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
743                         /* Update the block admin table */\r
744                         CurrentJob.AdminFlsBlockPtr->Status =  BLOCK_STATUS_INUSE;\r
745                         CurrentJob.AdminFlsBlockPtr->BlockAdminAddress = CurrentJob.Op.Write.WriteAdminAddress;\r
746                         CurrentJob.AdminFlsBlockPtr->BlockDataAddress = CurrentJob.Op.Write.WriteDataAddress;\r
747 \r
748                         FinnishJob();\r
749                 } else {\r
750                         AbortJob(Fls_GetJobResult());\r
751                 }\r
752         }\r
753 }\r
754 \r
755 \r
756 /*\r
757  * Check if any bank is marked as old\r
758  */\r
759 static void CheckIfGarbageCollectionNeeded(void)\r
760 {\r
761         if ((AdminFls.BankStatus[0] == BANK_STATUS_OLD) || (AdminFls.BankStatus[1] == BANK_STATUS_OLD)) {\r
762                 ModuleStatus = MEMIF_BUSY_INTERNAL;\r
763                 JobResult = MEMIF_JOB_PENDING;\r
764 \r
765                 CurrentJob.State = FEE_GARBAGE_COLLECT_REQUESTED;\r
766         }\r
767 }\r
768 \r
769 \r
770 /*\r
771  * Checks if any blocks needs to be moved if so start with writing a new header\r
772  * or if no blocks needs to be moved request for bank erase.\r
773  */\r
774 static void GarbageCollectStartJob(void)\r
775 {\r
776         uint16 blockIndex;\r
777         uint16 set;\r
778         boolean found = FALSE;\r
779         uint8 sourceBank;\r
780 \r
781         if (Fls_GetStatus() == MEMIF_IDLE) {\r
782                 if ((AdminFls.BankStatus[0] == BANK_STATUS_OLD) || (AdminFls.BankStatus[1] == BANK_STATUS_OLD)) {\r
783                         if (AdminFls.BankStatus[0] == BANK_STATUS_OLD) {\r
784                                 sourceBank = 0;\r
785                         } else {\r
786                                 sourceBank = 1;\r
787                         }\r
788 \r
789                         for (blockIndex = 0; (blockIndex < FEE_NUM_OF_BLOCKS) && (!found); blockIndex++) {\r
790                                 for (set = 0; (set < FEE_MAX_NUM_SETS) && (!found); set++) {\r
791                                         if (AdminFls.BlockDescrTbl[blockIndex][set].Status != BLOCK_STATUS_EMPTY) {\r
792                                                 if ((AdminFls.BlockDescrTbl[blockIndex][set].BlockAdminAddress >= BankProp[sourceBank].Start) && (AdminFls.BlockDescrTbl[blockIndex][set].BlockAdminAddress < (BankProp[sourceBank].End))) {\r
793                                                         CurrentJob.AdminFlsBlockPtr = &AdminFls.BlockDescrTbl[blockIndex][set];\r
794                                                         CurrentJob.BlockConfigPtr = &Fee_Config.BlockConfig[blockIndex];\r
795                                                         CurrentJob.BlockNumber = BLOCK_INDEX_AND_SET_TO_BLOCKNR(blockIndex, set);\r
796                                                         if (AdminFls.BlockDescrTbl[blockIndex][set].Status == BLOCK_STATUS_INVALIDATED) {\r
797                                                                 CurrentJob.Length = 0;\r
798                                                         } else {\r
799                                                                 CurrentJob.Length = PAGE_ALIGN(CurrentJob.BlockConfigPtr->BlockSize);\r
800                                                         }\r
801 \r
802                                                         found = TRUE;\r
803                                                 }\r
804                                         }\r
805                                 }\r
806                         }\r
807 \r
808                         if (found) {\r
809                                 CurrentJob.Op.GarbageCollect.WriteDataAddress = AdminFls.NewBlockDataAddress;\r
810                                 CurrentJob.Op.GarbageCollect.WriteAdminAddress = AdminFls.NewBlockAdminAddress;\r
811 \r
812                                 CurrentJob.State = FEE_GARBAGE_COLLECT_HEADER_WRITE;\r
813                                 BlockHeaderDataWrite();\r
814                         } else {\r
815                                 if (Fls_Erase(BankProp[sourceBank].Start, BankProp[sourceBank].End - BankProp[sourceBank].Start) == E_OK) {\r
816                                         SetFlsJobBusy();\r
817                                 } else {\r
818                                         AbortJob(Fls_GetJobResult());\r
819                                 }\r
820                                 CurrentJob.Op.GarbageCollect.BankNumber = sourceBank;\r
821                                 CurrentJob.State = FEE_GARBAGE_COLLECT_ERASE;\r
822                         }\r
823                 } else {\r
824                         CurrentJob.State = FEE_IDLE;\r
825                 }\r
826         }\r
827 }\r
828 \r
829 \r
830 /*\r
831  * Check job result of write header, if ok request for read block data\r
832  */\r
833 static void GarbageCollectWriteHeader(void)\r
834 {\r
835         if (CheckFlsJobFinnished()) {\r
836                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
837                         if (CurrentJob.AdminFlsBlockPtr->Status == BLOCK_STATUS_INUSE) {\r
838                                 CurrentJob.Op.GarbageCollect.BytesLeft = PAGE_ALIGN(CurrentJob.BlockConfigPtr->BlockSize);\r
839                                 CurrentJob.Op.GarbageCollect.DataOffset = 0;\r
840                                 CurrentJob.State = FEE_GARBAGE_COLLECT_DATA_READ_REQUESTED;\r
841                         } else {\r
842                                 /* Yes, we are finished */\r
843                                 VALIDATE_NO_RV(CurrentJob.AdminFlsBlockPtr->Status == BLOCK_STATUS_INVALIDATED, FEE_GARBAGE_WRITE_HEADER_ID, FEE_UNEXPECTED_STATUS);\r
844                                 CurrentJob.State = FEE_GARBAGE_COLLECT_MAGIC_WRITE_REQUESTED;\r
845                         }\r
846                 } else {\r
847                         AbortJob(Fls_GetJobResult());\r
848                 }\r
849         }\r
850 }\r
851 \r
852 \r
853 /*\r
854  * Start of read block data, if data length is more than buffer size\r
855  * the reading is segmented.\r
856  */\r
857 static void GarbageCollectReadDataRequested(void)\r
858 {\r
859         if (Fls_GetStatus() == MEMIF_IDLE) {\r
860                 CurrentJob.State = FEE_GARBAGE_COLLECT_DATA_READ;\r
861                 if (CurrentJob.Op.GarbageCollect.BytesLeft <= RWBUFFER_SIZE) {\r
862                         CurrentJob.Length = CurrentJob.Op.GarbageCollect.BytesLeft;\r
863                 } else {\r
864                         CurrentJob.Length = RWBUFFER_SIZE;\r
865                 }\r
866                 if (Fls_Read(CurrentJob.AdminFlsBlockPtr->BlockDataAddress + CurrentJob.Op.GarbageCollect.DataOffset, RWBuffer.Byte, CurrentJob.Length) == E_OK) {\r
867                         SetFlsJobBusy();\r
868                 } else {\r
869                         AbortJob(Fls_GetJobResult());\r
870                 }\r
871         }\r
872 }\r
873 \r
874 \r
875 /*\r
876  * Check job result of read block data, if ok request for a data write\r
877  */\r
878 static void GarbageCollectReadData(void)\r
879 {\r
880         if (CheckFlsJobFinnished()) {\r
881                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
882                         CurrentJob.State = FEE_GARBAGE_COLLECT_DATA_WRITE_REQUESTED;\r
883                 } else {\r
884                         AbortJob(Fls_GetJobResult());\r
885                 }\r
886         }\r
887 }\r
888 \r
889 \r
890 /*\r
891  * Start of write block data\r
892  */\r
893 static void GarbageCollectWriteDataRequested(void)\r
894 {\r
895         if (Fls_GetStatus() == MEMIF_IDLE) {\r
896                 CurrentJob.State = FEE_GARBAGE_COLLECT_DATA_WRITE;\r
897                 /* Write the actual data */\r
898                 if (Fls_Write(CurrentJob.Op.GarbageCollect.WriteDataAddress + CurrentJob.Op.GarbageCollect.DataOffset, RWBuffer.Byte, CurrentJob.Length) == E_OK) {\r
899                         SetFlsJobBusy();\r
900                 } else {\r
901                         AbortJob(Fls_GetJobResult());\r
902                 }\r
903         } else {\r
904                 AbortJob(Fls_GetJobResult());\r
905         }\r
906 }\r
907 \r
908 \r
909 /*\r
910  * Check job result of write data, if ok request for write magic or\r
911  * next data read depending on if there are more block data to move.\r
912  */\r
913 static void GarbageCollectWriteData(void)\r
914 {\r
915         if (CheckFlsJobFinnished()) {\r
916                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
917                         if (CurrentJob.Op.GarbageCollect.BytesLeft <= RWBUFFER_SIZE) {\r
918                                 /* Yes, we are finished */\r
919                                 CurrentJob.State = FEE_GARBAGE_COLLECT_MAGIC_WRITE_REQUESTED;\r
920                         } else {\r
921                                 /* More data to move */\r
922                                 CurrentJob.Op.GarbageCollect.DataOffset += RWBUFFER_SIZE;\r
923                                 CurrentJob.Op.GarbageCollect.BytesLeft -= RWBUFFER_SIZE;\r
924                                 CurrentJob.State = FEE_GARBAGE_COLLECT_DATA_READ_REQUESTED;\r
925                         }\r
926                 } else {\r
927                         AbortJob(Fls_GetJobResult());\r
928                 }\r
929         }\r
930 }\r
931 \r
932 \r
933 /*\r
934  * Start write magic\r
935  */\r
936 static void GarbageCollectWriteMagicRequested(void)\r
937 {\r
938         if (Fls_GetStatus() == MEMIF_IDLE) {\r
939                 CurrentJob.State = FEE_GARBAGE_COLLECT_MAGIC_WRITE;\r
940                 memset(RWBuffer.BlockCtrl.MagicPage.Byte, 0xff, BLOCK_CTRL_MAGIC_PAGE_SIZE);\r
941                 memcpy(RWBuffer.BlockCtrl.MagicPage.Magic, BlockMagicMaster, BLOCK_MAGIC_LEN);\r
942                 if (Fls_Write(CurrentJob.Op.GarbageCollect.WriteAdminAddress + BLOCK_CTRL_MAGIC_POS_OFFSET, RWBuffer.BlockCtrl.MagicPage.Byte, BLOCK_CTRL_MAGIC_PAGE_SIZE) == E_OK) {\r
943                         SetFlsJobBusy();\r
944                 } else {\r
945                         AbortJob(Fls_GetJobResult());\r
946                 }\r
947         }\r
948 }\r
949 \r
950 \r
951 /*\r
952  * Check the job result of write magic, if ok update the admin table with the new position of data.\r
953  */\r
954 static void GarbageCollectWriteMagic(void)\r
955 {\r
956         if (CheckFlsJobFinnished()) {\r
957                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
958                         CurrentJob.AdminFlsBlockPtr->BlockAdminAddress = CurrentJob.Op.GarbageCollect.WriteAdminAddress;\r
959                         CurrentJob.AdminFlsBlockPtr->BlockDataAddress = CurrentJob.Op.GarbageCollect.WriteDataAddress;\r
960                         FinnishJob();\r
961                 } else {\r
962                         AbortJob(Fls_GetJobResult());\r
963                 }\r
964         }\r
965 }\r
966 \r
967 \r
968 /*\r
969  * Check the result of the erase job\r
970  */\r
971 static void GarbageCollectErase(void)\r
972 {\r
973         if (CheckFlsJobFinnished()) {\r
974                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
975                         AdminFls.BankStatus[CurrentJob.Op.GarbageCollect.BankNumber] = BANK_STATUS_NEW;\r
976                         FinnishJob();\r
977                 } else {\r
978                         AbortJob(Fls_GetJobResult());\r
979                 }\r
980         }\r
981 }\r
982 \r
983 \r
984 /*\r
985  * Write an "Invalidated" block header\r
986  */\r
987 static void BlockHeaderInvalidWrite(void)\r
988 {\r
989         // Write the header including the magic\r
990         memset(RWBuffer.Byte, 0xff, BLOCK_CTRL_PAGE_SIZE);\r
991         RWBuffer.BlockCtrl.DataPage.Data.Status = BLOCK_STATUS_INVALIDATED;\r
992         RWBuffer.BlockCtrl.DataPage.Data.BlockNo = CurrentJob.BlockNumber;\r
993         RWBuffer.BlockCtrl.DataPage.Data.BlockDataAddress = AdminFls.NewBlockDataAddress;\r
994         RWBuffer.BlockCtrl.DataPage.Data.BlockDataLength = 0;\r
995         memset(RWBuffer.BlockCtrl.MagicPage.Byte, 0xff, BLOCK_CTRL_MAGIC_PAGE_SIZE);\r
996         memcpy(RWBuffer.BlockCtrl.MagicPage.Magic, BlockMagicMaster, BLOCK_MAGIC_LEN);\r
997 \r
998         if (Fls_Write(CurrentJob.Op.Invalidate.WriteAdminAddress + BLOCK_CTRL_DATA_POS_OFFSET, RWBuffer.Byte, BLOCK_CTRL_PAGE_SIZE) == E_OK) {\r
999                 SetFlsJobBusy();\r
1000                 AdminFls.NewBlockDataAddress += CurrentJob.Length;\r
1001                 AdminFls.NewBlockAdminAddress -= BLOCK_CTRL_PAGE_SIZE;\r
1002         } else {\r
1003                 AbortJob(Fls_GetJobResult());\r
1004         }\r
1005 }\r
1006 \r
1007 \r
1008 /*\r
1009  * Check if bank switch is needed, if yes request for marking current bank as old,\r
1010  * if no request for writing a header with "Invalid" status set.\r
1011  */\r
1012 static void InvalidateStartJob(void)\r
1013 {\r
1014         if (Fls_GetStatus() == MEMIF_IDLE) {\r
1015                 if (AdminFls.NewBlockDataAddress + CurrentJob.BlockConfigPtr->BlockSize > AdminFls.NewBlockAdminAddress - BLOCK_CTRL_PAGE_SIZE) {\r
1016                         /* Bank switch needed, mark current bank as "old" */\r
1017                         CurrentJob.State = FEE_INVALIDATE_MARK_BANK_OLD;\r
1018                         BankHeaderOldWrite(AdminFls.BankNumber);\r
1019                 } else {\r
1020                         CurrentJob.Op.Invalidate.WriteDataAddress = AdminFls.NewBlockDataAddress;\r
1021                         CurrentJob.Op.Invalidate.WriteAdminAddress = AdminFls.NewBlockAdminAddress;\r
1022 \r
1023                         CurrentJob.State = FEE_WRITE_INVALIDATE_HEADER;\r
1024                         BlockHeaderInvalidWrite();\r
1025                 }\r
1026         }\r
1027 }\r
1028 \r
1029 \r
1030 /*\r
1031  * Check job result of mark bank old, if ok continue with request for writing\r
1032  * a header with "Invalid" status set.\r
1033  */\r
1034 static void InvalidateMarkBankOld(void)\r
1035 {\r
1036         if (CheckFlsJobFinnished()) {\r
1037                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
1038                         // Mark for garbage collection\r
1039                         AdminFls.BankStatus[AdminFls.BankNumber] = BANK_STATUS_OLD;\r
1040 \r
1041                         // Change of bank\r
1042                         AdminFls.BankNumber ^= 0x1u;\r
1043                         AdminFls.NewBlockDataAddress = BankProp[AdminFls.BankNumber].Start;\r
1044                         AdminFls.NewBlockAdminAddress = BankProp[AdminFls.BankNumber].End - (BLOCK_CTRL_PAGE_SIZE + BANK_CTRL_PAGE_SIZE);\r
1045 \r
1046                         CurrentJob.Op.Invalidate.WriteDataAddress = AdminFls.NewBlockDataAddress;\r
1047                         CurrentJob.Op.Invalidate.WriteAdminAddress = AdminFls.NewBlockAdminAddress;\r
1048 \r
1049                         CurrentJob.State = FEE_WRITE_INVALIDATE_HEADER_REQUESTED;\r
1050                 } else {\r
1051                         AbortJob(Fls_GetJobResult());\r
1052                 }\r
1053         }\r
1054 }\r
1055 \r
1056 /*\r
1057  * Start the writing of the "Invalid" header.
1058  */\r
1059 static void InvalidateWriteInvalidateHeaderRequested(void)\r
1060 {\r
1061         if (Fls_GetStatus() == MEMIF_IDLE) {\r
1062                 CurrentJob.State = FEE_WRITE_INVALIDATE_HEADER;\r
1063                 BlockHeaderInvalidWrite();\r
1064         }\r
1065 }\r
1066 \r
1067 \r
1068 /*\r
1069  * Check the job result of "Invalid" header write, if ok update the block admin table\r
1070  */\r
1071 static void InvalidateWriteInvalidateHeader(void)\r
1072 {\r
1073         if (CheckFlsJobFinnished()) {\r
1074                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
1075                         // Update the block admin table\r
1076                         CurrentJob.AdminFlsBlockPtr->Status =  BLOCK_STATUS_INVALIDATED;\r
1077                         CurrentJob.AdminFlsBlockPtr->BlockAdminAddress = CurrentJob.Op.Invalidate.WriteAdminAddress;\r
1078                         CurrentJob.AdminFlsBlockPtr->BlockDataAddress = CurrentJob.Op.Invalidate.WriteDataAddress;\r
1079 \r
1080                         FinnishJob();\r
1081                 } else {\r
1082                         AbortJob(Fls_GetJobResult());\r
1083                 }\r
1084         }\r
1085 }\r
1086 \r
1087 \r
1088 /***************************************\r
1089  *    External accessible functions    *\r
1090  ***************************************/\r
1091 /*\r
1092  * Procedure:   Fee_Init\r
1093  * Reentrant:   No\r
1094  */\r
1095 void Fee_Init(void)\r
1096 {\r
1097         uint16 i,j;\r
1098 \r
1099         /* Reporting information */\r
1100         ModuleStatus = MEMIF_BUSY_INTERNAL;\r
1101         JobResult = MEMIF_JOB_OK;\r
1102 \r
1103         /* State of device */\r
1104         CurrentJob.State = FEE_STARTUP_REQUESTED;\r
1105         CurrentJob.InStateCounter = 0;\r
1106 #if (FEE_POLLING_MODE == STD_OFF)\r
1107         FlsJobReady = TRUE;\r
1108 #endif\r
1109 \r
1110         AdminFls.BankNumber = 0;\r
1111         AdminFls.NewBlockDataAddress = BankProp[AdminFls.BankNumber].Start;\r
1112         AdminFls.NewBlockAdminAddress = BankProp[AdminFls.BankNumber].End - (BLOCK_CTRL_PAGE_SIZE + BANK_CTRL_PAGE_SIZE);\r
1113 \r
1114         for (i = 0; i < NUM_OF_BANKS; i++) {\r
1115                 AdminFls.BankStatus[i] = BANK_STATUS_NEW;\r
1116         }\r
1117 \r
1118         for (i = 0; i < FEE_NUM_OF_BLOCKS; i++) {\r
1119                 for (j = 0; j < FEE_MAX_NUM_SETS; j++) {\r
1120                         AdminFls.BlockDescrTbl[i][j].Status = BLOCK_STATUS_EMPTY;\r
1121                         AdminFls.BlockDescrTbl[i][j].BlockAdminAddress= 0;\r
1122                         AdminFls.BlockDescrTbl[i][j].BlockDataAddress = 0;\r
1123                 }\r
1124         }\r
1125 }\r
1126 \r
1127 \r
1128 /*\r
1129  * Procedure:   Fee_SetMode\r
1130  * Reentrant:   No\r
1131  */\r
1132 void Fee_SetMode(MemIf_ModeType mode)\r
1133 {\r
1134 #if ( FLS_SET_MODE_API == STD_ON )\r
1135         Fls_SetMode(mode);\r
1136 #else\r
1137         //lint --e{715} PC-Lint (715) - variable "mode" not used in this case\r
1138         DET_REPORTERROR(MODULE_ID_FEE, 0, FEE_SET_MODE_ID, FEE_E_NOT_SUPPORTED);\r
1139 #endif\r
1140 }\r
1141 \r
1142 /*\r
1143  * Procedure:   Fee_Read\r
1144  * Reentrant:   No\r
1145  */\r
1146 Std_ReturnType Fee_Read(uint16 blockNumber, uint16 blockOffset, uint8* dataBufferPtr, uint16 length)\r
1147 {\r
1148         uint16 blockIndex;\r
1149         uint16 dataset;\r
1150 \r
1151         VALIDATE_RV(ModuleStatus != MEMIF_UNINIT, FEE_READ_ID, FEE_E_UNINIT, E_NOT_OK);\r
1152         VALIDATE_RV(ModuleStatus == MEMIF_IDLE, FEE_READ_ID, FEE_E_BUSY, E_NOT_OK);\r
1153 \r
1154         VALIDATE_RV(blockNumber >= MIN_BLOCKNR, FEE_READ_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);\r
1155         blockIndex = GET_BLOCK_INDEX_FROM_BLOCK_NUMBER(blockNumber);\r
1156         VALIDATE_RV(blockIndex < FEE_NUM_OF_BLOCKS, FEE_READ_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);\r
1157         VALIDATE_RV(dataBufferPtr != NULL, FEE_READ_ID, FEE_E_INVALID_DATA_PTR, E_NOT_OK);\r
1158         VALIDATE_RV(blockOffset < Fee_Config.BlockConfig[blockIndex].BlockSize, FEE_READ_ID, FEE_E_INVALID_BLOCK_OFS, E_NOT_OK);\r
1159         VALIDATE_RV(blockOffset + length <= Fee_Config.BlockConfig[blockIndex].BlockSize, FEE_READ_ID, FEE_E_INVALID_BLOCK_LEN, E_NOT_OK);\r
1160 \r
1161         dataset = GET_DATASET_FROM_BLOCK_NUMBER(blockNumber);\r
1162         VALIDATE_RV(dataset < FEE_MAX_NUM_SETS, FEE_READ_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);\r
1163 \r
1164 \r
1165         /** @req FEE022 */\r
1166         ModuleStatus = MEMIF_BUSY;\r
1167         JobResult = MEMIF_JOB_PENDING;\r
1168 \r
1169         CurrentJob.BlockNumber = blockNumber;\r
1170         CurrentJob.BlockConfigPtr = &Fee_Config.BlockConfig[blockIndex];\r
1171         CurrentJob.AdminFlsBlockPtr = &AdminFls.BlockDescrTbl[blockIndex][dataset];\r
1172         CurrentJob.Length = length;\r
1173         CurrentJob.Op.Read.Offset = blockOffset;\r
1174         CurrentJob.Op.Read.RamPtr = dataBufferPtr;\r
1175         CurrentJob.State = FEE_READ_REQUESTED;\r
1176 \r
1177         return E_OK;\r
1178 }\r
1179 \r
1180 \r
1181 /*\r
1182  * Procedure:   Fee_Write\r
1183  * Reentrant:   No\r
1184  */\r
1185 Std_ReturnType Fee_Write(uint16 blockNumber, uint8* dataBufferPtr)\r
1186 {\r
1187         uint16 blockIndex;\r
1188         uint16 dataset;\r
1189 \r
1190         VALIDATE_RV(ModuleStatus != MEMIF_UNINIT, FEE_WRITE_ID, FEE_E_UNINIT, E_NOT_OK);\r
1191         VALIDATE_RV(ModuleStatus == MEMIF_IDLE, FEE_WRITE_ID, FEE_E_BUSY, E_NOT_OK);\r
1192 \r
1193         VALIDATE_RV(blockNumber >= MIN_BLOCKNR, FEE_WRITE_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);\r
1194         blockIndex = GET_BLOCK_INDEX_FROM_BLOCK_NUMBER(blockNumber);\r
1195         VALIDATE_RV(blockIndex < FEE_NUM_OF_BLOCKS, FEE_WRITE_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);\r
1196         VALIDATE_RV(dataBufferPtr != NULL, FEE_WRITE_ID, FEE_E_INVALID_DATA_PTR, E_NOT_OK);\r
1197 \r
1198         dataset = GET_DATASET_FROM_BLOCK_NUMBER(blockNumber);\r
1199         VALIDATE_RV(dataset < FEE_MAX_NUM_SETS, FEE_WRITE_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);\r
1200 \r
1201 \r
1202         /** @req FEE025 */\r
1203         ModuleStatus = MEMIF_BUSY;\r
1204         JobResult = MEMIF_JOB_PENDING;\r
1205 \r
1206         CurrentJob.BlockConfigPtr = &Fee_Config.BlockConfig[blockIndex];\r
1207         CurrentJob.AdminFlsBlockPtr = &AdminFls.BlockDescrTbl[blockIndex][dataset];\r
1208         CurrentJob.BlockNumber = blockNumber;\r
1209         CurrentJob.Length = PAGE_ALIGN(CurrentJob.BlockConfigPtr->BlockSize);\r
1210         CurrentJob.Op.Write.RamPtr = dataBufferPtr;\r
1211         CurrentJob.State = FEE_WRITE_REQUESTED;\r
1212 \r
1213         return E_OK;\r
1214 }\r
1215 \r
1216 \r
1217 /*\r
1218  * Procedure:   Fee_Cancel\r
1219  * Reentrant:   No\r
1220  */\r
1221 void Fee_Cancel(void)\r
1222 {\r
1223         DET_REPORTERROR(MODULE_ID_FEE, 0, FEE_CANCEL_ID, FEE_E_NOT_IMPLEMENTED_YET);\r
1224 }\r
1225 \r
1226 \r
1227 /*\r
1228  * Procedure:   Fee_GetStatus\r
1229  * Reentrant:   No\r
1230  */\r
1231 MemIf_StatusType Fee_GetStatus(void)\r
1232 {\r
1233         return ModuleStatus;\r
1234 }\r
1235 \r
1236 \r
1237 /*\r
1238  * Procedure:   Fee_GetJobResult\r
1239  * Reentrant:   No\r
1240  */\r
1241 MemIf_JobResultType Fee_GetJobResult(void)\r
1242 {\r
1243         return JobResult;\r
1244 }\r
1245 \r
1246 \r
1247 /*\r
1248  * Procedure:   Fee_InvalidateBlock\r
1249  * Reentrant:   No\r
1250  */\r
1251 Std_ReturnType Fee_InvalidateBlock(uint16 blockNumber)\r
1252 {\r
1253         uint16 blockIndex;\r
1254         uint16 dataset;\r
1255 \r
1256         VALIDATE_RV(ModuleStatus != MEMIF_UNINIT, FEE_INVALIDATE_BLOCK_ID, FEE_E_UNINIT, E_NOT_OK);\r
1257         VALIDATE_RV(ModuleStatus == MEMIF_IDLE, FEE_INVALIDATE_BLOCK_ID, FEE_E_BUSY, E_NOT_OK);\r
1258 \r
1259         VALIDATE_RV(blockNumber >= MIN_BLOCKNR, FEE_INVALIDATE_BLOCK_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);\r
1260         blockIndex = GET_BLOCK_INDEX_FROM_BLOCK_NUMBER(blockNumber);\r
1261         VALIDATE_RV(blockIndex < FEE_NUM_OF_BLOCKS, FEE_INVALIDATE_BLOCK_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);\r
1262 \r
1263         dataset = GET_DATASET_FROM_BLOCK_NUMBER(blockNumber);\r
1264         VALIDATE_RV(dataset < FEE_MAX_NUM_SETS, FEE_INVALIDATE_BLOCK_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);\r
1265 \r
1266 \r
1267         ModuleStatus = MEMIF_BUSY;\r
1268         JobResult = MEMIF_JOB_PENDING;\r
1269 \r
1270         CurrentJob.BlockConfigPtr = &Fee_Config.BlockConfig[blockIndex];\r
1271         CurrentJob.AdminFlsBlockPtr = &AdminFls.BlockDescrTbl[blockIndex][dataset];\r
1272         CurrentJob.BlockNumber = blockNumber;\r
1273         CurrentJob.State = FEE_INVALIDATE_REQUESTED;\r
1274 \r
1275         return E_OK;\r
1276 }\r
1277 \r
1278 \r
1279 /*\r
1280  * Procedure:   Fee_EraseImmediateBlock\r
1281  * Reentrant:   No\r
1282  */\r
1283 Std_ReturnType Fee_EraseImmediateBlock(uint16 blockNumber)\r
1284 {\r
1285         //lint --e{715} PC-Lint (715) - function is not implemented and thus variable "blockNumber" is not used yet\r
1286 \r
1287         DET_REPORTERROR(MODULE_ID_FEE, 0, FEE_ERASE_IMMEDIATE_ID, FEE_E_NOT_IMPLEMENTED_YET);\r
1288 \r
1289 \r
1290         return E_NOT_OK;\r
1291 }\r
1292 \r
1293 \r
1294 /***************************************\r
1295  *         Scheduled functions         *\r
1296  ***************************************/\r
1297 /*\r
1298  * Procedure:   Fee_MainFunction\r
1299  * Reentrant:   No\r
1300  */\r
1301 void Fee_MainFunction(void)\r
1302 {\r
1303         static CurrentJobStateType LastState = FEE_UNINITIALIZED;\r
1304 \r
1305         if (CurrentJob.State == LastState) {\r
1306                 if (CurrentJob.InStateCounter < STATE_COUNTER_MAX) {\r
1307                         CurrentJob.InStateCounter++;\r
1308                 }\r
1309         } else {\r
1310                 LastState = CurrentJob.State;\r
1311                 CurrentJob.InStateCounter = 0;\r
1312         }\r
1313 \r
1314         switch (CurrentJob.State) {\r
1315         case FEE_UNINITIALIZED:\r
1316                 break;\r
1317 \r
1318         case FEE_IDLE:\r
1319                 if (CurrentJob.InStateCounter > GARBAGE_COLLECTION_DELAY) {\r
1320                         CheckIfGarbageCollectionNeeded();\r
1321                 }\r
1322                 break;\r
1323 \r
1324                 /*\r
1325                  * Startup states\r
1326                  */\r
1327         case FEE_STARTUP_REQUESTED:\r
1328                 StartupStartJob();\r
1329                 break;\r
1330 \r
1331         case FEE_STARTUP_READ_BANK1_STATUS:\r
1332                 StartupReadBank1Status();\r
1333                 break;\r
1334 \r
1335         case FEE_STARTUP_READ_BANK2_STATUS_REQUESTED:\r
1336                 StartupReadBank2StatusRequested();\r
1337                 break;\r
1338 \r
1339         case FEE_STARTUP_READ_BANK2_STATUS:\r
1340                 StartupReadBank2Status();\r
1341                 break;\r
1342 \r
1343         case FEE_STARTUP_READ_BLOCK_ADMIN_REQUESTED:\r
1344                 StartupReadBlockAdminRequested();\r
1345                 break;\r
1346 \r
1347         case FEE_STARTUP_READ_BLOCK_ADMIN:\r
1348                 StartupReadBlockAdmin();\r
1349                 break;\r
1350 \r
1351         /*\r
1352          *  Read states\r
1353          */\r
1354         case FEE_READ_REQUESTED:\r
1355                 ReadStartJob();\r
1356                 break;\r
1357 \r
1358         case FEE_READ:\r
1359                 Reading();\r
1360                 break;\r
1361 \r
1362         /*\r
1363          * Write states
1364          */\r
1365         case FEE_WRITE_REQUESTED:\r
1366                 WriteStartJob();\r
1367                 break;\r
1368 \r
1369         case FEE_WRITE_MARK_BANK_OLD:\r
1370                 WriteMarkBankOldState();\r
1371                 break;\r
1372 \r
1373         case FEE_WRITE_HEADER_REQUESTED:\r
1374                 WriteHeaderRequested();\r
1375                 break;\r
1376 \r
1377         case FEE_WRITE_HEADER:\r
1378                 WriteHeaderState();\r
1379                 break;\r
1380 \r
1381         case FEE_WRITE_DATA_REQUESTED:\r
1382                 WriteDataRequested();\r
1383                 break;\r
1384 \r
1385         case FEE_WRITE_DATA:\r
1386                 WriteDataState();\r
1387                 break;\r
1388 \r
1389         case FEE_WRITE_MAGIC_REQUESTED:\r
1390                 WriteMagicRequested();\r
1391                 break;\r
1392 \r
1393         case FEE_WRITE_MAGIC:\r
1394                 WriteMagicState();\r
1395                 break;\r
1396 \r
1397         /*\r
1398          * Garbage collection states
1399          */\r
1400         case FEE_GARBAGE_COLLECT_REQUESTED:\r
1401                 GarbageCollectStartJob();\r
1402                 break;\r
1403 \r
1404         case FEE_GARBAGE_COLLECT_HEADER_WRITE:\r
1405                 GarbageCollectWriteHeader();\r
1406                 break;\r
1407 \r
1408         case FEE_GARBAGE_COLLECT_DATA_READ_REQUESTED:\r
1409                 GarbageCollectReadDataRequested();\r
1410                 break;\r
1411 \r
1412         case FEE_GARBAGE_COLLECT_DATA_READ:\r
1413                 GarbageCollectReadData();\r
1414                 break;\r
1415 \r
1416         case FEE_GARBAGE_COLLECT_DATA_WRITE_REQUESTED:\r
1417                 GarbageCollectWriteDataRequested();\r
1418                 break;\r
1419 \r
1420         case FEE_GARBAGE_COLLECT_DATA_WRITE:\r
1421                 GarbageCollectWriteData();\r
1422                 break;\r
1423 \r
1424         case FEE_GARBAGE_COLLECT_MAGIC_WRITE_REQUESTED:\r
1425                 GarbageCollectWriteMagicRequested();\r
1426                 break;\r
1427 \r
1428         case FEE_GARBAGE_COLLECT_MAGIC_WRITE:\r
1429                 GarbageCollectWriteMagic();\r
1430                 break;\r
1431 \r
1432         case FEE_GARBAGE_COLLECT_ERASE:\r
1433                 GarbageCollectErase();\r
1434                 break;\r
1435 \r
1436         /*\r
1437          * Invalidate states
1438          */\r
1439         case FEE_INVALIDATE_REQUESTED:\r
1440                 InvalidateStartJob();\r
1441                 break;\r
1442 \r
1443         case FEE_INVALIDATE_MARK_BANK_OLD:\r
1444                 InvalidateMarkBankOld();\r
1445                 break;\r
1446 \r
1447         case FEE_WRITE_INVALIDATE_HEADER_REQUESTED:\r
1448                 InvalidateWriteInvalidateHeaderRequested();\r
1449                 break;\r
1450 \r
1451         case FEE_WRITE_INVALIDATE_HEADER:\r
1452                 InvalidateWriteInvalidateHeader();\r
1453                 break;\r
1454 \r
1455 \r
1456         /*\r
1457          * Other
1458          */\r
1459         default:\r
1460                 break;\r
1461         }\r
1462 }\r
1463 \r
1464 \r
1465 /***************************************\r
1466  *  Call-back notifications functions  *\r
1467  ***************************************/\r
1468 #if (FEE_POLLING_MODE == STD_OFF)\r
1469 /*\r
1470  * Procedure:   Fee_JobEndNotification\r
1471  * Reentrant:   No\r
1472  */\r
1473 void Fee_JobEndNotification(void)\r
1474 {\r
1475         FlsJobReady = TRUE;\r
1476 }\r
1477 \r
1478 \r
1479 /*\r
1480  * Procedure:   Fee_JobErrorNotification\r
1481  * Reentrant:   No\r
1482  */\r
1483 void Fee_JobErrorNotification(void)\r
1484 {\r
1485         FlsJobReady = TRUE;\r
1486 }\r
1487 #endif\r