lx_nor_flash_block_reclaim.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 | /** */ | ||
| 18 | /** LevelX Component */ | ||
| 19 | /** */ | ||
| 20 | /** NOR Flash */ | ||
| 21 | /** */ | ||
| 22 | /**************************************************************************/ | ||
| 23 | /**************************************************************************/ | ||
| 24 | |||
| 25 | #define LX_SOURCE_CODE | ||
| 26 | |||
| 27 | |||
| 28 | /* Disable ThreadX error checking. */ | ||
| 29 | |||
| 30 | #ifndef LX_DISABLE_ERROR_CHECKING | ||
| 31 | #define LX_DISABLE_ERROR_CHECKING | ||
| 32 | #endif | ||
| 33 | |||
| 34 | |||
| 35 | /* Include necessary system files. */ | ||
| 36 | |||
| 37 | #include "lx_api.h" | ||
| 38 | |||
| 39 | |||
| 40 | /**************************************************************************/ | ||
| 41 | /* */ | ||
| 42 | /* FUNCTION RELEASE */ | ||
| 43 | /* */ | ||
| 44 | /* _lx_nor_flash_block_reclaim PORTABLE C */ | ||
| 45 | /* 6.3.0 */ | ||
| 46 | /* AUTHOR */ | ||
| 47 | /* */ | ||
| 48 | /* William E. Lamie, Microsoft Corporation */ | ||
| 49 | /* */ | ||
| 50 | /* DESCRIPTION */ | ||
| 51 | /* */ | ||
| 52 | /* This function reclaims one block from the NOR flash. */ | ||
| 53 | /* */ | ||
| 54 | /* INPUT */ | ||
| 55 | /* */ | ||
| 56 | /* nor_flash NOR flash instance */ | ||
| 57 | /* */ | ||
| 58 | /* OUTPUT */ | ||
| 59 | /* */ | ||
| 60 | /* return status */ | ||
| 61 | /* */ | ||
| 62 | /* CALLS */ | ||
| 63 | /* */ | ||
| 64 | /* _lx_nor_flash_driver_block_erase Driver erase block */ | ||
| 65 | /* _lx_nor_flash_driver_write Driver flash sector write */ | ||
| 66 | /* _lx_nor_flash_driver_read Driver flash sector read */ | ||
| 67 | /* _lx_nor_flash_next_block_to_erase_find */ | ||
| 68 | /* Find next block to erase */ | ||
| 69 | /* _lx_nor_flash_physical_sector_allocate */ | ||
| 70 | /* Allocate new logical sector */ | ||
| 71 | /* _lx_nor_flash_sector_mapping_cache_invalidate */ | ||
| 72 | /* Invalidate cache entry */ | ||
| 73 | /* _lx_nor_flash_system_error Internal system error handler */ | ||
| 74 | /* */ | ||
| 75 | /* CALLED BY */ | ||
| 76 | /* */ | ||
| 77 | /* Internal LevelX */ | ||
| 78 | /* */ | ||
| 79 | /**************************************************************************/ | ||
| 80 | 11620 | UINT _lx_nor_flash_block_reclaim(LX_NOR_FLASH *nor_flash) | |
| 81 | { | ||
| 82 | |||
| 83 | ULONG *block_word_ptr; | ||
| 84 | ULONG *list_word_ptr; | ||
| 85 | ULONG list_word; | ||
| 86 | ULONG i; | ||
| 87 | ULONG erase_block; | ||
| 88 | ULONG erase_count; | ||
| 89 | ULONG temp_erase_count; | ||
| 90 | ULONG erase_started_value; | ||
| 91 | ULONG mapped_sectors; | ||
| 92 | ULONG obsolete_sectors; | ||
| 93 | ULONG free_sectors; | ||
| 94 | ULONG logical_sector; | ||
| 95 | ULONG *new_mapping_address; | ||
| 96 | ULONG *new_sector_address; | ||
| 97 | ULONG new_mapping_entry; | ||
| 98 | UINT status; | ||
| 99 | |||
| 100 | |||
| 101 | /* Determine the next block to erase. */ | ||
| 102 | 11620 | _lx_nor_flash_next_block_to_erase_find(nor_flash, &erase_block, &erase_count, &mapped_sectors, &obsolete_sectors); | |
| 103 | |||
| 104 | /* Determine if the search pointer is set for this block. */ | ||
| 105 |
2/2✓ Branch 3 → 4 taken 1980 times.
✓ Branch 3 → 6 taken 9640 times.
|
11620 | if (nor_flash -> lx_nor_flash_free_block_search == erase_block) |
| 106 | { | ||
| 107 | |||
| 108 | /* Ensure the search block is not the block we are trying to free. */ | ||
| 109 | 1980 | nor_flash -> lx_nor_flash_free_block_search = erase_block + 1; | |
| 110 | |||
| 111 | /* Check for wrap condition. */ | ||
| 112 |
2/2✓ Branch 4 → 5 taken 220 times.
✓ Branch 4 → 6 taken 1760 times.
|
1980 | if (nor_flash -> lx_nor_flash_free_block_search >= nor_flash -> lx_nor_flash_total_blocks) |
| 113 | 220 | nor_flash -> lx_nor_flash_free_block_search = 0; | |
| 114 | } | ||
| 115 | |||
| 116 | /* Setup the block word pointer to the first word of the search block. */ | ||
| 117 | 11620 | block_word_ptr = nor_flash -> lx_nor_flash_base_address + (nor_flash -> lx_nor_flash_words_per_block * erase_block); | |
| 118 | |||
| 119 | /* Determine if this block is completely obsolete. */ | ||
| 120 |
2/3✗ Branch 6 → 7 not taken.
✓ Branch 6 → 34 taken 9296 times.
✓ Branch 6 → 35 taken 2324 times.
|
11620 | if (obsolete_sectors == nor_flash -> lx_nor_flash_physical_sectors_per_block) |
| 121 | { | ||
| 122 | |||
| 123 | /* Write the erased started indication. */ | ||
| 124 | ✗ | erase_started_value = LX_BLOCK_ERASE_STARTED; | |
| 125 | ✗ | status = _lx_nor_flash_driver_write(nor_flash, block_word_ptr, &erase_started_value, 1); | |
| 126 | |||
| 127 | /* Check for an error from flash driver. Drivers should never return an error.. */ | ||
| 128 | ✗ | if (status) | |
| 129 | { | ||
| 130 | |||
| 131 | /* Call system error handler. */ | ||
| 132 | ✗ | _lx_nor_flash_system_error(nor_flash, status); | |
| 133 | |||
| 134 | /* Return the error. */ | ||
| 135 | ✗ | return(status); | |
| 136 | } | ||
| 137 | |||
| 138 | /* Erase the entire block. */ | ||
| 139 | ✗ | status = _lx_nor_flash_driver_block_erase(nor_flash, erase_block, erase_count+1); | |
| 140 | |||
| 141 | /* Check for an error from flash driver. Drivers should never return an error.. */ | ||
| 142 | ✗ | if (status) | |
| 143 | { | ||
| 144 | |||
| 145 | /* Call system error handler. */ | ||
| 146 | ✗ | _lx_nor_flash_system_error(nor_flash, status); | |
| 147 | |||
| 148 | /* Return the error. */ | ||
| 149 | ✗ | return(status); | |
| 150 | } | ||
| 151 | |||
| 152 | /* Determine if the erase count is at the minimum. */ | ||
| 153 | ✗ | if (erase_count == nor_flash -> lx_nor_flash_minimum_erase_count) | |
| 154 | { | ||
| 155 | |||
| 156 | /* Yes, decrement the minimum erased block count. */ | ||
| 157 | ✗ | nor_flash -> lx_nor_flash_minimum_erased_blocks--; | |
| 158 | } | ||
| 159 | |||
| 160 | /* Increment the erase count. */ | ||
| 161 | ✗ | erase_count++; | |
| 162 | |||
| 163 | /* Determine if the new erase count exceeds the maximum. */ | ||
| 164 | ✗ | if (erase_count > ((ULONG) LX_BLOCK_ERASE_COUNT_MAX)) | |
| 165 | { | ||
| 166 | |||
| 167 | /* Yes, erase count is in overflow. Stay at the maximum count. */ | ||
| 168 | ✗ | erase_count = ((ULONG) LX_BLOCK_ERASE_COUNT_MAX); | |
| 169 | } | ||
| 170 | |||
| 171 | /* Determine if we need to update the maximum erase count. */ | ||
| 172 | ✗ | if (erase_count > nor_flash -> lx_nor_flash_maximum_erase_count) | |
| 173 | { | ||
| 174 | |||
| 175 | /* Yes, a new maximum is present. */ | ||
| 176 | ✗ | nor_flash -> lx_nor_flash_maximum_erase_count = erase_count; | |
| 177 | } | ||
| 178 | |||
| 179 | /* Setup the free bit map that corresponds to the free physical sectors in this | ||
| 180 | block. Note that we only need to setup the portion of the free bit map that doesn't | ||
| 181 | have sectors associated with it. */ | ||
| 182 | ✗ | status = _lx_nor_flash_driver_write(nor_flash, block_word_ptr+(nor_flash -> lx_nor_flash_block_free_bit_map_offset + (nor_flash -> lx_nor_flash_block_bit_map_words - 1)), | |
| 183 | &(nor_flash -> lx_nor_flash_block_bit_map_mask), 1); | ||
| 184 | |||
| 185 | /* Check for an error from flash driver. Drivers should never return an error.. */ | ||
| 186 | ✗ | if (status) | |
| 187 | { | ||
| 188 | |||
| 189 | /* Call system error handler. */ | ||
| 190 | ✗ | _lx_nor_flash_system_error(nor_flash, status); | |
| 191 | |||
| 192 | /* Return the error. */ | ||
| 193 | ✗ | return(status); | |
| 194 | } | ||
| 195 | |||
| 196 | /* Write the initial erase count for the block with upper bit set. */ | ||
| 197 | ✗ | temp_erase_count = (erase_count | LX_BLOCK_ERASED); | |
| 198 | ✗ | status = _lx_nor_flash_driver_write(nor_flash, block_word_ptr, &temp_erase_count, 1); | |
| 199 | |||
| 200 | /* Check for an error from flash driver. Drivers should never return an error.. */ | ||
| 201 | ✗ | if (status) | |
| 202 | { | ||
| 203 | |||
| 204 | /* Call system error handler. */ | ||
| 205 | ✗ | _lx_nor_flash_system_error(nor_flash, status); | |
| 206 | |||
| 207 | /* Return the error. */ | ||
| 208 | ✗ | return(status); | |
| 209 | } | ||
| 210 | |||
| 211 | /* Write the final initial erase count for the block. */ | ||
| 212 | ✗ | status = _lx_nor_flash_driver_write(nor_flash, block_word_ptr, &erase_count, 1); | |
| 213 | |||
| 214 | /* Check for an error from flash driver. Drivers should never return an error.. */ | ||
| 215 | ✗ | if (status) | |
| 216 | { | ||
| 217 | |||
| 218 | /* Call system error handler. */ | ||
| 219 | ✗ | _lx_nor_flash_system_error(nor_flash, status); | |
| 220 | |||
| 221 | /* Return the error. */ | ||
| 222 | ✗ | return(status); | |
| 223 | } | ||
| 224 | |||
| 225 | /* Update parameters of this flash. */ | ||
| 226 | ✗ | nor_flash -> lx_nor_flash_free_physical_sectors = nor_flash -> lx_nor_flash_free_physical_sectors + obsolete_sectors; | |
| 227 | ✗ | nor_flash -> lx_nor_flash_obsolete_physical_sectors = nor_flash -> lx_nor_flash_obsolete_physical_sectors - obsolete_sectors; | |
| 228 | #ifdef LX_NOR_ENABLE_OBSOLETE_COUNT_CACHE | ||
| 229 | |||
| 230 | /* Check if the block is cached by obsolete count cache. */ | ||
| 231 | ✗ | if (erase_block < nor_flash -> lx_nor_flash_extended_cache_obsolete_count_max_block) | |
| 232 | { | ||
| 233 | |||
| 234 | /* Yes, clear the obsolete count for this block. */ | ||
| 235 | ✗ | nor_flash -> lx_nor_flash_extended_cache_obsolete_count[erase_block] = 0; | |
| 236 | } | ||
| 237 | #endif | ||
| 238 | } | ||
| 239 | else | ||
| 240 | { | ||
| 241 | |||
| 242 | /* Calculate the number of free sectors in this block. */ | ||
| 243 | 11620 | free_sectors = nor_flash -> lx_nor_flash_physical_sectors_per_block - (obsolete_sectors + mapped_sectors); | |
| 244 | |||
| 245 | /* Determine if there are enough free sectors outside of this block to reclaim this block. */ | ||
| 246 |
2/5✓ Branch 34 → 35 taken 9296 times.
✗ Branch 34 → 105 not taken.
✗ Branch 34 → 113 not taken.
✓ Branch 35 → 36 taken 2324 times.
✗ Branch 35 → 115 not taken.
|
11620 | if (mapped_sectors <= (nor_flash -> lx_nor_flash_free_physical_sectors - free_sectors)) |
| 247 | { | ||
| 248 | |||
| 249 | /* Setup a pointer to the mapped list. */ | ||
| 250 | 11620 | list_word_ptr = block_word_ptr + nor_flash -> lx_nor_flash_block_physical_sector_mapping_offset; | |
| 251 | |||
| 252 | /* Now search through the list to find mapped sectors to move. */ | ||
| 253 |
3/6✓ Branch 77 → 36 taken 34216 times.
✗ Branch 77 → 78 not taken.
✓ Branch 85 → 36 taken 102648 times.
✗ Branch 85 → 86 not taken.
✓ Branch 86 → 37 taken 34216 times.
✗ Branch 86 → 87 not taken.
|
171080 | for (i = 0; i < nor_flash -> lx_nor_flash_physical_sectors_per_block; i++) |
| 254 | { | ||
| 255 | |||
| 256 | /* Pickup the mapped sector list entry. */ | ||
| 257 | #ifdef LX_DIRECT_READ | ||
| 258 | |||
| 259 | /* Read the word directly. */ | ||
| 260 | 34216 | list_word = *(list_word_ptr); | |
| 261 | #else | ||
| 262 | 136864 | status = _lx_nor_flash_driver_read(nor_flash, list_word_ptr, &list_word, 1); | |
| 263 | |||
| 264 | /* Check for an error from flash driver. Drivers should never return an error.. */ | ||
| 265 |
2/4✗ Branch 37 → 38 not taken.
✓ Branch 37 → 40 taken 102648 times.
✗ Branch 38 → 39 not taken.
✓ Branch 38 → 41 taken 34216 times.
|
136864 | if (status) |
| 266 | { | ||
| 267 | |||
| 268 | /* Call system error handler. */ | ||
| 269 | ✗ | _lx_nor_flash_system_error(nor_flash, status); | |
| 270 | |||
| 271 | /* Return the error. */ | ||
| 272 | ✗ | return(status); | |
| 273 | } | ||
| 274 | #endif | ||
| 275 | |||
| 276 | /* Determine if the entry hasn't been used. */ | ||
| 277 |
3/6✗ Branch 36 → 37 not taken.
✓ Branch 36 → 38 taken 34216 times.
✗ Branch 40 → 41 not taken.
✓ Branch 40 → 42 taken 102648 times.
✗ Branch 41 → 42 not taken.
✓ Branch 41 → 43 taken 34216 times.
|
171080 | if (list_word == LX_NOR_PHYSICAL_SECTOR_FREE) |
| 278 | { | ||
| 279 | |||
| 280 | /* Since allocations are done sequentially in the block, we know nothing | ||
| 281 | else exists after this point. */ | ||
| 282 | ✗ | break; | |
| 283 | } | ||
| 284 | |||
| 285 | /* Is this entry mapped? */ | ||
| 286 |
6/6✓ Branch 38 → 39 taken 30240 times.
✓ Branch 38 → 76 taken 3976 times.
✓ Branch 42 → 43 taken 90720 times.
✓ Branch 42 → 84 taken 11928 times.
✓ Branch 43 → 44 taken 30240 times.
✓ Branch 43 → 85 taken 3976 times.
|
171080 | if (list_word & LX_NOR_PHYSICAL_SECTOR_VALID) |
| 287 | { | ||
| 288 | |||
| 289 | /* Pickup the logical sector associated with this mapped physical sector. */ | ||
| 290 | 151200 | logical_sector = list_word & LX_NOR_LOGICAL_SECTOR_MASK; | |
| 291 | |||
| 292 | /* Invalidate the old sector mapping cache entry. */ | ||
| 293 | 151200 | _lx_nor_flash_sector_mapping_cache_invalidate(nor_flash, logical_sector); | |
| 294 | |||
| 295 | /* Allocate a new physical sector for this write. */ | ||
| 296 | 151200 | _lx_nor_flash_physical_sector_allocate(nor_flash, logical_sector, &new_mapping_address, &new_sector_address); | |
| 297 | |||
| 298 | /* Check to see if the new sector is also in the erase block. */ | ||
| 299 |
11/11✓ Branch 41 → 42 taken 30238 times.
✓ Branch 41 → 51 taken 2 times.
✓ Branch 42 → 43 taken 14422 times.
✓ Branch 42 → 51 taken 15816 times.
✓ Branch 45 → 46 taken 90714 times.
✓ Branch 45 → 55 taken 6 times.
✓ Branch 46 → 47 taken 73504 times.
✓ Branch 46 → 55 taken 47448 times.
✓ Branch 46 → 56 taken 2 times.
✓ Branch 47 → 48 taken 14422 times.
✓ Branch 47 → 56 taken 15816 times.
|
151200 | if ((new_mapping_address != LX_NULL) && (new_sector_address >= block_word_ptr) && |
| 300 |
6/6✓ Branch 43 → 44 taken 2 times.
✓ Branch 43 → 51 taken 14420 times.
✓ Branch 47 → 48 taken 6 times.
✓ Branch 47 → 55 taken 43260 times.
✓ Branch 48 → 49 taken 2 times.
✓ Branch 48 → 56 taken 14420 times.
|
72110 | (new_sector_address < (block_word_ptr + nor_flash -> lx_nor_flash_words_per_block))) |
| 301 | { | ||
| 302 | |||
| 303 | /* Yes, the new sector was found in the block to be erased. Simply move the search pointer | ||
| 304 | to the block after the erase block and search for another sector from there. */ | ||
| 305 | 10 | nor_flash -> lx_nor_flash_free_block_search = erase_block + 1; | |
| 306 | |||
| 307 | /* Check for wrap condition. */ | ||
| 308 |
3/6✗ Branch 44 → 45 not taken.
✓ Branch 44 → 46 taken 2 times.
✗ Branch 48 → 49 not taken.
✓ Branch 48 → 50 taken 6 times.
✗ Branch 49 → 50 not taken.
✓ Branch 49 → 51 taken 2 times.
|
10 | if (nor_flash -> lx_nor_flash_free_block_search >= nor_flash -> lx_nor_flash_total_blocks) |
| 309 | ✗ | nor_flash -> lx_nor_flash_free_block_search = 0; | |
| 310 | |||
| 311 | /* Allocate a new physical sector for this write. */ | ||
| 312 | 10 | _lx_nor_flash_physical_sector_allocate(nor_flash, logical_sector, &new_mapping_address, &new_sector_address); | |
| 313 | |||
| 314 | /* Check again for the new sector inside of the block to erase. This should be impossible, since | ||
| 315 | we check previously if there are enough free sectors outside of this block needed to reclaim | ||
| 316 | this block. */ | ||
| 317 |
3/11✗ Branch 47 → 48 not taken.
✓ Branch 47 → 51 taken 2 times.
✗ Branch 48 → 49 not taken.
✗ Branch 48 → 51 not taken.
✗ Branch 51 → 52 not taken.
✓ Branch 51 → 55 taken 6 times.
✗ Branch 52 → 53 not taken.
✗ Branch 52 → 55 not taken.
✓ Branch 52 → 56 taken 2 times.
✗ Branch 53 → 54 not taken.
✗ Branch 53 → 56 not taken.
|
10 | if ((new_mapping_address != LX_NULL) && (new_sector_address >= block_word_ptr) && |
| 318 | ✗ | (new_sector_address < (block_word_ptr + LX_NOR_SECTOR_SIZE))) | |
| 319 | { | ||
| 320 | |||
| 321 | /* System error, a new sector is not available outside of the erase block. | ||
| 322 | Clear the new sector so we fall through to the error handling. */ | ||
| 323 | ✗ | new_mapping_address = LX_NULL; | |
| 324 | } | ||
| 325 | } | ||
| 326 | |||
| 327 | /* Determine if the new sector allocation was successful. */ | ||
| 328 |
6/6✓ Branch 51 → 52 taken 30236 times.
✓ Branch 51 → 72 taken 4 times.
✓ Branch 55 → 56 taken 90708 times.
✓ Branch 55 → 80 taken 12 times.
✓ Branch 56 → 57 taken 30236 times.
✓ Branch 56 → 81 taken 4 times.
|
151200 | if (new_mapping_address) |
| 329 | { | ||
| 330 | |||
| 331 | /* Yes, we were able to allocate a new physical sector. */ | ||
| 332 | |||
| 333 | #ifdef LX_DIRECT_READ | ||
| 334 | /* First, write the sector data to the new physical sector. */ | ||
| 335 | 30236 | status = _lx_nor_flash_driver_write(nor_flash, new_sector_address, (block_word_ptr + nor_flash -> lx_nor_flash_block_physical_sector_offset) + | |
| 336 | (i * LX_NOR_SECTOR_SIZE), LX_NOR_SECTOR_SIZE); | ||
| 337 | |||
| 338 | /* Check for an error from flash driver. Drivers should never return an error.. */ | ||
| 339 |
1/2✗ Branch 53 → 54 not taken.
✓ Branch 53 → 56 taken 30236 times.
|
30236 | if (status) |
| 340 | { | ||
| 341 | |||
| 342 | /* Call system error handler. */ | ||
| 343 | ✗ | _lx_nor_flash_system_error(nor_flash, status); | |
| 344 | |||
| 345 | /* Return the error. */ | ||
| 346 | ✗ | return(status); | |
| 347 | } | ||
| 348 | #else | ||
| 349 | |||
| 350 | /* First, read the sector data into the internal memory of the NOR flash instance. This internal memory | ||
| 351 | is supplied by the underlying driver during initialization. */ | ||
| 352 | 120944 | status = _lx_nor_flash_driver_read(nor_flash, (block_word_ptr + nor_flash -> lx_nor_flash_block_physical_sector_offset) + | |
| 353 | (i * LX_NOR_SECTOR_SIZE), nor_flash -> lx_nor_flash_sector_buffer, | ||
| 354 | LX_NOR_SECTOR_SIZE); | ||
| 355 | |||
| 356 | /* Check for an error from flash driver. Drivers should never return an error.. */ | ||
| 357 |
2/4✗ Branch 57 → 58 not taken.
✓ Branch 57 → 60 taken 90708 times.
✗ Branch 58 → 59 not taken.
✓ Branch 58 → 61 taken 30236 times.
|
120944 | if (status) |
| 358 | { | ||
| 359 | |||
| 360 | /* Call system error handler. */ | ||
| 361 | ✗ | _lx_nor_flash_system_error(nor_flash, status); | |
| 362 | |||
| 363 | /* Return the error. */ | ||
| 364 | ✗ | return(status); | |
| 365 | } | ||
| 366 | |||
| 367 | /* Next, write the sector data from the internal buffer to the new physical sector. */ | ||
| 368 | 120944 | status = _lx_nor_flash_driver_write(nor_flash, new_sector_address, nor_flash -> lx_nor_flash_sector_buffer, LX_NOR_SECTOR_SIZE); | |
| 369 | |||
| 370 | /* Check for an error from flash driver. Drivers should never return an error.. */ | ||
| 371 |
2/4✗ Branch 61 → 62 not taken.
✓ Branch 61 → 64 taken 90708 times.
✗ Branch 62 → 63 not taken.
✓ Branch 62 → 65 taken 30236 times.
|
120944 | if (status) |
| 372 | { | ||
| 373 | |||
| 374 | /* Call system error handler. */ | ||
| 375 | ✗ | _lx_nor_flash_system_error(nor_flash, status); | |
| 376 | |||
| 377 | /* Return the error. */ | ||
| 378 | ✗ | return(status); | |
| 379 | } | ||
| 380 | #endif | ||
| 381 | |||
| 382 | /* Now deprecate the old sector mapping. */ | ||
| 383 | |||
| 384 | /* Clear bit 30, which indicates this sector is superceded. */ | ||
| 385 | 151180 | list_word = list_word & ~((ULONG) LX_NOR_PHYSICAL_SECTOR_SUPERCEDED); | |
| 386 | |||
| 387 | /* Write the value back to the flash to clear bit 30. */ | ||
| 388 | 151180 | status = _lx_nor_flash_driver_write(nor_flash, list_word_ptr, &list_word, 1); | |
| 389 | |||
| 390 | /* Check for an error from flash driver. Drivers should never return an error.. */ | ||
| 391 |
3/6✗ Branch 57 → 58 not taken.
✓ Branch 57 → 60 taken 30236 times.
✗ Branch 65 → 66 not taken.
✓ Branch 65 → 68 taken 90708 times.
✗ Branch 66 → 67 not taken.
✓ Branch 66 → 69 taken 30236 times.
|
151180 | if (status) |
| 392 | { | ||
| 393 | |||
| 394 | /* Call system error handler. */ | ||
| 395 | ✗ | _lx_nor_flash_system_error(nor_flash, status); | |
| 396 | |||
| 397 | /* Return the error. */ | ||
| 398 | ✗ | return(status); | |
| 399 | } | ||
| 400 | |||
| 401 | /* Now build the new mapping entry - with the not valid bit set initially. */ | ||
| 402 | 151180 | new_mapping_entry = ((ULONG) LX_NOR_PHYSICAL_SECTOR_VALID) | ((ULONG) LX_NOR_PHYSICAL_SECTOR_SUPERCEDED) | (ULONG) LX_NOR_PHYSICAL_SECTOR_MAPPING_NOT_VALID | logical_sector; | |
| 403 | |||
| 404 | /* Write out the new mapping entry. */ | ||
| 405 | 151180 | status = _lx_nor_flash_driver_write(nor_flash, new_mapping_address, &new_mapping_entry, 1); | |
| 406 | |||
| 407 | /* Check for an error from flash driver. Drivers should never return an error.. */ | ||
| 408 |
3/6✗ Branch 61 → 62 not taken.
✓ Branch 61 → 64 taken 30236 times.
✗ Branch 69 → 70 not taken.
✓ Branch 69 → 72 taken 90708 times.
✗ Branch 70 → 71 not taken.
✓ Branch 70 → 73 taken 30236 times.
|
151180 | if (status) |
| 409 | { | ||
| 410 | |||
| 411 | /* Call system error handler. */ | ||
| 412 | ✗ | _lx_nor_flash_system_error(nor_flash, status); | |
| 413 | |||
| 414 | /* Return the error. */ | ||
| 415 | ✗ | return(status); | |
| 416 | } | ||
| 417 | |||
| 418 | /* Now clear the not valid bit to make this sector mapping valid. This is done because the writing of the extra bytes itself can | ||
| 419 | be interrupted and we need to make sure this can be detected when the flash is opened again. */ | ||
| 420 | 151180 | new_mapping_entry = new_mapping_entry & ~((ULONG) LX_NOR_PHYSICAL_SECTOR_MAPPING_NOT_VALID); | |
| 421 | |||
| 422 | /* Clear the not valid bit. */ | ||
| 423 | 151180 | status = _lx_nor_flash_driver_write(nor_flash, new_mapping_address, &new_mapping_entry, 1); | |
| 424 | |||
| 425 | /* Check for an error from flash driver. Drivers should never return an error.. */ | ||
| 426 |
3/6✗ Branch 65 → 66 not taken.
✓ Branch 65 → 68 taken 30236 times.
✗ Branch 73 → 74 not taken.
✓ Branch 73 → 76 taken 90708 times.
✗ Branch 74 → 75 not taken.
✓ Branch 74 → 77 taken 30236 times.
|
151180 | if (status) |
| 427 | { | ||
| 428 | |||
| 429 | /* Call system error handler. */ | ||
| 430 | ✗ | _lx_nor_flash_system_error(nor_flash, status); | |
| 431 | |||
| 432 | /* Return the error. */ | ||
| 433 | ✗ | return(status); | |
| 434 | } | ||
| 435 | |||
| 436 | /* Now clear bit 31, which indicates this sector is now obsoleted. */ | ||
| 437 | 151180 | list_word = list_word & ~((ULONG) LX_NOR_PHYSICAL_SECTOR_VALID); | |
| 438 | |||
| 439 | /* Write the value back to the flash to clear bit 31. */ | ||
| 440 | 151180 | status = _lx_nor_flash_driver_write(nor_flash, list_word_ptr, &list_word, 1); | |
| 441 | |||
| 442 | /* Check for an error from flash driver. Drivers should never return an error.. */ | ||
| 443 |
3/6✗ Branch 69 → 70 not taken.
✓ Branch 69 → 74 taken 30236 times.
✗ Branch 77 → 78 not taken.
✓ Branch 77 → 82 taken 90708 times.
✗ Branch 78 → 79 not taken.
✓ Branch 78 → 83 taken 30236 times.
|
151180 | if (status) |
| 444 | { | ||
| 445 | |||
| 446 | /* Call system error handler. */ | ||
| 447 | ✗ | _lx_nor_flash_system_error(nor_flash, status); | |
| 448 | |||
| 449 | /* Return the error. */ | ||
| 450 | ✗ | return(status); | |
| 451 | } | ||
| 452 | } | ||
| 453 | else | ||
| 454 | { | ||
| 455 | |||
| 456 | /* Call system error handler - the allocation should always succeed at this point. */ | ||
| 457 | 20 | _lx_nor_flash_system_error(nor_flash, LX_SYSTEM_ALLOCATION_FAILED); | |
| 458 | |||
| 459 | /* Return the error. */ | ||
| 460 | 20 | return(LX_SYSTEM_ALLOCATION_FAILED); | |
| 461 | } | ||
| 462 | |||
| 463 | /* Decrement the number of mapped sectors. */ | ||
| 464 | 151180 | mapped_sectors--; | |
| 465 | |||
| 466 | /* Determine if we are done. */ | ||
| 467 |
6/6✓ Branch 74 → 75 taken 2320 times.
✓ Branch 74 → 76 taken 27916 times.
✓ Branch 82 → 83 taken 6960 times.
✓ Branch 82 → 84 taken 83748 times.
✓ Branch 83 → 84 taken 2320 times.
✓ Branch 83 → 85 taken 27916 times.
|
151180 | if (mapped_sectors == 0) |
| 468 | 11600 | break; | |
| 469 | } | ||
| 470 | |||
| 471 | /* Move the list pointer ahead. */ | ||
| 472 | 159460 | list_word_ptr++; | |
| 473 | } | ||
| 474 | |||
| 475 | /* Write the erased started indication. */ | ||
| 476 | 11600 | erase_started_value = LX_BLOCK_ERASE_STARTED; | |
| 477 | 11600 | status = _lx_nor_flash_driver_write(nor_flash, block_word_ptr, &erase_started_value, 1); | |
| 478 | |||
| 479 | /* Check for an error from flash driver. Drivers should never return an error.. */ | ||
| 480 |
3/6✗ Branch 79 → 80 not taken.
✓ Branch 79 → 82 taken 2320 times.
✗ Branch 87 → 88 not taken.
✓ Branch 87 → 90 taken 6960 times.
✗ Branch 88 → 89 not taken.
✓ Branch 88 → 91 taken 2320 times.
|
11600 | if (status) |
| 481 | { | ||
| 482 | |||
| 483 | /* Call system error handler. */ | ||
| 484 | ✗ | _lx_nor_flash_system_error(nor_flash, status); | |
| 485 | |||
| 486 | /* Return the error. */ | ||
| 487 | ✗ | return(status); | |
| 488 | } | ||
| 489 | |||
| 490 | /* Erase the entire block. */ | ||
| 491 | 11600 | status = _lx_nor_flash_driver_block_erase(nor_flash, erase_block, erase_count+1); | |
| 492 | |||
| 493 | /* Check for an error from flash driver. Drivers should never return an error.. */ | ||
| 494 |
3/6✗ Branch 83 → 84 not taken.
✓ Branch 83 → 86 taken 2320 times.
✗ Branch 91 → 92 not taken.
✓ Branch 91 → 94 taken 6960 times.
✗ Branch 92 → 93 not taken.
✓ Branch 92 → 95 taken 2320 times.
|
11600 | if (status) |
| 495 | { | ||
| 496 | |||
| 497 | /* Call system error handler. */ | ||
| 498 | ✗ | _lx_nor_flash_system_error(nor_flash, status); | |
| 499 | |||
| 500 | /* Return the error. */ | ||
| 501 | ✗ | return(status); | |
| 502 | } | ||
| 503 | |||
| 504 | /* Determine if the erase count is at the minimum. */ | ||
| 505 |
6/6✓ Branch 86 → 87 taken 1164 times.
✓ Branch 86 → 88 taken 1156 times.
✓ Branch 94 → 95 taken 3492 times.
✓ Branch 94 → 96 taken 3468 times.
✓ Branch 95 → 96 taken 1164 times.
✓ Branch 95 → 97 taken 1156 times.
|
11600 | if (erase_count == nor_flash -> lx_nor_flash_minimum_erase_count) |
| 506 | { | ||
| 507 | |||
| 508 | /* Yes, decrement the minimum erased block count. */ | ||
| 509 | 5820 | nor_flash -> lx_nor_flash_minimum_erased_blocks--; | |
| 510 | } | ||
| 511 | |||
| 512 | /* Increment the erase count. */ | ||
| 513 | 11600 | erase_count++; | |
| 514 | |||
| 515 | /* Determine if the new erase count exceeds the maximum. */ | ||
| 516 |
3/6✗ Branch 88 → 89 not taken.
✓ Branch 88 → 90 taken 2320 times.
✗ Branch 96 → 97 not taken.
✓ Branch 96 → 98 taken 6960 times.
✗ Branch 97 → 98 not taken.
✓ Branch 97 → 99 taken 2320 times.
|
11600 | if (erase_count > ((ULONG) LX_BLOCK_ERASE_COUNT_MAX)) |
| 517 | { | ||
| 518 | |||
| 519 | /* Yes, erase count is in overflow. Stay at the maximum count. */ | ||
| 520 | ✗ | erase_count = ((ULONG) LX_BLOCK_ERASE_COUNT_MAX); | |
| 521 | } | ||
| 522 | |||
| 523 | /* Determine if we need to update the maximum erase count. */ | ||
| 524 |
6/6✓ Branch 90 → 91 taken 300 times.
✓ Branch 90 → 92 taken 2020 times.
✓ Branch 98 → 99 taken 900 times.
✓ Branch 98 → 100 taken 6060 times.
✓ Branch 99 → 100 taken 300 times.
✓ Branch 99 → 101 taken 2020 times.
|
11600 | if (erase_count > nor_flash -> lx_nor_flash_maximum_erase_count) |
| 525 | { | ||
| 526 | |||
| 527 | /* Yes, a new maximum is present. */ | ||
| 528 | 1500 | nor_flash -> lx_nor_flash_maximum_erase_count = erase_count; | |
| 529 | } | ||
| 530 | |||
| 531 | /* Setup the free bit map that corresponds to the free physical sectors in this | ||
| 532 | block. Note that we only need to setup the portion of the free bit map that doesn't | ||
| 533 | have sectors associated with it. */ | ||
| 534 | 11600 | status = _lx_nor_flash_driver_write(nor_flash, block_word_ptr+(nor_flash -> lx_nor_flash_block_free_bit_map_offset + (nor_flash -> lx_nor_flash_block_bit_map_words - 1)) , | |
| 535 | &(nor_flash -> lx_nor_flash_block_bit_map_mask), 1); | ||
| 536 | |||
| 537 | /* Check for an error from flash driver. Drivers should never return an error.. */ | ||
| 538 |
3/6✗ Branch 93 → 94 not taken.
✓ Branch 93 → 96 taken 2320 times.
✗ Branch 101 → 102 not taken.
✓ Branch 101 → 104 taken 6960 times.
✗ Branch 102 → 103 not taken.
✓ Branch 102 → 105 taken 2320 times.
|
11600 | if (status) |
| 539 | { | ||
| 540 | |||
| 541 | /* Call system error handler. */ | ||
| 542 | ✗ | _lx_nor_flash_system_error(nor_flash, status); | |
| 543 | |||
| 544 | /* Return the error. */ | ||
| 545 | ✗ | return(status); | |
| 546 | } | ||
| 547 | |||
| 548 | /* Write the initial erase count for the block with the upper bit set. */ | ||
| 549 | 11600 | temp_erase_count = (erase_count | LX_BLOCK_ERASED); | |
| 550 | 11600 | status = _lx_nor_flash_driver_write(nor_flash, block_word_ptr, &temp_erase_count, 1); | |
| 551 | |||
| 552 | /* Check for an error from flash driver. Drivers should never return an error.. */ | ||
| 553 |
3/6✗ Branch 97 → 98 not taken.
✓ Branch 97 → 100 taken 2320 times.
✗ Branch 105 → 106 not taken.
✓ Branch 105 → 108 taken 6960 times.
✗ Branch 106 → 107 not taken.
✓ Branch 106 → 109 taken 2320 times.
|
11600 | if (status) |
| 554 | { | ||
| 555 | |||
| 556 | /* Call system error handler. */ | ||
| 557 | ✗ | _lx_nor_flash_system_error(nor_flash, status); | |
| 558 | |||
| 559 | /* Return the error. */ | ||
| 560 | ✗ | return(status); | |
| 561 | } | ||
| 562 | |||
| 563 | /* Write the final initial erase count for the block. */ | ||
| 564 | 11600 | status = _lx_nor_flash_driver_write(nor_flash, block_word_ptr, &erase_count, 1); | |
| 565 | |||
| 566 | /* Check for an error from flash driver. Drivers should never return an error.. */ | ||
| 567 |
3/6✗ Branch 101 → 102 not taken.
✓ Branch 101 → 104 taken 2320 times.
✗ Branch 109 → 110 not taken.
✓ Branch 109 → 112 taken 6960 times.
✗ Branch 110 → 111 not taken.
✓ Branch 110 → 113 taken 2320 times.
|
11600 | if (status) |
| 568 | { | ||
| 569 | |||
| 570 | /* Call system error handler. */ | ||
| 571 | ✗ | _lx_nor_flash_system_error(nor_flash, status); | |
| 572 | |||
| 573 | /* Return the error. */ | ||
| 574 | ✗ | return(status); | |
| 575 | } | ||
| 576 | |||
| 577 | /* Update parameters of this flash. */ | ||
| 578 | 11600 | nor_flash -> lx_nor_flash_free_physical_sectors = nor_flash -> lx_nor_flash_free_physical_sectors + obsolete_sectors; | |
| 579 | 11600 | nor_flash -> lx_nor_flash_obsolete_physical_sectors = nor_flash -> lx_nor_flash_obsolete_physical_sectors - obsolete_sectors; | |
| 580 | #ifdef LX_NOR_ENABLE_OBSOLETE_COUNT_CACHE | ||
| 581 | |||
| 582 | /* Check if the block is cached by obsolete count cache. */ | ||
| 583 |
2/2✓ Branch 113 → 114 taken 1160 times.
✓ Branch 113 → 115 taken 1160 times.
|
2320 | if (erase_block < nor_flash -> lx_nor_flash_extended_cache_obsolete_count_max_block) |
| 584 | { | ||
| 585 | |||
| 586 | /* Yes, clear the obsolete count for this block. */ | ||
| 587 | 1160 | nor_flash -> lx_nor_flash_extended_cache_obsolete_count[erase_block] = 0; | |
| 588 | } | ||
| 589 | #endif | ||
| 590 | } | ||
| 591 | } | ||
| 592 | |||
| 593 | /* Return status. */ | ||
| 594 | 11600 | return(LX_SUCCESS); | |
| 595 | } | ||
| 596 | |||
| 597 |