GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lx_nor_flash_open_extended.c Lines: 132 190 69.5 %
Date: 2026-01-12 23:08:29 Branches: 70 100 70.0 %

Line Branch Exec Source
1
/***************************************************************************
2
 * Copyright (c) 2025 Microsoft Corporation
3
 * Portion Copyright (c) 2025 STMicroelectronics
4
 *
5
 * This program and the accompanying materials are made available under the
6
 * terms of the MIT License which is available at
7
 * https://opensource.org/licenses/MIT.
8
 *
9
 * SPDX-License-Identifier: MIT
10
 **************************************************************************/
11
12
13
/**************************************************************************/
14
/**************************************************************************/
15
/**                                                                       */
16
/** LevelX Component                                                      */
17
/**                                                                       */
18
/**   NOR Flash                                                           */
19
/**                                                                       */
20
/**************************************************************************/
21
/**************************************************************************/
22
23
#define LX_SOURCE_CODE
24
25
26
/* Disable ThreadX error checking.  */
27
28
#ifndef LX_DISABLE_ERROR_CHECKING
29
#define LX_DISABLE_ERROR_CHECKING
30
#endif
31
32
33
/* Include necessary system files.  */
34
35
#include "lx_api.h"
36
37
/**************************************************************************/
38
/*                                                                        */
39
/*  FUNCTION                                               RELEASE        */
40
/*                                                                        */
41
/*    _lx_nor_flash_open_extended                         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
/*    nor_driver_info_ptr                   Driver user data pointer      */
58
/*                                                                        */
59
/*  OUTPUT                                                                */
60
/*                                                                        */
61
/*    return status                                                       */
62
/*                                                                        */
63
/*  CALLS                                                                 */
64
/*                                                                        */
65
/*    (nor_driver_initialize)               Driver initialize             */
66
/*    _lx_nor_flash_driver_read             Driver read                   */
67
/*    _lx_nor_flash_driver_write            Driver write                  */
68
/*    (lx_nor_flash_driver_block_erased_verify)                           */
69
/*                                          NOR flash verify block erased */
70
/*    _lx_nor_flash_driver_block_erase      Driver block erase            */
71
/*    _lx_nor_flash_logical_sector_find     Find logical sector           */
72
/*    _lx_nor_flash_system_error            System error handler          */
73
/*    tx_mutex_create                       Create thread-safe mutex      */
74
/*                                                                        */
75
/*  CALLED BY                                                             */
76
/*                                                                        */
77
/*    Application Code                                                    */
78
/*                                                                        */
79
/*  RELEASE HISTORY                                                       */
80
/*                                                                        */
81
/*    DATE              NAME                      DESCRIPTION             */
82
/*                                                                        */
83
/*  05-19-2020     William E. Lamie         Initial Version 6.0           */
84
/*  09-30-2020     William E. Lamie         Modified comment(s),          */
85
/*                                            resulting in version 6.1    */
86
/*  11-09-2020     William E. Lamie         Modified comment(s),          */
87
/*                                            fixed compiler warnings,    */
88
/*                                            resulting in version 6.1.2  */
89
/*  12-30-2020     William E. Lamie         Modified comment(s),          */
90
/*                                            fixed compiler warnings,    */
91
/*                                            resulting in version 6.1.3  */
92
/*  06-02-2021     Bhupendra Naphade        Modified comment(s), and      */
93
/*                                            updated product constants   */
94
/*                                            resulting in version 6.1.7  */
95
/*  03-08-2023     Xiuwen Cai               Modified comment(s),          */
96
/*                                            added new driver interface, */
97
/*                                            resulting in version 6.2.1  */
98
/*  10-31-2023     Xiuwen Cai               Modified comment(s),          */
99
/*                                            added count for minimum     */
100
/*                                            erased blocks, added        */
101
/*                                            obsolete count cache,       */
102
/*                                            avoided clearing user       */
103
/*                                            extension in flash control  */
104
/*                                            block,                      */
105
/*                                            resulting in version 6.3.0  */
106
/*                                                                        */
107
/**************************************************************************/
108
109
19
UINT  _lx_nor_flash_open_extended(LX_NOR_FLASH  *nor_flash, CHAR *name, UINT (*nor_driver_initialize)(LX_NOR_FLASH *), VOID *nor_driver_info_ptr)
110
{
111
ULONG           sectors_per_block;
112
ULONG           sector_map_words;
113
ULONG           bit_map_words;
114
ULONG           bit_map_mask;
115
ULONG           total_header_words;
116
ULONG           header_sectors;
117
ULONG           *block_word_ptr;
118
ULONG           block_word;
119
ULONG           temp;
120
ULONG           free_sectors;
121
ULONG           used_sectors;
122
ULONG           *new_map_entry;
123
ULONG           *new_sector_address;
124
ULONG           erased_count, min_erased_count, max_erased_count, temp_erased_count, min_erased_blocks;
125
ULONG           j, k, l;
126
UINT            status;
127
#ifdef LX_FREE_SECTOR_DATA_VERIFY
128
ULONG           *sector_word_ptr;
129
ULONG           sector_word;
130
#endif
131
LX_NOR_FLASH   *tail_ptr;
132
LX_INTERRUPT_SAVE_AREA
133
134
    LX_PARAMETER_NOT_USED(name);
135
136
    /* Clear the NOR flash control block. User extension is not cleared.  */
137
9291
    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));
138
139
    /* Pass the driver info ptr */
140
19
    nor_flash -> lx_nor_flash_driver_info_ptr = nor_driver_info_ptr;
141
142
    /* Call the flash driver's initialization function.  */
143
19
    (nor_driver_initialize)(nor_flash);
144
145
#ifndef LX_DIRECT_READ
146
147
    /* Determine if the driver supplied a RAM buffer for reading the NOR sector if direct read is not
148
       supported.  */
149
19
    if (nor_flash -> lx_nor_flash_sector_buffer == LX_NULL)
150
    {
151
152
        /* Return an error.  */
153
        return(LX_NO_MEMORY);
154
    }
155
#endif
156
157
    /* Setup the offset to the free bit map.  */
158
19
    nor_flash -> lx_nor_flash_block_free_bit_map_offset =  sizeof(LX_NOR_FLASH_BLOCK_HEADER)/sizeof(ULONG);
159
160
    /* Calculate the number of bits we need in the free physical sector bit map.  Subtract 1 to account for the
161
       flash block header itself. The case where multiple physical sectors are needed for certain sized flash
162
       devices is handled below.  */
163
19
    sectors_per_block =  (nor_flash -> lx_nor_flash_words_per_block / LX_NOR_SECTOR_SIZE) - 1;
164
165
    /* Calculate the number of words required for the sector map array.  */
166
19
    sector_map_words =  sectors_per_block;
167
168
    /* Calculate the number of words we need for the free physical sector bit map.  */
169
19
    bit_map_words =  (sectors_per_block + 31)/ 32;
170
171
    /* Save the number of bit map words.  */
172
19
    nor_flash -> lx_nor_flash_block_bit_map_words =  bit_map_words;
173
174
    /* Setup the offset (in words) to the array of physical sector mapping.  */
175
19
    nor_flash -> lx_nor_flash_block_physical_sector_mapping_offset =  nor_flash -> lx_nor_flash_block_free_bit_map_offset + bit_map_words;
176
177
    /* Calculate the total number of words required for the flash block header.  */
178
19
    total_header_words =  sizeof(LX_NOR_FLASH_BLOCK_HEADER)/sizeof(ULONG) + bit_map_words + sector_map_words;
179
180
    /* Determine if more physical sectors are needed, which can happen on large devices.  */
181
19
    if (total_header_words <= LX_NOR_SECTOR_SIZE)
182
    {
183
184
        /* Round up to the size of 1 physical sector.  */
185
19
        total_header_words =  LX_NOR_SECTOR_SIZE;
186
    }
187
    else
188
    {
189
190
        /* Otherwise calculate how many header sectors are necessary.  */
191
        header_sectors =  (total_header_words-1)/LX_NOR_SECTOR_SIZE;
192
193
        /* Round up to the next sector.  */
194
        header_sectors++;
195
196
        /* Compute the total header words, rounding to the next sector.  */
197
        total_header_words =  header_sectors * LX_NOR_SECTOR_SIZE;
198
199
        /* Adjust the number of sectors per block.  */
200
        sectors_per_block =  sectors_per_block - (header_sectors - 1);
201
    }
202
203
    /* Save the offset to the sector area.  */
204
19
    nor_flash -> lx_nor_flash_block_physical_sector_offset =  total_header_words;
205
206
    /* Save the physical sectors per block and total physical sectors.  */
207
19
    nor_flash -> lx_nor_flash_physical_sectors_per_block =  sectors_per_block;
208
19
    nor_flash -> lx_nor_flash_total_physical_sectors =      nor_flash -> lx_nor_flash_total_blocks * sectors_per_block;
209
210
    /* Build the free bit map mask, for the portion of the bit map that is less than 32 bits.  */
211
19
    if ((sectors_per_block % 32) != 0)
212
    {
213
19
        bit_map_mask =  (ULONG)(1 << (sectors_per_block % 32));
214
19
        bit_map_mask =  bit_map_mask - 1;
215
    }
216
    else
217
    {
218
219
        /* Exactly 32 sectors for the bit map mask.  */
220
        bit_map_mask =  LX_ALL_ONES;
221
    }
222
223
    /* Save the free bit map mask in the control block.  */
224
19
    nor_flash -> lx_nor_flash_block_bit_map_mask =  bit_map_mask;
225
226
    /* Setup default values for the max/min erased counts.  */
227
19
    min_erased_count =  LX_ALL_ONES;
228
19
    min_erased_blocks = 0;
229
19
    max_erased_count =  0;
230
231
    /* Setup the block word pointer to the first word of the first block, which is effectively the
232
       flash base address.  */
233
19
    block_word_ptr =  nor_flash -> lx_nor_flash_base_address;
234
235
    /* Loop through the blocks to determine the minimum and maximum erase count.  */
236
171
    for (l = 0; l < nor_flash -> lx_nor_flash_total_blocks; l++)
237
    {
238
239
            /* Pickup the first word of the block. If the flash manager has executed before, this word contains the
240
            erase count for the block. Otherwise, if the word is 0xFFFFFFFF, this flash block was either erased
241
            or this is the first time it was used.  */
242
#ifdef LX_DIRECT_READ
243
244
            /* Read the word directly.  */
245
            block_word =  *block_word_ptr;
246
#else
247
248
152
            status =  _lx_nor_flash_driver_read(nor_flash, block_word_ptr, &block_word, 1);
249
250
            /* Check for an error from flash driver. Drivers should never return an error..  */
251
152
            if (status)
252
            {
253
254
                /* Call system error handler.  */
255
                _lx_nor_flash_system_error(nor_flash, status);
256
257
                /* Return an error.  */
258
                return(LX_ERROR);
259
            }
260
#endif
261
262
            /* Is the block erased?  */
263

152
            if (((block_word & LX_BLOCK_ERASED) != LX_BLOCK_ERASED) && (block_word != LX_BLOCK_ERASE_STARTED))
264
            {
265
266
                /* No, valid block.  Isolate the erased count.  */
267
92
                erased_count =  (block_word & LX_BLOCK_ERASE_COUNT_MASK);
268
269
                /* Is the erased count the minimum?  */
270
92
                if (erased_count == min_erased_count)
271
                {
272
273
                    /* Yes, increment the minimum erased block count.  */
274
80
                    min_erased_blocks++;
275
                }
276
277
                /* Is this the new minimum?  */
278
92
                if (erased_count < min_erased_count)
279
                {
280
281
                    /* Yes, remember the new minimum.  */
282
12
                    min_erased_count =  erased_count;
283
284
                    /* Reset the minimum erased block count.  */
285
12
                    min_erased_blocks =  1;
286
                }
287
288
                /* Is this the new maximum?  */
289
92
                if (erased_count > max_erased_count)
290
                {
291
292
                    /* Yes, remember the new maximum.  */
293
12
                    max_erased_count =  erased_count;
294
                }
295
            }
296
297
            /* Move to the next flash block.  */
298
152
            block_word_ptr =  block_word_ptr + (nor_flash -> lx_nor_flash_words_per_block);
299
        }
300
301
    /* If we haven't found any erased counts, we can assume the flash is completely erased and needs to
302
       be setup for the first time.  */
303
19
    if (min_erased_count == LX_ALL_ONES)
304
    {
305
306
        /* Indicate that this is the initial format.  */
307
7
        nor_flash -> lx_nor_flash_diagnostic_initial_format =  LX_TRUE;
308
309
        /* Setup the block word pointer to the first word of the first block, which is effectively the
310
           flash base address.  */
311
7
        block_word_ptr =  nor_flash -> lx_nor_flash_base_address;
312
313
        /* Loop through the blocks to setup the flash the fist time.  */
314
63
        for (l = 0; l < nor_flash -> lx_nor_flash_total_blocks; l++)
315
        {
316
317
            /* Setup the free bit map that corresponds to the free physical sectors in this
318
               block. Note that we only need to setup the portion of the free bit map that doesn't
319
               have sectors associated with it.  */
320
56
            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);
321
322
            /* Check for an error from flash driver. Drivers should never return an error..  */
323
56
            if (status)
324
            {
325
326
                /* Call system error handler.  */
327
                _lx_nor_flash_system_error(nor_flash, status);
328
329
                /* Return an error.  */
330
                return(LX_ERROR);
331
            }
332
333
            /* Setup the initial erase count to 1.  */
334
56
            block_word =  ((ULONG) 1);
335
336
            /* Write the initial erase count for the block.  */
337
56
            status =  _lx_nor_flash_driver_write(nor_flash, block_word_ptr, &block_word, 1);
338
339
            /* Check for an error from flash driver. Drivers should never return an error..  */
340
56
            if (status)
341
            {
342
343
                /* Call system error handler.  */
344
                _lx_nor_flash_system_error(nor_flash, status);
345
346
                /* Return an error.  */
347
                return(LX_ERROR);
348
            }
349
350
            /* Update the overall minimum and maximum erase count.  */
351
56
            nor_flash -> lx_nor_flash_minimum_erase_count =  1;
352
56
            nor_flash -> lx_nor_flash_minimum_erased_blocks =  nor_flash -> lx_nor_flash_total_blocks;
353
56
            nor_flash -> lx_nor_flash_maximum_erase_count =  1;
354
355
            /* Update the number of free physical sectors.  */
356
56
            nor_flash -> lx_nor_flash_free_physical_sectors =   nor_flash -> lx_nor_flash_free_physical_sectors + sectors_per_block;
357
358
            /* Move to the next flash block.  */
359
56
            block_word_ptr =  block_word_ptr + (nor_flash -> lx_nor_flash_words_per_block);
360
        }
361
    }
362
    else
363
    {
364
365
        /* At this point, we have a previously managed flash structure. This needs to be traversed to prepare for the
366
           current flash operation.  */
367
368
        /* Default the flash free sector search to an invalid value.  */
369
12
        nor_flash -> lx_nor_flash_free_block_search =  nor_flash -> lx_nor_flash_total_blocks;
370
371
        /* Setup the block word pointer to the first word of the first block, which is effectively the
372
           flash base address.  */
373
12
        block_word_ptr =  nor_flash -> lx_nor_flash_base_address;
374
375
        /* Loop through the blocks.  */
376
108
        for (l = 0; l < nor_flash -> lx_nor_flash_total_blocks; l++)
377
        {
378
379
            /* First, determine if this block has a valid erase count.  */
380
#ifdef LX_DIRECT_READ
381
382
            /* Read the word directly.  */
383
            block_word =  *block_word_ptr;
384
#else
385
96
            status =  _lx_nor_flash_driver_read(nor_flash, block_word_ptr, &block_word, 1);
386
387
            /* Check for an error from flash driver. Drivers should never return an error..  */
388
96
            if (status)
389
            {
390
391
                /* Call system error handler.  */
392
                _lx_nor_flash_system_error(nor_flash, status);
393
394
                /* Return an error.  */
395
                return(LX_ERROR);
396
            }
397
#endif
398
399
            /* Is the block erased?  */
400

96
            if (((block_word & LX_BLOCK_ERASED) == LX_BLOCK_ERASED) || (block_word == LX_BLOCK_ERASE_STARTED))
401
            {
402
403
                /* This can happen if we were previously in the process of erasing the flash block and a
404
                   power interruption occurs.  It should only occur once though. */
405
406
                /* Is this the first time?  */
407
4
                if (nor_flash -> lx_nor_flash_diagnostic_erased_block)
408
                {
409
410
                    /* No, this is a potential format error, since this should only happen once in a given
411
                       NOR flash format.  */
412
                    _lx_nor_flash_system_error(nor_flash, LX_SYSTEM_INVALID_BLOCK);
413
414
                    /* Return an error.  */
415
                    return(LX_ERROR);
416
                }
417
418
                /* Increment the erased block diagnostic.  */
419
4
                nor_flash -> lx_nor_flash_diagnostic_erased_block++;
420
421
                /* Check to see if the block is erased. */
422
#ifdef LX_NOR_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
423
                status =  (nor_flash -> lx_nor_flash_driver_block_erased_verify)(nor_flash, l);
424
#else
425
4
                status =  (nor_flash -> lx_nor_flash_driver_block_erased_verify)(l);
426
#endif
427
428
                /* Is the block completely erased?  */
429
4
                if (status != LX_SUCCESS)
430
                {
431
432
                    /* Is this the first time?  */
433
2
                    if (nor_flash -> lx_nor_flash_diagnostic_re_erase_block)
434
                    {
435
436
                        /* No, this is a potential format error, since this should only happen once in a given
437
                           NOR flash format.  */
438
                        _lx_nor_flash_system_error(nor_flash, LX_SYSTEM_INVALID_BLOCK);
439
440
                        /* Return an error.  */
441
                        return(LX_ERROR);
442
                    }
443
444
                    /* Increment the erased block diagnostic.  */
445
2
                    nor_flash -> lx_nor_flash_diagnostic_re_erase_block++;
446
447
                    /* No, the block is not fully erased, erase it again.  */
448
2
                    status =  _lx_nor_flash_driver_block_erase(nor_flash, l, max_erased_count);
449
450
                    /* Check for an error from flash driver. Drivers should never return an error..  */
451
2
                    if (status)
452
                    {
453
454
                        /* Call system error handler.  */
455
                        _lx_nor_flash_system_error(nor_flash, status);
456
457
                        /* Return an error.  */
458
                        return(LX_ERROR);
459
                    }
460
                }
461
462
                /* Setup the free bit map that corresponds to the free physical sectors in this
463
                   block. Note that we only need to setup the portion of the free bit map that doesn't
464
                   have sectors associated with it.  */
465
4
                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);
466
467
                /* Check for an error from flash driver. Drivers should never return an error..  */
468
4
                if (status)
469
                {
470
471
                    /* Call system error handler.  */
472
                    _lx_nor_flash_system_error(nor_flash, status);
473
474
                    /* Return an error.  */
475
                    return(LX_ERROR);
476
                }
477
478
                /* Write the initial erase count for the block with upper bit set.  */
479
4
                temp_erased_count =  (max_erased_count | LX_BLOCK_ERASED);
480
4
                status =  _lx_nor_flash_driver_write(nor_flash, block_word_ptr, &temp_erased_count, 1);
481
482
                /* Check for an error from flash driver. Drivers should never return an error..  */
483
4
                if (status)
484
                {
485
486
                    /* Call system error handler.  */
487
                    _lx_nor_flash_system_error(nor_flash, status);
488
489
                    /* Return an error.  */
490
                    return(LX_ERROR);
491
                }
492
493
                /* Write the final initial erase count for the block.  */
494
4
                status =  _lx_nor_flash_driver_write(nor_flash, block_word_ptr, &max_erased_count, 1);
495
496
                /* Check for an error from flash driver. Drivers should never return an error..  */
497
4
                if (status)
498
                {
499
500
                    /* Call system error handler.  */
501
                    _lx_nor_flash_system_error(nor_flash, status);
502
503
                    /* Return an error.  */
504
                    return(LX_ERROR);
505
                }
506
507
                /* Update the number of free physical sectors.  */
508
4
                nor_flash -> lx_nor_flash_free_physical_sectors =   nor_flash -> lx_nor_flash_free_physical_sectors + sectors_per_block;
509
            }
510
            else
511
            {
512
513
                /* Calculate the number of free sectors from the free sector bit map.  */
514
92
                free_sectors =  0;
515
184
                for (j = 0; j < bit_map_words; j++)
516
                {
517
518
                    /* Read this word of the free sector bit map.  */
519
#ifdef LX_DIRECT_READ
520
521
                    /* Read the word directly.  */
522
                    block_word =  *(block_word_ptr + nor_flash -> lx_nor_flash_block_free_bit_map_offset + j);
523
#else
524
92
                    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);
525
526
                    /* Check for an error from flash driver. Drivers should never return an error..  */
527
92
                    if (status)
528
                    {
529
530
                        /* Call system error handler.  */
531
                        _lx_nor_flash_system_error(nor_flash, status);
532
533
                        /* Return an error.  */
534
                        return(LX_ERROR);
535
                    }
536
#endif
537
538
                    /* Count the number of set bits (free sectors).  */
539
3036
                    for (k = 0; k < 32; k++)
540
                    {
541
542
                        /* Is this sector free?  */
543
2944
                        if (block_word & 1)
544
                        {
545
                            /* Yes, this sector is free, increment the free sectors count.  */
546
1252
                            free_sectors++;
547
548
                            /* Determine if we need to update the search pointer.  */
549
1252
                            if (nor_flash -> lx_nor_flash_free_block_search == nor_flash -> lx_nor_flash_total_blocks)
550
                            {
551
552
                                /* Remember the block with free sectors.  */
553
12
                                nor_flash -> lx_nor_flash_free_block_search =  l;
554
                            }
555
                        }
556
557
                        /* Shift down the free sector.  */
558
2944
                        block_word =  block_word >> 1;
559
                    }
560
                }
561
562
                /* Update the number of free physical sectors.  */
563
92
                nor_flash -> lx_nor_flash_free_physical_sectors =   nor_flash -> lx_nor_flash_free_physical_sectors + free_sectors;
564
565
                /* We need to now examine the mapping list.  */
566
567
                /* Calculate how many non-free sectors there are - this includes valid and obsolete sectors.  */
568
92
                used_sectors =  sectors_per_block - free_sectors;
569
570
                /* Now walk the list of logical-physical sector mapping.  */
571
1472
                for (j = 0; j < sectors_per_block; j++)
572
                {
573
574
                    /* Read this word of the sector mapping list.  */
575
#ifdef LX_DIRECT_READ
576
577
                    /* Read the word directly.  */
578
                    block_word =  *(block_word_ptr + nor_flash -> lx_nor_flash_block_physical_sector_mapping_offset + j);
579
#else
580
1380
                    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);
581
582
                    /* Check for an error from flash driver. Drivers should never return an error..  */
583
1380
                    if (status)
584
                    {
585
586
                        /* Call system error handler.  */
587
                        _lx_nor_flash_system_error(nor_flash, status);
588
589
                        /* Return an error.  */
590
                        return(LX_ERROR);
591
                    }
592
#endif
593
594
                    /* Determine if we are expecting to find a used sector.   */
595
1380
                    if (used_sectors)
596
                    {
597
598
                        /* Yes, we expect this entry to be used.  */
599
600
                        /* Is this sector in-use?  */
601
128
                        if ((block_word & LX_NOR_LOGICAL_SECTOR_MASK) != LX_NOR_LOGICAL_SECTOR_MASK)
602
                        {
603
604
                            /* Determine if the valid bit is set and the superceded bit is clear. This indicates the block was
605
                               about to become obsolete.  */
606

122
                            if ((block_word & LX_NOR_PHYSICAL_SECTOR_VALID) && ((block_word & LX_NOR_PHYSICAL_SECTOR_SUPERCEDED) == 0))
607
                            {
608
609
610
                                /* Increment the being obsoleted count.  */
611
4
                                nor_flash -> lx_nor_flash_diagnostic_sector_being_obsoleted++;
612
613
                                /* Save the currently mapped physical sectors.  */
614
4
                                temp =  nor_flash -> lx_nor_flash_mapped_physical_sectors;
615
616
                                /* Indicate all the physical sectors are mapped for the purpose of this search.  */
617
4
                                nor_flash -> lx_nor_flash_mapped_physical_sectors =  nor_flash -> lx_nor_flash_total_physical_sectors;
618
619
                                /* Yes, this block was about to become obsolete. Perform a search for a logical sector entry that
620
                                   has both of these bits set.  */
621
4
                                _lx_nor_flash_logical_sector_find(nor_flash, (block_word & LX_NOR_LOGICAL_SECTOR_MASK), LX_TRUE, &new_map_entry, &new_sector_address);
622
623
                                /* Restore the number of mapped physical sectors.  */
624
4
                                nor_flash -> lx_nor_flash_mapped_physical_sectors =  temp;
625
626
                                /* Determine if the new logical sector entry is present.  */
627
4
                                if (new_map_entry)
628
                                {
629
630
                                    /* Yes, make the current entry obsolete in favor of the new entry.  */
631
2
                                    block_word =  block_word & ~((ULONG) LX_NOR_PHYSICAL_SECTOR_VALID);
632
2
                                    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);
633
634
                                    /* Check for an error from flash driver. Drivers should never return an error..  */
635
2
                                    if (status)
636
                                    {
637
638
                                        /* Call system error handler.  */
639
                                        _lx_nor_flash_system_error(nor_flash, status);
640
641
                                        /* Return an error.  */
642
                                        return(LX_ERROR);
643
                                    }
644
645
                                    /* Is this the first time?  */
646
2
                                    if (nor_flash -> lx_nor_flash_diagnostic_sector_obsoleted)
647
                                    {
648
649
                                        /* No, this is a potential format error, since this should only happen once in a given
650
                                           NOR flash format.  */
651
                                        _lx_nor_flash_system_error(nor_flash, LX_SYSTEM_INVALID_FORMAT);
652
653
                                        /* Return an error.  */
654
                                        return(LX_ERROR);
655
                                    }
656
657
                                    /* Increment the obsoleted count.  */
658
2
                                    nor_flash -> lx_nor_flash_diagnostic_sector_obsoleted++;
659
                                }
660
                            }
661
                        }
662
663
                        /* Determine if the sector is free.  */
664
6
                        else if (block_word == LX_NOR_PHYSICAL_SECTOR_FREE)
665
                        {
666
667
                            /* A free entry when there are still used sectors implies that the sector was allocated and a power interruption
668
                               took place prior to writing the new logical sector number into the list.  */
669
670
                            /* Is this the first time?  */
671
6
                            if (nor_flash -> lx_nor_flash_diagnostic_mapping_invalidated)
672
                            {
673
674
                                /* No, this is a potential format error, since this should only happen once in a given
675
                                   NOR flash format.  */
676
                                _lx_nor_flash_system_error(nor_flash, LX_SYSTEM_INVALID_FORMAT);
677
678
                                /* Return an error.  */
679
                                return(LX_ERROR);
680
                            }
681
682
                            /* Write 0s out to this entry to invalidate the sector entry.  */
683
6
                            block_word =  0;
684
6
                            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);
685
686
                            /* Check for an error from flash driver. Drivers should never return an error..  */
687
6
                            if (status)
688
                            {
689
690
                                /* Call system error handler.  */
691
                                _lx_nor_flash_system_error(nor_flash, status);
692
693
                                /* Return an error.  */
694
                                return(LX_ERROR);
695
                            }
696
697
                            /* Increment the number of mapping invalidates.  */
698
6
                            nor_flash -> lx_nor_flash_diagnostic_mapping_invalidated++;
699
                        }
700
701
                        /* Yes, now determine if the sector is obsolete.  */
702
128
                        if ((block_word & LX_NOR_PHYSICAL_SECTOR_VALID) == 0)
703
                        {
704
705
                            /* Increment the number of obsolete sectors.  */
706
20
                            nor_flash -> lx_nor_flash_obsolete_physical_sectors++;
707
                        }
708
709
                        /* Determine if the mapping for this sector isn't yet valid.  */
710
108
                        else if (block_word & LX_NOR_PHYSICAL_SECTOR_MAPPING_NOT_VALID)
711
                        {
712
713
                            /* Yes, a power interruption or reset occurred while the sector mapping entry was being written.  */
714
715
                            /* Increment the number of obsolete sectors.  */
716
                            nor_flash -> lx_nor_flash_obsolete_physical_sectors++;
717
718
                            /* Increment the interrupted mapping counter.  */
719
                            nor_flash -> lx_nor_flash_diagnostic_mapping_write_interrupted++;
720
721
                            /* Invalidate this entry - clearing valid bit, superceded bit and logical sector.  */
722
                            block_word =  0;
723
                            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);
724
725
                            /* Check for an error from flash driver. Drivers should never return an error..  */
726
                            if (status)
727
                            {
728
729
                                /* Call system error handler.  */
730
                                _lx_nor_flash_system_error(nor_flash, status);
731
732
                                /* Return an error.  */
733
                                return(LX_ERROR);
734
                            }
735
                        }
736
                        else
737
                        {
738
                            /* Increment the number of mapped physical sectors.  */
739
108
                            nor_flash -> lx_nor_flash_mapped_physical_sectors++;
740
                        }
741
742
                        /* Decrease the number of used sectors.  */
743
128
                        used_sectors--;
744
                    }
745
                    else
746
                    {
747
748
                        /* No more used sectors in this flash block.  */
749
750
                        /* In this case the entry must be free or there is a serious NOR flash format error present.  */
751
1252
                        if (block_word != LX_NOR_PHYSICAL_SECTOR_FREE)
752
                        {
753
754
                            /* Increment the sector not free diagnostic.  */
755
                            nor_flash -> lx_nor_flash_diagnostic_sector_not_free++;
756
757
                            /* NOR flash format.  */
758
                            _lx_nor_flash_system_error(nor_flash, LX_SYSTEM_INVALID_FORMAT);
759
760
                            /* Write 0s out to this entry to invalidate the sector entry.  */
761
                            block_word =  0;
762
                            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);
763
764
                            /* Check for an error from flash driver. Drivers should never return an error..  */
765
                            if (status)
766
                            {
767
768
                                /* Call system error handler.  */
769
                                _lx_nor_flash_system_error(nor_flash, status);
770
771
                                /* Return an error.  */
772
                                return(LX_ERROR);
773
                            }
774
                        }
775
776
#ifdef LX_FREE_SECTOR_DATA_VERIFY
777
778
                        /* Pickup address of the free sector data area.  */
779
                        sector_word_ptr =  block_word_ptr + (nor_flash -> lx_nor_flash_block_physical_sector_offset) + (j * LX_NOR_SECTOR_SIZE);
780
781
                        /* Determine if the data for this sector is free.  */
782
                        for (k = 0; k < LX_NOR_SECTOR_SIZE; k++)
783
                        {
784
785
#ifdef LX_DIRECT_READ
786
787
                            /* Read the word directly.  */
788
                            sector_word =  *(sector_word_ptr);
789
#else
790
                            status =  _lx_nor_flash_driver_read(nor_flash, (sector_word_ptr), &sector_word, 1);
791
792
                            /* Check for an error from flash driver. Drivers should never return an error..  */
793
                            if (status)
794
                            {
795
796
                                /* Call system error handler.  */
797
                                _lx_nor_flash_system_error(nor_flash, status);
798
799
                                /* Return an error.  */
800
                                return(LX_ERROR);
801
                            }
802
#endif
803
804
                            /* Determine if this word is not available.  */
805
                            if (sector_word != LX_NOR_PHYSICAL_SECTOR_FREE)
806
                            {
807
808
                                /* Increment the sector data not free diagnostic.  */
809
                                nor_flash -> lx_nor_flash_diagnostic_sector_data_not_free++;
810
811
                                /* This is a format error.  */
812
                                _lx_nor_flash_system_error(nor_flash, LX_SYSTEM_INVALID_BLOCK);
813
814
                                /* Return an error.  */
815
                                return(LX_ERROR);
816
                            }
817
818
                            /* Move to the next word in the sector.  */
819
                            sector_word_ptr++;
820
                        }
821
#endif
822
                    }
823
                }
824
            }
825
826
            /* Move to the next flash block.  */
827
96
            block_word_ptr =  block_word_ptr + (nor_flash -> lx_nor_flash_words_per_block);
828
        }
829
830
        /* Update the overall minimum and maximum erase count.  */
831
12
        nor_flash -> lx_nor_flash_minimum_erase_count =  min_erased_count;
832
12
        nor_flash -> lx_nor_flash_minimum_erased_blocks =  min_erased_blocks;
833
12
        nor_flash -> lx_nor_flash_maximum_erase_count =  max_erased_count;
834
835
        /* Determine if we need to update the free sector search pointer.  */
836
12
        if (nor_flash -> lx_nor_flash_free_block_search == nor_flash -> lx_nor_flash_total_blocks)
837
        {
838
839
            /* Just start at the beginning.  */
840
            nor_flash -> lx_nor_flash_free_block_search =  0;
841
        }
842
    }
843
844
#ifdef LX_THREAD_SAFE_ENABLE
845
846
    /* If the thread safe option is enabled, create a ThreadX mutex that will be used in all external APIs
847
       in order to provide thread-safe operation.  */
848
    status =  tx_mutex_create(&nor_flash -> lx_nor_flash_mutex, "NOR Flash Mutex", TX_NO_INHERIT);
849
850
    /* Determine if the mutex creation encountered an error.  */
851
    if (status != LX_SUCCESS)
852
    {
853
854
        /* Call system error handler, since this should not happen.  */
855
        _lx_nor_flash_system_error(nor_flash, LX_SYSTEM_MUTEX_CREATE_FAILED);
856
857
        /* Return error to caller.  */
858
        return(LX_ERROR);
859
    }
860
#endif
861
862
    /* Enable the sector mapping cache.  */
863
19
    nor_flash -> lx_nor_flash_sector_mapping_cache_enabled =  LX_TRUE;
864
865
    /* Initialize the last found block and sector markers.  */
866
19
    nor_flash -> lx_nor_flash_found_block_search =   0;
867
19
    nor_flash -> lx_nor_flash_found_sector_search =  0;
868
869
    /* Lockout interrupts.  */
870
19
    LX_DISABLE
871
872
    /* At this point, the NOR flash has been opened successfully.  Place the
873
       NOR flash control block on the linked list of currently opened NOR flashes.  */
874
875
    /* Set the NOR flash state to open.  */
876
19
    nor_flash -> lx_nor_flash_state =  LX_NOR_FLASH_OPENED;
877
878
    /* Place the NOR flash control block on the list of opened NOR flashes.  First,
879
       check for an empty list.  */
880
19
    if (_lx_nor_flash_opened_count)
881
    {
882
883
        /* List is not empty - other NOR flashes are open.  */
884
885
        /* Pickup tail pointer.  */
886
        tail_ptr =  _lx_nor_flash_opened_ptr -> lx_nor_flash_open_previous;
887
888
        /* Place the new NOR flash control block in the list.  */
889
        _lx_nor_flash_opened_ptr -> lx_nor_flash_open_previous =  nor_flash;
890
        tail_ptr -> lx_nor_flash_open_next =                       nor_flash;
891
892
        /* Setup this NOR flash's opened links.  */
893
        nor_flash -> lx_nor_flash_open_previous =  tail_ptr;
894
        nor_flash -> lx_nor_flash_open_next =      _lx_nor_flash_opened_ptr;
895
    }
896
    else
897
    {
898
899
        /* The opened NOR flash list is empty.  Add the NOR flash to empty list.  */
900
19
        _lx_nor_flash_opened_ptr =                 nor_flash;
901
19
        nor_flash -> lx_nor_flash_open_next =      nor_flash;
902
19
        nor_flash -> lx_nor_flash_open_previous =  nor_flash;
903
    }
904
905
    /* Increment the opened NOR flash counter.  */
906
19
    _lx_nor_flash_opened_count++;
907
908
    /* Restore interrupts.  */
909
19
    LX_RESTORE
910
911
    /* Return a successful completion.  */
912
19
    return(LX_SUCCESS);
913
}
914