lx_nand_flash_sector_release.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_sector_release PORTABLE C */ | ||
| 44 | /* 6.2.1 */ | ||
| 45 | /* AUTHOR */ | ||
| 46 | /* */ | ||
| 47 | /* Xiuwen Cai, Microsoft Corporation */ | ||
| 48 | /* */ | ||
| 49 | /* DESCRIPTION */ | ||
| 50 | /* */ | ||
| 51 | /* This function releases a logical sector from being managed in the */ | ||
| 52 | /* NAND flash. */ | ||
| 53 | /* */ | ||
| 54 | /* INPUT */ | ||
| 55 | /* */ | ||
| 56 | /* nand_flash NAND flash instance */ | ||
| 57 | /* logical_sector Logical sector number */ | ||
| 58 | /* */ | ||
| 59 | /* OUTPUT */ | ||
| 60 | /* */ | ||
| 61 | /* return status */ | ||
| 62 | /* */ | ||
| 63 | /* CALLS */ | ||
| 64 | /* */ | ||
| 65 | /* _lx_nand_flash_block_find Find the mapped block */ | ||
| 66 | /* lx_nand_flash_driver_pages_read Read pages */ | ||
| 67 | /* _lx_nand_flash_block_allocate Allocate block */ | ||
| 68 | /* _lx_nand_flash_mapped_block_list_remove */ | ||
| 69 | /* Remove mapped block */ | ||
| 70 | /* _lx_nand_flash_data_page_copy Copy data pages */ | ||
| 71 | /* _lx_nand_flash_free_block_list_add Add free block to list */ | ||
| 72 | /* _lx_nand_flash_block_mapping_set Set block mapping */ | ||
| 73 | /* _lx_nand_flash_driver_block_erase Erase block */ | ||
| 74 | /* _lx_nand_flash_erase_count_set Set erase count */ | ||
| 75 | /* _lx_nand_flash_block_data_move Move block data */ | ||
| 76 | /* _lx_nand_flash_block_status_set Set block status */ | ||
| 77 | /* _lx_nand_flash_mapped_block_list_add Add mapped block to list */ | ||
| 78 | /* _lx_nand_flash_system_error Internal system error handler */ | ||
| 79 | /* tx_mutex_get Get thread protection */ | ||
| 80 | /* tx_mutex_put Release thread protection */ | ||
| 81 | /* */ | ||
| 82 | /* CALLED BY */ | ||
| 83 | /* */ | ||
| 84 | /* Application Code */ | ||
| 85 | /* */ | ||
| 86 | /**************************************************************************/ | ||
| 87 | 67380 | UINT _lx_nand_flash_sector_release(LX_NAND_FLASH *nand_flash, ULONG logical_sector) | |
| 88 | { | ||
| 89 | |||
| 90 | UINT status; | ||
| 91 | ULONG block; | ||
| 92 | USHORT block_status; | ||
| 93 | UCHAR *spare_buffer_ptr; | ||
| 94 | ULONG available_pages; | ||
| 95 | LONG page; | ||
| 96 | 67380 | UINT release_sector = LX_FALSE; | |
| 97 | ULONG new_block; | ||
| 98 | USHORT new_block_status; | ||
| 99 | |||
| 100 | #ifdef LX_THREAD_SAFE_ENABLE | ||
| 101 | |||
| 102 | /* Obtain the thread safe mutex. */ | ||
| 103 | 6738 | tx_mutex_get(&nand_flash -> lx_nand_flash_mutex, TX_WAIT_FOREVER); | |
| 104 | #endif | ||
| 105 | |||
| 106 | /* Increment the number of release requests. */ | ||
| 107 | 67380 | nand_flash -> lx_nand_flash_diagnostic_sector_release_requests++; | |
| 108 | |||
| 109 | |||
| 110 | /* See if we can find the sector in the current mapping. */ | ||
| 111 | 67380 | status = _lx_nand_flash_block_find(nand_flash, logical_sector, &block, &block_status); | |
| 112 | |||
| 113 | /* Check return status. */ | ||
| 114 |
2/4✗ Branch 3 → 4 not taken.
✓ Branch 3 → 7 taken 60642 times.
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 9 taken 6738 times.
|
67380 | if (status != LX_SUCCESS) |
| 115 | { | ||
| 116 | |||
| 117 | /* Call system error handler. */ | ||
| 118 | ✗ | _lx_nand_flash_system_error(nand_flash, status, block, 0); | |
| 119 | |||
| 120 | /* Determine if the error is fatal. */ | ||
| 121 | ✗ | if (status != LX_NAND_ERROR_CORRECTED) | |
| 122 | { | ||
| 123 | #ifdef LX_THREAD_SAFE_ENABLE | ||
| 124 | |||
| 125 | /* Release the thread safe mutex. */ | ||
| 126 | ✗ | tx_mutex_put(&nand_flash -> lx_nand_flash_mutex); | |
| 127 | #endif | ||
| 128 | |||
| 129 | /* Return an error. */ | ||
| 130 | ✗ | return(LX_ERROR); | |
| 131 | } | ||
| 132 | } | ||
| 133 | |||
| 134 | /* Determine if the block is mapped. */ | ||
| 135 |
5/5✓ Branch 7 → 8 taken 3222 times.
✓ Branch 7 → 77 taken 19140 times.
✓ Branch 7 → 80 taken 38280 times.
✓ Branch 9 → 10 taken 358 times.
✓ Branch 9 → 92 taken 6380 times.
|
67380 | if (block != LX_NAND_BLOCK_UNMAPPED) |
| 136 | { | ||
| 137 | |||
| 138 | /* Setup spare buffer pointer. */ | ||
| 139 | 3580 | spare_buffer_ptr = (UCHAR*)nand_flash -> lx_nand_flash_page_buffer; | |
| 140 | |||
| 141 | /* Get available pages in this block. */ | ||
| 142 |
4/4✓ Branch 8 → 9 taken 18 times.
✓ Branch 8 → 10 taken 3204 times.
✓ Branch 10 → 11 taken 2 times.
✓ Branch 10 → 12 taken 356 times.
|
3580 | 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; |
| 143 | |||
| 144 | /* Determine if the pages are recorded sequentially. */ | ||
| 145 |
4/4✓ Branch 11 → 12 taken 3204 times.
✓ Branch 11 → 22 taken 18 times.
✓ Branch 13 → 14 taken 356 times.
✓ Branch 13 → 25 taken 2 times.
|
3580 | if (block_status & LX_NAND_BLOCK_STATUS_NON_SEQUENTIAL) |
| 146 | { | ||
| 147 | |||
| 148 | /* Loop to search the logical page. */ | ||
| 149 |
4/4✓ Branch 21 → 13 taken 102717 times.
✓ Branch 21 → 24 taken 3204 times.
✓ Branch 24 → 15 taken 11413 times.
✓ Branch 24 → 27 taken 356 times.
|
117690 | for (page = (LONG)available_pages - 1; page >= 0; page--) |
| 150 | { | ||
| 151 | |||
| 152 | /* Read a page. */ | ||
| 153 | #ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE | ||
| 154 | 11413 | status = (nand_flash -> lx_nand_flash_driver_pages_read)(nand_flash, block, (ULONG)page, LX_NULL, spare_buffer_ptr, 1); | |
| 155 | #else | ||
| 156 | 102717 | status = (nand_flash -> lx_nand_flash_driver_pages_read)(block, (ULONG)page, LX_NULL, spare_buffer_ptr, 1); | |
| 157 | #endif | ||
| 158 | |||
| 159 | /* Check for an error from flash driver. */ | ||
| 160 |
2/4✗ Branch 14 → 15 not taken.
✓ Branch 14 → 17 taken 102717 times.
✗ Branch 16 → 17 not taken.
✓ Branch 16 → 20 taken 11413 times.
|
114130 | if (status) |
| 161 | { | ||
| 162 | |||
| 163 | /* Call system error handler. */ | ||
| 164 | ✗ | _lx_nand_flash_system_error(nand_flash, status, block, 0); | |
| 165 | #ifdef LX_THREAD_SAFE_ENABLE | ||
| 166 | |||
| 167 | /* Release the thread safe mutex. */ | ||
| 168 | ✗ | tx_mutex_put(&nand_flash -> lx_nand_flash_mutex); | |
| 169 | #endif | ||
| 170 | |||
| 171 | /* Return an error. */ | ||
| 172 | ✗ | return(LX_ERROR); | |
| 173 | } | ||
| 174 | |||
| 175 | /* Get the logical sector number from spare bytes, and check if it matches the addressed sector number. */ | ||
| 176 |
4/4✓ Branch 17 → 18 taken 468 times.
✓ Branch 17 → 20 taken 102249 times.
✓ Branch 20 → 21 taken 52 times.
✓ Branch 20 → 23 taken 11361 times.
|
114130 | 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) |
| 177 | { | ||
| 178 | |||
| 179 | /* Make sure the sector is not released. */ | ||
| 180 |
2/4✓ Branch 18 → 19 taken 468 times.
✗ Branch 18 → 20 not taken.
✓ Branch 21 → 22 taken 52 times.
✗ Branch 21 → 23 not taken.
|
520 | 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)) |
| 181 | { | ||
| 182 | |||
| 183 | /* Set release sector flag. */ | ||
| 184 | 520 | release_sector = LX_TRUE; | |
| 185 | } | ||
| 186 | } | ||
| 187 | } | ||
| 188 | } | ||
| 189 | else | ||
| 190 | { | ||
| 191 | |||
| 192 | /* Check if the logical sector is available. */ | ||
| 193 |
2/4✓ Branch 22 → 23 taken 18 times.
✗ Branch 22 → 24 not taken.
✓ Branch 25 → 26 taken 2 times.
✗ Branch 25 → 27 not taken.
|
20 | if (logical_sector % nand_flash -> lx_nand_flash_pages_per_block < available_pages) |
| 194 | { | ||
| 195 | |||
| 196 | /* Set release sector flag. */ | ||
| 197 | 20 | release_sector = LX_TRUE; | |
| 198 | } | ||
| 199 | } | ||
| 200 | |||
| 201 | /* Determine if the sector needs to be released. */ | ||
| 202 |
5/5✓ Branch 24 → 25 taken 486 times.
✓ Branch 24 → 77 taken 912 times.
✓ Branch 24 → 80 taken 1824 times.
✓ Branch 27 → 28 taken 54 times.
✓ Branch 27 → 92 taken 304 times.
|
3580 | if (release_sector) |
| 203 | { | ||
| 204 | |||
| 205 | /* Check if the block is full. */ | ||
| 206 |
4/4✓ Branch 25 → 26 taken 18 times.
✓ Branch 25 → 65 taken 468 times.
✓ Branch 28 → 29 taken 2 times.
✓ Branch 28 → 75 taken 52 times.
|
540 | if (block_status & LX_NAND_BLOCK_STATUS_FULL) |
| 207 | { | ||
| 208 | |||
| 209 | #ifdef LX_NAND_FLASH_ENABLE_LAZY_SECTOR_RELEASE | ||
| 210 | /* Lazy path: defer the copy+erase when enough free blocks are available. | ||
| 211 | The old block is kept as a compaction source; a new block holds only | ||
| 212 | the tombstone for the released sector. */ | ||
| 213 | if (nand_flash -> lx_nand_flash_free_block_list_tail > | ||
| 214 | (ULONG)LX_NAND_FLASH_SECTOR_RELEASE_LAZY_THRESHOLD) | ||
| 215 | { | ||
| 216 | |||
| 217 | /* Allocate a new block for the tombstone. */ | ||
| 218 | status = _lx_nand_flash_block_allocate(nand_flash, &new_block); | ||
| 219 | |||
| 220 | /* Check return status. */ | ||
| 221 | if (status != LX_SUCCESS) | ||
| 222 | { | ||
| 223 | |||
| 224 | /* Call system error handler. */ | ||
| 225 | _lx_nand_flash_system_error(nand_flash, status, new_block, 0); | ||
| 226 | #ifdef LX_THREAD_SAFE_ENABLE | ||
| 227 | |||
| 228 | /* Release the thread safe mutex. */ | ||
| 229 | tx_mutex_put(&nand_flash -> lx_nand_flash_mutex); | ||
| 230 | #endif | ||
| 231 | /* Return an error. */ | ||
| 232 | return(LX_ERROR); | ||
| 233 | } | ||
| 234 | |||
| 235 | /* Set page buffer to all 0xFF (data = erased, sector is released). */ | ||
| 236 | LX_MEMSET(nand_flash -> lx_nand_flash_page_buffer, 0xFF, | ||
| 237 | nand_flash -> lx_nand_flash_bytes_per_page + | ||
| 238 | nand_flash -> lx_nand_flash_spare_total_length); | ||
| 239 | |||
| 240 | /* Setup spare buffer pointer. */ | ||
| 241 | spare_buffer_ptr = nand_flash -> lx_nand_flash_page_buffer + | ||
| 242 | nand_flash -> lx_nand_flash_bytes_per_page; | ||
| 243 | |||
| 244 | /* Save metadata block number in spare bytes if space allows. */ | ||
| 245 | if (nand_flash -> lx_nand_flash_spare_data2_length >= sizeof(USHORT)) | ||
| 246 | { | ||
| 247 | LX_UTILITY_SHORT_SET(&spare_buffer_ptr[nand_flash -> lx_nand_flash_spare_data2_offset], | ||
| 248 | nand_flash -> lx_nand_flash_metadata_block_number); | ||
| 249 | } | ||
| 250 | |||
| 251 | /* Set page type to USER_DATA_RELEASED. */ | ||
| 252 | LX_UTILITY_LONG_SET(&spare_buffer_ptr[nand_flash -> lx_nand_flash_spare_data1_offset], | ||
| 253 | LX_NAND_PAGE_TYPE_USER_DATA_RELEASED | logical_sector); | ||
| 254 | |||
| 255 | /* Write the tombstone page to page 0 of the new block. */ | ||
| 256 | #ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE | ||
| 257 | status = (nand_flash -> lx_nand_flash_driver_pages_write)(nand_flash, new_block, 0, | ||
| 258 | (UCHAR*)nand_flash -> lx_nand_flash_page_buffer, spare_buffer_ptr, 1); | ||
| 259 | #else | ||
| 260 | status = (nand_flash -> lx_nand_flash_driver_pages_write)(new_block, 0, | ||
| 261 | (UCHAR*)nand_flash -> lx_nand_flash_page_buffer, spare_buffer_ptr, 1); | ||
| 262 | #endif | ||
| 263 | |||
| 264 | /* Check for an error from flash driver. */ | ||
| 265 | if (status) | ||
| 266 | { | ||
| 267 | _lx_nand_flash_system_error(nand_flash, status, new_block, 0); | ||
| 268 | #ifdef LX_THREAD_SAFE_ENABLE | ||
| 269 | tx_mutex_put(&nand_flash -> lx_nand_flash_mutex); | ||
| 270 | #endif | ||
| 271 | return(LX_ERROR); | ||
| 272 | } | ||
| 273 | |||
| 274 | /* Set new block status: allocated, non-sequential, 1 page written. */ | ||
| 275 | new_block_status = (USHORT)(LX_NAND_BLOCK_STATUS_ALLOCATED | | ||
| 276 | LX_NAND_BLOCK_STATUS_NON_SEQUENTIAL | 1u); | ||
| 277 | status = _lx_nand_flash_block_status_set(nand_flash, new_block, new_block_status); | ||
| 278 | if (status) | ||
| 279 | { | ||
| 280 | _lx_nand_flash_system_error(nand_flash, status, new_block, 0); | ||
| 281 | #ifdef LX_THREAD_SAFE_ENABLE | ||
| 282 | tx_mutex_put(&nand_flash -> lx_nand_flash_mutex); | ||
| 283 | #endif | ||
| 284 | return(LX_ERROR); | ||
| 285 | } | ||
| 286 | |||
| 287 | /* Mark old block as compaction-pending (persisted to flash). | ||
| 288 | Write order: tombstone written → new_block status set → | ||
| 289 | COMPACTION_PENDING set → mapping updated. | ||
| 290 | This ordering ensures safe crash recovery at open time. */ | ||
| 291 | status = _lx_nand_flash_block_status_set(nand_flash, block, | ||
| 292 | (USHORT)(block_status | LX_NAND_BLOCK_STATUS_COMPACTION_PENDING)); | ||
| 293 | if (status) | ||
| 294 | { | ||
| 295 | _lx_nand_flash_system_error(nand_flash, status, block, 0); | ||
| 296 | #ifdef LX_THREAD_SAFE_ENABLE | ||
| 297 | tx_mutex_put(&nand_flash -> lx_nand_flash_mutex); | ||
| 298 | #endif | ||
| 299 | return(LX_ERROR); | ||
| 300 | } | ||
| 301 | |||
| 302 | /* Remove old mapping before updating to new block. */ | ||
| 303 | _lx_nand_flash_mapped_block_list_remove(nand_flash, | ||
| 304 | logical_sector / nand_flash -> lx_nand_flash_pages_per_block); | ||
| 305 | |||
| 306 | /* Update logical-to-physical mapping to the new tombstone block. */ | ||
| 307 | _lx_nand_flash_block_mapping_set(nand_flash, logical_sector, new_block); | ||
| 308 | |||
| 309 | /* Record the old block as the compaction source (RAM only; rebuilt at open). */ | ||
| 310 | nand_flash -> lx_nand_flash_block_compaction_table[logical_sector / nand_flash -> lx_nand_flash_pages_per_block] = (USHORT)block; | ||
| 311 | |||
| 312 | /* Add new tombstone block to the mapped list. */ | ||
| 313 | _lx_nand_flash_mapped_block_list_add(nand_flash, | ||
| 314 | logical_sector / nand_flash -> lx_nand_flash_pages_per_block); | ||
| 315 | } | ||
| 316 | else | ||
| 317 | #endif /* LX_NAND_FLASH_ENABLE_LAZY_SECTOR_RELEASE */ | ||
| 318 | { | ||
| 319 | |||
| 320 | /* Eager path (existing): allocate a new block and copy + erase immediately. */ | ||
| 321 | |||
| 322 | /* Allocate a new block. */ | ||
| 323 | 20 | status = _lx_nand_flash_block_allocate(nand_flash, &new_block); | |
| 324 | |||
| 325 | /* Check return status. */ | ||
| 326 |
2/4✗ Branch 27 → 28 not taken.
✓ Branch 27 → 30 taken 18 times.
✗ Branch 30 → 31 not taken.
✓ Branch 30 → 34 taken 2 times.
|
20 | if (status != LX_SUCCESS) |
| 327 | { | ||
| 328 | /* Call system error handler. */ | ||
| 329 | ✗ | _lx_nand_flash_system_error(nand_flash, status, new_block, 0); | |
| 330 | #ifdef LX_THREAD_SAFE_ENABLE | ||
| 331 | |||
| 332 | /* Release the thread safe mutex. */ | ||
| 333 | ✗ | tx_mutex_put(&nand_flash -> lx_nand_flash_mutex); | |
| 334 | #endif | ||
| 335 | |||
| 336 | /* Return an error. */ | ||
| 337 | ✗ | return(LX_ERROR); | |
| 338 | |||
| 339 | } | ||
| 340 | |||
| 341 | /* Set new block status to allocated. */ | ||
| 342 | 20 | new_block_status = LX_NAND_BLOCK_STATUS_ALLOCATED; | |
| 343 | |||
| 344 | /* Remove the old block from mapped block list. */ | ||
| 345 | 20 | _lx_nand_flash_mapped_block_list_remove(nand_flash, logical_sector / nand_flash -> lx_nand_flash_pages_per_block); | |
| 346 | |||
| 347 | /* Copy valid sector to new block. */ | ||
| 348 | 20 | 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)); | |
| 349 | |||
| 350 | /* Check for an error from flash driver. */ | ||
| 351 |
2/4✗ Branch 32 → 33 not taken.
✓ Branch 32 → 35 taken 18 times.
✗ Branch 36 → 37 not taken.
✓ Branch 36 → 40 taken 2 times.
|
20 | if (status) |
| 352 | { | ||
| 353 | |||
| 354 | /* Call system error handler. */ | ||
| 355 | ✗ | _lx_nand_flash_system_error(nand_flash, status, new_block, 0); | |
| 356 | #ifdef LX_THREAD_SAFE_ENABLE | ||
| 357 | |||
| 358 | /* Release the thread safe mutex. */ | ||
| 359 | ✗ | tx_mutex_put(&nand_flash -> lx_nand_flash_mutex); | |
| 360 | #endif | ||
| 361 | |||
| 362 | /* Return an error. */ | ||
| 363 | ✗ | return(LX_ERROR); | |
| 364 | } | ||
| 365 | |||
| 366 | /* Determine if there are sectors after the addressed sector need to be copied. */ | ||
| 367 |
2/4✓ Branch 35 → 36 taken 18 times.
✗ Branch 35 → 40 not taken.
✓ Branch 40 → 41 taken 2 times.
✗ Branch 40 → 46 not taken.
|
20 | if (logical_sector % nand_flash -> lx_nand_flash_pages_per_block < nand_flash -> lx_nand_flash_pages_per_block - 1) |
| 368 | { | ||
| 369 | |||
| 370 | /* Copy valid sector to new block. */ | ||
| 371 | 20 | 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)); | |
| 372 | |||
| 373 | /* Check for an error from flash driver. */ | ||
| 374 |
2/4✗ Branch 37 → 38 not taken.
✓ Branch 37 → 40 taken 18 times.
✗ Branch 42 → 43 not taken.
✓ Branch 42 → 46 taken 2 times.
|
20 | if (status) |
| 375 | { | ||
| 376 | |||
| 377 | /* Call system error handler. */ | ||
| 378 | ✗ | _lx_nand_flash_system_error(nand_flash, status, new_block, 0); | |
| 379 | #ifdef LX_THREAD_SAFE_ENABLE | ||
| 380 | |||
| 381 | /* Release the thread safe mutex. */ | ||
| 382 | ✗ | tx_mutex_put(&nand_flash -> lx_nand_flash_mutex); | |
| 383 | #endif | ||
| 384 | |||
| 385 | /* Return an error. */ | ||
| 386 | ✗ | return(LX_ERROR); | |
| 387 | } | ||
| 388 | } | ||
| 389 | |||
| 390 | /* Check new block status to see if there is valid pages in the block. */ | ||
| 391 |
2/4✗ Branch 40 → 41 not taken.
✓ Branch 40 → 43 taken 18 times.
✗ Branch 46 → 47 not taken.
✓ Branch 46 → 49 taken 2 times.
|
20 | if ((new_block_status & LX_NAND_BLOCK_STATUS_PAGE_NUMBER_MASK) == 0) |
| 392 | { | ||
| 393 | |||
| 394 | /* Add the block to free block list. */ | ||
| 395 | ✗ | _lx_nand_flash_free_block_list_add(nand_flash, new_block); | |
| 396 | |||
| 397 | /* Set new block to unmapped. */ | ||
| 398 | ✗ | new_block = LX_NAND_BLOCK_UNMAPPED; | |
| 399 | } | ||
| 400 | else | ||
| 401 | { | ||
| 402 | |||
| 403 | /* Set new block status. */ | ||
| 404 | 20 | status = _lx_nand_flash_block_status_set(nand_flash, new_block, new_block_status); | |
| 405 | |||
| 406 | /* Check for an error from flash driver. */ | ||
| 407 |
2/4✗ Branch 44 → 45 not taken.
✓ Branch 44 → 47 taken 18 times.
✗ Branch 50 → 51 not taken.
✓ Branch 50 → 54 taken 2 times.
|
20 | if (status) |
| 408 | { | ||
| 409 | |||
| 410 | /* Call system error handler. */ | ||
| 411 | ✗ | _lx_nand_flash_system_error(nand_flash, status, block, 0); | |
| 412 | #ifdef LX_THREAD_SAFE_ENABLE | ||
| 413 | |||
| 414 | /* Release the thread safe mutex. */ | ||
| 415 | ✗ | tx_mutex_put(&nand_flash -> lx_nand_flash_mutex); | |
| 416 | #endif | ||
| 417 | |||
| 418 | /* Return an error. */ | ||
| 419 | ✗ | return(LX_ERROR); | |
| 420 | } | ||
| 421 | } | ||
| 422 | |||
| 423 | /* Update block mapping. */ | ||
| 424 | 20 | _lx_nand_flash_block_mapping_set(nand_flash, logical_sector, new_block); | |
| 425 | |||
| 426 | /* Erase old block. */ | ||
| 427 | 20 | 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); | |
| 428 | |||
| 429 | /* Check for an error from flash driver. */ | ||
| 430 |
2/4✗ Branch 49 → 50 not taken.
✓ Branch 49 → 52 taken 18 times.
✗ Branch 56 → 57 not taken.
✓ Branch 56 → 60 taken 2 times.
|
20 | if (status) |
| 431 | { | ||
| 432 | |||
| 433 | /* Call system error handler. */ | ||
| 434 | ✗ | _lx_nand_flash_system_error(nand_flash, status, block, 0); | |
| 435 | #ifdef LX_THREAD_SAFE_ENABLE | ||
| 436 | |||
| 437 | /* Release the thread safe mutex. */ | ||
| 438 | ✗ | tx_mutex_put(&nand_flash -> lx_nand_flash_mutex); | |
| 439 | #endif | ||
| 440 | |||
| 441 | /* Return an error. */ | ||
| 442 | ✗ | return(LX_ERROR); | |
| 443 | } | ||
| 444 | |||
| 445 | /* Update erase count for the old block. */ | ||
| 446 | 20 | status = _lx_nand_flash_erase_count_set(nand_flash, block, (UCHAR)(nand_flash -> lx_nand_flash_erase_count_table[block] + 1)); | |
| 447 | |||
| 448 | /* Check for an error from flash driver. */ | ||
| 449 |
2/4✗ Branch 53 → 54 not taken.
✓ Branch 53 → 56 taken 18 times.
✗ Branch 61 → 62 not taken.
✓ Branch 61 → 65 taken 2 times.
|
20 | if (status) |
| 450 | { | ||
| 451 | |||
| 452 | /* Call system error handler. */ | ||
| 453 | ✗ | _lx_nand_flash_system_error(nand_flash, status, block, 0); | |
| 454 | #ifdef LX_THREAD_SAFE_ENABLE | ||
| 455 | |||
| 456 | /* Release the thread safe mutex. */ | ||
| 457 | ✗ | tx_mutex_put(&nand_flash -> lx_nand_flash_mutex); | |
| 458 | #endif | ||
| 459 | |||
| 460 | /* Return an error. */ | ||
| 461 | ✗ | return(LX_ERROR); | |
| 462 | } | ||
| 463 | |||
| 464 | /* Check if the block has too many erases. */ | ||
| 465 |
2/4✗ Branch 56 → 57 not taken.
✓ Branch 56 → 58 taken 18 times.
✗ Branch 65 → 66 not taken.
✓ Branch 65 → 67 taken 2 times.
|
20 | if (nand_flash -> lx_nand_flash_erase_count_table[block] > LX_NAND_FLASH_MAX_ERASE_COUNT_DELTA) |
| 466 | { | ||
| 467 | |||
| 468 | /* Move data from less worn block. */ | ||
| 469 | ✗ | _lx_nand_flash_block_data_move(nand_flash, block); | |
| 470 | } | ||
| 471 | else | ||
| 472 | { | ||
| 473 | |||
| 474 | /* Set the block status to free. */ | ||
| 475 | 20 | status = _lx_nand_flash_block_status_set(nand_flash, block, LX_NAND_BLOCK_STATUS_FREE); | |
| 476 | |||
| 477 | /* Check for an error from flash driver. */ | ||
| 478 |
2/4✗ Branch 59 → 60 not taken.
✓ Branch 59 → 62 taken 18 times.
✗ Branch 68 → 69 not taken.
✓ Branch 68 → 72 taken 2 times.
|
20 | if (status) |
| 479 | { | ||
| 480 | |||
| 481 | /* Call system error handler. */ | ||
| 482 | ✗ | _lx_nand_flash_system_error(nand_flash, status, block, 0); | |
| 483 | #ifdef LX_THREAD_SAFE_ENABLE | ||
| 484 | |||
| 485 | /* Release the thread safe mutex. */ | ||
| 486 | ✗ | tx_mutex_put(&nand_flash -> lx_nand_flash_mutex); | |
| 487 | #endif | ||
| 488 | |||
| 489 | /* Return an error. */ | ||
| 490 | ✗ | return(LX_ERROR); | |
| 491 | } | ||
| 492 | |||
| 493 | /* Add the block to free block list. */ | ||
| 494 | 20 | _lx_nand_flash_free_block_list_add(nand_flash, block); | |
| 495 | } | ||
| 496 | |||
| 497 | /* Check if there is valid pages in the new block. */ | ||
| 498 |
2/5✓ Branch 63 → 64 taken 18 times.
✗ Branch 63 → 77 not taken.
✗ Branch 63 → 80 not taken.
✓ Branch 73 → 74 taken 2 times.
✗ Branch 73 → 92 not taken.
|
20 | if ((new_block_status & LX_NAND_BLOCK_STATUS_PAGE_NUMBER_MASK) != 0) |
| 499 | { | ||
| 500 | |||
| 501 | /* Add the new block to mapped block list. */ | ||
| 502 | 20 | _lx_nand_flash_mapped_block_list_add(nand_flash, logical_sector / nand_flash -> lx_nand_flash_pages_per_block); | |
| 503 | } | ||
| 504 | } /* end eager path else block */ | ||
| 505 | } | ||
| 506 | else | ||
| 507 | { | ||
| 508 | |||
| 509 | /* Set page buffer to all 0xFF bytes. */ | ||
| 510 |
4/4✓ Branch 67 → 66 taken 164736 times.
✓ Branch 67 → 68 taken 312 times.
✓ Branch 77 → 76 taken 27456 times.
✓ Branch 77 → 78 taken 52 times.
|
192712 | 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); |
| 511 | |||
| 512 | /* Setup spare buffer pointer. */ | ||
| 513 | 520 | spare_buffer_ptr = nand_flash -> lx_nand_flash_page_buffer + nand_flash -> lx_nand_flash_bytes_per_page; | |
| 514 | |||
| 515 | /* Check if there is enough spare data for metadata block number. */ | ||
| 516 |
3/6✓ Branch 65 → 66 taken 156 times.
✗ Branch 65 → 67 not taken.
✓ Branch 68 → 69 taken 312 times.
✗ Branch 68 → 70 not taken.
✓ Branch 78 → 79 taken 52 times.
✗ Branch 78 → 80 not taken.
|
520 | if (nand_flash -> lx_nand_flash_spare_data2_length >= sizeof(USHORT)) |
| 517 | { | ||
| 518 | |||
| 519 | /* Save metadata block number in spare bytes. */ | ||
| 520 | 520 | LX_UTILITY_SHORT_SET(&spare_buffer_ptr[nand_flash -> lx_nand_flash_spare_data2_offset], nand_flash -> lx_nand_flash_metadata_block_number); | |
| 521 | } | ||
| 522 | |||
| 523 | /* Set page type and sector address. */ | ||
| 524 | 520 | LX_UTILITY_LONG_SET(&spare_buffer_ptr[nand_flash -> lx_nand_flash_spare_data1_offset], LX_NAND_PAGE_TYPE_USER_DATA_RELEASED | logical_sector); | |
| 525 | |||
| 526 | /* Write the page. */ | ||
| 527 | #ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE | ||
| 528 | 52 | 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); | |
| 529 | #else | ||
| 530 | 468 | status = (nand_flash -> lx_nand_flash_driver_pages_write)(block, available_pages, (UCHAR*)nand_flash -> lx_nand_flash_page_buffer, spare_buffer_ptr, 1); | |
| 531 | #endif | ||
| 532 | |||
| 533 | /* Check for an error from flash driver. */ | ||
| 534 |
3/6✗ Branch 68 → 69 not taken.
✓ Branch 68 → 71 taken 156 times.
✗ Branch 71 → 72 not taken.
✓ Branch 71 → 74 taken 312 times.
✗ Branch 81 → 82 not taken.
✓ Branch 81 → 85 taken 52 times.
|
520 | if (status) |
| 535 | { | ||
| 536 | |||
| 537 | /* Call system error handler. */ | ||
| 538 | ✗ | _lx_nand_flash_system_error(nand_flash, status, block, 0); | |
| 539 | #ifdef LX_THREAD_SAFE_ENABLE | ||
| 540 | |||
| 541 | /* Release the thread safe mutex. */ | ||
| 542 | ✗ | tx_mutex_put(&nand_flash -> lx_nand_flash_mutex); | |
| 543 | #endif | ||
| 544 | |||
| 545 | /* Return an error. */ | ||
| 546 | ✗ | return(LX_ERROR); | |
| 547 | } | ||
| 548 | |||
| 549 | /* Increase available pages count. */ | ||
| 550 | 520 | available_pages++; | |
| 551 | |||
| 552 | /* Check if available pages count reaches total pages per block. */ | ||
| 553 |
6/6✓ Branch 71 → 72 taken 6 times.
✓ Branch 71 → 73 taken 150 times.
✓ Branch 74 → 75 taken 12 times.
✓ Branch 74 → 76 taken 300 times.
✓ Branch 85 → 86 taken 2 times.
✓ Branch 85 → 87 taken 50 times.
|
520 | if (available_pages == nand_flash -> lx_nand_flash_pages_per_block) |
| 554 | { | ||
| 555 | |||
| 556 | /* Set block full status flag. */ | ||
| 557 | 20 | block_status |= LX_NAND_BLOCK_STATUS_FULL; | |
| 558 | } | ||
| 559 | |||
| 560 | /* Build block status word. */ | ||
| 561 | 520 | block_status = (USHORT)(available_pages | (block_status & ~LX_NAND_BLOCK_STATUS_PAGE_NUMBER_MASK)); | |
| 562 | |||
| 563 | /* Set non sequential status flag. */ | ||
| 564 | 520 | block_status |= LX_NAND_BLOCK_STATUS_NON_SEQUENTIAL; | |
| 565 | |||
| 566 | /* Set block status. */ | ||
| 567 | 520 | status = _lx_nand_flash_block_status_set(nand_flash, block, block_status); | |
| 568 | |||
| 569 | /* Check for an error from flash driver. */ | ||
| 570 |
3/6✗ Branch 74 → 75 not taken.
✓ Branch 74 → 77 taken 156 times.
✗ Branch 77 → 78 not taken.
✓ Branch 77 → 80 taken 312 times.
✗ Branch 88 → 89 not taken.
✓ Branch 88 → 92 taken 52 times.
|
520 | if (status) |
| 571 | { | ||
| 572 | |||
| 573 | /* Call system error handler. */ | ||
| 574 | ✗ | _lx_nand_flash_system_error(nand_flash, status, block, 0); | |
| 575 | #ifdef LX_THREAD_SAFE_ENABLE | ||
| 576 | |||
| 577 | /* Release the thread safe mutex. */ | ||
| 578 | ✗ | tx_mutex_put(&nand_flash -> lx_nand_flash_mutex); | |
| 579 | #endif | ||
| 580 | |||
| 581 | /* Return an error. */ | ||
| 582 | ✗ | return(LX_ERROR); | |
| 583 | } | ||
| 584 | } | ||
| 585 | } | ||
| 586 | } | ||
| 587 | #ifdef LX_THREAD_SAFE_ENABLE | ||
| 588 | |||
| 589 | /* Release the thread safe mutex. */ | ||
| 590 | 6738 | tx_mutex_put(&nand_flash -> lx_nand_flash_mutex); | |
| 591 | #endif | ||
| 592 | |||
| 593 | /* Return status. */ | ||
| 594 | 67380 | return(status); | |
| 595 | } | ||
| 596 | |||
| 597 |