lx_nand_flash_data_page_copy.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_data_page_copy PORTABLE C */ | ||
| 43 | /* 6.4.0 */ | ||
| 44 | /* AUTHOR */ | ||
| 45 | /* */ | ||
| 46 | /* Xiuwen Cai, Microsoft Corporation */ | ||
| 47 | /* */ | ||
| 48 | /* DESCRIPTION */ | ||
| 49 | /* */ | ||
| 50 | /* This function copies logical sectors into new block. */ | ||
| 51 | /* */ | ||
| 52 | /* INPUT */ | ||
| 53 | /* */ | ||
| 54 | /* nand_flash NAND flash instance */ | ||
| 55 | /* logical_sector Logical sector number */ | ||
| 56 | /* source_block Source block number */ | ||
| 57 | /* src_block_status Source block status */ | ||
| 58 | /* destination_block Destination block number */ | ||
| 59 | /* dest_block_status_ptr Pointer to destination block */ | ||
| 60 | /* status */ | ||
| 61 | /* sectors Number of sectors to copy */ | ||
| 62 | /* */ | ||
| 63 | /* OUTPUT */ | ||
| 64 | /* */ | ||
| 65 | /* return status */ | ||
| 66 | /* */ | ||
| 67 | /* CALLS */ | ||
| 68 | /* */ | ||
| 69 | /* lx_nand_flash_driver_pages_copy Driver pages copy */ | ||
| 70 | /* lx_nand_flash_driver_pages_read Driver pages read */ | ||
| 71 | /* _lx_nand_flash_system_error Internal system error handler */ | ||
| 72 | /* */ | ||
| 73 | /* CALLED BY */ | ||
| 74 | /* */ | ||
| 75 | /* Internal LevelX */ | ||
| 76 | /* */ | ||
| 77 | /**************************************************************************/ | ||
| 78 | 22780 | UINT _lx_nand_flash_data_page_copy(LX_NAND_FLASH* nand_flash, ULONG logical_sector, ULONG source_block, USHORT src_block_status, | |
| 79 | ULONG destination_block, USHORT* dest_block_status_ptr, ULONG sectors) | ||
| 80 | { | ||
| 81 | |||
| 82 | LONG source_page; | ||
| 83 | ULONG destination_page; | ||
| 84 | 22780 | UINT status = LX_SUCCESS; | |
| 85 | UINT i; | ||
| 86 | ULONG available_pages; | ||
| 87 | ULONG spare_data1; | ||
| 88 | UCHAR *spare_buffer_ptr; | ||
| 89 | ULONG dest_block_status; | ||
| 90 | ULONG number_of_pages; | ||
| 91 | |||
| 92 | |||
| 93 | /* Get the destination block status. */ | ||
| 94 | 22780 | dest_block_status = *dest_block_status_ptr; | |
| 95 | |||
| 96 | /* Get the current page number of the destination block. */ | ||
| 97 | 22780 | destination_page = dest_block_status & LX_NAND_BLOCK_STATUS_PAGE_NUMBER_MASK; | |
| 98 | |||
| 99 | /* Get the available pages in the source block. */ | ||
| 100 |
1/2✓ Branch 2 → 3 taken 22780 times.
✗ Branch 2 → 4 not taken.
|
22780 | available_pages = (src_block_status & LX_NAND_BLOCK_STATUS_FULL) ? (nand_flash -> lx_nand_flash_pages_per_block) : (src_block_status & LX_NAND_BLOCK_STATUS_PAGE_NUMBER_MASK); |
| 101 | |||
| 102 | /* Check if pages in the source block are sequential. */ | ||
| 103 |
2/2✓ Branch 5 → 6 taken 560 times.
✓ Branch 5 → 27 taken 22220 times.
|
22780 | if (src_block_status & LX_NAND_BLOCK_STATUS_NON_SEQUENTIAL) |
| 104 | { | ||
| 105 | |||
| 106 | /* Get buffer for spare data. */ | ||
| 107 | 560 | spare_buffer_ptr = nand_flash -> lx_nand_flash_page_buffer + nand_flash -> lx_nand_flash_bytes_per_page; | |
| 108 | |||
| 109 | /* Loop to copy the data. */ | ||
| 110 |
2/2✓ Branch 26 → 7 taken 71400 times.
✓ Branch 26 → 42 taken 560 times.
|
71960 | for (i = 0; i < sectors; i++) |
| 111 | { | ||
| 112 | |||
| 113 | /* Loop to search the page. */ | ||
| 114 |
2/2✓ Branch 24 → 8 taken 9878160 times.
✓ Branch 24 → 25 taken 6260 times.
|
9884420 | for (source_page = (LONG)(available_pages - 1); source_page >= 0; source_page--) |
| 115 | { | ||
| 116 | |||
| 117 | /* Read one page. */ | ||
| 118 | #ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE | ||
| 119 | 987816 | status = (nand_flash -> lx_nand_flash_driver_pages_read)(nand_flash, source_block, (ULONG)source_page, LX_NULL, spare_buffer_ptr, 1); | |
| 120 | #else | ||
| 121 | 8890344 | status = (nand_flash -> lx_nand_flash_driver_pages_read)(source_block, (ULONG)source_page, LX_NULL, spare_buffer_ptr, 1); | |
| 122 | #endif | ||
| 123 | |||
| 124 | /* Check for an error from flash driver. */ | ||
| 125 |
1/2✗ Branch 9 → 10 not taken.
✓ Branch 9 → 12 taken 9878160 times.
|
9878160 | if (status) |
| 126 | { | ||
| 127 | |||
| 128 | /* Call system error handler. */ | ||
| 129 | ✗ | _lx_nand_flash_system_error(nand_flash, status, source_block, 0); | |
| 130 | |||
| 131 | /* Return an error. */ | ||
| 132 | ✗ | return(LX_ERROR); | |
| 133 | } | ||
| 134 | |||
| 135 | /* Get the spare data. */ | ||
| 136 | 9878160 | spare_data1 = LX_UTILITY_LONG_GET(&spare_buffer_ptr[nand_flash -> lx_nand_flash_spare_data1_offset]); | |
| 137 | |||
| 138 | /* Check the address match. */ | ||
| 139 |
2/2✓ Branch 12 → 13 taken 65140 times.
✓ Branch 12 → 23 taken 9813020 times.
|
9878160 | if ((spare_data1 & LX_NAND_PAGE_TYPE_USER_DATA_MASK) == (logical_sector + i)) |
| 140 | { | ||
| 141 | |||
| 142 | /* Check if the page contains valid data. */ | ||
| 143 |
2/2✓ Branch 13 → 14 taken 65130 times.
✓ Branch 13 → 22 taken 10 times.
|
65140 | if ((spare_data1 & (~LX_NAND_PAGE_TYPE_USER_DATA_MASK)) == (LX_NAND_PAGE_TYPE_USER_DATA)) |
| 144 | { | ||
| 145 | |||
| 146 | /* Call the driver to copy the page. */ | ||
| 147 | #ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE | ||
| 148 | 6513 | status = (nand_flash -> lx_nand_flash_driver_pages_copy)(nand_flash, source_block, (ULONG)source_page, destination_block, destination_page, 1, nand_flash -> lx_nand_flash_page_buffer); | |
| 149 | #else | ||
| 150 | 58617 | status = (nand_flash -> lx_nand_flash_driver_pages_copy)(source_block, (ULONG)source_page, destination_block, destination_page, 1, nand_flash -> lx_nand_flash_page_buffer); | |
| 151 | #endif | ||
| 152 | |||
| 153 | /* Check for an error from flash driver. */ | ||
| 154 |
1/2✗ Branch 15 → 16 not taken.
✓ Branch 15 → 18 taken 65130 times.
|
65130 | if (status) |
| 155 | { | ||
| 156 | |||
| 157 | /* Call system error handler. */ | ||
| 158 | ✗ | _lx_nand_flash_system_error(nand_flash, status, source_block, 0); | |
| 159 | |||
| 160 | /* Return an error. */ | ||
| 161 | ✗ | return(LX_ERROR); | |
| 162 | } | ||
| 163 | |||
| 164 | /* Check if the pages in destination block is still sequential. */ | ||
| 165 |
2/2✓ Branch 18 → 19 taken 2530 times.
✓ Branch 18 → 20 taken 62600 times.
|
65130 | if (destination_page != ((logical_sector + i) % nand_flash -> lx_nand_flash_pages_per_block)) |
| 166 | { | ||
| 167 | /* Mark the block status as non sequential. */ | ||
| 168 | 2530 | dest_block_status |= LX_NAND_BLOCK_STATUS_NON_SEQUENTIAL; | |
| 169 | } | ||
| 170 | |||
| 171 | /* Update the available pages. */ | ||
| 172 | 65130 | destination_page++; | |
| 173 | |||
| 174 | /* Check if available page count reaches pages per block. */ | ||
| 175 |
2/2✓ Branch 20 → 21 taken 50 times.
✓ Branch 20 → 22 taken 65080 times.
|
65130 | if (destination_page == nand_flash -> lx_nand_flash_pages_per_block) |
| 176 | { | ||
| 177 | |||
| 178 | /* Set block full flag. */ | ||
| 179 | 50 | dest_block_status |= LX_NAND_BLOCK_STATUS_FULL; | |
| 180 | } | ||
| 181 | } | ||
| 182 | 65140 | break; | |
| 183 | } | ||
| 184 | } | ||
| 185 | } | ||
| 186 | } | ||
| 187 | else | ||
| 188 | { | ||
| 189 | |||
| 190 | /* Get the source page number. */ | ||
| 191 | 22220 | source_page = (LONG)(logical_sector % nand_flash -> lx_nand_flash_pages_per_block); | |
| 192 | |||
| 193 | /* Check if the page to copy is greater than the available pages. */ | ||
| 194 | 44440 | number_of_pages = ((ULONG)source_page + sectors) > available_pages ? | |
| 195 |
1/4✗ Branch 27 → 28 not taken.
✓ Branch 27 → 32 taken 22220 times.
✗ Branch 28 → 29 not taken.
✗ Branch 28 → 30 not taken.
|
22220 | (available_pages > (ULONG)source_page ? available_pages - (ULONG)source_page : 0) : sectors; |
| 196 | |||
| 197 | /* Check if there is any pages to be copied. */ | ||
| 198 |
2/2✓ Branch 33 → 34 taken 22180 times.
✓ Branch 33 → 42 taken 40 times.
|
22220 | if (number_of_pages) |
| 199 | { | ||
| 200 | |||
| 201 | /* Call the driver to copy pages. */ | ||
| 202 | #ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE | ||
| 203 | 2218 | status = (nand_flash -> lx_nand_flash_driver_pages_copy)(nand_flash, source_block, (ULONG)source_page, destination_block, destination_page, number_of_pages, nand_flash -> lx_nand_flash_page_buffer); | |
| 204 | #else | ||
| 205 | 19962 | status = (nand_flash -> lx_nand_flash_driver_pages_copy)(source_block, (ULONG)source_page, destination_block, destination_page, number_of_pages, nand_flash -> lx_nand_flash_page_buffer); | |
| 206 | #endif | ||
| 207 | |||
| 208 | /* Check for an error from flash driver. */ | ||
| 209 |
1/2✗ Branch 35 → 36 not taken.
✓ Branch 35 → 38 taken 22180 times.
|
22180 | if (status) |
| 210 | { | ||
| 211 | |||
| 212 | /* Call system error handler. */ | ||
| 213 | ✗ | _lx_nand_flash_system_error(nand_flash, status, source_block, 0); | |
| 214 | |||
| 215 | /* Return an error. */ | ||
| 216 | ✗ | return(LX_ERROR); | |
| 217 | } | ||
| 218 | |||
| 219 | /* Check if the pages in destination block is still sequential. */ | ||
| 220 |
2/2✓ Branch 38 → 39 taken 10 times.
✓ Branch 38 → 40 taken 22170 times.
|
22180 | if ((ULONG)source_page != destination_page) |
| 221 | { | ||
| 222 | |||
| 223 | /* Mark the block status as non sequential. */ | ||
| 224 | 10 | dest_block_status |= LX_NAND_BLOCK_STATUS_NON_SEQUENTIAL; | |
| 225 | } | ||
| 226 | |||
| 227 | /* Update the available pages. */ | ||
| 228 | 22180 | destination_page += number_of_pages; | |
| 229 | |||
| 230 | /* Check if available page count reaches pages per block. */ | ||
| 231 |
2/2✓ Branch 40 → 41 taken 11070 times.
✓ Branch 40 → 42 taken 11110 times.
|
22180 | if (destination_page == nand_flash -> lx_nand_flash_pages_per_block) |
| 232 | { | ||
| 233 | |||
| 234 | /* Set block full flag. */ | ||
| 235 | 11070 | dest_block_status |= LX_NAND_BLOCK_STATUS_FULL; | |
| 236 | } | ||
| 237 | } | ||
| 238 | } | ||
| 239 | |||
| 240 | /* Return the block status. */ | ||
| 241 | 22780 | *dest_block_status_ptr = (USHORT)(destination_page | (dest_block_status & ~LX_NAND_BLOCK_STATUS_PAGE_NUMBER_MASK)); | |
| 242 | |||
| 243 | /* Return status. */ | ||
| 244 | 22780 | return(status); | |
| 245 | } | ||
| 246 | |||
| 247 |