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