GCC Code Coverage Report


Directory: common/src/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 73.1% 57 / 0 / 78
Functions: 100.0% 1 / 0 / 1
Branches: 55.9% 38 / 0 / 68

lx_nand_flash_metadata_allocate.c
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 369460 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 369460 page = nand_flash -> lx_nand_flash_metadata_block_current_page;
91
92 /* Check if new metadata block is required. */
93
2/2
✓ Branch 2 → 3 taken 368030 times.
✓ Branch 2 → 4 taken 1430 times.
369460 if (page < nand_flash -> lx_nand_flash_pages_per_block)
94 {
95
96 /* No new block is required. Just return success. */
97 368030 return(LX_SUCCESS);
98 }
99
100 /* Advance to next metadata block. */
101 1430 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 1430 nand_flash -> lx_nand_flash_metadata_block_current_page = 0;
105
106 /* Advance to next backup metadata block. */
107 1430 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 1430 nand_flash -> lx_nand_flash_backup_metadata_block_current_page = 0;
111
112 /* Check if number of allocated blocks reaches maximum. */
113
3/3
✓ Branch 4 → 5 taken 460 times.
✓ Branch 4 → 42 taken 873 times.
✓ Branch 4 → 44 taken 97 times.
1430 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
2/2
✓ Branch 7 → 6 taken 1380 times.
✓ Branch 7 → 8 taken 460 times.
1840 for (j = 0; j < LX_NAND_FLASH_MAX_METADATA_BLOCKS - 1; j++)
118 {
119
120 /* Free metadata block. */
121 1380 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 1380 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 1380 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 1380 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 460 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 460 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 460 min_erase_count = 255;
141
142 /* Loop to find the minimum erase count. */
143
2/2
✓ Branch 13 → 9 taken 471040 times.
✓ Branch 13 → 14 taken 460 times.
471500 for (j = 0; j < nand_flash -> lx_nand_flash_total_blocks; j++)
144 {
145
146 /* Exclude erase count of bad block. */
147
1/2
✓ Branch 9 → 10 taken 471040 times.
✗ Branch 9 → 12 not taken.
471040 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
2/2
✓ Branch 10 → 11 taken 920 times.
✓ Branch 10 → 12 taken 470120 times.
471040 if (nand_flash -> lx_nand_flash_erase_count_table[j] < min_erase_count)
152 {
153
154 /* Update the minimum erase count. */
155 920 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
1/2
✗ Branch 14 → 15 not taken.
✓ Branch 14 → 21 taken 460 times.
460 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 460 status = _lx_nand_flash_metadata_build(nand_flash);
183
184 /* Check return status. */
185
1/2
✗ Branch 22 → 23 not taken.
✓ Branch 22 → 24 taken 460 times.
460 if (status != LX_SUCCESS)
186 {
187
188 /* Return error status. */
189 ✗ return(status);
190 }
191
192 /* Loop to erase freed blocks. */
193
4/4
✓ Branch 40 → 25 taken 1242 times.
✓ Branch 40 → 41 taken 414 times.
✓ Branch 42 → 25 taken 138 times.
✓ Branch 42 → 43 taken 46 times.
1840 for (j = 0; j < LX_NAND_FLASH_MAX_METADATA_BLOCKS - 1; j++)
194 {
195
196 /* Get the block number to erase. */
197 1380 block = nand_flash -> lx_nand_flash_metadata_block[j];
198
199 /* Erase the block. */
200 1380 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
2/3
✗ Branch 26 → 27 not taken.
✓ Branch 26 → 29 taken 1242 times.
✓ Branch 26 → 30 taken 138 times.
1380 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
2/4
✗ Branch 29 → 30 not taken.
✓ Branch 29 → 31 taken 1242 times.
✗ Branch 30 → 31 not taken.
✓ Branch 30 → 32 taken 138 times.
1380 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 1380 _lx_nand_flash_free_block_list_add(nand_flash, block);
230 }
231
232 /* Get the block number from backup metadata blocks. */
233 1380 block = nand_flash -> lx_nand_flash_backup_metadata_block[j];
234
235 /* Erase the block. */
236 1380 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
2/4
✗ Branch 33 → 34 not taken.
✓ Branch 33 → 36 taken 1242 times.
✗ Branch 34 → 35 not taken.
✓ Branch 34 → 38 taken 138 times.
1380 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
2/4
✗ Branch 36 → 37 not taken.
✓ Branch 36 → 38 taken 1242 times.
✗ Branch 38 → 39 not taken.
✓ Branch 38 → 40 taken 138 times.
1380 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 1380 _lx_nand_flash_free_block_list_add(nand_flash, block);
266 }
267 }
268
269 /* Update metadata block list. */
270 460 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 460 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 460 nand_flash -> lx_nand_flash_metadata_block_count = 1;
277 }
278
279 /* Allocate new block for metadata. */
280 1430 status = _lx_nand_flash_block_allocate(nand_flash, &block);
281
282 /* Check return status. */
283
2/4
✗ Branch 43 → 44 not taken.
✓ Branch 43 → 47 taken 1287 times.
✗ Branch 45 → 46 not taken.
✓ Branch 45 → 49 taken 143 times.
1430 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 1430 nand_flash -> lx_nand_flash_metadata_block_number_next = block;
300
301 /* Save the new block in metadata block list. */
302 1430 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 1430 status = _lx_nand_flash_block_status_set(nand_flash, block, LX_NAND_BLOCK_STATUS_ALLOCATED);
306
307 /* Check return status. */
308
2/4
✗ Branch 48 → 49 not taken.
✓ Branch 48 → 50 taken 1287 times.
✗ Branch 50 → 51 not taken.
✓ Branch 50 → 52 taken 143 times.
1430 if (status != LX_SUCCESS)
309 {
310
311 /* Return status. */
312 ✗ return (status);
313 }
314
315 /* Allocate new block for backup metadata. */
316 1430 status = _lx_nand_flash_block_allocate(nand_flash, &block);
317
318 /* Check return status. */
319
2/4
✗ Branch 51 → 52 not taken.
✓ Branch 51 → 55 taken 1287 times.
✗ Branch 53 → 54 not taken.
✓ Branch 53 → 57 taken 143 times.
1430 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 1430 nand_flash -> lx_nand_flash_backup_metadata_block_number_next = block;
336
337 /* Save the new block in metadata block list. */
338 1430 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 1430 status = _lx_nand_flash_block_status_set(nand_flash, block, LX_NAND_BLOCK_STATUS_ALLOCATED);
342
2/4
✗ Branch 56 → 57 not taken.
✓ Branch 56 → 58 taken 1287 times.
✗ Branch 58 → 59 not taken.
✓ Branch 58 → 60 taken 143 times.
1430 if (status != LX_SUCCESS)
343 {
344 ✗ return (status);
345 }
346
347 /* Setup page buffer. */
348 1430 page_buffer_ptr = nand_flash -> lx_nand_flash_page_buffer;
349
350 /* Initialize page data. */
351
4/4
✓ Branch 60 → 59 taken 439296 times.
✓ Branch 60 → 61 taken 858 times.
✓ Branch 62 → 61 taken 73216 times.
✓ Branch 62 → 63 taken 143 times.
513942 LX_MEMSET(page_buffer_ptr, 0xFF, nand_flash -> lx_nand_flash_bytes_per_page);
352
353 /* Save next block number. */
354 1430 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 1430 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 1430 status = _lx_nand_flash_metadata_write(nand_flash, page_buffer_ptr, LX_NAND_PAGE_TYPE_BLOCK_LINK);
361
362 /* Increase metadata block count. */
363 1430 nand_flash -> lx_nand_flash_metadata_block_count++;
364
365 /* Return sector not found status. */
366 1430 return(status);
367 }
368
369