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