GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lx_nand_flash_metadata_allocate.c Lines: 57 76 75.0 %
Date: 2024-03-11 05:20:25 Branches: 25 44 56.8 %

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