1 /***************************************************************************
2  * Copyright (c) 2024 Microsoft Corporation
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the MIT License which is available at
6  * https://opensource.org/licenses/MIT.
7  *
8  * SPDX-License-Identifier: MIT
9  **************************************************************************/
10 
11 
12 /**************************************************************************/
13 /**************************************************************************/
14 /**                                                                       */
15 /** LevelX Component                                                      */
16 /**                                                                       */
17 /**   NOR Flash                                                           */
18 /**                                                                       */
19 /**************************************************************************/
20 /**************************************************************************/
21 
22 #define LX_SOURCE_CODE
23 
24 
25 /* Disable ThreadX error checking.  */
26 
27 #ifndef LX_DISABLE_ERROR_CHECKING
28 #define LX_DISABLE_ERROR_CHECKING
29 #endif
30 
31 
32 /* Include necessary system files.  */
33 
34 #include "lx_api.h"
35 
36 
37 /**************************************************************************/
38 /*                                                                        */
39 /*  FUNCTION                                               RELEASE        */
40 /*                                                                        */
41 /*    _lx_nor_flash_open                                  PORTABLE C      */
42 /*                                                           6.3.0        */
43 /*  AUTHOR                                                                */
44 /*                                                                        */
45 /*    William E. Lamie, Microsoft Corporation                             */
46 /*                                                                        */
47 /*  DESCRIPTION                                                           */
48 /*                                                                        */
49 /*    This function opens a NOR flash instance and ensures the NOR flash  */
50 /*    is in a coherent state.                                             */
51 /*                                                                        */
52 /*  INPUT                                                                 */
53 /*                                                                        */
54 /*    nor_flash                             NOR flash instance            */
55 /*    name                                  Name of NOR flash instance    */
56 /*    nor_driver_initialize                 Driver initialize             */
57 /*                                                                        */
58 /*  OUTPUT                                                                */
59 /*                                                                        */
60 /*    return status                                                       */
61 /*                                                                        */
62 /*  CALLS                                                                 */
63 /*                                                                        */
64 /*    (nor_driver_initialize)               Driver initialize             */
65 /*    _lx_nor_flash_driver_read             Driver read                   */
66 /*    _lx_nor_flash_driver_write            Driver write                  */
67 /*    (lx_nor_flash_driver_block_erased_verify)                           */
68 /*                                          NOR flash verify block erased */
69 /*    _lx_nor_flash_driver_block_erase      Driver block erase            */
70 /*    _lx_nor_flash_logical_sector_find     Find logical sector           */
71 /*    _lx_nor_flash_system_error            System error handler          */
72 /*    tx_mutex_create                       Create thread-safe mutex      */
73 /*                                                                        */
74 /*  CALLED BY                                                             */
75 /*                                                                        */
76 /*    Application Code                                                    */
77 /*                                                                        */
78 /*  RELEASE HISTORY                                                       */
79 /*                                                                        */
80 /*    DATE              NAME                      DESCRIPTION             */
81 /*                                                                        */
82 /*  05-19-2020     William E. Lamie         Initial Version 6.0           */
83 /*  09-30-2020     William E. Lamie         Modified comment(s),          */
84 /*                                            resulting in version 6.1    */
85 /*  11-09-2020     William E. Lamie         Modified comment(s),          */
86 /*                                            fixed compiler warnings,    */
87 /*                                            resulting in version 6.1.2  */
88 /*  12-30-2020     William E. Lamie         Modified comment(s),          */
89 /*                                            fixed compiler warnings,    */
90 /*                                            resulting in version 6.1.3  */
91 /*  06-02-2021     Bhupendra Naphade        Modified comment(s), and      */
92 /*                                            updated product constants   */
93 /*                                            resulting in version 6.1.7  */
94 /*  03-08-2023     Xiuwen Cai               Modified comment(s),          */
95 /*                                            added new driver interface, */
96 /*                                            resulting in version 6.2.1  */
97 /*  10-31-2023     Xiuwen Cai               Modified comment(s),          */
98 /*                                            added count for minimum     */
99 /*                                            erased blocks, added        */
100 /*                                            obsolete count cache,       */
101 /*                                            avoided clearing user       */
102 /*                                            extension in flash control  */
103 /*                                            block,                      */
104 /*                                            resulting in version 6.3.0  */
105 /*                                                                        */
106 /**************************************************************************/
_lx_nor_flash_open(LX_NOR_FLASH * nor_flash,CHAR * name,UINT (* nor_driver_initialize)(LX_NOR_FLASH *))107 UINT  _lx_nor_flash_open(LX_NOR_FLASH  *nor_flash, CHAR *name, UINT (*nor_driver_initialize)(LX_NOR_FLASH *))
108 {
109 ULONG           sectors_per_block;
110 ULONG           sector_map_words;
111 ULONG           bit_map_words;
112 ULONG           bit_map_mask;
113 ULONG           total_header_words;
114 ULONG           header_sectors;
115 ULONG           *block_word_ptr;
116 ULONG           block_word;
117 ULONG           temp;
118 ULONG           free_sectors;
119 ULONG           used_sectors;
120 ULONG           *new_map_entry;
121 ULONG           *new_sector_address;
122 ULONG           erased_count, min_erased_count, max_erased_count, temp_erased_count, min_erased_blocks;
123 ULONG           j, k, l;
124 UINT            status;
125 #ifdef LX_FREE_SECTOR_DATA_VERIFY
126 ULONG           *sector_word_ptr;
127 ULONG           sector_word;
128 #endif
129 LX_NOR_FLASH   *tail_ptr;
130 LX_INTERRUPT_SAVE_AREA
131 
132     LX_PARAMETER_NOT_USED(name);
133 
134     /* Clear the NOR flash control block. User extension is not cleared.  */
135     LX_MEMSET(nor_flash, 0, (ULONG)((UCHAR*)&(nor_flash -> lx_nor_flash_open_previous) - (UCHAR*)nor_flash) + sizeof(nor_flash -> lx_nor_flash_open_previous));
136 
137     /* Call the flash driver's initialization function.  */
138     (nor_driver_initialize)(nor_flash);
139 
140 #ifndef LX_DIRECT_READ
141 
142     /* Determine if the driver supplied a RAM buffer for reading the NOR sector if direct read is not
143        supported.  */
144     if (nor_flash -> lx_nor_flash_sector_buffer == LX_NULL)
145     {
146 
147         /* Return an error.  */
148         return(LX_NO_MEMORY);
149     }
150 #endif
151 
152     /* Setup the offset to the free bit map.  */
153     nor_flash -> lx_nor_flash_block_free_bit_map_offset =  sizeof(LX_NOR_FLASH_BLOCK_HEADER)/sizeof(ULONG);
154 
155     /* Calculate the number of bits we need in the free physical sector bit map.  Subtract 1 to account for the
156        flash block header itself. The case where multiple physical sectors are needed for certain sized flash
157        devices is handled below.  */
158     sectors_per_block =  (nor_flash -> lx_nor_flash_words_per_block / LX_NOR_SECTOR_SIZE) - 1;
159 
160     /* Calculate the number of words required for the sector map array.  */
161     sector_map_words =  sectors_per_block;
162 
163     /* Calculate the number of words we need for the free physical sector bit map.  */
164     bit_map_words =  (sectors_per_block + 31)/ 32;
165 
166     /* Save the number of bit map words.  */
167     nor_flash -> lx_nor_flash_block_bit_map_words =  bit_map_words;
168 
169     /* Setup the offset (in words) to the array of physical sector mapping.  */
170     nor_flash -> lx_nor_flash_block_physical_sector_mapping_offset =  nor_flash -> lx_nor_flash_block_free_bit_map_offset + bit_map_words;
171 
172     /* Calculate the total number of words required for the flash block header.  */
173     total_header_words =  sizeof(LX_NOR_FLASH_BLOCK_HEADER)/sizeof(ULONG) + bit_map_words + sector_map_words;
174 
175     /* Determine if more physical sectors are needed, which can happen on large devices.  */
176     if (total_header_words <= LX_NOR_SECTOR_SIZE)
177     {
178 
179         /* Round up to the size of 1 physical sector.  */
180         total_header_words =  LX_NOR_SECTOR_SIZE;
181     }
182     else
183     {
184 
185         /* Otherwise calculate how many header sectors are necessary.  */
186         header_sectors =  (total_header_words-1)/LX_NOR_SECTOR_SIZE;
187 
188         /* Round up to the next sector.  */
189         header_sectors++;
190 
191         /* Compute the total header words, rounding to the next sector.  */
192         total_header_words =  header_sectors * LX_NOR_SECTOR_SIZE;
193 
194         /* Adjust the number of sectors per block.  */
195         sectors_per_block =  sectors_per_block - (header_sectors - 1);
196     }
197 
198     /* Save the offset to the sector area.  */
199     nor_flash -> lx_nor_flash_block_physical_sector_offset =  total_header_words;
200 
201     /* Save the physical sectors per block and total physical sectors.  */
202     nor_flash -> lx_nor_flash_physical_sectors_per_block =  sectors_per_block;
203     nor_flash -> lx_nor_flash_total_physical_sectors =      nor_flash -> lx_nor_flash_total_blocks * sectors_per_block;
204 
205     /* Build the free bit map mask, for the portion of the bit map that is less than 32 bits.  */
206     if ((sectors_per_block % 32) != 0)
207     {
208         bit_map_mask =  (ULONG)(1 << (sectors_per_block % 32));
209         bit_map_mask =  bit_map_mask - 1;
210     }
211     else
212     {
213 
214         /* Exactly 32 sectors for the bit map mask.  */
215         bit_map_mask =  LX_ALL_ONES;
216     }
217 
218     /* Save the free bit map mask in the control block.  */
219     nor_flash -> lx_nor_flash_block_bit_map_mask =  bit_map_mask;
220 
221     /* Setup default values for the max/min erased counts.  */
222     min_erased_count =  LX_ALL_ONES;
223     min_erased_blocks = 0;
224     max_erased_count =  0;
225 
226     /* Setup the block word pointer to the first word of the first block, which is effectively the
227        flash base address.  */
228     block_word_ptr =  nor_flash -> lx_nor_flash_base_address;
229 
230     /* Loop through the blocks to determine the minimum and maximum erase count.  */
231     for (l = 0; l < nor_flash -> lx_nor_flash_total_blocks; l++)
232     {
233 
234         /* Pickup the first word of the block. If the flash manager has executed before, this word contains the
235            erase count for the block. Otherwise, if the word is 0xFFFFFFFF, this flash block was either erased
236            or this is the first time it was used.  */
237 #ifdef LX_DIRECT_READ
238 
239         /* Read the word directly.  */
240         block_word =  *block_word_ptr;
241 #else
242 
243 
244 
245         status =  _lx_nor_flash_driver_read(nor_flash, block_word_ptr, &block_word, 1);
246 
247         /* Check for an error from flash driver. Drivers should never return an error..  */
248         if (status)
249         {
250 
251             /* Call system error handler.  */
252             _lx_nor_flash_system_error(nor_flash, status);
253 
254             /* Return an error.  */
255             return(LX_ERROR);
256         }
257 #endif
258 
259         /* Is the block erased?  */
260         if (((block_word & LX_BLOCK_ERASED) != LX_BLOCK_ERASED) && (block_word != LX_BLOCK_ERASE_STARTED))
261         {
262 
263             /* No, valid block.  Isolate the erased count.  */
264             erased_count =  (block_word & LX_BLOCK_ERASE_COUNT_MASK);
265 
266             /* Is the erased count the minimum?  */
267             if (erased_count == min_erased_count)
268             {
269 
270                 /* Yes, increment the minimum erased block count.  */
271                 min_erased_blocks++;
272             }
273 
274             /* Is this the new minimum?  */
275             if (erased_count < min_erased_count)
276             {
277 
278                 /* Yes, remember the new minimum.  */
279                 min_erased_count =  erased_count;
280 
281                 /* Reset the minimum erased block count.  */
282                 min_erased_blocks =  1;
283             }
284 
285             /* Is this the new maximum?  */
286             if (erased_count > max_erased_count)
287             {
288 
289                 /* Yes, remember the new maximum.  */
290                 max_erased_count =  erased_count;
291             }
292         }
293 
294         /* Move to the next flash block.  */
295         block_word_ptr =  block_word_ptr + (nor_flash -> lx_nor_flash_words_per_block);
296     }
297 
298     /* If we haven't found any erased counts, we can assume the flash is completely erased and needs to
299        be setup for the first time.  */
300     if (min_erased_count == LX_ALL_ONES)
301     {
302 
303         /* Indicate that this is the initial format.  */
304         nor_flash -> lx_nor_flash_diagnostic_initial_format =  LX_TRUE;
305 
306         /* Setup the block word pointer to the first word of the first block, which is effectively the
307            flash base address.  */
308         block_word_ptr =  nor_flash -> lx_nor_flash_base_address;
309 
310         /* Loop through the blocks to setup the flash the fist time.  */
311         for (l = 0; l < nor_flash -> lx_nor_flash_total_blocks; l++)
312         {
313 
314             /* Setup the free bit map that corresponds to the free physical sectors in this
315                block. Note that we only need to setup the portion of the free bit map that doesn't
316                have sectors associated with it.  */
317             status =  _lx_nor_flash_driver_write(nor_flash, block_word_ptr+(nor_flash -> lx_nor_flash_block_free_bit_map_offset + (bit_map_words-1)) , &bit_map_mask, 1);
318 
319             /* Check for an error from flash driver. Drivers should never return an error..  */
320             if (status)
321             {
322 
323                 /* Call system error handler.  */
324                 _lx_nor_flash_system_error(nor_flash, status);
325 
326                 /* Return an error.  */
327                 return(LX_ERROR);
328             }
329 
330             /* Setup the initial erase count to 1.  */
331             block_word =  ((ULONG) 1);
332 
333             /* Write the initial erase count for the block.  */
334             status =  _lx_nor_flash_driver_write(nor_flash, block_word_ptr, &block_word, 1);
335 
336             /* Check for an error from flash driver. Drivers should never return an error..  */
337             if (status)
338             {
339 
340                 /* Call system error handler.  */
341                 _lx_nor_flash_system_error(nor_flash, status);
342 
343                 /* Return an error.  */
344                 return(LX_ERROR);
345             }
346 
347             /* Update the overall minimum and maximum erase count.  */
348             nor_flash -> lx_nor_flash_minimum_erase_count =  1;
349             nor_flash -> lx_nor_flash_minimum_erased_blocks =  nor_flash -> lx_nor_flash_total_blocks;
350             nor_flash -> lx_nor_flash_maximum_erase_count =  1;
351 
352             /* Update the number of free physical sectors.  */
353             nor_flash -> lx_nor_flash_free_physical_sectors =   nor_flash -> lx_nor_flash_free_physical_sectors + sectors_per_block;
354 
355             /* Move to the next flash block.  */
356             block_word_ptr =  block_word_ptr + (nor_flash -> lx_nor_flash_words_per_block);
357         }
358     }
359     else
360     {
361 
362         /* At this point, we have a previously managed flash structure. This needs to be traversed to prepare for the
363            current flash operation.  */
364 
365         /* Default the flash free sector search to an invalid value.  */
366         nor_flash -> lx_nor_flash_free_block_search =  nor_flash -> lx_nor_flash_total_blocks;
367 
368         /* Setup the block word pointer to the first word of the first block, which is effectively the
369            flash base address.  */
370         block_word_ptr =  nor_flash -> lx_nor_flash_base_address;
371 
372         /* Loop through the blocks.  */
373         for (l = 0; l < nor_flash -> lx_nor_flash_total_blocks; l++)
374         {
375 
376             /* First, determine if this block has a valid erase count.  */
377 #ifdef LX_DIRECT_READ
378 
379             /* Read the word directly.  */
380             block_word =  *block_word_ptr;
381 #else
382             status =  _lx_nor_flash_driver_read(nor_flash, block_word_ptr, &block_word, 1);
383 
384             /* Check for an error from flash driver. Drivers should never return an error..  */
385             if (status)
386             {
387 
388                 /* Call system error handler.  */
389                 _lx_nor_flash_system_error(nor_flash, status);
390 
391                 /* Return an error.  */
392                 return(LX_ERROR);
393             }
394 #endif
395 
396             /* Is the block erased?  */
397             if (((block_word & LX_BLOCK_ERASED) == LX_BLOCK_ERASED) || (block_word == LX_BLOCK_ERASE_STARTED))
398             {
399 
400                 /* This can happen if we were previously in the process of erasing the flash block and a
401                    power interruption occurs.  It should only occur once though. */
402 
403                 /* Is this the first time?  */
404                 if (nor_flash -> lx_nor_flash_diagnostic_erased_block)
405                 {
406 
407                     /* No, this is a potential format error, since this should only happen once in a given
408                        NOR flash format.  */
409                     _lx_nor_flash_system_error(nor_flash, LX_SYSTEM_INVALID_BLOCK);
410 
411                     /* Return an error.  */
412                     return(LX_ERROR);
413                 }
414 
415                 /* Increment the erased block diagnostic.  */
416                 nor_flash -> lx_nor_flash_diagnostic_erased_block++;
417 
418                 /* Check to see if the block is erased. */
419 #ifdef LX_NOR_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
420                 status =  (nor_flash -> lx_nor_flash_driver_block_erased_verify)(nor_flash, l);
421 #else
422                 status =  (nor_flash -> lx_nor_flash_driver_block_erased_verify)(l);
423 #endif
424 
425                 /* Is the block completely erased?  */
426                 if (status != LX_SUCCESS)
427                 {
428 
429                     /* Is this the first time?  */
430                     if (nor_flash -> lx_nor_flash_diagnostic_re_erase_block)
431                     {
432 
433                         /* No, this is a potential format error, since this should only happen once in a given
434                            NOR flash format.  */
435                         _lx_nor_flash_system_error(nor_flash, LX_SYSTEM_INVALID_BLOCK);
436 
437                         /* Return an error.  */
438                         return(LX_ERROR);
439                     }
440 
441                     /* Increment the erased block diagnostic.  */
442                     nor_flash -> lx_nor_flash_diagnostic_re_erase_block++;
443 
444                     /* No, the block is not fully erased, erase it again.  */
445                     status =  _lx_nor_flash_driver_block_erase(nor_flash, l, max_erased_count);
446 
447                     /* Check for an error from flash driver. Drivers should never return an error..  */
448                     if (status)
449                     {
450 
451                         /* Call system error handler.  */
452                         _lx_nor_flash_system_error(nor_flash, status);
453 
454                         /* Return an error.  */
455                         return(LX_ERROR);
456                     }
457                 }
458 
459                 /* Setup the free bit map that corresponds to the free physical sectors in this
460                    block. Note that we only need to setup the portion of the free bit map that doesn't
461                    have sectors associated with it.  */
462                 status =  _lx_nor_flash_driver_write(nor_flash, block_word_ptr+(nor_flash -> lx_nor_flash_block_free_bit_map_offset + (bit_map_words-1)) , &bit_map_mask, 1);
463 
464                 /* Check for an error from flash driver. Drivers should never return an error..  */
465                 if (status)
466                 {
467 
468                     /* Call system error handler.  */
469                     _lx_nor_flash_system_error(nor_flash, status);
470 
471                     /* Return an error.  */
472                     return(LX_ERROR);
473                 }
474 
475                 /* Write the initial erase count for the block with upper bit set.  */
476                 temp_erased_count =  (max_erased_count | LX_BLOCK_ERASED);
477                 status =  _lx_nor_flash_driver_write(nor_flash, block_word_ptr, &temp_erased_count, 1);
478 
479                 /* Check for an error from flash driver. Drivers should never return an error..  */
480                 if (status)
481                 {
482 
483                     /* Call system error handler.  */
484                     _lx_nor_flash_system_error(nor_flash, status);
485 
486                     /* Return an error.  */
487                     return(LX_ERROR);
488                 }
489 
490                 /* Write the final initial erase count for the block.  */
491                 status =  _lx_nor_flash_driver_write(nor_flash, block_word_ptr, &max_erased_count, 1);
492 
493                 /* Check for an error from flash driver. Drivers should never return an error..  */
494                 if (status)
495                 {
496 
497                     /* Call system error handler.  */
498                     _lx_nor_flash_system_error(nor_flash, status);
499 
500                     /* Return an error.  */
501                     return(LX_ERROR);
502                 }
503 
504                 /* Update the number of free physical sectors.  */
505                 nor_flash -> lx_nor_flash_free_physical_sectors =   nor_flash -> lx_nor_flash_free_physical_sectors + sectors_per_block;
506             }
507             else
508             {
509 
510                 /* Calculate the number of free sectors from the free sector bit map.  */
511                 free_sectors =  0;
512                 for (j = 0; j < bit_map_words; j++)
513                 {
514 
515                     /* Read this word of the free sector bit map.  */
516 #ifdef LX_DIRECT_READ
517 
518                     /* Read the word directly.  */
519                     block_word =  *(block_word_ptr + nor_flash -> lx_nor_flash_block_free_bit_map_offset + j);
520 #else
521                     status =  _lx_nor_flash_driver_read(nor_flash, (block_word_ptr + nor_flash -> lx_nor_flash_block_free_bit_map_offset + j), &block_word, 1);
522 
523                     /* Check for an error from flash driver. Drivers should never return an error..  */
524                     if (status)
525                     {
526 
527                         /* Call system error handler.  */
528                         _lx_nor_flash_system_error(nor_flash, status);
529 
530                         /* Return an error.  */
531                         return(LX_ERROR);
532                     }
533 #endif
534 
535                     /* Count the number of set bits (free sectors).  */
536                     for (k = 0; k < 32; k++)
537                     {
538 
539                         /* Is this sector free?  */
540                         if (block_word & 1)
541                         {
542                             /* Yes, this sector is free, increment the free sectors count.  */
543                             free_sectors++;
544 
545                             /* Determine if we need to update the search pointer.  */
546                             if (nor_flash -> lx_nor_flash_free_block_search == nor_flash -> lx_nor_flash_total_blocks)
547                             {
548 
549                                 /* Remember the block with free sectors.  */
550                                 nor_flash -> lx_nor_flash_free_block_search =  l;
551                             }
552                         }
553 
554                         /* Shift down the free sector.  */
555                         block_word =  block_word >> 1;
556                     }
557                 }
558 
559                 /* Update the number of free physical sectors.  */
560                 nor_flash -> lx_nor_flash_free_physical_sectors =   nor_flash -> lx_nor_flash_free_physical_sectors + free_sectors;
561 
562                 /* We need to now examine the mapping list.  */
563 
564                 /* Calculate how many non-free sectors there are - this includes valid and obsolete sectors.  */
565                 used_sectors =  sectors_per_block - free_sectors;
566 
567                 /* Now walk the list of logical-physical sector mapping.  */
568                 for (j = 0; j < sectors_per_block; j++)
569                 {
570 
571                     /* Read this word of the sector mapping list.  */
572 #ifdef LX_DIRECT_READ
573 
574                     /* Read the word directly.  */
575                     block_word =  *(block_word_ptr + nor_flash -> lx_nor_flash_block_physical_sector_mapping_offset + j);
576 #else
577                     status =  _lx_nor_flash_driver_read(nor_flash, (block_word_ptr + nor_flash -> lx_nor_flash_block_physical_sector_mapping_offset + j), &block_word, 1);
578 
579                     /* Check for an error from flash driver. Drivers should never return an error..  */
580                     if (status)
581                     {
582 
583                         /* Call system error handler.  */
584                         _lx_nor_flash_system_error(nor_flash, status);
585 
586                         /* Return an error.  */
587                         return(LX_ERROR);
588                     }
589 #endif
590 
591                     /* Determine if we are expecting to find a used sector.   */
592                     if (used_sectors)
593                     {
594 
595                         /* Yes, we expect this entry to be used.  */
596 
597                         /* Is this sector in-use?  */
598                         if ((block_word & LX_NOR_LOGICAL_SECTOR_MASK) != LX_NOR_LOGICAL_SECTOR_MASK)
599                         {
600 
601                             /* Determine if the valid bit is set and the superceded bit is clear. This indicates the block was
602                                about to become obsolete.  */
603                             if ((block_word & LX_NOR_PHYSICAL_SECTOR_VALID) && ((block_word & LX_NOR_PHYSICAL_SECTOR_SUPERCEDED) == 0))
604                             {
605 
606 
607                                 /* Increment the being obsoleted count.  */
608                                 nor_flash -> lx_nor_flash_diagnostic_sector_being_obsoleted++;
609 
610                                 /* Save the currently mapped physical sectors.  */
611                                 temp =  nor_flash -> lx_nor_flash_mapped_physical_sectors;
612 
613                                 /* Indicate all the physical sectors are mapped for the purpose of this search.  */
614                                 nor_flash -> lx_nor_flash_mapped_physical_sectors =  nor_flash -> lx_nor_flash_total_physical_sectors;
615 
616                                 /* Yes, this block was about to become obsolete. Perform a search for a logical sector entry that
617                                    has both of these bits set.  */
618                                 _lx_nor_flash_logical_sector_find(nor_flash, (block_word & LX_NOR_LOGICAL_SECTOR_MASK), LX_TRUE, &new_map_entry, &new_sector_address);
619 
620                                 /* Restore the number of mapped physical sectors.  */
621                                 nor_flash -> lx_nor_flash_mapped_physical_sectors =  temp;
622 
623                                 /* Determine if the new logical sector entry is present.  */
624                                 if (new_map_entry)
625                                 {
626 
627                                     /* Yes, make the current entry obsolete in favor of the new entry.  */
628                                     block_word =  block_word & ~((ULONG) LX_NOR_PHYSICAL_SECTOR_VALID);
629                                     status =  _lx_nor_flash_driver_write(nor_flash, (block_word_ptr + nor_flash -> lx_nor_flash_block_physical_sector_mapping_offset + j), &block_word, 1);
630 
631                                     /* Check for an error from flash driver. Drivers should never return an error..  */
632                                     if (status)
633                                     {
634 
635                                         /* Call system error handler.  */
636                                         _lx_nor_flash_system_error(nor_flash, status);
637 
638                                         /* Return an error.  */
639                                         return(LX_ERROR);
640                                     }
641 
642                                     /* Is this the first time?  */
643                                     if (nor_flash -> lx_nor_flash_diagnostic_sector_obsoleted)
644                                     {
645 
646                                         /* No, this is a potential format error, since this should only happen once in a given
647                                            NOR flash format.  */
648                                         _lx_nor_flash_system_error(nor_flash, LX_SYSTEM_INVALID_FORMAT);
649 
650                                         /* Return an error.  */
651                                         return(LX_ERROR);
652                                     }
653 
654                                     /* Increment the obsoleted count.  */
655                                     nor_flash -> lx_nor_flash_diagnostic_sector_obsoleted++;
656                                 }
657                             }
658                         }
659 
660                         /* Determine if the sector is free.  */
661                         else if (block_word == LX_NOR_PHYSICAL_SECTOR_FREE)
662                         {
663 
664                             /* A free entry when there are still used sectors implies that the sector was allocated and a power interruption
665                                took place prior to writing the new logical sector number into the list.  */
666 
667                             /* Is this the first time?  */
668                             if (nor_flash -> lx_nor_flash_diagnostic_mapping_invalidated)
669                             {
670 
671                                 /* No, this is a potential format error, since this should only happen once in a given
672                                    NOR flash format.  */
673                                 _lx_nor_flash_system_error(nor_flash, LX_SYSTEM_INVALID_FORMAT);
674 
675                                 /* Return an error.  */
676                                 return(LX_ERROR);
677                             }
678 
679                             /* Write 0s out to this entry to invalidate the sector entry.  */
680                             block_word =  0;
681                             status =  _lx_nor_flash_driver_write(nor_flash, (block_word_ptr + nor_flash -> lx_nor_flash_block_physical_sector_mapping_offset + j), &block_word, 1);
682 
683                             /* Check for an error from flash driver. Drivers should never return an error..  */
684                             if (status)
685                             {
686 
687                                 /* Call system error handler.  */
688                                 _lx_nor_flash_system_error(nor_flash, status);
689 
690                                 /* Return an error.  */
691                                 return(LX_ERROR);
692                             }
693 
694                             /* Increment the number of mapping invalidates.  */
695                             nor_flash -> lx_nor_flash_diagnostic_mapping_invalidated++;
696                         }
697 
698                         /* Yes, now determine if the sector is obsolete.  */
699                         if ((block_word & LX_NOR_PHYSICAL_SECTOR_VALID) == 0)
700                         {
701 
702                             /* Increment the number of obsolete sectors.  */
703                             nor_flash -> lx_nor_flash_obsolete_physical_sectors++;
704                         }
705 
706                         /* Determine if the mapping for this sector isn't yet valid.  */
707                         else if (block_word & LX_NOR_PHYSICAL_SECTOR_MAPPING_NOT_VALID)
708                         {
709 
710                             /* Yes, a power interruption or reset occurred while the sector mapping entry was being written.  */
711 
712                             /* Increment the number of obsolete sectors.  */
713                             nor_flash -> lx_nor_flash_obsolete_physical_sectors++;
714 
715                             /* Increment the interrupted mapping counter.  */
716                             nor_flash -> lx_nor_flash_diagnostic_mapping_write_interrupted++;
717 
718                             /* Invalidate this entry - clearing valid bit, superceded bit and logical sector.  */
719                             block_word =  0;
720                             status =  _lx_nor_flash_driver_write(nor_flash, (block_word_ptr + nor_flash -> lx_nor_flash_block_physical_sector_mapping_offset + j), &block_word, 1);
721 
722                             /* Check for an error from flash driver. Drivers should never return an error..  */
723                             if (status)
724                             {
725 
726                                 /* Call system error handler.  */
727                                 _lx_nor_flash_system_error(nor_flash, status);
728 
729                                 /* Return an error.  */
730                                 return(LX_ERROR);
731                             }
732                         }
733                         else
734                         {
735                             /* Increment the number of mapped physical sectors.  */
736                             nor_flash -> lx_nor_flash_mapped_physical_sectors++;
737                         }
738 
739                         /* Decrease the number of used sectors.  */
740                         used_sectors--;
741                     }
742                     else
743                     {
744 
745                         /* No more used sectors in this flash block.  */
746 
747                         /* In this case the entry must be free or there is a serious NOR flash format error present.  */
748                         if (block_word != LX_NOR_PHYSICAL_SECTOR_FREE)
749                         {
750 
751                             /* Increment the sector not free diagnostic.  */
752                             nor_flash -> lx_nor_flash_diagnostic_sector_not_free++;
753 
754                             /* NOR flash format.  */
755                             _lx_nor_flash_system_error(nor_flash, LX_SYSTEM_INVALID_FORMAT);
756 
757                             /* Write 0s out to this entry to invalidate the sector entry.  */
758                             block_word =  0;
759                             status =  _lx_nor_flash_driver_write(nor_flash, (block_word_ptr + nor_flash -> lx_nor_flash_block_physical_sector_mapping_offset + j), &block_word, 1);
760 
761                             /* Check for an error from flash driver. Drivers should never return an error..  */
762                             if (status)
763                             {
764 
765                                 /* Call system error handler.  */
766                                 _lx_nor_flash_system_error(nor_flash, status);
767 
768                                 /* Return an error.  */
769                                 return(LX_ERROR);
770                             }
771                         }
772 
773 #ifdef LX_FREE_SECTOR_DATA_VERIFY
774 
775                         /* Pickup address of the free sector data area.  */
776                         sector_word_ptr =  block_word_ptr + (nor_flash -> lx_nor_flash_block_physical_sector_offset) + (j * LX_NOR_SECTOR_SIZE);
777 
778                         /* Determine if the data for this sector is free.  */
779                         for (k = 0; k < LX_NOR_SECTOR_SIZE; k++)
780                         {
781 
782 #ifdef LX_DIRECT_READ
783 
784                             /* Read the word directly.  */
785                             sector_word =  *(sector_word_ptr);
786 #else
787                             status =  _lx_nor_flash_driver_read(nor_flash, (sector_word_ptr), &sector_word, 1);
788 
789                             /* Check for an error from flash driver. Drivers should never return an error..  */
790                             if (status)
791                             {
792 
793                                 /* Call system error handler.  */
794                                 _lx_nor_flash_system_error(nor_flash, status);
795 
796                                 /* Return an error.  */
797                                 return(LX_ERROR);
798                             }
799 #endif
800 
801                             /* Determine if this word is not available.  */
802                             if (sector_word != LX_NOR_PHYSICAL_SECTOR_FREE)
803                             {
804 
805                                 /* Increment the sector data not free diagnostic.  */
806                                 nor_flash -> lx_nor_flash_diagnostic_sector_data_not_free++;
807 
808                                 /* This is a format error.  */
809                                 _lx_nor_flash_system_error(nor_flash, LX_SYSTEM_INVALID_BLOCK);
810 
811                                 /* Return an error.  */
812                                 return(LX_ERROR);
813                             }
814 
815                             /* Move to the next word in the sector.  */
816                             sector_word_ptr++;
817                         }
818 #endif
819                     }
820                 }
821             }
822 
823             /* Move to the next flash block.  */
824             block_word_ptr =  block_word_ptr + (nor_flash -> lx_nor_flash_words_per_block);
825         }
826 
827         /* Update the overall minimum and maximum erase count.  */
828         nor_flash -> lx_nor_flash_minimum_erase_count =  min_erased_count;
829         nor_flash -> lx_nor_flash_minimum_erased_blocks =  min_erased_blocks;
830         nor_flash -> lx_nor_flash_maximum_erase_count =  max_erased_count;
831 
832         /* Determine if we need to update the free sector search pointer.  */
833         if (nor_flash -> lx_nor_flash_free_block_search == nor_flash -> lx_nor_flash_total_blocks)
834         {
835 
836             /* Just start at the beginning.  */
837             nor_flash -> lx_nor_flash_free_block_search =  0;
838         }
839     }
840 
841 #ifdef LX_THREAD_SAFE_ENABLE
842 
843     /* If the thread safe option is enabled, create a ThreadX mutex that will be used in all external APIs
844        in order to provide thread-safe operation.  */
845     status =  tx_mutex_create(&nor_flash -> lx_nor_flash_mutex, "NOR Flash Mutex", TX_NO_INHERIT);
846 
847     /* Determine if the mutex creation encountered an error.  */
848     if (status != LX_SUCCESS)
849     {
850 
851         /* Call system error handler, since this should not happen.  */
852         _lx_nor_flash_system_error(nor_flash, LX_SYSTEM_MUTEX_CREATE_FAILED);
853 
854         /* Return error to caller.  */
855         return(LX_ERROR);
856     }
857 #endif
858 
859     /* Enable the sector mapping cache.  */
860     nor_flash -> lx_nor_flash_sector_mapping_cache_enabled =  LX_TRUE;
861 
862     /* Initialize the last found block and sector markers.  */
863     nor_flash -> lx_nor_flash_found_block_search =   0;
864     nor_flash -> lx_nor_flash_found_sector_search =  0;
865 
866     /* Lockout interrupts.  */
867     LX_DISABLE
868 
869     /* At this point, the NOR flash has been opened successfully.  Place the
870        NOR flash control block on the linked list of currently opened NOR flashes.  */
871 
872     /* Set the NOR flash state to open.  */
873     nor_flash -> lx_nor_flash_state =  LX_NOR_FLASH_OPENED;
874 
875     /* Place the NOR flash control block on the list of opened NOR flashes.  First,
876        check for an empty list.  */
877     if (_lx_nor_flash_opened_count)
878     {
879 
880         /* List is not empty - other NOR flashes are open.  */
881 
882         /* Pickup tail pointer.  */
883         tail_ptr =  _lx_nor_flash_opened_ptr -> lx_nor_flash_open_previous;
884 
885         /* Place the new NOR flash control block in the list.  */
886         _lx_nor_flash_opened_ptr -> lx_nor_flash_open_previous =  nor_flash;
887         tail_ptr -> lx_nor_flash_open_next =                       nor_flash;
888 
889         /* Setup this NOR flash's opened links.  */
890         nor_flash -> lx_nor_flash_open_previous =  tail_ptr;
891         nor_flash -> lx_nor_flash_open_next =      _lx_nor_flash_opened_ptr;
892     }
893     else
894     {
895 
896         /* The opened NOR flash list is empty.  Add the NOR flash to empty list.  */
897         _lx_nor_flash_opened_ptr =                 nor_flash;
898         nor_flash -> lx_nor_flash_open_next =      nor_flash;
899         nor_flash -> lx_nor_flash_open_previous =  nor_flash;
900     }
901 
902     /* Increment the opened NOR flash counter.  */
903     _lx_nor_flash_opened_count++;
904 
905     /* Restore interrupts.  */
906     LX_RESTORE
907 
908     /* Return a successful completion.  */
909     return(LX_SUCCESS);
910 }
911 
912