GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lx_nor_flash_open_extended.c Lines: 132 190 69.5 %
Date: 2026-03-06 18:45:40 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
/**************************************************************************/
80
81
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)
82
{
83
ULONG           sectors_per_block;
84
ULONG           sector_map_words;
85
ULONG           bit_map_words;
86
ULONG           bit_map_mask;
87
ULONG           total_header_words;
88
ULONG           header_sectors;
89
ULONG           *block_word_ptr;
90
ULONG           block_word;
91
ULONG           temp;
92
ULONG           free_sectors;
93
ULONG           used_sectors;
94
ULONG           *new_map_entry;
95
ULONG           *new_sector_address;
96
ULONG           erased_count, min_erased_count, max_erased_count, temp_erased_count, min_erased_blocks;
97
ULONG           j, k, l;
98
UINT            status;
99
#ifdef LX_FREE_SECTOR_DATA_VERIFY
100
ULONG           *sector_word_ptr;
101
ULONG           sector_word;
102
#endif
103
LX_NOR_FLASH   *tail_ptr;
104
LX_INTERRUPT_SAVE_AREA
105
106
    LX_PARAMETER_NOT_USED(name);
107
108
    /* Clear the NOR flash control block. User extension is not cleared.  */
109
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));
110
111
    /* Pass the driver info ptr */
112
19
    nor_flash -> lx_nor_flash_driver_info_ptr = nor_driver_info_ptr;
113
114
    /* Call the flash driver's initialization function.  */
115
19
    (nor_driver_initialize)(nor_flash);
116
117
#ifndef LX_DIRECT_READ
118
119
    /* Determine if the driver supplied a RAM buffer for reading the NOR sector if direct read is not
120
       supported.  */
121
19
    if (nor_flash -> lx_nor_flash_sector_buffer == LX_NULL)
122
    {
123
124
        /* Return an error.  */
125
        return(LX_NO_MEMORY);
126
    }
127
#endif
128
129
    /* Setup the offset to the free bit map.  */
130
19
    nor_flash -> lx_nor_flash_block_free_bit_map_offset =  sizeof(LX_NOR_FLASH_BLOCK_HEADER)/sizeof(ULONG);
131
132
    /* Calculate the number of bits we need in the free physical sector bit map.  Subtract 1 to account for the
133
       flash block header itself. The case where multiple physical sectors are needed for certain sized flash
134
       devices is handled below.  */
135
19
    sectors_per_block =  (nor_flash -> lx_nor_flash_words_per_block / LX_NOR_SECTOR_SIZE) - 1;
136
137
    /* Calculate the number of words required for the sector map array.  */
138
19
    sector_map_words =  sectors_per_block;
139
140
    /* Calculate the number of words we need for the free physical sector bit map.  */
141
19
    bit_map_words =  (sectors_per_block + 31)/ 32;
142
143
    /* Save the number of bit map words.  */
144
19
    nor_flash -> lx_nor_flash_block_bit_map_words =  bit_map_words;
145
146
    /* Setup the offset (in words) to the array of physical sector mapping.  */
147
19
    nor_flash -> lx_nor_flash_block_physical_sector_mapping_offset =  nor_flash -> lx_nor_flash_block_free_bit_map_offset + bit_map_words;
148
149
    /* Calculate the total number of words required for the flash block header.  */
150
19
    total_header_words =  sizeof(LX_NOR_FLASH_BLOCK_HEADER)/sizeof(ULONG) + bit_map_words + sector_map_words;
151
152
    /* Determine if more physical sectors are needed, which can happen on large devices.  */
153
19
    if (total_header_words <= LX_NOR_SECTOR_SIZE)
154
    {
155
156
        /* Round up to the size of 1 physical sector.  */
157
19
        total_header_words =  LX_NOR_SECTOR_SIZE;
158
    }
159
    else
160
    {
161
162
        /* Otherwise calculate how many header sectors are necessary.  */
163
        header_sectors =  (total_header_words-1)/LX_NOR_SECTOR_SIZE;
164
165
        /* Round up to the next sector.  */
166
        header_sectors++;
167
168
        /* Compute the total header words, rounding to the next sector.  */
169
        total_header_words =  header_sectors * LX_NOR_SECTOR_SIZE;
170
171
        /* Adjust the number of sectors per block.  */
172
        sectors_per_block =  sectors_per_block - (header_sectors - 1);
173
    }
174
175
    /* Save the offset to the sector area.  */
176
19
    nor_flash -> lx_nor_flash_block_physical_sector_offset =  total_header_words;
177
178
    /* Save the physical sectors per block and total physical sectors.  */
179
19
    nor_flash -> lx_nor_flash_physical_sectors_per_block =  sectors_per_block;
180
19
    nor_flash -> lx_nor_flash_total_physical_sectors =      nor_flash -> lx_nor_flash_total_blocks * sectors_per_block;
181
182
    /* Build the free bit map mask, for the portion of the bit map that is less than 32 bits.  */
183
19
    if ((sectors_per_block % 32) != 0)
184
    {
185
19
        bit_map_mask =  (ULONG)(1 << (sectors_per_block % 32));
186
19
        bit_map_mask =  bit_map_mask - 1;
187
    }
188
    else
189
    {
190
191
        /* Exactly 32 sectors for the bit map mask.  */
192
        bit_map_mask =  LX_ALL_ONES;
193
    }
194
195
    /* Save the free bit map mask in the control block.  */
196
19
    nor_flash -> lx_nor_flash_block_bit_map_mask =  bit_map_mask;
197
198
    /* Setup default values for the max/min erased counts.  */
199
19
    min_erased_count =  LX_ALL_ONES;
200
19
    min_erased_blocks = 0;
201
19
    max_erased_count =  0;
202
203
    /* Setup the block word pointer to the first word of the first block, which is effectively the
204
       flash base address.  */
205
19
    block_word_ptr =  nor_flash -> lx_nor_flash_base_address;
206
207
    /* Loop through the blocks to determine the minimum and maximum erase count.  */
208
171
    for (l = 0; l < nor_flash -> lx_nor_flash_total_blocks; l++)
209
    {
210
211
            /* Pickup the first word of the block. If the flash manager has executed before, this word contains the
212
            erase count for the block. Otherwise, if the word is 0xFFFFFFFF, this flash block was either erased
213
            or this is the first time it was used.  */
214
#ifdef LX_DIRECT_READ
215
216
            /* Read the word directly.  */
217
            block_word =  *block_word_ptr;
218
#else
219
220
152
            status =  _lx_nor_flash_driver_read(nor_flash, block_word_ptr, &block_word, 1);
221
222
            /* Check for an error from flash driver. Drivers should never return an error..  */
223
152
            if (status)
224
            {
225
226
                /* Call system error handler.  */
227
                _lx_nor_flash_system_error(nor_flash, status);
228
229
                /* Return an error.  */
230
                return(LX_ERROR);
231
            }
232
#endif
233
234
            /* Is the block erased?  */
235

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

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

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