GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lx_nand_flash_metadata_allocate.c Lines: 57 76 75.0 %
Date: 2026-03-06 18:45:40 Branches: 25 44 56.8 %

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_metadata_allocate                    PORTABLE C      */
43
/*                                                           6.2.1       */
44
/*  AUTHOR                                                                */
45
/*                                                                        */
46
/*    Xiuwen Cai, Microsoft Corporation                                   */
47
/*                                                                        */
48
/*  DESCRIPTION                                                           */
49
/*                                                                        */
50
/*    This function allocates new blocks for metadata if current metadata */
51
/*    block is full. This function also frees metadata blocks if the chain*/
52
/*    is too long.                                                        */
53
/*                                                                        */
54
/*  INPUT                                                                 */
55
/*                                                                        */
56
/*    nand_flash                            NAND flash instance           */
57
/*                                                                        */
58
/*  OUTPUT                                                                */
59
/*                                                                        */
60
/*    return status                                                       */
61
/*                                                                        */
62
/*  CALLS                                                                 */
63
/*                                                                        */
64
/*    _lx_nand_flash_metadata_build         Build metadata                */
65
/*    _lx_nand_flash_driver_block_erase     Erase block                   */
66
/*    _lx_nand_flash_block_data_move        Move block data               */
67
/*    _lx_nand_flash_free_block_list_add    Add free block list           */
68
/*    _lx_nand_flash_block_allocate         Allocate block                */
69
/*    _lx_nand_flash_block_status_set       Set block status              */
70
/*    _lx_nand_flash_metadata_write         Write metadata                */
71
/*    _lx_nand_flash_system_error           Internal system error handler */
72
/*                                                                        */
73
/*  CALLED BY                                                             */
74
/*                                                                        */
75
/*    Internal LevelX                                                     */
76
/*                                                                        */
77
/**************************************************************************/
78
36946
UINT  _lx_nand_flash_metadata_allocate(LX_NAND_FLASH *nand_flash)
79
{
80
81
ULONG   block;
82
ULONG   page;
83
UINT    status;
84
UCHAR  *page_buffer_ptr;
85
UINT    j;
86
UCHAR   min_erase_count;
87
88
89
    /* Get current page for metadata block.  */
90
36946
    page = nand_flash -> lx_nand_flash_metadata_block_current_page;
91
92
    /* Check if new metadata block is required.  */
93
36946
    if (page < nand_flash -> lx_nand_flash_pages_per_block)
94
    {
95
96
        /* No new block is required. Just return success.  */
97
36803
        return(LX_SUCCESS);
98
    }
99
100
    /* Advance to next metadata block.  */
101
143
    nand_flash -> lx_nand_flash_metadata_block_number_current = nand_flash -> lx_nand_flash_metadata_block_number_next;
102
103
    /* Reset current page number.  */
104
143
    nand_flash -> lx_nand_flash_metadata_block_current_page = 0;
105
106
    /* Advance to next backup metadata block.  */
107
143
    nand_flash -> lx_nand_flash_backup_metadata_block_number_current = nand_flash -> lx_nand_flash_backup_metadata_block_number_next;
108
109
    /* Reset current page number for backup metadata block.  */
110
143
    nand_flash -> lx_nand_flash_backup_metadata_block_current_page = 0;
111
112
    /* Check if number of allocated blocks reaches maximum.  */
113
143
    if (nand_flash -> lx_nand_flash_metadata_block_count == LX_NAND_FLASH_MAX_METADATA_BLOCKS)
114
    {
115
116
        /* Loop to mark metadata blocks as free.  */
117
184
        for (j = 0; j < LX_NAND_FLASH_MAX_METADATA_BLOCKS - 1; j++)
118
        {
119
120
            /* Free metadata block.  */
121
138
            nand_flash -> lx_nand_flash_block_status_table[nand_flash -> lx_nand_flash_metadata_block[j]] = LX_NAND_BLOCK_STATUS_FREE;
122
123
            /* Free backup metadata block.  */
124
138
            nand_flash -> lx_nand_flash_block_status_table[nand_flash -> lx_nand_flash_backup_metadata_block[j]] = LX_NAND_BLOCK_STATUS_FREE;
125
126
            /* Increase erase count.  */
127
138
            nand_flash -> lx_nand_flash_erase_count_table[nand_flash -> lx_nand_flash_metadata_block[j]]++;
128
129
            /* Increase erase count for backup metadata block.  */
130
138
            nand_flash -> lx_nand_flash_erase_count_table[nand_flash -> lx_nand_flash_backup_metadata_block[j]]++;
131
        }
132
133
        /* Set new metadata block head.  */
134
46
        nand_flash -> lx_nand_flash_metadata_block_number = nand_flash -> lx_nand_flash_metadata_block_number_current;
135
136
        /* Set new backup metadata block head.  */
137
46
        nand_flash -> lx_nand_flash_backup_metadata_block_number = nand_flash -> lx_nand_flash_backup_metadata_block_number_current;
138
139
        /* Set erase count to maximum.  */
140
46
        min_erase_count = 255;
141
142
        /* Loop to find the minimum erase count.  */
143
47150
        for (j = 0; j < nand_flash -> lx_nand_flash_total_blocks; j++)
144
        {
145
146
            /* Exclude erase count of bad block.  */
147
47104
            if(nand_flash -> lx_nand_flash_block_status_table[j] != LX_NAND_BLOCK_STATUS_BAD)
148
            {
149
150
                /* Check if it has less erase count.  */
151
47104
                if (nand_flash -> lx_nand_flash_erase_count_table[j] < min_erase_count)
152
                {
153
154
                    /* Update the minimum erase count.  */
155
92
                    min_erase_count = nand_flash -> lx_nand_flash_erase_count_table[j];
156
                }
157
            }
158
        }
159
160
        /* Check if the minimum erase count is larger than zero.  */
161
46
        if (min_erase_count > 0)
162
        {
163
164
            /* Loop to update erase count.  */
165
            for (j = 0; j < nand_flash -> lx_nand_flash_total_blocks; j++)
166
            {
167
168
                /* Skip bad blocks.  */
169
                if (nand_flash -> lx_nand_flash_block_status_table[j] != LX_NAND_BLOCK_STATUS_BAD)
170
                {
171
172
                    /* Update erase count.  */
173
                     nand_flash -> lx_nand_flash_erase_count_table[j] = (UCHAR)(nand_flash -> lx_nand_flash_erase_count_table[j] - min_erase_count);
174
                }
175
            }
176
177
            /* Update base erase count.  */
178
            nand_flash -> lx_nand_flash_base_erase_count += (ULONG)min_erase_count;
179
        }
180
181
        /* Rebuild metadata pages.  */
182
46
        status = _lx_nand_flash_metadata_build(nand_flash);
183
184
        /* Check return status.  */
185
46
        if (status != LX_SUCCESS)
186
        {
187
188
            /* Return error status.  */
189
            return(status);
190
        }
191
192
        /* Loop to erase freed blocks.  */
193
184
        for (j = 0; j < LX_NAND_FLASH_MAX_METADATA_BLOCKS - 1; j++)
194
        {
195
196
            /* Get the block number to erase.  */
197
138
            block = nand_flash -> lx_nand_flash_metadata_block[j];
198
199
            /* Erase the block.  */
200
138
            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]);
201
202
            /* Check for an error from flash driver.   */
203
138
            if (status)
204
            {
205
206
                /* Call system error handler.  */
207
                _lx_nand_flash_system_error(nand_flash, status, block, 0);
208
#ifdef LX_THREAD_SAFE_ENABLE
209
210
                /* Release the thread safe mutex.  */
211
                tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
212
#endif
213
214
                /* Return an error.  */
215
                return(LX_ERROR);
216
            }
217
218
            /* Check if the block has too many erases.  */
219
138
            if (nand_flash -> lx_nand_flash_erase_count_table[block] > LX_NAND_FLASH_MAX_ERASE_COUNT_DELTA)
220
            {
221
222
                /* Move data from less worn block.  */
223
                _lx_nand_flash_block_data_move(nand_flash, block);
224
            }
225
            else
226
            {
227
228
                /* Add the block to free block list.  */
229
138
                _lx_nand_flash_free_block_list_add(nand_flash, block);
230
            }
231
232
            /* Get the block number from backup metadata blocks.  */
233
138
            block = nand_flash -> lx_nand_flash_backup_metadata_block[j];
234
235
            /* Erase the block.  */
236
138
            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]);
237
238
            /* Check for an error from flash driver.   */
239
138
            if (status)
240
            {
241
242
                /* Call system error handler.  */
243
                _lx_nand_flash_system_error(nand_flash, status, block, 0);
244
#ifdef LX_THREAD_SAFE_ENABLE
245
246
                /* Release the thread safe mutex.  */
247
                tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
248
#endif
249
250
                /* Return an error.  */
251
                return(LX_ERROR);
252
            }
253
254
            /* Check if the block has too many erases.  */
255
138
            if (nand_flash -> lx_nand_flash_erase_count_table[block] > LX_NAND_FLASH_MAX_ERASE_COUNT_DELTA)
256
            {
257
258
                /* Move data from less worn block.  */
259
                _lx_nand_flash_block_data_move(nand_flash, block);
260
            }
261
            else
262
            {
263
264
                /* Add the block to free block list.  */
265
138
                _lx_nand_flash_free_block_list_add(nand_flash, block);
266
            }
267
        }
268
269
        /* Update metadata block list.  */
270
46
        nand_flash -> lx_nand_flash_metadata_block[0] = (USHORT)nand_flash -> lx_nand_flash_metadata_block_number_current;
271
272
        /* Update metadata block list.  */
273
46
        nand_flash -> lx_nand_flash_backup_metadata_block[0] = (USHORT)nand_flash -> lx_nand_flash_backup_metadata_block_number_current;
274
275
        /* Set metadata block count to one.  */
276
46
        nand_flash -> lx_nand_flash_metadata_block_count = 1;
277
    }
278
279
    /* Allocate new block for metadata.  */
280
143
    status = _lx_nand_flash_block_allocate(nand_flash, &block);
281
282
    /* Check return status.  */
283
143
    if (status != LX_SUCCESS)
284
    {
285
286
        /* Call system error handler.  */
287
        _lx_nand_flash_system_error(nand_flash, status, block, 0);
288
289
        /* Determine if the error is fatal.  */
290
        if (status != LX_NAND_ERROR_CORRECTED)
291
        {
292
293
            /* Return an error.  */
294
            return(LX_ERROR);
295
        }
296
    }
297
298
    /* Update next metadata block number.  */
299
143
    nand_flash -> lx_nand_flash_metadata_block_number_next = block;
300
301
    /* Save the new block in metadata block list.  */
302
143
    nand_flash -> lx_nand_flash_metadata_block[nand_flash -> lx_nand_flash_metadata_block_count] = (USHORT)block;
303
304
    /* Set the block status to allocated.  */
305
143
    status = _lx_nand_flash_block_status_set(nand_flash, block, LX_NAND_BLOCK_STATUS_ALLOCATED);
306
307
    /* Check return status.  */
308
143
    if (status != LX_SUCCESS)
309
    {
310
311
        /* Return status.  */
312
        return (status);
313
    }
314
315
    /* Allocate new block for backup metadata.  */
316
143
    status = _lx_nand_flash_block_allocate(nand_flash, &block);
317
318
    /* Check return status.  */
319
143
    if (status != LX_SUCCESS)
320
    {
321
322
        /* Call system error handler.  */
323
        _lx_nand_flash_system_error(nand_flash, status, block, 0);
324
325
        /* Determine if the error is fatal.  */
326
        if (status != LX_NAND_ERROR_CORRECTED)
327
        {
328
329
            /* Return an error.  */
330
            return(LX_ERROR);
331
        }
332
    }
333
334
    /* Update next backup metadata block number.  */
335
143
    nand_flash -> lx_nand_flash_backup_metadata_block_number_next = block;
336
337
    /* Save the new block in metadata block list.  */
338
143
    nand_flash -> lx_nand_flash_backup_metadata_block[nand_flash -> lx_nand_flash_metadata_block_count] = (USHORT)block;
339
340
    /* Set the block status to allocated.  */
341
143
    status = _lx_nand_flash_block_status_set(nand_flash, block, LX_NAND_BLOCK_STATUS_ALLOCATED);
342
143
    if (status != LX_SUCCESS)
343
    {
344
        return (status);
345
    }
346
347
    /* Setup page buffer.  */
348
143
    page_buffer_ptr = nand_flash -> lx_nand_flash_page_buffer;
349
350
    /* Initialize page data.  */
351
73359
    LX_MEMSET(page_buffer_ptr, 0xFF, nand_flash -> lx_nand_flash_bytes_per_page);
352
353
    /* Save next block number.  */
354
143
    LX_UTILITY_LONG_SET(&page_buffer_ptr[LX_NAND_BLOCK_LINK_MAIN_METADATA_OFFSET], nand_flash -> lx_nand_flash_metadata_block_number_next);
355
356
    /* Save next block number for backup metadata.  */
357
143
    LX_UTILITY_LONG_SET(&page_buffer_ptr[LX_NAND_BLOCK_LINK_BACKUP_METADATA_OFFSET], nand_flash -> lx_nand_flash_backup_metadata_block_number_next);
358
359
    /* Write metadata.  */
360
143
    status = _lx_nand_flash_metadata_write(nand_flash, page_buffer_ptr, LX_NAND_PAGE_TYPE_BLOCK_LINK);
361
362
    /* Increase metadata block count.  */
363
143
    nand_flash -> lx_nand_flash_metadata_block_count++;
364
365
    /* Return sector not found status.  */
366
143
    return(status);
367
}
368