GCC Code Coverage Report


Directory: common/src/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 74.3% 101 / 0 / 136
Functions: 100.0% 1 / 0 / 1
Branches: 59.0% 92 / 0 / 156

lx_nand_flash_open_extended.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 // Portions of this file were generated with AI assistance.
13
14 /**************************************************************************/
15 /**************************************************************************/
16 /** */
17 /** LevelX Component */
18 /** */
19 /** NAND Flash */
20 /** */
21 /**************************************************************************/
22 /**************************************************************************/
23
24 #define LX_SOURCE_CODE
25
26
27 /* Disable ThreadX error checking. */
28
29 #ifndef LX_DISABLE_ERROR_CHECKING
30 #define LX_DISABLE_ERROR_CHECKING
31 #endif
32
33
34 /* Include necessary system files. */
35
36 #include "lx_api.h"
37
38
39 /**************************************************************************/
40 /* */
41 /* FUNCTION RELEASE */
42 /* */
43 /* _lx_nand_flash_open PORTABLE C */
44 /* 6.3.0 */
45 /* AUTHOR */
46 /* */
47 /* Xiuwen Cai, Microsoft Corporation */
48 /* */
49 /* DESCRIPTION */
50 /* */
51 /* This function opens a NAND flash instance and ensures the */
52 /* NAND flash is in a coherent state. */
53 /* */
54 /* INPUT */
55 /* */
56 /* nand_flash NAND flash instance */
57 /* name Name of NAND flash instance */
58 /* nand_driver_initialize Driver initialize */
59 /* memory_ptr Pointer to memory used by the */
60 /* LevelX for this NAND. */
61 /* memory_size Size of memory - must at least*/
62 /* 7 * total block count + */
63 /* 2 * page size */
64 /* */
65 /* OUTPUT */
66 /* */
67 /* return status */
68 /* */
69 /* CALLS */
70 /* */
71 /* (nand_driver_initialize) Driver initialize */
72 /* _lx_nand_flash_memory_initialize Initialize buffer */
73 /* _lx_nand_flash_driver_block_status_get */
74 /* Get block status */
75 /* lx_nand_flash_driver_pages_read Read pages */
76 /* _lx_nand_flash_free_block_list_add Add free block to list */
77 /* _lx_nand_flash_mapped_block_list_add Add mapped block to list */
78 /* _lx_nand_flash_system_error System error handler */
79 /* tx_mutex_create Create thread-safe mutex */
80 /* */
81 /* CALLED BY */
82 /* */
83 /* Application Code */
84 /* */
85 /**************************************************************************/
86
87 50 UINT _lx_nand_flash_open_extended(LX_NAND_FLASH *nand_flash, CHAR *name, UINT (*nand_driver_initialize)(LX_NAND_FLASH *),
88 VOID *nand_driver_info_ptr, ULONG* memory_ptr, UINT memory_size)
89 {
90
91 ULONG block;
92 ULONG page;
93 UCHAR block_status;
94 ULONG block_count;
95 UINT status;
96 LX_NAND_FLASH *tail_ptr;
97 LX_NAND_DEVICE_INFO *nand_device_info_page;
98 UCHAR *spare_buffer_ptr;
99 UCHAR *page_buffer_ptr;
100 ULONG page_type;
101 UCHAR page_index;
102 LX_INTERRUPT_SAVE_AREA
103
104 LX_PARAMETER_NOT_USED(name);
105
106 /* Clear the NAND flash control block. User extension is not cleared. */
107
2/2
✓ Branch 4 → 3 taken 10900 times.
✓ Branch 4 → 5 taken 35 times.
10950 LX_MEMSET(nand_flash, 0, (ULONG)((UCHAR*)&(nand_flash -> lx_nand_flash_open_previous) - (UCHAR*)nand_flash) + sizeof(nand_flash -> lx_nand_flash_open_previous));
108
109 /* Pass the driver_info_ptr */
110 50 nand_flash -> lx_nand_flash_driver_info_ptr = nand_driver_info_ptr;
111
112 /* Call the flash driver's initialization function. */
113 50 (nand_driver_initialize)(nand_flash);
114
115 /* Determine if we can support this NAND flash size. */
116
4/8
✓ Branch 3 → 4 taken 15 times.
✗ Branch 3 → 5 not taken.
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 15 times.
✓ Branch 6 → 7 taken 35 times.
✗ Branch 6 → 8 not taken.
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 35 times.
50 if (nand_flash -> lx_nand_flash_pages_per_block > LX_NAND_MAX_PAGE_PER_BLOCK || nand_flash -> lx_nand_flash_total_blocks > LX_NAND_MAX_BLOCK_COUNT)
117 {
118
119 /* Return an error. */
120 ✗ return(LX_ERROR);
121 }
122
123 /* Check if it is new LevelX NAND driver. */
124
6/12
✓ Branch 6 → 7 taken 15 times.
✗ Branch 6 → 9 not taken.
✓ Branch 7 → 8 taken 15 times.
✗ Branch 7 → 9 not taken.
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 15 times.
✓ Branch 9 → 10 taken 35 times.
✗ Branch 9 → 12 not taken.
✓ Branch 10 → 11 taken 35 times.
✗ Branch 10 → 12 not taken.
✗ Branch 11 → 12 not taken.
✓ Branch 11 → 13 taken 35 times.
50 if (nand_flash -> lx_nand_flash_driver_pages_read == LX_NULL || nand_flash -> lx_nand_flash_driver_pages_write == LX_NULL || nand_flash -> lx_nand_flash_driver_pages_copy == LX_NULL)
125 {
126
127 /* Return an error. */
128 ✗ return(LX_ERROR);
129 }
130
131 /* Check the spare data length. */
132
2/4
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 15 times.
✗ Branch 13 → 14 not taken.
✓ Branch 13 → 15 taken 35 times.
50 if (nand_flash -> lx_nand_flash_spare_data1_length < sizeof(ULONG))
133 {
134
135 /* Return an error. */
136 ✗ return(LX_ERROR);
137 }
138
139 /* Calculate the number of words per block and per page. */
140 50 nand_flash -> lx_nand_flash_words_per_page = (nand_flash -> lx_nand_flash_bytes_per_page / sizeof(ULONG));
141 50 nand_flash -> lx_nand_flash_words_per_block = (nand_flash -> lx_nand_flash_words_per_page * nand_flash -> lx_nand_flash_pages_per_block);
142
143 /* Calculate the total pages. */
144 50 nand_flash -> lx_nand_flash_total_pages = nand_flash -> lx_nand_flash_total_blocks * nand_flash -> lx_nand_flash_pages_per_block;
145
146 /* Initialize memory buffer. */
147 50 status = _lx_nand_flash_memory_initialize(nand_flash, memory_ptr, memory_size);
148
2/4
✗ Branch 13 → 14 not taken.
✓ Branch 13 → 15 taken 15 times.
✗ Branch 16 → 17 not taken.
✓ Branch 16 → 18 taken 35 times.
50 if (status != LX_SUCCESS)
149 {
150 ✗ return(status);
151 }
152
153 /* Initialize block numbers. */
154 50 nand_flash -> lx_nand_flash_metadata_block_number = LX_NAND_BLOCK_UNMAPPED;
155 50 nand_flash -> lx_nand_flash_backup_metadata_block_number = LX_NAND_BLOCK_UNMAPPED;
156
157 /* Setup page buffer and spare buffer pointers. */
158 50 page_buffer_ptr = nand_flash -> lx_nand_flash_page_buffer;
159 50 spare_buffer_ptr = page_buffer_ptr + nand_flash -> lx_nand_flash_bytes_per_page;
160
161 /* Loop through the blocks to check for bad blocks and determine the minimum and maximum erase count for each good block. */
162
2/4
✓ Branch 32 → 16 taken 15 times.
✗ Branch 32 → 33 not taken.
✓ Branch 35 → 19 taken 35 times.
✗ Branch 35 → 36 not taken.
50 for (block = 0; block < nand_flash -> lx_nand_flash_total_blocks; block++)
163 {
164
165 /* First, check to make sure this block is good. */
166 50 status = _lx_nand_flash_driver_block_status_get(nand_flash, block, &block_status);
167
168 /* Check for an error from flash driver. */
169
2/4
✗ Branch 17 → 18 not taken.
✓ Branch 17 → 20 taken 15 times.
✗ Branch 20 → 21 not taken.
✓ Branch 20 → 23 taken 35 times.
50 if (status)
170 {
171
172 /* Call system error handler. */
173 ✗ _lx_nand_flash_system_error(nand_flash, status, block, 0);
174
175 /* Return an error. */
176 ✗ return(LX_ERROR);
177 }
178
179 /* Is this block bad? */
180
2/4
✗ Branch 20 → 21 not taken.
✓ Branch 20 → 22 taken 15 times.
✗ Branch 23 → 24 not taken.
✓ Branch 23 → 25 taken 35 times.
50 if (block_status != LX_NAND_GOOD_BLOCK)
181 {
182
183 /* Yes, this block is bad. */
184
185 /* Increment the number of bad blocks. */
186 ✗ nand_flash -> lx_nand_flash_bad_blocks++;
187
188 /* Save the block status. */
189 ✗ nand_flash -> lx_nand_flash_block_status_table[block] = LX_NAND_BLOCK_STATUS_BAD;
190
191 /* Continue to the next block. */
192 ✗ continue;
193 }
194
195 /* Call driver read function to read page 0. */
196 #ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
197 5 status = (nand_flash -> lx_nand_flash_driver_pages_read)(nand_flash, block, 0, page_buffer_ptr, spare_buffer_ptr, 1);
198 #else
199 45 status = (nand_flash -> lx_nand_flash_driver_pages_read)(block, 0, page_buffer_ptr, spare_buffer_ptr, 1);
200 #endif
201
202 /* Check for an error from flash driver. */
203
2/4
✗ Branch 23 → 24 not taken.
✓ Branch 23 → 27 taken 15 times.
✗ Branch 26 → 27 not taken.
✓ Branch 26 → 30 taken 35 times.
50 if (status)
204 {
205
206 /* Call system error handler. */
207 ✗ _lx_nand_flash_system_error(nand_flash, status, block, 0);
208
209 /* Determine if the error is fatal. */
210 ✗ if (status != LX_NAND_ERROR_CORRECTED)
211 {
212
213 /* Return an error. */
214 ✗ return(LX_ERROR);
215 }
216 }
217
218 /* Get the page type. */
219 50 page_type = LX_UTILITY_LONG_GET(&spare_buffer_ptr[nand_flash -> lx_nand_flash_spare_data1_offset]);
220
221 /* Check if the type is device info. */
222
2/4
✓ Branch 27 → 28 taken 15 times.
✗ Branch 27 → 31 not taken.
✓ Branch 30 → 31 taken 35 times.
✗ Branch 30 → 34 not taken.
50 if (page_type == LX_NAND_PAGE_TYPE_DEVICE_INFO)
223 {
224
225 /* Get the device info page. */
226 50 nand_device_info_page = (LX_NAND_DEVICE_INFO*)page_buffer_ptr;
227
228 /* Check signature. */
229
2/4
✓ Branch 28 → 29 taken 15 times.
✗ Branch 28 → 31 not taken.
✓ Branch 31 → 32 taken 35 times.
✗ Branch 31 → 34 not taken.
50 if (nand_device_info_page -> lx_nand_device_info_signature1 == LX_NAND_DEVICE_INFO_SIGNATURE1 &&
230
2/4
✓ Branch 29 → 30 taken 15 times.
✗ Branch 29 → 31 not taken.
✓ Branch 32 → 33 taken 35 times.
✗ Branch 32 → 34 not taken.
50 nand_device_info_page -> lx_nand_device_info_signature2 == LX_NAND_DEVICE_INFO_SIGNATURE2)
231 {
232
233 /* Save the block numbers. */
234 50 nand_flash -> lx_nand_flash_metadata_block_number = nand_device_info_page -> lx_nand_device_info_metadata_block_number;
235 50 nand_flash -> lx_nand_flash_backup_metadata_block_number = nand_device_info_page -> lx_nand_device_info_backup_metadata_block_number;
236 50 break;
237 }
238
239 }
240
241 }
242
243 /* Check if we have found the metadata block. */
244
2/4
✗ Branch 33 → 34 not taken.
✓ Branch 33 → 35 taken 15 times.
✗ Branch 36 → 37 not taken.
✓ Branch 36 → 38 taken 35 times.
50 if (nand_flash -> lx_nand_flash_metadata_block_number == LX_NAND_BLOCK_UNMAPPED)
245 {
246
247 /* Not found, return an error. */
248 ✗ return (LX_ERROR);
249 }
250
251 /* Initialize metadata block numbers and lists. */
252 50 nand_flash -> lx_nand_flash_metadata_block_number_current = nand_flash -> lx_nand_flash_metadata_block_number;
253 50 nand_flash -> lx_nand_flash_backup_metadata_block_number_current = nand_flash -> lx_nand_flash_backup_metadata_block_number;
254 50 nand_flash -> lx_nand_flash_metadata_block[0] = (USHORT)nand_flash -> lx_nand_flash_metadata_block_number;
255 50 nand_flash -> lx_nand_flash_backup_metadata_block[0] = (USHORT)nand_flash -> lx_nand_flash_backup_metadata_block_number;
256
257 /* Found one metadata block. */
258 50 nand_flash -> lx_nand_flash_metadata_block_count = 1;
259
260 /* Clear searched block count. */
261 50 block_count = 0;
262
263 do
264 {
265
266 /* Initialize next block to unmapped. */
267 70 nand_flash -> lx_nand_flash_metadata_block_number_next = LX_NAND_BLOCK_UNMAPPED;
268 70 nand_flash -> lx_nand_flash_backup_metadata_block_number_next = LX_NAND_BLOCK_UNMAPPED;
269
270 /* Loop to read pages in the metadata block. */
271
4/4
✓ Branch 59 → 37 taken 1782 times.
✓ Branch 59 → 60 taken 21 times.
✓ Branch 62 → 40 taken 4158 times.
✓ Branch 62 → 63 taken 49 times.
6010 for (page = 0; page < nand_flash -> lx_nand_flash_pages_per_block ; page++)
272 {
273
274 /* Call driver read function to read page. */
275 #ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
276 594 status = (nand_flash -> lx_nand_flash_driver_pages_read)(nand_flash, block, page, page_buffer_ptr, spare_buffer_ptr, 1);
277 #else
278 5346 status = (nand_flash -> lx_nand_flash_driver_pages_read)(block, page, page_buffer_ptr, spare_buffer_ptr, 1);
279 #endif
280
281 /* Check for an error from flash driver. */
282
2/4
✗ Branch 38 → 39 not taken.
✓ Branch 38 → 42 taken 1782 times.
✗ Branch 41 → 42 not taken.
✓ Branch 41 → 45 taken 4158 times.
5940 if (status)
283 {
284
285 /* Call system error handler. */
286 ✗ _lx_nand_flash_system_error(nand_flash, status, block, 0);
287
288 /* Determine if the error is fatal. */
289 ✗ if (status != LX_NAND_ERROR_CORRECTED)
290 {
291
292 /* Return an error. */
293 ✗ return(LX_ERROR);
294 }
295 }
296
297 /* Get page type and page index. */
298 5940 page_type = LX_UTILITY_LONG_GET(&spare_buffer_ptr[nand_flash -> lx_nand_flash_spare_data1_offset]) & (~LX_NAND_PAGE_TYPE_PAGE_NUMBER_MASK);
299 5940 page_index = LX_UTILITY_LONG_GET(&spare_buffer_ptr[nand_flash -> lx_nand_flash_spare_data1_offset]) & LX_NAND_PAGE_TYPE_PAGE_NUMBER_MASK;
300
301 /* Process metadata page by type. */
302
12/14
✓ Branch 42 → 43 taken 15 times.
✓ Branch 42 → 44 taken 30 times.
✓ Branch 42 → 47 taken 69 times.
✓ Branch 42 → 50 taken 1632 times.
✓ Branch 42 → 53 taken 15 times.
✓ Branch 42 → 54 taken 21 times.
✗ Branch 42 → 55 not taken.
✓ Branch 45 → 46 taken 35 times.
✓ Branch 45 → 47 taken 70 times.
✓ Branch 45 → 50 taken 161 times.
✓ Branch 45 → 53 taken 3808 times.
✓ Branch 45 → 56 taken 35 times.
✓ Branch 45 → 57 taken 49 times.
✗ Branch 45 → 58 not taken.
5940 switch (page_type)
303 {
304 50 case LX_NAND_PAGE_TYPE_DEVICE_INFO:
305
306 /* This page is for device info. */
307 50 nand_device_info_page = (LX_NAND_DEVICE_INFO*)page_buffer_ptr;
308
309 /* Get the base erase count. */
310 50 nand_flash -> lx_nand_flash_base_erase_count = nand_device_info_page -> lx_nand_device_info_base_erase_count;
311 50 break;
312
313 100 case LX_NAND_PAGE_TYPE_ERASE_COUNT_TABLE:
314
315 /* Check if page index is valid. */
316
2/4
✗ Branch 44 → 45 not taken.
✓ Branch 44 → 46 taken 30 times.
✗ Branch 47 → 48 not taken.
✓ Branch 47 → 49 taken 70 times.
100 if (((ULONG)page_index + 1) * nand_flash -> lx_nand_flash_bytes_per_page > nand_flash -> lx_nand_flash_erase_count_table_size)
317 {
318
319 /* Invalid page index. Return an error. */
320 ✗ status = LX_ERROR;
321 ✗ break;
322 }
323
324 /* Copy page data to erase count table. */
325 100 LX_MEMCPY(nand_flash -> lx_nand_flash_erase_count_table + page_index * nand_flash -> lx_nand_flash_bytes_per_page, /* Use case of memcpy is verified. */
326 page_buffer_ptr, nand_flash -> lx_nand_flash_bytes_per_page);
327 100 break;
328
329 230 case LX_NAND_PAGE_TYPE_BLOCK_MAPPING_TABLE:
330
331 /* Check if page index is valid. */
332
2/4
✗ Branch 47 → 48 not taken.
✓ Branch 47 → 49 taken 69 times.
✗ Branch 50 → 51 not taken.
✓ Branch 50 → 52 taken 161 times.
230 if (((ULONG)page_index + 1) * nand_flash -> lx_nand_flash_bytes_per_page > nand_flash -> lx_nand_flash_block_mapping_table_size)
333 {
334
335 /* Invalid page index. Return an error. */
336 ✗ status = LX_ERROR;
337 ✗ break;
338 }
339
340 /* Copy page data to block mapping table. */
341 230 LX_MEMCPY(nand_flash -> lx_nand_flash_block_mapping_table + page_index * nand_flash -> lx_nand_flash_bytes_per_page / sizeof(*nand_flash -> lx_nand_flash_block_mapping_table), /* Use case of memcpy is verified. */
342 page_buffer_ptr, nand_flash -> lx_nand_flash_bytes_per_page);
343 230 break;
344
345 5440 case LX_NAND_PAGE_TYPE_BLOCK_STATUS_TABLE:
346
347 /* Check if page index is valid. */
348
2/4
✗ Branch 50 → 51 not taken.
✓ Branch 50 → 52 taken 1632 times.
✗ Branch 53 → 54 not taken.
✓ Branch 53 → 55 taken 3808 times.
5440 if (((ULONG)page_index + 1) * nand_flash -> lx_nand_flash_bytes_per_page > nand_flash -> lx_nand_flash_block_status_table_size)
349 {
350
351 /* Invalid page index. Return an error. */
352 ✗ status = LX_ERROR;
353 ✗ break;
354 }
355
356 /* Copy page data to block status table. */
357 5440 LX_MEMCPY(nand_flash -> lx_nand_flash_block_status_table + page_index * nand_flash -> lx_nand_flash_bytes_per_page / sizeof(*nand_flash -> lx_nand_flash_block_status_table), /* Use case of memcpy is verified. */
358 page_buffer_ptr, nand_flash -> lx_nand_flash_bytes_per_page);
359 5440 break;
360
361 50 case LX_NAND_PAGE_TYPE_FREE_PAGE:
362
363 /* Found a free page. Update current page. */
364 50 nand_flash -> lx_nand_flash_metadata_block_current_page = page;
365 50 nand_flash -> lx_nand_flash_backup_metadata_block_current_page = page;
366
367 /* Skip all the remaining pages. */
368 50 page = nand_flash -> lx_nand_flash_pages_per_block;
369 50 break;
370
371 70 case LX_NAND_PAGE_TYPE_BLOCK_LINK:
372
373 /* Found next blocks. Update next block numbers. */
374 70 nand_flash -> lx_nand_flash_metadata_block_number_next = LX_UTILITY_LONG_GET(&page_buffer_ptr[LX_NAND_BLOCK_LINK_MAIN_METADATA_OFFSET]);
375 70 nand_flash -> lx_nand_flash_backup_metadata_block_number_next = LX_UTILITY_LONG_GET(&page_buffer_ptr[LX_NAND_BLOCK_LINK_BACKUP_METADATA_OFFSET]);
376
377 /* Save block numbers in metadata block lists. */
378 70 nand_flash -> lx_nand_flash_metadata_block[nand_flash -> lx_nand_flash_metadata_block_count] = (USHORT)LX_UTILITY_LONG_GET(&page_buffer_ptr[LX_NAND_BLOCK_LINK_MAIN_METADATA_OFFSET]);
379 70 nand_flash -> lx_nand_flash_backup_metadata_block[nand_flash -> lx_nand_flash_metadata_block_count] = (USHORT)LX_UTILITY_LONG_GET(&page_buffer_ptr[LX_NAND_BLOCK_LINK_BACKUP_METADATA_OFFSET]);
380
381 /* Increase metadata block count. */
382 70 nand_flash -> lx_nand_flash_metadata_block_count++;
383
384 70 break;
385
386 ✗ default:
387
388 /* Unknown type, return error. */
389 ✗ status = LX_ERROR;
390 }
391
392 /* Check status. */
393
2/4
✗ Branch 56 → 57 not taken.
✓ Branch 56 → 58 taken 1782 times.
✗ Branch 59 → 60 not taken.
✓ Branch 59 → 61 taken 4158 times.
5940 if (status == LX_ERROR)
394 {
395
396 /* Error, break the loop. */
397 ✗ break;
398 }
399
400 }
401
402 /* Check if we have reached the last page. */
403
4/4
✓ Branch 60 → 61 taken 6 times.
✓ Branch 60 → 64 taken 15 times.
✓ Branch 63 → 64 taken 14 times.
✓ Branch 63 → 67 taken 35 times.
70 if (page == nand_flash -> lx_nand_flash_pages_per_block)
404 {
405
406 /* Move to next block. */
407 20 nand_flash -> lx_nand_flash_metadata_block_number_current = nand_flash -> lx_nand_flash_metadata_block_number_next;
408 20 nand_flash -> lx_nand_flash_backup_metadata_block_number_current = nand_flash -> lx_nand_flash_backup_metadata_block_number_next;
409
410 /* Make sure the block is valid. */
411
2/4
✗ Branch 61 → 62 not taken.
✓ Branch 61 → 63 taken 6 times.
✗ Branch 64 → 65 not taken.
✓ Branch 64 → 66 taken 14 times.
20 if (nand_flash -> lx_nand_flash_metadata_block_number_current == LX_NAND_BLOCK_UNMAPPED)
412 {
413
414 /* Error, break the loop. */
415 ✗ break;
416 }
417
418 /* Get the block to process. */
419 20 block = nand_flash -> lx_nand_flash_metadata_block_number_current;
420 }
421
422 /* Increase the processed block number. */
423 70 block_count++;
424
425 /* If block count is larger than total blocks, there is an error. */
426
2/4
✗ Branch 64 → 65 not taken.
✓ Branch 64 → 66 taken 21 times.
✗ Branch 67 → 68 not taken.
✓ Branch 67 → 69 taken 49 times.
70 if (block_count >= nand_flash -> lx_nand_flash_total_blocks)
427 {
428
429 /* Break the loop. */
430 ✗ break;
431 }
432
6/8
✓ Branch 66 → 67 taken 6 times.
✓ Branch 66 → 69 taken 15 times.
✓ Branch 67 → 68 taken 6 times.
✗ Branch 67 → 69 not taken.
✓ Branch 69 → 70 taken 14 times.
✓ Branch 69 → 72 taken 35 times.
✓ Branch 70 → 71 taken 14 times.
✗ Branch 70 → 72 not taken.
70 } while (nand_flash -> lx_nand_flash_metadata_block_current_page == 0 && status != LX_ERROR);
433
434 /* Check if metadata page is processed correctly. */
435
4/8
✓ Branch 69 → 70 taken 15 times.
✗ Branch 69 → 71 not taken.
✗ Branch 70 → 71 not taken.
✓ Branch 70 → 72 taken 15 times.
✓ Branch 72 → 73 taken 35 times.
✗ Branch 72 → 74 not taken.
✗ Branch 73 → 74 not taken.
✓ Branch 73 → 75 taken 35 times.
50 if (nand_flash -> lx_nand_flash_metadata_block_current_page == 0 || status == LX_ERROR)
436 {
437
438 /* Return an error. */
439 ✗ return(LX_ERROR);
440 }
441
442 /* Loop to build free and mapped block lists. */
443
4/4
✓ Branch 78 → 73 taken 15360 times.
✓ Branch 78 → 79 taken 15 times.
✓ Branch 81 → 76 taken 35840 times.
✓ Branch 81 → 82 taken 35 times.
51250 for (block = 0; block < nand_flash -> lx_nand_flash_total_blocks; block++)
444 {
445
446 /* Check for free blocks. */
447
4/4
✓ Branch 73 → 74 taken 15279 times.
✓ Branch 73 → 75 taken 81 times.
✓ Branch 76 → 77 taken 35651 times.
✓ Branch 76 → 78 taken 189 times.
51200 if (nand_flash -> lx_nand_flash_block_status_table[block] == LX_NAND_BLOCK_STATUS_FREE)
448 {
449
450 /* Add the block to free block list. */
451 50930 _lx_nand_flash_free_block_list_add(nand_flash, block);
452 }
453
454 /* Check for mapped blocks. */
455
4/4
✓ Branch 75 → 76 taken 9 times.
✓ Branch 75 → 77 taken 15351 times.
✓ Branch 78 → 79 taken 21 times.
✓ Branch 78 → 80 taken 35819 times.
51200 if (nand_flash -> lx_nand_flash_block_mapping_table[block] != LX_NAND_BLOCK_UNMAPPED)
456 {
457
458 /* Add the block to free block list. */
459 30 _lx_nand_flash_mapped_block_list_add(nand_flash, block);
460 }
461 }
462
463
464 #ifdef LX_NAND_FLASH_ENABLE_LAZY_SECTOR_RELEASE
465 {
466
467 ULONG blk;
468 ULONG lg;
469 USHORT blk_status;
470
471 /* Phase 1: Rebuild compaction table and recover from mid-release crashes.
472 Scan all blocks for COMPACTION_PENDING. */
473 for (blk = 0; blk < nand_flash -> lx_nand_flash_total_blocks; blk++)
474 {
475
476 blk_status = nand_flash -> lx_nand_flash_block_status_table[blk];
477
478 /* FREE (0xFFFF) and BAD (0xFF00) both have COMPACTION_PENDING bit set; skip them. */
479 if ((blk_status == LX_NAND_BLOCK_STATUS_FREE) || (blk_status == LX_NAND_BLOCK_STATUS_BAD))
480 {
481 continue;
482 }
483
484 if (blk_status & LX_NAND_BLOCK_STATUS_COMPACTION_PENDING)
485 {
486
487 /* Check if any logical group still maps to this physical block.
488 If so, the mapping update didn't happen — abort the lazy release. */
489 lg = nand_flash -> lx_nand_flash_total_blocks;
490 {
491 ULONG search_lg;
492 for (search_lg = 0; search_lg < nand_flash -> lx_nand_flash_total_blocks; search_lg++)
493 {
494 if (nand_flash -> lx_nand_flash_block_mapping_table[search_lg] == (USHORT)blk)
495 {
496 lg = search_lg;
497 break;
498 }
499 }
500 }
501
502 if (lg != nand_flash -> lx_nand_flash_total_blocks)
503 {
504
505 /* Scenario A: crash after COMPACTION_PENDING set, before mapping updated.
506 Clear COMPACTION_PENDING to restore the block to its normal state. */
507 blk_status = (USHORT)(blk_status & (USHORT)(~LX_NAND_BLOCK_STATUS_COMPACTION_PENDING));
508 (void)_lx_nand_flash_block_status_set(nand_flash, blk, blk_status);
509 }
510 else
511 {
512
513 /* Scenario B: deferred compaction — scan block pages to find the LG. */
514 ULONG page;
515 ULONG spare_word;
516 ULONG found_lg;
517 UCHAR *spare_ptr;
518
519 spare_ptr = (UCHAR*)nand_flash -> lx_nand_flash_page_buffer;
520 found_lg = nand_flash -> lx_nand_flash_total_blocks;
521
522 for (page = 0; page < nand_flash -> lx_nand_flash_pages_per_block; page++)
523 {
524
525 #ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
526 status = (nand_flash -> lx_nand_flash_driver_pages_read)(nand_flash, blk, page, (UCHAR*)NULL, spare_ptr, 1);
527 #else
528 status = (nand_flash -> lx_nand_flash_driver_pages_read)(blk, page, (UCHAR*)NULL, spare_ptr, 1);
529 #endif
530
531 if (status)
532 {
533 break;
534 }
535
536 spare_word = LX_UTILITY_LONG_GET(&spare_ptr[nand_flash -> lx_nand_flash_spare_data1_offset]);
537
538 if ((spare_word & (~LX_NAND_PAGE_TYPE_USER_DATA_MASK)) == LX_NAND_PAGE_TYPE_USER_DATA)
539 {
540 found_lg = (spare_word & LX_NAND_PAGE_TYPE_USER_DATA_MASK) /
541 nand_flash -> lx_nand_flash_pages_per_block;
542 break;
543 }
544 }
545
546 if ((found_lg != nand_flash -> lx_nand_flash_total_blocks) &&
547 (found_lg < nand_flash -> lx_nand_flash_total_blocks))
548 {
549 nand_flash -> lx_nand_flash_block_compaction_table[found_lg] = (USHORT)blk;
550 }
551 }
552 }
553 }
554
555 /* Phase 2: Orphan block recovery — erase ALLOCATED blocks not referenced
556 by any mapping entry and not marked COMPACTION_PENDING. */
557 for (blk = 0; blk < nand_flash -> lx_nand_flash_total_blocks; blk++)
558 {
559
560 ULONG found;
561
562 blk_status = nand_flash -> lx_nand_flash_block_status_table[blk];
563
564 if ((blk_status == LX_NAND_BLOCK_STATUS_FREE) || (blk_status == LX_NAND_BLOCK_STATUS_BAD))
565 {
566 continue;
567 }
568
569 if (blk_status & LX_NAND_BLOCK_STATUS_COMPACTION_PENDING)
570 {
571 continue;
572 }
573
574 if (!(blk_status & LX_NAND_BLOCK_STATUS_ALLOCATED))
575 {
576 continue;
577 }
578
579 /* Search for this block in the mapping table. */
580 found = LX_FALSE;
581 for (lg = 0; lg < nand_flash -> lx_nand_flash_total_blocks; lg++)
582 {
583 if (nand_flash -> lx_nand_flash_block_mapping_table[lg] == (USHORT)blk)
584 {
585 found = LX_TRUE;
586 break;
587 }
588 }
589
590 if (!found)
591 {
592
593 /* Orphan block: erase and reclaim. */
594 status = _lx_nand_flash_driver_block_erase(nand_flash, blk,
595 nand_flash -> lx_nand_flash_base_erase_count +
596 nand_flash -> lx_nand_flash_erase_count_table[blk] + 1);
597
598 if (status)
599 {
600 _lx_nand_flash_system_error(nand_flash, status, blk, 0);
601 continue;
602 }
603
604 status = _lx_nand_flash_erase_count_set(nand_flash, blk,
605 (UCHAR)(nand_flash -> lx_nand_flash_erase_count_table[blk] + 1));
606
607 if (!status)
608 {
609 (void)_lx_nand_flash_block_status_set(nand_flash, blk, LX_NAND_BLOCK_STATUS_FREE);
610 _lx_nand_flash_free_block_list_add(nand_flash, blk);
611 }
612 }
613 }
614
615 }
616 #endif /* LX_NAND_FLASH_ENABLE_LAZY_SECTOR_RELEASE */
617
618
619 #ifdef LX_THREAD_SAFE_ENABLE
620
621 /* If the thread safe option is enabled, create a ThreadX mutex that will be used in all external APIs
622 in order to provide thread-safe operation. */
623 5 status = tx_mutex_create(&nand_flash -> lx_nand_flash_mutex, "NAND Flash Mutex", TX_NO_INHERIT);
624
625 /* Determine if the mutex creation encountered an error. */
626
1/2
✗ Branch 83 → 84 not taken.
✓ Branch 83 → 86 taken 5 times.
5 if (status != LX_SUCCESS)
627 {
628
629 /* Call system error handler, since this should not happen. */
630 ✗ _lx_nand_flash_system_error(nand_flash, LX_SYSTEM_MUTEX_CREATE_FAILED, 0, 0);
631
632 /* Return error to caller. */
633 ✗ return(LX_ERROR);
634 }
635 #endif
636
637 /* Lockout interrupts. */
638 35 LX_DISABLE
639
640 /* At this point, the NAND flash has been opened successfully. Place the
641 NAND flash control block on the linked list of currently opened NAND flashes. */
642
643 /* Set the NAND flash state to open. */
644 50 nand_flash -> lx_nand_flash_state = LX_NAND_FLASH_OPENED;
645
646 /* Place the NAND flash control block on the list of opened NAND flashes. First,
647 check for an empty list. */
648
3/6
✗ Branch 79 → 80 not taken.
✓ Branch 79 → 81 taken 15 times.
✗ Branch 83 → 84 not taken.
✓ Branch 83 → 85 taken 30 times.
✗ Branch 87 → 88 not taken.
✓ Branch 87 → 89 taken 5 times.
50 if (_lx_nand_flash_opened_count)
649 {
650
651 /* List is not empty - other NAND flashes are open. */
652
653 /* Pickup tail pointer. */
654 ✗ tail_ptr = _lx_nand_flash_opened_ptr -> lx_nand_flash_open_previous;
655
656 /* Place the new NAND flash control block in the list. */
657 ✗ _lx_nand_flash_opened_ptr -> lx_nand_flash_open_previous = nand_flash;
658 ✗ tail_ptr -> lx_nand_flash_open_next = nand_flash;
659
660 /* Setup this NAND flash's opened links. */
661 ✗ nand_flash -> lx_nand_flash_open_previous = tail_ptr;
662 ✗ nand_flash -> lx_nand_flash_open_next = _lx_nand_flash_opened_ptr;
663 }
664 else
665 {
666
667 /* The opened NAND flash list is empty. Add the NAND flash to empty list. */
668 50 _lx_nand_flash_opened_ptr = nand_flash;
669 50 nand_flash -> lx_nand_flash_open_next = nand_flash;
670 50 nand_flash -> lx_nand_flash_open_previous = nand_flash;
671 }
672
673 /* Increment the opened NAND flash counter. */
674 50 _lx_nand_flash_opened_count++;
675
676 /* Restore interrupts. */
677 35 LX_RESTORE
678
679 /* Return a successful completion. */
680 50 return(LX_SUCCESS);
681 }
682
683