GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lx_nand_flash_sector_release.c Lines: 57 83 68.7 %
Date: 2026-03-06 18:45:40 Branches: 36 56 64.3 %

Line Branch Exec Source
1
/***************************************************************************
2
 * Copyright (c) 2024 Microsoft Corporation
3
 * Copyright (c) 2026-present Eclipse ThreadX contributors
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
/**   NAND 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
/*                                                                        */
40
/*  FUNCTION                                               RELEASE        */
41
/*                                                                        */
42
/*    _lx_nand_flash_sector_release                       PORTABLE C      */
43
/*                                                           6.2.1       */
44
/*  AUTHOR                                                                */
45
/*                                                                        */
46
/*    Xiuwen Cai, Microsoft Corporation                                   */
47
/*                                                                        */
48
/*  DESCRIPTION                                                           */
49
/*                                                                        */
50
/*    This function releases a logical sector from being managed in the   */
51
/*    NAND flash.                                                         */
52
/*                                                                        */
53
/*  INPUT                                                                 */
54
/*                                                                        */
55
/*    nand_flash                            NAND flash instance           */
56
/*    logical_sector                        Logical sector number         */
57
/*                                                                        */
58
/*  OUTPUT                                                                */
59
/*                                                                        */
60
/*    return status                                                       */
61
/*                                                                        */
62
/*  CALLS                                                                 */
63
/*                                                                        */
64
/*    _lx_nand_flash_block_find             Find the mapped block         */
65
/*    lx_nand_flash_driver_pages_read       Read pages                    */
66
/*    _lx_nand_flash_block_allocate         Allocate block                */
67
/*    _lx_nand_flash_mapped_block_list_remove                             */
68
/*                                          Remove mapped block           */
69
/*    _lx_nand_flash_data_page_copy         Copy data pages               */
70
/*    _lx_nand_flash_free_block_list_add    Add free block to list        */
71
/*    _lx_nand_flash_block_mapping_set      Set block mapping             */
72
/*    _lx_nand_flash_driver_block_erase     Erase block                   */
73
/*    _lx_nand_flash_erase_count_set        Set erase count               */
74
/*    _lx_nand_flash_block_data_move        Move block data               */
75
/*    _lx_nand_flash_block_status_set       Set block status              */
76
/*    _lx_nand_flash_mapped_block_list_add  Add mapped block to list      */
77
/*    _lx_nand_flash_system_error           Internal system error handler */
78
/*    tx_mutex_get                          Get thread protection         */
79
/*    tx_mutex_put                          Release thread protection     */
80
/*                                                                        */
81
/*  CALLED BY                                                             */
82
/*                                                                        */
83
/*    Application Code                                                    */
84
/*                                                                        */
85
/**************************************************************************/
86
6738
UINT  _lx_nand_flash_sector_release(LX_NAND_FLASH *nand_flash, ULONG logical_sector)
87
{
88
89
UINT        status;
90
ULONG       block;
91
USHORT      block_status;
92
UCHAR       *spare_buffer_ptr;
93
ULONG       available_pages;
94
LONG        page;
95
6738
UINT        release_sector = LX_FALSE;
96
ULONG       new_block;
97
USHORT      new_block_status;
98
99
#ifdef LX_THREAD_SAFE_ENABLE
100
101
    /* Obtain the thread safe mutex.  */
102
    tx_mutex_get(&nand_flash -> lx_nand_flash_mutex, TX_WAIT_FOREVER);
103
#endif
104
105
    /* Increment the number of release requests.  */
106
6738
    nand_flash -> lx_nand_flash_diagnostic_sector_release_requests++;
107
108
109
    /* See if we can find the sector in the current mapping.  */
110
6738
    status = _lx_nand_flash_block_find(nand_flash, logical_sector, &block, &block_status);
111
112
    /* Check return status.   */
113
6738
    if (status != LX_SUCCESS)
114
    {
115
116
        /* Call system error handler.  */
117
        _lx_nand_flash_system_error(nand_flash, status, block, 0);
118
119
        /* Determine if the error is fatal.  */
120
        if (status != LX_NAND_ERROR_CORRECTED)
121
        {
122
#ifdef LX_THREAD_SAFE_ENABLE
123
124
            /* Release the thread safe mutex.  */
125
            tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
126
#endif
127
128
            /* Return an error.  */
129
            return(LX_ERROR);
130
        }
131
    }
132
133
    /* Determine if the block is mapped.  */
134
6738
    if (block != LX_NAND_BLOCK_UNMAPPED)
135
    {
136
137
        /* Setup spare buffer pointer.  */
138
358
        spare_buffer_ptr = (UCHAR*)nand_flash -> lx_nand_flash_page_buffer;
139
140
        /* Get available pages in this block.  */
141
358
        available_pages = block_status & LX_NAND_BLOCK_STATUS_FULL ? nand_flash -> lx_nand_flash_pages_per_block : block_status & LX_NAND_BLOCK_STATUS_PAGE_NUMBER_MASK;
142
143
        /* Determine if the pages are recorded sequentially.  */
144
358
        if (block_status & LX_NAND_BLOCK_STATUS_NON_SEQUENTIAL)
145
        {
146
147
            /* Loop to search the logical page.  */
148
11769
            for (page = (LONG)available_pages - 1; page >= 0; page--)
149
            {
150
151
                /* Read a page.  */
152
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
153
                status = (nand_flash -> lx_nand_flash_driver_pages_read)(nand_flash, block, (ULONG)page, LX_NULL, spare_buffer_ptr, 1);
154
#else
155
11413
                status = (nand_flash -> lx_nand_flash_driver_pages_read)(block, (ULONG)page, LX_NULL, spare_buffer_ptr, 1);
156
#endif
157
158
                /* Check for an error from flash driver.   */
159
11413
                if (status)
160
                {
161
162
                    /* Call system error handler.  */
163
                    _lx_nand_flash_system_error(nand_flash, status, block, 0);
164
#ifdef LX_THREAD_SAFE_ENABLE
165
166
                    /* Release the thread safe mutex.  */
167
                    tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
168
#endif
169
170
                    /* Return an error.  */
171
                    return(LX_ERROR);
172
                }
173
174
                /* Get the logical sector number from spare bytes, and check if it matches the addressed sector number.  */
175
11413
                if ((LX_UTILITY_LONG_GET(&spare_buffer_ptr[nand_flash -> lx_nand_flash_spare_data1_offset]) & LX_NAND_PAGE_TYPE_USER_DATA_MASK) == logical_sector)
176
                {
177
178
                    /* Make sure the sector is not released.  */
179
52
                    if ((LX_UTILITY_LONG_GET(&spare_buffer_ptr[nand_flash -> lx_nand_flash_spare_data1_offset]) & (~LX_NAND_PAGE_TYPE_USER_DATA_MASK)) == (LX_NAND_PAGE_TYPE_USER_DATA))
180
                    {
181
182
                        /* Set release sector flag.  */
183
52
                        release_sector = LX_TRUE;
184
                    }
185
                }
186
            }
187
        }
188
        else
189
        {
190
191
            /* Check if the logical sector is available.  */
192
2
            if (logical_sector % nand_flash -> lx_nand_flash_pages_per_block < available_pages)
193
            {
194
195
                /* Set release sector flag.  */
196
2
                release_sector = LX_TRUE;
197
            }
198
        }
199
200
        /* Determine if the sector needs to be released.  */
201
358
        if (release_sector)
202
        {
203
204
            /* Check if the block is full.  */
205
54
            if (block_status & LX_NAND_BLOCK_STATUS_FULL)
206
            {
207
208
                /* Allocate a new block.  */
209
2
                status = _lx_nand_flash_block_allocate(nand_flash, &new_block);
210
211
                /* Check return status.   */
212
2
                if (status != LX_SUCCESS)
213
                {
214
                    /* Call system error handler.  */
215
                    _lx_nand_flash_system_error(nand_flash, status, new_block, 0);
216
#ifdef LX_THREAD_SAFE_ENABLE
217
218
                    /* Release the thread safe mutex.  */
219
                    tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
220
#endif
221
222
                    /* Return an error.  */
223
                    return(LX_ERROR);
224
225
                }
226
227
                /* Set new block status to allocated.  */
228
2
                new_block_status = LX_NAND_BLOCK_STATUS_ALLOCATED;
229
230
                /* Remove the old block from mapped block list.  */
231
2
                _lx_nand_flash_mapped_block_list_remove(nand_flash, logical_sector / nand_flash -> lx_nand_flash_pages_per_block);
232
233
                /* Copy valid sector to new block.  */
234
2
                status = _lx_nand_flash_data_page_copy(nand_flash, logical_sector - (logical_sector % nand_flash -> lx_nand_flash_pages_per_block), block, block_status, new_block, &new_block_status, (logical_sector % nand_flash -> lx_nand_flash_pages_per_block));
235
236
                /* Check for an error from flash driver.   */
237
2
                if (status)
238
                {
239
240
                    /* Call system error handler.  */
241
                    _lx_nand_flash_system_error(nand_flash, status, new_block, 0);
242
#ifdef LX_THREAD_SAFE_ENABLE
243
244
                    /* Release the thread safe mutex.  */
245
                    tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
246
#endif
247
248
                    /* Return an error.  */
249
                    return(LX_ERROR);
250
                }
251
252
                /* Determine if there are sectors after the addressed sector need to be copied.  */
253
2
                if (logical_sector % nand_flash -> lx_nand_flash_pages_per_block < nand_flash -> lx_nand_flash_pages_per_block - 1)
254
                {
255
256
                    /* Copy valid sector to new block.  */
257
2
                    status = _lx_nand_flash_data_page_copy(nand_flash, logical_sector + 1, block, block_status, new_block, &new_block_status, (nand_flash -> lx_nand_flash_pages_per_block - 1) - (logical_sector % nand_flash -> lx_nand_flash_pages_per_block));
258
259
                    /* Check for an error from flash driver.   */
260
2
                    if (status)
261
                    {
262
263
                        /* Call system error handler.  */
264
                        _lx_nand_flash_system_error(nand_flash, status, new_block, 0);
265
#ifdef LX_THREAD_SAFE_ENABLE
266
267
                        /* Release the thread safe mutex.  */
268
                        tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
269
#endif
270
271
                        /* Return an error.  */
272
                        return(LX_ERROR);
273
                    }
274
                }
275
276
                /* Check new block status to see if there is valid pages in the block.  */
277
2
                if ((new_block_status & LX_NAND_BLOCK_STATUS_PAGE_NUMBER_MASK) == 0)
278
                {
279
280
                    /* Add the block to free block list.  */
281
                    _lx_nand_flash_free_block_list_add(nand_flash, new_block);
282
283
                    /* Set new block to unmapped.  */
284
                    new_block = LX_NAND_BLOCK_UNMAPPED;
285
                }
286
                else
287
                {
288
289
                    /* Set new block status.  */
290
2
                    status = _lx_nand_flash_block_status_set(nand_flash, new_block, new_block_status);
291
292
                    /* Check for an error from flash driver.   */
293
2
                    if (status)
294
                    {
295
296
                        /* Call system error handler.  */
297
                        _lx_nand_flash_system_error(nand_flash, status, block, 0);
298
#ifdef LX_THREAD_SAFE_ENABLE
299
300
                        /* Release the thread safe mutex.  */
301
                        tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
302
#endif
303
304
                        /* Return an error.  */
305
                        return(LX_ERROR);
306
                    }
307
                }
308
309
                /* Update block mapping.  */
310
2
                _lx_nand_flash_block_mapping_set(nand_flash, logical_sector, new_block);
311
312
                /* Erase old block.  */
313
2
                status = _lx_nand_flash_driver_block_erase(nand_flash, block, nand_flash -> lx_nand_flash_base_erase_count + nand_flash -> lx_nand_flash_erase_count_table[block] + 1);
314
315
                /* Check for an error from flash driver.   */
316
2
                if (status)
317
                {
318
319
                    /* Call system error handler.  */
320
                    _lx_nand_flash_system_error(nand_flash, status, block, 0);
321
#ifdef LX_THREAD_SAFE_ENABLE
322
323
                    /* Release the thread safe mutex.  */
324
                    tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
325
#endif
326
327
                    /* Return an error.  */
328
                    return(LX_ERROR);
329
                }
330
331
                /* Update erase count for the old block.  */
332
2
                status = _lx_nand_flash_erase_count_set(nand_flash, block, (UCHAR)(nand_flash -> lx_nand_flash_erase_count_table[block] + 1));
333
334
                /* Check for an error from flash driver.   */
335
2
                if (status)
336
                {
337
338
                    /* Call system error handler.  */
339
                    _lx_nand_flash_system_error(nand_flash, status, block, 0);
340
#ifdef LX_THREAD_SAFE_ENABLE
341
342
                    /* Release the thread safe mutex.  */
343
                    tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
344
#endif
345
346
                    /* Return an error.  */
347
                    return(LX_ERROR);
348
                }
349
350
                /* Check if the block has too many erases.  */
351
2
                if (nand_flash -> lx_nand_flash_erase_count_table[block] > LX_NAND_FLASH_MAX_ERASE_COUNT_DELTA)
352
                {
353
354
                    /* Move data from less worn block.  */
355
                    _lx_nand_flash_block_data_move(nand_flash, block);
356
                }
357
                else
358
                {
359
360
                    /* Set the block status to free.  */
361
2
                    status = _lx_nand_flash_block_status_set(nand_flash, block, LX_NAND_BLOCK_STATUS_FREE);
362
363
                    /* Check for an error from flash driver.   */
364
2
                    if (status)
365
                    {
366
367
                        /* Call system error handler.  */
368
                        _lx_nand_flash_system_error(nand_flash, status, block, 0);
369
#ifdef LX_THREAD_SAFE_ENABLE
370
371
                        /* Release the thread safe mutex.  */
372
                        tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
373
#endif
374
375
                        /* Return an error.  */
376
                        return(LX_ERROR);
377
                    }
378
379
                    /* Add the block to free block list.  */
380
2
                    _lx_nand_flash_free_block_list_add(nand_flash, block);
381
                }
382
383
                /* Check if there is valid pages in the new block.  */
384
2
                if ((new_block_status & LX_NAND_BLOCK_STATUS_PAGE_NUMBER_MASK) != 0)
385
                {
386
387
                    /* Add the new block to mapped block list.  */
388
2
                    _lx_nand_flash_mapped_block_list_add(nand_flash, logical_sector / nand_flash -> lx_nand_flash_pages_per_block);
389
                }
390
            }
391
            else
392
            {
393
394
                /* Set page buffer to all 0xFF bytes.  */
395
27508
                LX_MEMSET(nand_flash -> lx_nand_flash_page_buffer, 0xFF, nand_flash -> lx_nand_flash_bytes_per_page + nand_flash -> lx_nand_flash_spare_total_length);
396
397
                /* Setup spare buffer pointer.  */
398
52
                spare_buffer_ptr = nand_flash -> lx_nand_flash_page_buffer + nand_flash -> lx_nand_flash_bytes_per_page;
399
400
                /* Check if there is enough spare data for metadata block number.  */
401
52
                if (nand_flash -> lx_nand_flash_spare_data2_length >= sizeof(USHORT))
402
                {
403
404
                    /* Save metadata block number in spare bytes.  */
405
52
                    LX_UTILITY_SHORT_SET(&spare_buffer_ptr[nand_flash -> lx_nand_flash_spare_data2_offset], nand_flash -> lx_nand_flash_metadata_block_number);
406
                }
407
408
                /* Set page type and sector address.  */
409
52
                LX_UTILITY_LONG_SET(&spare_buffer_ptr[nand_flash -> lx_nand_flash_spare_data1_offset], LX_NAND_PAGE_TYPE_USER_DATA_RELEASED | logical_sector);
410
411
                /* Write the page.  */
412
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
413
                status = (nand_flash -> lx_nand_flash_driver_pages_write)(nand_flash, block, available_pages, (UCHAR*)nand_flash -> lx_nand_flash_page_buffer, spare_buffer_ptr, 1);
414
#else
415
52
                status = (nand_flash -> lx_nand_flash_driver_pages_write)(block, available_pages, (UCHAR*)nand_flash -> lx_nand_flash_page_buffer, spare_buffer_ptr, 1);
416
#endif
417
418
                /* Check for an error from flash driver.   */
419
52
                if (status)
420
                {
421
422
                    /* Call system error handler.  */
423
                    _lx_nand_flash_system_error(nand_flash, status, block, 0);
424
#ifdef LX_THREAD_SAFE_ENABLE
425
426
                    /* Release the thread safe mutex.  */
427
                    tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
428
#endif
429
430
                    /* Return an error.  */
431
                    return(LX_ERROR);
432
                }
433
434
                /* Increase available pages count.  */
435
52
                available_pages++;
436
437
                /* Check if available pages count reaches total pages per block.  */
438
52
                if (available_pages == nand_flash -> lx_nand_flash_pages_per_block)
439
                {
440
441
                    /* Set block full status flag.  */
442
2
                    block_status |= LX_NAND_BLOCK_STATUS_FULL;
443
                }
444
445
                /* Build block status word.  */
446
52
                block_status = (USHORT)(available_pages | (block_status & ~LX_NAND_BLOCK_STATUS_PAGE_NUMBER_MASK));
447
448
                /* Set non sequential status flag.  */
449
52
                block_status |= LX_NAND_BLOCK_STATUS_NON_SEQUENTIAL;
450
451
                /* Set block status.  */
452
52
                status = _lx_nand_flash_block_status_set(nand_flash, block, block_status);
453
454
                /* Check for an error from flash driver.   */
455
52
                if (status)
456
                {
457
458
                    /* Call system error handler.  */
459
                    _lx_nand_flash_system_error(nand_flash, status, block, 0);
460
#ifdef LX_THREAD_SAFE_ENABLE
461
462
                    /* Release the thread safe mutex.  */
463
                    tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
464
#endif
465
466
                    /* Return an error.  */
467
                    return(LX_ERROR);
468
                }
469
            }
470
        }
471
    }
472
#ifdef LX_THREAD_SAFE_ENABLE
473
474
    /* Release the thread safe mutex.  */
475
    tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
476
#endif
477
478
    /* Return status.  */
479
6738
    return(status);
480
}
481